nfs-ganesha 1.4

posixdb_replace.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include "posixdb_internal.h"
00006 #include "posixdb_consistency.h"
00007 #include <string.h>
00008 
00009 fsal_posixdb_status_t fsal_posixdb_replace(fsal_posixdb_conn * p_conn,  /* IN */
00010                                            fsal_posixdb_fileinfo_t * p_object_info,     /* IN */
00011                                            posixfsal_handle_t * p_parent_directory_handle_old,  /* IN */
00012                                            fsal_name_t * p_filename_old,        /* IN */
00013                                            posixfsal_handle_t * p_parent_directory_handle_new,  /* IN */
00014                                            fsal_name_t * p_filename_new /* IN */ )
00015 {
00016   PGresult *p_res;
00017   char handleidparentold_str[MAX_HANDLEIDSTR_SIZE];
00018   char handletsparentold_str[MAX_HANDLETSSTR_SIZE];
00019   char handleidparentnew_str[MAX_HANDLEIDSTR_SIZE];
00020   char handletsparentnew_str[MAX_HANDLETSSTR_SIZE];
00021   const char *paramValues[6];
00022   const char *paramValuesL[3];
00023   fsal_posixdb_status_t st;
00024 
00025   /*******************
00026    * 1/ sanity check *
00027    *******************/
00028 
00029   if(!p_conn || !p_object_info || !p_parent_directory_handle_old || !p_filename_old
00030      || !p_parent_directory_handle_new || !p_filename_new)
00031     ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00032 
00033   CheckConn(p_conn);
00034 
00035   BeginTransaction(p_conn, p_res);
00036 
00037   /**************************************************************************
00038    * 2/ check that 'p_filename_old' exists in p_parent_directory_handle_old *
00039    **************************************************************************/
00040 
00041   /* 
00042      There are three cases :
00043      * the entry do not exists -> return an error (NOENT)
00044      * the entry exists.
00045      * the entry exists but its information are not consistent with p_object_info -> return an error (CONSISTENCY)
00046    */
00047   /* uses paramValues[0] & paramValues[1] from the last request */
00048   snprintf(handleidparentold_str, MAX_HANDLEIDSTR_SIZE, "%lli",
00049            p_parent_directory_handle_old->data.id);
00050   snprintf(handletsparentold_str, MAX_HANDLETSSTR_SIZE, "%i",
00051            p_parent_directory_handle_old->data.ts);
00052   paramValues[0] = handleidparentold_str;
00053   paramValues[1] = handletsparentold_str;
00054   paramValues[2] = p_filename_old->name;
00055 
00056   /* check if info is in cache or if this info is inconsistent */
00057   if(!fsal_posixdb_GetInodeCache(p_parent_directory_handle_old)
00058      || fsal_posixdb_consistency_check(&(p_parent_directory_handle_old->data.info),
00059                                        p_object_info))
00060     {
00061 
00062       p_res = PQexecPrepared(p_conn, "lookupHandleByName", 3, paramValues, NULL, NULL, 0);
00063       CheckResult(p_res);
00064 
00065       if(PQntuples(p_res) != 1)
00066         {
00067           /* parent entry not found */
00068           PQclear(p_res);
00069           RollbackTransaction(p_conn, p_res);
00070           ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);
00071         }
00072 
00073       /* fill 'infodb' with information about the handle in the database */
00074       posixdb_internal_fillFileinfoFromStrValues(&(p_parent_directory_handle_old->data.info), PQgetvalue(p_res, 0, 2),       /* devid */
00075                                                  PQgetvalue(p_res, 0, 3),       /* inode */
00076                                                  PQgetvalue(p_res, 0, 4),       /* nlink */
00077                                                  PQgetvalue(p_res, 0, 5),       /* ctime */
00078                                                  PQgetvalue(p_res, 0, 6)        /* ftype */
00079           );
00080       /* check consistency */
00081 
00082       if(fsal_posixdb_consistency_check
00083          (&(p_parent_directory_handle_old->data.info), p_object_info))
00084         {
00085           LogCrit(COMPONENT_FSAL, "Consistency check failed while renaming a file : Handle deleted");
00086           st = fsal_posixdb_recursiveDelete(p_conn, PQgetvalue(p_res, 0, 0),
00087                                             PQgetvalue(p_res, 0, 1), FSAL_TYPE_DIR);
00088           PQclear(p_res);
00089           EndTransaction(p_conn, p_res);
00090           return st;
00091         }
00092 
00093       PQclear(p_res);
00094     }
00095 
00096   /**********************************************************************************
00097    * 3/ update the parent entry (in order to change its name and its parent handle) *
00098    **********************************************************************************/
00099 
00100   /*
00101      Different cases :
00102      * a line has been updated -> everything goes well.
00103      * no line has been updated -> the entry does not exists in the database. -> return NOENT (should never happen because of the previous check)
00104      * foreign key constraint violation -> new parentdir handle does not exists -> return NOENT
00105      * unique constraint violation -> there is already a file with this name in the directory -> replace it !
00106      PQresultErrorField( p_res, PG_DIAG_SQLSTATE ) -> "23503" pour foreign key violation et "23505" pour unique violation
00107      (cf http://docs.postgresqlfr.org/pgsql-8.1.3-fr/errcodes-appendix.html )
00108    */
00109   /* uses paramValues[0..2] from the last call */
00110   snprintf(handleidparentnew_str, MAX_HANDLEIDSTR_SIZE, "%lli",
00111            p_parent_directory_handle_new->data.id);
00112   snprintf(handletsparentnew_str, MAX_HANDLETSSTR_SIZE, "%i",
00113            p_parent_directory_handle_new->data.ts);
00114   paramValues[3] = handleidparentnew_str;
00115   paramValues[4] = handletsparentnew_str;
00116   paramValues[5] = p_filename_new->name;
00117 
00118   /* Remove target entry if it exists */
00119   paramValuesL[0] = handleidparentnew_str;
00120   paramValuesL[1] = handletsparentnew_str;
00121   paramValuesL[2] = p_filename_new->name;
00122 
00123   p_res = PQexecPrepared(p_conn, "lookupHandleByNameFU", 3, paramValuesL, NULL, NULL, 0);
00124 
00125   if(PQntuples(p_res) > 0)
00126     {
00127 
00128       st = fsal_posixdb_deleteParent(p_conn, PQgetvalue(p_res, 0, 0),
00129                                      PQgetvalue(p_res, 0, 1), handleidparentnew_str,
00130                                      handletsparentnew_str, p_filename_new->name,
00131                                      atoi(PQgetvalue(p_res, 0, 4)) /* nlink */ );
00132 
00133       if(FSAL_POSIXDB_IS_ERROR(st) && !FSAL_POSIXDB_IS_NOENT(st))
00134         {
00135           PQclear(p_res);
00136           RollbackTransaction(p_conn, p_res);
00137           return st;
00138         }
00139 
00140     }
00141   PQclear(p_res);
00142 
00143  update:
00144 
00145   /* invalidate name cache */
00146   fsal_posixdb_InvalidateCache();
00147 
00148   p_res = PQexecPrepared(p_conn, "updateParent", 6, paramValues, NULL, NULL, 0);
00149 
00150   if(PQresultStatus(p_res) == PGRES_COMMAND_OK)
00151     {
00152       if((PQcmdTuples(p_res) != NULL) && (atoi(PQcmdTuples(p_res)) == 1))
00153         {
00154           /* there was 1 update */
00155           st.major = ERR_FSAL_POSIXDB_NOERR;
00156           st.minor = 0;
00157         }
00158       else
00159         {
00160           /* no row updated */
00161           st.major = ERR_FSAL_POSIXDB_NOENT;
00162           st.minor = 0;
00163         }
00164     }
00165   else
00166     {
00167       /* error */
00168       const char *paramValuesL[3];
00169       char *resultError = PQresultErrorField(p_res, PG_DIAG_SQLSTATE);
00170       int sqlstate;
00171 
00172       if(resultError)
00173         sqlstate = atoi(resultError);
00174       else
00175         sqlstate = -1;
00176 
00177       PQclear(p_res);
00178 
00179       switch (sqlstate)
00180         {
00181 
00182         case 23503:
00183           /* Foreign key violation : new parentdir does not exist, do nothing */
00184           st.major = ERR_FSAL_POSIXDB_NOENT;
00185           st.minor = sqlstate;
00186           break;
00187 
00188         case 23505:
00189           /* Unique violation : there is already a file with the same name in parentdir_new */
00190           /* Delete the existing entry, and then do the update again */
00191           paramValuesL[0] = handleidparentnew_str;
00192           paramValuesL[1] = handletsparentnew_str;
00193           paramValuesL[2] = p_filename_new->name;
00194 
00195           p_res =
00196               PQexecPrepared(p_conn, "lookupHandleByNameFU", 3, paramValuesL, NULL, NULL,
00197                              0);
00198 
00199           CheckResult(p_res);
00200 
00201           if(PQntuples(p_res) > 0)
00202             {
00203 
00204               st = fsal_posixdb_deleteParent(p_conn, PQgetvalue(p_res, 0, 0),
00205                                              PQgetvalue(p_res, 0, 1),
00206                                              handleidparentnew_str, handletsparentnew_str,
00207                                              p_filename_new->name,
00208                                              atoi(PQgetvalue(p_res, 0, 4)) /* nlink */ );
00209 
00210               if(FSAL_POSIXDB_IS_ERROR(st) && !FSAL_POSIXDB_IS_NOENT(st))
00211                 {
00212                   PQclear(p_res);
00213                   break;
00214                 }
00215             }
00216 
00217           PQclear(p_res);
00218 
00219           /* the entry has been deleted, the update can now be done */
00220           goto update;
00221 
00222           break;
00223 
00224         default:
00225           st.major = ERR_FSAL_POSIXDB_CMDFAILED;
00226           st.minor = sqlstate;
00227         }
00228     }
00229 
00230   if(FSAL_POSIXDB_IS_ERROR(st))
00231     RollbackTransaction(p_conn, p_res);
00232   else
00233     EndTransaction(p_conn, p_res);
00234 
00235   return st;
00236 }