nfs-ganesha 1.4

posixdb_internal.c

Go to the documentation of this file.
00001 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
00002  * vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 #ifdef HAVE_CONFIG_H
00005 #include "config.h"
00006 #endif
00007 #include <string.h>
00008 #include "posixdb_internal.h"
00009 #include "posixdb_consistency.h"
00010 #include "RW_Lock.h"
00011 
00012 /* cyclic cache of paths */
00013 
00014 typedef struct cache_path_entry__
00015 {
00016   int is_set;
00017   int path_is_set;
00018   int info_is_set;
00019   posixfsal_handle_t handle;
00020   fsal_path_t path;
00021   rw_lock_t entry_lock;
00022 
00023 } cache_path_entry_t;
00024 
00025 #define CACHE_PATH_SIZE 509     /* prime near 512 */
00026 
00027 int fsal_posixdb_cache_init()
00028 {
00029 #ifdef _ENABLE_CACHE_PATH
00030   unsigned int i;
00031 
00032   memset((char *)cache_array, 0, CACHE_PATH_SIZE * sizeof(cache_path_entry_t));
00033 
00034   for(i = 0; i < CACHE_PATH_SIZE; i++)
00035     {
00036       if(rw_lock_init(&cache_array[i].entry_lock))
00037         return -1;
00038 
00039       cache_array[i].is_set = 0;
00040       cache_array[i].path_is_set = 0;
00041       cache_array[i].info_is_set = 0;
00042     }
00043 
00044 #endif
00045   return 0;
00046 }
00047 
00048 /* @todo pour augmenter les performances d'acces au cache,
00049  * on hash le handle, et on considere qu'un seul element
00050  * ayant un hash donne peut occuper une case du tableau.
00051  */
00052 
00053 void fsal_posixdb_CachePath(posixfsal_handle_t * p_handle,      /* IN */
00054                             fsal_path_t * p_path /* IN */ )
00055 {
00056 
00057 #ifdef _ENABLE_CACHE_PATH
00058 
00059   unsigned int i;
00060 
00061   LogDebug(COMPONENT_FSAL, "fsal_posixdb_CachePath: %u, %u = %s", (unsigned int)(p_handle->id),
00062            (unsigned int)(p_handle->ts), p_path->path);
00063 
00064   i = hash_cache_path(p_handle->id, p_handle->ts);
00065 
00066   /* in the handle already in cache ? */
00067   P_w(&cache_array[i].entry_lock);
00068 
00069   if(cache_array[i].is_set
00070      && cache_array[i].handle.id == p_handle->id
00071      && cache_array[i].handle.ts == p_handle->ts)
00072     {
00073       cache_array[i].path_is_set = TRUE;
00074 
00075       /* override it */
00076       cache_array[i].path = *p_path;
00077 
00078       V_w(&cache_array[i].entry_lock);
00079       return;
00080     }
00081 
00082   /* add it (replace previous handle) */
00083   cache_array[i].is_set = TRUE;
00084   cache_array[i].path_is_set = TRUE;
00085   cache_array[i].info_is_set = FALSE;
00086   cache_array[i].handle = *p_handle;
00087   cache_array[i].path = *p_path;
00088   V_w(&cache_array[i].entry_lock);
00089 
00090 #endif
00091   return;
00092 }
00093 
00094 /* set/update informations about a handle */
00095 int fsal_posixdb_UpdateInodeCache(posixfsal_handle_t * p_handle)        /* IN */
00096 {
00097 #ifdef _ENABLE_CACHE_PATH
00098 
00099   unsigned int i;
00100 
00101   LogDebug(COMPONENT_FSAL, "UpdateInodeCache: inode_id=%llu", p_handle->info.inode);
00102 
00103   i = hash_cache_path(p_handle->id, p_handle->ts);
00104 
00105   /* in the handle in cache ? */
00106   P_w(&cache_array[i].entry_lock);
00107 
00108   if(cache_array[i].is_set
00109      && cache_array[i].handle.id == p_handle->id
00110      && cache_array[i].handle.ts == p_handle->ts)
00111     {
00112       /* update its inode info */
00113       cache_array[i].handle.info = p_handle->info;
00114       cache_array[i].info_is_set = TRUE;
00115 
00116       LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (existing entry)",
00117                (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts));
00118 
00119       V_w(&cache_array[i].entry_lock);
00120 
00121       return TRUE;
00122     }
00123   LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (new entry)",
00124            (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts));
00125 
00126   /* add it (replace previous handle) */
00127   cache_array[i].is_set = TRUE;
00128   cache_array[i].path_is_set = FALSE;
00129   cache_array[i].info_is_set = TRUE;
00130   cache_array[i].handle = *p_handle;
00131   memset(&cache_array[i].path, 0, sizeof(fsal_path_t));
00132 
00133   V_w(&cache_array[i].entry_lock);
00134 #endif
00135   return FALSE;
00136 
00137 }
00138 
00139 /* retrieve last informations about a handle */
00140 int fsal_posixdb_GetInodeCache(posixfsal_handle_t * p_handle)   /* IN/OUT */
00141 {
00142 #ifdef _ENABLE_CACHE_PATH
00143   unsigned int i;
00144 
00145   i = hash_cache_path(p_handle->id, p_handle->ts);
00146 
00147   /* in the handle in cache ? */
00148   P_r(&cache_array[i].entry_lock);
00149   if(cache_array[i].is_set
00150      && cache_array[i].handle.id == p_handle->id
00151      && cache_array[i].handle.ts == p_handle->ts)
00152     {
00153       if(cache_array[i].info_is_set)
00154         {
00155           p_handle->info = cache_array[i].handle.info;
00156 
00157           LogDebug(COMPONENT_FSAL, "fsal_posixdb_GetInodeCache(%u, %u)", (unsigned int)(p_handle->id),
00158                    (unsigned int)(p_handle->ts));
00159           V_r(&cache_array[i].entry_lock);
00160 
00161           return TRUE;
00162         }
00163     }
00164   V_r(&cache_array[i].entry_lock);
00165 #endif
00166   return FALSE;
00167 
00168 }
00169 
00170 void fsal_posixdb_InvalidateCache()
00171 {
00172 #ifdef _ENABLE_CACHE_PATH
00173   unsigned int i;
00174 
00175   LogDebug(COMPONENT_FSAL, "fsal_posixdb_InvalidateCache");
00176 
00177   for(i = 0; i < CACHE_PATH_SIZE; i++)
00178     {
00179       P_w(&cache_array[i].entry_lock);
00180       cache_array[i].is_set = FALSE;
00181       cache_array[i].path_is_set = FALSE;
00182       cache_array[i].info_is_set = FALSE;
00183       cache_array[i].handle.id = 0;
00184       cache_array[i].handle.ts = 0;
00185       V_w(&cache_array[i].entry_lock);
00186     }
00187 
00188 #endif
00189 }
00190 
00191 int fsal_posixdb_GetPathCache(posixfsal_handle_t * p_handle,    /* IN */
00192                               fsal_path_t * p_path /* OUT */ )
00193 {
00194 #ifdef _ENABLE_CACHE_PATH
00195 
00196   unsigned int i;
00197 
00198   i = hash_cache_path(p_handle->id, p_handle->ts);
00199 
00200   /* in the handle in cache ? */
00201   P_r(&cache_array[i].entry_lock);
00202   if(cache_array[i].is_set
00203      && cache_array[i].handle.id == p_handle->id
00204      && cache_array[i].handle.ts == p_handle->ts)
00205     {
00206       if(cache_array[i].path_is_set)
00207         {
00208           /* return path it */
00209           memcpy(p_path, &cache_array[i].path, sizeof(fsal_path_t));
00210           V_r(&cache_array[i].entry_lock);
00211 
00212           LogDebug(COMPONENT_FSAL, "fsal_posixdb_GetPathCache(%u, %u)=%s",
00213                    (unsigned int)p_handle->id, (unsigned int)p_handle->ts,
00214                    p_path->path);
00215           return TRUE;
00216         }
00217     }
00218   V_r(&cache_array[i].entry_lock);
00219 #endif
00220   return FALSE;
00221 }
00222 
00223 fsal_posixdb_status_t mysql_error_convert(int err)
00224 {
00225   switch (err)
00226     {
00227     case 0:
00228       ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00229     case ER_NO_SUCH_TABLE:
00230       ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, err);
00231     case ER_DUP_ENTRY:
00232       ReturnCodeDB(ERR_FSAL_POSIXDB_CONSISTENCY, err);
00233     case ER_BAD_FIELD_ERROR:
00234     case ER_PARSE_ERROR:
00235       LogCrit(COMPONENT_FSAL, "SQL request parse error or invalid field");
00236       ReturnCodeDB(ERR_FSAL_POSIXDB_CMDFAILED, err);
00237     default:
00238       LogMajor(COMPONENT_FSAL,
00239                       "Unhandled error %d: default conversion to ERR_FSAL_POSIXDB_CMDFAILED",
00240                       err);
00241       ReturnCodeDB(ERR_FSAL_POSIXDB_CMDFAILED, err);
00242     }
00243 }
00244 
00245 int db_is_retryable(int sql_err)
00246 {
00247   switch (sql_err)
00248     {
00249     case ER_SERVER_SHUTDOWN:
00250     case CR_CONNECTION_ERROR:
00251     case CR_SERVER_GONE_ERROR:
00252     case CR_SERVER_LOST:
00253       return TRUE;
00254     default:
00255       return FALSE;
00256     }
00257 }
00258 
00259 fsal_posixdb_status_t db_exec_sql(fsal_posixdb_conn * conn, const char *query,
00260                                   result_handle_t * p_result)
00261 {
00262   int rc;
00263   /* TODO manage retry period */
00264 /*    unsigned int   retry = lmgr_config.connect_retry_min; */
00265   unsigned int retry = 1;
00266 
00267   LogFullDebug(COMPONENT_FSAL, "SQL query: %s", query);
00268 
00269   do
00270     {
00271       rc = mysql_real_query(&conn->db_conn, query, strlen(query));
00272 
00273       if(rc && db_is_retryable(mysql_errno(&conn->db_conn)))
00274         {
00275           LogMajor(COMPONENT_FSAL, "Connection to database lost... Retrying in %u sec.",
00276                    retry);
00277           sleep(retry);
00278           retry *= 2;
00279           /*if ( retry > lmgr_config.connect_retry_max )
00280              retry = lmgr_config.connect_retry_max; */
00281         }
00282 
00283     }
00284   while(rc && db_is_retryable(mysql_errno(&conn->db_conn)));
00285 
00286   if(rc)
00287     {
00288       LogMajor(COMPONENT_FSAL, "DB request failed: %s (query: %s)",
00289                mysql_error(&conn->db_conn), query);
00290       return mysql_error_convert(mysql_errno(&conn->db_conn));
00291     }
00292   else
00293     {
00294       if(p_result)
00295         *p_result = mysql_store_result(&conn->db_conn);
00296 
00297       ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00298     }
00299 }
00300 
00301 fsal_posixdb_status_t fsal_posixdb_buildOnePath(fsal_posixdb_conn * p_conn,
00302                                                 posixfsal_handle_t * p_handle,
00303                                                 fsal_path_t * p_path)
00304 {
00305   unsigned int shift;
00306   char *new_pos;
00307   int toomanypaths = 0;
00308 
00309   MYSQL_BIND input[2];          /* input = id, timestamp */
00310 
00311   const int output_num = 3;
00312   MYSQL_BIND output[output_num];        /* output = path, id, timestamp */
00313   my_bool is_null[output_num];
00314   unsigned long length[output_num];
00315   my_bool error[output_num];
00316 
00317   unsigned long long last_id;
00318   unsigned int last_ts;
00319   unsigned long long id;
00320   unsigned int ts;
00321 
00322   char name[FSAL_MAX_NAME_LEN];
00323   int root_reached = FALSE;
00324   MYSQL_STMT *stmt;
00325   int rc;
00326 
00327   memset(output, 0, sizeof(MYSQL_BIND) * output_num);
00328   memset(is_null, 0, sizeof(my_bool) * output_num);
00329   memset(length, 0, sizeof(unsigned long) * output_num);
00330   memset(error, 0, sizeof(my_bool) * output_num);
00331 
00332   if(!p_conn || !p_handle || !p_path)
00333     {
00334       ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00335     }
00336 
00337   stmt = p_conn->stmt_tab[BUILDONEPATH];
00338 
00339   /* init values */
00340   memset(p_path, 0, sizeof(fsal_path_t));
00341 
00342   /* Nothing to do, it's the root path */
00343   if(p_handle->data.id == 0 && p_handle->data.ts == 0)
00344     ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00345 
00346   /* check if the entry is in the cache */
00347   if(fsal_posixdb_GetPathCache(p_handle, p_path))
00348     ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00349 
00350   last_id = p_handle->data.id;
00351   last_ts = p_handle->data.ts;
00352 
00353   /* Bind input parameters */
00354 
00355   input[0].buffer_type = MYSQL_TYPE_LONGLONG;
00356   input[0].buffer = (char *)&last_id;
00357   input[0].is_null = (my_bool *) 0;
00358   input[0].is_unsigned = 1;
00359   input[0].length = NULL;
00360 
00361   input[1].buffer_type = MYSQL_TYPE_LONG;
00362   input[1].buffer = (char *)&last_ts;
00363   input[1].is_null = (my_bool *) 0;
00364   input[1].is_unsigned = 1;
00365   input[1].length = NULL;
00366 
00367   if(mysql_stmt_bind_param(stmt, input))
00368     {
00369       LogCrit(COMPONENT_FSAL, "mysql_stmt_bind_param() failed: %s", mysql_stmt_error(stmt));
00370       return mysql_error_convert(mysql_stmt_errno(stmt));
00371     }
00372 
00373   /* Bind output values */
00374 
00375   output[0].buffer_type = MYSQL_TYPE_STRING;
00376   output[0].buffer = (char *)name;
00377   output[0].buffer_length = FSAL_MAX_NAME_LEN;
00378   output[0].is_null = &is_null[0];
00379   output[0].length = &length[0];
00380   output[0].error = &error[0];
00381 
00382   output[1].buffer_type = MYSQL_TYPE_LONGLONG;
00383   output[1].buffer = (char *)&id;
00384   output[1].is_unsigned = 1;
00385   output[1].is_null = &is_null[1];
00386   output[1].length = &length[1];
00387   output[1].error = &error[1];
00388 
00389   output[2].buffer_type = MYSQL_TYPE_LONG;
00390   output[2].buffer = (char *)&ts;
00391   output[2].is_unsigned = 1;
00392   output[2].is_null = &is_null[2];
00393   output[2].length = &length[2];
00394   output[2].error = &error[2];
00395 
00396   if(mysql_stmt_bind_result(stmt, output))
00397     {
00398       LogCrit(COMPONENT_FSAL, "mysql_stmt_bind_result() failed: %s", mysql_stmt_error(stmt));
00399       return mysql_error_convert(mysql_stmt_errno(stmt));
00400     }
00401 
00402   root_reached = FALSE;
00403 
00404   while(!root_reached)
00405     {
00406 
00407       rc = mysql_stmt_execute(stmt);
00408       if(rc)
00409         return mysql_error_convert(mysql_stmt_errno(stmt));
00410 
00411       if(mysql_stmt_store_result(stmt))
00412         {
00413           LogCrit(COMPONENT_FSAL, "mysql_stmt_store_result() failed: %s", mysql_stmt_error(stmt));
00414           return mysql_error_convert(mysql_stmt_errno(stmt));
00415         }
00416 
00417       /* retrieve result */
00418       rc = mysql_stmt_fetch(stmt);
00419       if(rc == MYSQL_NO_DATA)
00420         {
00421           /* clean prepared statement */
00422           mysql_stmt_free_result(stmt);
00423           ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);      /* not found */
00424         }
00425       else if(rc)
00426         {
00427           /* clean prepared statement */
00428           mysql_stmt_free_result(stmt);
00429           LogCrit(COMPONENT_FSAL, "mysql_stmt_fetch() failed: %s", mysql_stmt_error(stmt));
00430           return mysql_error_convert(mysql_stmt_errno(stmt));
00431         }
00432 
00433       /* @TODO check if several results are returned */
00434 
00435       if((id == last_id) && (ts == last_ts))    /* handle is equal to its parent handle (root reached) */
00436         {
00437           root_reached = TRUE;
00438           break;
00439         }
00440 
00441       /* prepare next step */
00442       last_id = id;
00443       last_ts = ts;
00444 
00445       /* insert the name at the beginning of the path */
00446       shift = strlen(name);
00447       if(p_path->len + shift >= FSAL_MAX_PATH_LEN)
00448         ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0);
00449       new_pos = p_path->path + shift;
00450       memmove(new_pos, p_path->path, p_path->len);
00451       memcpy(p_path->path, name, shift);
00452       p_path->len += shift;
00453     }
00454 
00455   /* clean prepared statement */
00456   mysql_stmt_free_result(stmt);
00457 
00458   if(toomanypaths)
00459     {
00460       LogCrit(COMPONENT_FSAL, "Returned path: %s", p_path->path);
00461       ReturnCodeDB(ERR_FSAL_POSIXDB_TOOMANYPATHS, toomanypaths);        /* too many entries */
00462     }
00463   else
00464     {
00465       /* set result in cache and return */
00466       fsal_posixdb_CachePath(p_handle, p_path);
00467 
00468       ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00469     }
00470 }
00471 
00472 fsal_posixdb_status_t fsal_posixdb_recursiveDelete(fsal_posixdb_conn * p_conn,
00473                                                    unsigned long long id, unsigned int ts,
00474                                                    fsal_nodetype_t ftype)
00475 {
00476   fsal_posixdb_status_t st;
00477   fsal_nodetype_t ftype_tmp;
00478   char query[2048];
00479   result_handle_t res;
00480   MYSQL_ROW row;
00481 
00482   /* Sanity check */
00483   if(!p_conn)
00484     {
00485       ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00486     }
00487 
00488   if(ftype == FSAL_TYPE_DIR)
00489     {
00490       /* find all the children of the directory in order to delete them, and then we delete the current handle */
00491 
00492       snprintf(query, 2048,
00493                "SELECT Handle.handleid, Handle.handlets, Handle.ftype, Parent.name, Handle.nlink "
00494                "FROM Parent INNER JOIN Handle ON Handle.handleid=Parent.handleid "
00495                "AND Handle.handlets=Parent.handlets "
00496                "WHERE Parent.handleidparent=%llu AND Parent.handletsparent=%u "
00497                "AND NOT (Parent.handleidparent = Parent.handleid AND Parent.handletsparent = Parent.handlets) "
00498                "FOR UPDATE", id, ts);
00499       st = db_exec_sql(p_conn, query, &res);
00500       if(FSAL_POSIXDB_IS_ERROR(st))
00501         return st;
00502 
00503       while((row = mysql_fetch_row(res)) != NULL)
00504         {
00505           ftype_tmp = (fsal_nodetype_t) atoi(row[2]);
00506           if(ftype_tmp == FSAL_TYPE_DIR)
00507             {
00508               st = fsal_posixdb_recursiveDelete(p_conn, atoll(row[0]), atoi(row[1]),
00509                                                 ftype_tmp);
00510             }
00511           else
00512             {
00513               st = fsal_posixdb_deleteParent(p_conn, atoll(row[0]),     /* handleidparent */
00514                                              atoi(row[1]),      /* handletsparent */
00515                                              id, ts, row[3],    /* filename */
00516                                              atoi(row[4]));     /* nlink */
00517             }
00518           if(FSAL_POSIXDB_IS_ERROR(st))
00519             {
00520               mysql_free_result(res);
00521               return st;
00522             }
00523         }
00524       mysql_free_result(res);
00525     }
00526 
00527   /* invalidate name cache */
00528   fsal_posixdb_InvalidateCache();
00529 
00530   /* Delete the Handle (this also delete entries in Parent, thanks to DELETE CASCADE) */
00531   snprintf(query, 2048, "DELETE FROM Handle WHERE handleid=%llu AND handlets=%u", id, ts);
00532 
00533   st = db_exec_sql(p_conn, query, NULL);
00534   if(FSAL_POSIXDB_IS_ERROR(st))
00535     return st;
00536 
00537 #ifdef _NO_DELETE_CASCADE
00538   /* Delete this handle from parent table (it is supposed not having children now) */
00539 
00540   snprintf(query, 2048, "DELETE FROM Parent WHERE (handleid=%llu AND handlets=%u)", id,
00541            ts);
00542 
00543   st = db_exec_sql(p_conn, query, NULL);
00544   if(FSAL_POSIXDB_IS_ERROR(st))
00545     return st;
00546 #endif
00547 
00548   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00549 }
00550 
00551 fsal_posixdb_status_t fsal_posixdb_deleteParent(fsal_posixdb_conn * p_conn,     /* IN */
00552                                                 unsigned long long id,  /* IN */
00553                                                 unsigned int ts,        /* IN */
00554                                                 unsigned long long idparent,    /* IN */
00555                                                 unsigned int tsparent,  /* IN */
00556                                                 char *filename, /* IN */
00557                                                 int nlink)      /* IN */
00558 {
00559   char query[1024];
00560   fsal_posixdb_status_t st;
00561 
00562   /* Sanity check */
00563   if(!p_conn || !filename || nlink < 1)
00564     {
00565       ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00566     }
00567 
00568   snprintf(query, 1024,
00569            "DELETE FROM Parent WHERE handleidparent=%llu AND handletsparent=%u AND name='%s'",
00570            idparent, tsparent, filename);
00571   st = db_exec_sql(p_conn, query, NULL);
00572   if(FSAL_POSIXDB_IS_ERROR(st))
00573     return st;
00574 
00575   /* delete the handle or update it */
00576   if(nlink == 1)
00577     {
00578 
00579       /* invalidate cache */
00580       fsal_posixdb_InvalidateCache();
00581 
00582       /* delete the handle */
00583 
00584       snprintf(query, 1024, "DELETE FROM Handle WHERE handleid=%llu AND handlets=%u", id,
00585                ts);
00586       st = db_exec_sql(p_conn, query, NULL);
00587       if(FSAL_POSIXDB_IS_ERROR(st))
00588         return st;
00589 
00590 #ifdef _NO_DELETE_CASCADE
00591       /* Delete from parent table */
00592 
00593       snprintf(query, 1024, "DELETE FROM Parent WHERE handleid=%llu AND handlets=%u", id,
00594                ts);
00595       st = db_exec_sql(p_conn, query, NULL);
00596       if(FSAL_POSIXDB_IS_ERROR(st))
00597         return st;
00598 #endif
00599 
00600     }
00601   else
00602     {
00603       /* invalidate cache */
00604       fsal_posixdb_InvalidateCache();
00605 
00606       /* update the Handle entry ( Handle.nlink <- (nlink - 1) ) */
00607       snprintf(query, 1024,
00608                "UPDATE Handle SET nlink=%u WHERE handleid=%llu AND handlets=%u",
00609                nlink - 1, id, ts);
00610       st = db_exec_sql(p_conn, query, NULL);
00611       if(FSAL_POSIXDB_IS_ERROR(st))
00612         return st;
00613     }
00614 
00615   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00616 }
00617 
00618 fsal_posixdb_status_t fsal_posixdb_internal_delete(fsal_posixdb_conn * p_conn,  /* IN */
00619                                                    unsigned long long idparent, /* IN */
00620                                                    unsigned int tsparent,       /* IN */
00621                                                    char *filename,      /* IN */
00622                                                    fsal_posixdb_fileinfo_t *
00623                                                    p_object_info /* IN */ )
00624 {
00625   unsigned long long id;
00626   unsigned int ts;
00627   char query[2048];
00628 
00629   fsal_posixdb_status_t st;
00630   fsal_posixdb_fileinfo_t infodb;
00631   result_handle_t res;
00632   MYSQL_ROW row;
00633 
00634   if(!p_conn || !filename)
00635     ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00636 
00637   snprintf(query, 2048,
00638            "SELECT Parent.handleid, Parent.handlets, Handle.deviceid, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype "
00639            "FROM Parent INNER JOIN Handle ON Parent.handleid = Handle.handleid AND Parent.handlets=Handle.handlets "
00640            "WHERE handleidparent=%llu AND handletsparent=%u AND name='%s' "
00641            "FOR UPDATE", idparent, tsparent, filename);
00642 
00643   st = db_exec_sql(p_conn, query, &res);
00644   if(FSAL_POSIXDB_IS_ERROR(st))
00645     return st;
00646 
00647   /* result contains : handleid, handlets, deviceId, inode, nlink, ctime, ftype  */
00648 
00649   /* no entry found */
00650   if((mysql_num_rows(res) < 1) || ((row = mysql_fetch_row(res)) == NULL))
00651     {
00652       mysql_free_result(res);
00653       ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);
00654     }
00655 
00656   id = atoll(row[0]);
00657   ts = atoi(row[1]);
00658 
00659   /* consistency check */
00660   /* fill 'infodb' with information about the handle in the database */
00661   /* no need to compare inode & devid, they are the same */
00662   posixdb_internal_fillFileinfoFromStrValues(&infodb, row[2], row[3], row[4], row[5],
00663                                              row[6]);
00664   mysql_free_result(res);
00665 
00666   if(p_object_info && fsal_posixdb_consistency_check(&infodb, p_object_info))
00667     {
00668       /* not consistent, the bad handle have to be deleted */
00669       LogCrit(COMPONENT_FSAL, "Consistency check failed while deleting a Path : Handle deleted");
00670       infodb.ftype = FSAL_TYPE_DIR;     /* considers that the entry is a directory in order to delete all its Parent entries and its Handle */
00671     }
00672 
00673   switch (infodb.ftype)
00674     {
00675     case FSAL_TYPE_DIR:
00676       /* directory */
00677       st = fsal_posixdb_recursiveDelete(p_conn, id, ts, infodb.ftype);
00678       break;
00679     default:
00680       st = fsal_posixdb_deleteParent(p_conn,
00681                                      id, ts, idparent, tsparent, filename, infodb.nlink);
00682     }
00683   return st;
00684 }
00685 
00686 fsal_posixdb_status_t posixdb_internal_fillFileinfoFromStrValues(fsal_posixdb_fileinfo_t *
00687                                                                  p_info, char *devid_str,
00688                                                                  char *inode_str,
00689                                                                  char *nlink_str,
00690                                                                  char *ctime_str,
00691                                                                  char *ftype_str)
00692 {
00693 
00694   if(!p_info)
00695     ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00696 
00697   p_info->devid = devid_str ? (dev_t) atoll(devid_str) : 0;
00698   p_info->inode = inode_str ? (ino_t) atoll(inode_str) : 0;
00699   p_info->nlink = nlink_str ? atoi(nlink_str) : 0;
00700   p_info->ctime = ctime_str ? (time_t) atoi(ctime_str) : 0;
00701   p_info->ftype = ftype_str ? (fsal_nodetype_t) atoi(ftype_str) : 0;
00702 
00703   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00704 }