nfs-ganesha 1.4
|
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 }