nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 3 of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 */ 00025 00037 #ifdef HAVE_CONFIG_H 00038 #include "config.h" 00039 #endif 00040 00041 #ifdef _SOLARIS 00042 #include "solaris_port.h" 00043 #endif 00044 00045 #include <stdio.h> 00046 #include <string.h> 00047 #include <pthread.h> 00048 #include <fcntl.h> 00049 #include <sys/file.h> /* for having FNDELAY */ 00050 #include "HashData.h" 00051 #include "HashTable.h" 00052 #include "log.h" 00053 #include "ganesha_rpc.h" 00054 #include "nfs23.h" 00055 #include "nfs4.h" 00056 #include "mount.h" 00057 #include "nfs_core.h" 00058 #include "cache_inode.h" 00059 #include "nfs_exports.h" 00060 #include "nfs_creds.h" 00061 #include "nfs_proto_functions.h" 00062 #include "nfs_tools.h" 00063 #include "nfs_proto_tools.h" 00064 00084 int nfs_Rename(nfs_arg_t *parg, 00085 exportlist_t *pexport, 00086 fsal_op_context_t *pcontext, 00087 nfs_worker_data_t *pworker, 00088 struct svc_req *preq, 00089 nfs_res_t *pres) 00090 { 00091 char *str_entry_name = NULL; 00092 fsal_name_t entry_name; 00093 char *str_new_entry_name = NULL; 00094 fsal_name_t new_entry_name; 00095 cache_entry_t *parent_pentry = NULL; 00096 cache_entry_t *new_parent_pentry = NULL; 00097 cache_entry_t *should_not_exists = NULL; 00098 cache_entry_t *should_exists = NULL; 00099 cache_inode_status_t cache_status; 00100 fsal_attrib_list_t *ppre_attr; 00101 fsal_attrib_list_t pre_attr; 00102 fsal_attrib_list_t *pnew_pre_attr; 00103 fsal_attrib_list_t new_attr; 00104 fsal_attrib_list_t new_parent_attr; 00105 fsal_attrib_list_t attr; 00106 fsal_attrib_list_t tst_attr; 00107 cache_inode_file_type_t parent_filetype; 00108 cache_inode_file_type_t new_parent_filetype; 00109 int rc = NFS_REQ_OK; 00110 00111 if(isDebug(COMPONENT_NFSPROTO)) 00112 { 00113 char strto[LEN_FH_STR], strfrom[LEN_FH_STR]; 00114 00115 switch (preq->rq_vers) 00116 { 00117 case NFS_V2: 00118 str_entry_name = parg->arg_rename2.from.name; 00119 str_new_entry_name = parg->arg_rename2.to.name; 00120 break; 00121 00122 case NFS_V3: 00123 str_entry_name = parg->arg_rename3.from.name; 00124 str_new_entry_name = parg->arg_rename3.to.name; 00125 break; 00126 } 00127 00128 nfs_FhandleToStr(preq->rq_vers, 00129 &(parg->arg_rename2.from.dir), 00130 &(parg->arg_rename3.from.dir), 00131 NULL, 00132 strfrom); 00133 00134 nfs_FhandleToStr(preq->rq_vers, 00135 &(parg->arg_rename2.to.dir), 00136 &(parg->arg_rename3.to.dir), 00137 NULL, 00138 strto); 00139 LogDebug(COMPONENT_NFSPROTO, 00140 "REQUEST PROCESSING: Calling nfs_Rename from handle: %s name %s to handle: %s name: %s", 00141 strfrom, str_entry_name, strto, str_new_entry_name); 00142 } 00143 00144 if(preq->rq_vers == NFS_V3) 00145 { 00146 /* to avoid setting it on each error case */ 00147 pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.before.attributes_follow = FALSE; 00148 pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.after.attributes_follow = FALSE; 00149 pres->res_rename3.RENAME3res_u.resfail.todir_wcc.before.attributes_follow = FALSE; 00150 pres->res_rename3.RENAME3res_u.resfail.todir_wcc.after.attributes_follow = FALSE; 00151 ppre_attr = NULL; 00152 pnew_pre_attr = NULL; 00153 } 00154 00155 /* Convert fromdir file handle into a cache_entry */ 00156 if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, 00157 &(parg->arg_rename2.from.dir), 00158 &(parg->arg_rename3.from.dir), 00159 NULL, 00160 &(pres->res_dirop2.status), 00161 &(pres->res_create3.status), 00162 NULL, 00163 &pre_attr, pcontext, &rc)) == NULL) 00164 { 00165 /* Stale NFS FH ? */ 00166 goto out; 00167 } 00168 00169 /* Convert todir file handle into a cache_entry */ 00170 if((new_parent_pentry = nfs_FhandleToCache(preq->rq_vers, 00171 &(parg->arg_rename2.to.dir), 00172 &(parg->arg_rename3.to.dir), 00173 NULL, 00174 &(pres->res_dirop2.status), 00175 &(pres->res_create3.status), 00176 NULL, 00177 &new_parent_attr, 00178 pcontext, &rc)) == NULL) 00179 { 00180 /* Stale NFS FH ? */ 00181 goto out; 00182 } 00183 00184 /* get the attr pointers */ 00185 ppre_attr = &pre_attr; 00186 pnew_pre_attr = &new_parent_attr; 00187 00188 /* Get the filetypes */ 00189 parent_filetype = cache_inode_fsal_type_convert(pre_attr.type); 00190 new_parent_filetype = cache_inode_fsal_type_convert(new_parent_attr.type); 00191 00192 /* 00193 * Sanity checks: we must manage directories 00194 */ 00195 if((parent_filetype != DIRECTORY) || 00196 (new_parent_filetype != DIRECTORY)) 00197 { 00198 switch (preq->rq_vers) 00199 { 00200 case NFS_V2: 00201 pres->res_stat2 = NFSERR_NOTDIR; 00202 break; 00203 00204 case NFS_V3: 00205 pres->res_rename3.status = NFS3ERR_NOTDIR; 00206 break; 00207 } 00208 00209 rc = NFS_REQ_OK; 00210 goto out; 00211 } 00212 00213 switch (preq->rq_vers) 00214 { 00215 case NFS_V2: 00216 str_entry_name = parg->arg_rename2.from.name; 00217 str_new_entry_name = parg->arg_rename2.to.name; 00218 break; 00219 00220 case NFS_V3: 00221 str_entry_name = parg->arg_rename3.from.name; 00222 str_new_entry_name = parg->arg_rename3.to.name; 00223 break; 00224 } 00225 00226 if(str_entry_name == NULL || 00227 *str_entry_name == '\0' || 00228 str_new_entry_name == NULL || 00229 *str_new_entry_name == '\0' || 00230 FSAL_IS_ERROR(FSAL_str2name(str_entry_name, FSAL_MAX_NAME_LEN, &entry_name)) || 00231 FSAL_IS_ERROR(FSAL_str2name(str_new_entry_name, FSAL_MAX_NAME_LEN, &new_entry_name))) 00232 { 00233 cache_status = CACHE_INODE_INVALID_ARGUMENT; 00234 } 00235 else 00236 { 00237 /* 00238 * Lookup file to see if new entry exists 00239 * 00240 */ 00241 should_not_exists = cache_inode_lookup(new_parent_pentry, 00242 &new_entry_name, 00243 &tst_attr, 00244 pcontext, 00245 &cache_status); 00246 00247 if(cache_status == CACHE_INODE_NOT_FOUND) 00248 { 00249 /* We need to lookup over the old entry also */ 00250 should_exists = cache_inode_lookup(parent_pentry, 00251 &entry_name, 00252 &tst_attr, 00253 pcontext, 00254 &cache_status); 00255 00256 /* Rename entry */ 00257 if(cache_status == CACHE_INODE_SUCCESS) 00258 cache_inode_rename(parent_pentry, 00259 &entry_name, 00260 new_parent_pentry, 00261 &new_entry_name, 00262 &attr, &new_attr, 00263 pcontext, &cache_status); 00264 00265 if(cache_status == CACHE_INODE_SUCCESS) 00266 { 00267 switch (preq->rq_vers) 00268 { 00269 case NFS_V2: 00270 pres->res_stat2 = NFS_OK; 00271 break; 00272 00273 case NFS_V3: 00274 /* 00275 * Build Weak Cache Coherency 00276 * data 00277 */ 00278 nfs_SetWccData(pexport, 00279 ppre_attr, 00280 &attr, 00281 &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc)); 00282 00283 nfs_SetWccData(pexport, 00284 pnew_pre_attr, 00285 &new_attr, 00286 &(pres->res_rename3.RENAME3res_u.resok.todir_wcc)); 00287 00288 pres->res_rename3.status = NFS3_OK; 00289 break; 00290 00291 } 00292 00293 rc = NFS_REQ_OK; 00294 goto out; 00295 } 00296 } 00297 else 00298 { 00299 /* If name are the same (basically renaming a/file1 to a/file1, this is a non-erroneous situation to be managed */ 00300 if(new_parent_pentry == parent_pentry) 00301 { 00302 if(!FSAL_namecmp(&new_entry_name, &entry_name)) 00303 { 00304 /* trying to rename a file to himself, this is allowed */ 00305 cache_status = CACHE_INODE_SUCCESS; 00306 switch (preq->rq_vers) 00307 { 00308 case NFS_V2: 00309 pres->res_stat2 = NFS_OK; 00310 break; 00311 00312 case NFS_V3: 00313 /* 00314 * Build Weak Cache Coherency 00315 * data 00316 */ 00317 nfs_SetWccData(pexport, 00318 ppre_attr, 00319 &attr, 00320 &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc)); 00321 00322 nfs_SetWccData(pexport, 00323 ppre_attr, 00324 &attr, 00325 &(pres->res_rename3.RENAME3res_u.resok.todir_wcc)); 00326 00327 pres->res_rename3.status = NFS3_OK; 00328 break; 00329 00330 } 00331 00332 rc = NFS_REQ_OK; 00333 goto out; 00334 } 00335 00336 } 00337 00338 /* New entry already exists. In this case (see RFC), entry 00339 * should be compatible: Both are non-directories or both 00340 * are directories and 'todir' is empty. If compatible, old 00341 * 'todir' entry is scratched, if not returns EEXISTS */ 00342 if(should_not_exists != NULL) 00343 { 00344 /* We need to lookup over the old entry also */ 00345 if((should_exists = cache_inode_lookup(parent_pentry, 00346 &entry_name, 00347 &tst_attr, 00348 pcontext, 00349 &cache_status)) 00350 != NULL) 00351 { 00352 /* If pentry is the same for source and target, then 00353 * we are trying to rename a hard link to another 00354 * hard link with the same inode. This is a noop. */ 00355 if (should_not_exists == should_exists) 00356 { 00357 switch (preq->rq_vers) 00358 { 00359 case NFS_V2: 00360 pres->res_stat2 = NFS_OK; 00361 break; 00362 00363 case NFS_V3: 00364 /* 00365 * Build Weak Cache Coherency 00366 * data 00367 */ 00368 nfs_SetWccData(pexport, 00369 ppre_attr, 00370 ppre_attr, /* Attributes before and after will be unchanged. */ 00371 &(pres->res_rename3.RENAME3res_u.resok. 00372 fromdir_wcc)); 00373 00374 nfs_SetWccData(pexport, 00375 ppre_attr, 00376 ppre_attr, /* Attributes before and after will be unchanged. */ 00377 &(pres->res_rename3.RENAME3res_u.resok. 00378 todir_wcc)); 00379 00380 pres->res_rename3.status = NFS3_OK; 00381 break; 00382 00383 } 00384 00385 rc = NFS_REQ_OK; 00386 goto out; 00387 } 00388 00389 if(cache_inode_types_are_rename_compatible 00390 (should_exists, should_not_exists)) 00391 { 00392 /* Remove the old entry before renaming it */ 00393 if(cache_inode_remove(new_parent_pentry, 00394 &new_entry_name, 00395 &tst_attr, 00396 pcontext, 00397 &cache_status) == CACHE_INODE_SUCCESS) 00398 { 00399 if(cache_inode_rename(parent_pentry, 00400 &entry_name, 00401 new_parent_pentry, 00402 &new_entry_name, 00403 &attr, 00404 &new_attr, 00405 pcontext, 00406 &cache_status) == CACHE_INODE_SUCCESS) 00407 { 00408 switch (preq->rq_vers) 00409 { 00410 case NFS_V2: 00411 pres->res_stat2 = NFS_OK; 00412 break; 00413 00414 case NFS_V3: 00415 /* 00416 * Build Weak Cache Coherency 00417 * data 00418 */ 00419 nfs_SetWccData(pexport, 00420 ppre_attr, 00421 &attr, 00422 &(pres->res_rename3.RENAME3res_u.resok. 00423 fromdir_wcc)); 00424 00425 nfs_SetWccData(pexport, 00426 ppre_attr, 00427 &attr, 00428 &(pres->res_rename3.RENAME3res_u.resok. 00429 todir_wcc)); 00430 00431 pres->res_rename3.status = NFS3_OK; 00432 break; 00433 00434 } 00435 00436 rc = NFS_REQ_OK; 00437 goto out; 00438 } 00439 } 00440 00441 } 00442 } 00443 } 00444 00445 /* If this point is reached, then destination object already 00446 exists with that name in the directory and types are not 00447 compatible, we should return that the file exists */ 00448 cache_status = CACHE_INODE_ENTRY_EXISTS; 00449 } /* if( should_not_exists != NULL ) */ 00450 } 00451 00452 /* If we are here, there was an error */ 00453 if(nfs_RetryableError(cache_status)) 00454 { 00455 rc = NFS_REQ_DROP; 00456 goto out; 00457 } 00458 00459 nfs_SetFailedStatus(pcontext, pexport, 00460 preq->rq_vers, 00461 cache_status, 00462 &pres->res_stat2, 00463 &pres->res_rename3.status, 00464 NULL, NULL, 00465 parent_pentry, 00466 ppre_attr, 00467 &(pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc), 00468 new_parent_pentry, 00469 pnew_pre_attr, &(pres->res_rename3.RENAME3res_u.resfail.todir_wcc)); 00470 00471 rc = NFS_REQ_OK; 00472 00473 out: 00474 if (parent_pentry) 00475 cache_inode_put(parent_pentry); 00476 00477 if (new_parent_pentry) 00478 cache_inode_put(new_parent_pentry); 00479 00480 if (should_not_exists) 00481 cache_inode_put(should_not_exists); 00482 00483 if (should_exists) 00484 cache_inode_put(should_exists); 00485 00486 return (rc); 00487 00488 } /* nfs_Rename */ 00489 00498 void nfs_Rename_Free(nfs_res_t * resp) 00499 { 00500 /* Nothing to do here */ 00501 return; 00502 } /* nfs_Rename_Free */