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_file_handle.h" 00064 #include "nfs_proto_tools.h" 00065 00085 int nfs_Symlink(nfs_arg_t *parg, 00086 exportlist_t *pexport, 00087 fsal_op_context_t *pcontext, 00088 nfs_worker_data_t *pworker, 00089 struct svc_req *preq, 00090 nfs_res_t *pres) 00091 { 00092 char *str_symlink_name = NULL; 00093 fsal_name_t symlink_name; 00094 char *str_target_path = NULL; 00095 cache_inode_create_arg_t create_arg; 00096 fsal_accessmode_t mode = 0777; 00097 cache_entry_t *symlink_pentry = NULL; 00098 cache_entry_t *parent_pentry; 00099 cache_inode_file_type_t parent_filetype; 00100 fsal_attrib_list_t parent_attr; 00101 fsal_attrib_list_t attr_symlink; 00102 fsal_attrib_list_t attributes_symlink; 00103 fsal_attrib_list_t attr_parent_after; 00104 fsal_attrib_list_t *ppre_attr; 00105 cache_inode_status_t cache_status; 00106 cache_inode_status_t cache_status_parent; 00107 fsal_handle_t *pfsal_handle; 00108 int rc = NFS_REQ_OK; 00109 #ifdef _USE_QUOTA 00110 fsal_status_t fsal_status ; 00111 #endif 00112 00113 memset(&create_arg, 0, sizeof(create_arg)); 00114 00115 if(isDebug(COMPONENT_NFSPROTO)) 00116 { 00117 char str[LEN_FH_STR]; 00118 00119 switch (preq->rq_vers) 00120 { 00121 case NFS_V2: 00122 str_symlink_name = parg->arg_symlink2.from.name; 00123 str_target_path = parg->arg_symlink2.to; 00124 break; 00125 case NFS_V3: 00126 str_symlink_name = parg->arg_symlink3.where.name; 00127 str_target_path = parg->arg_symlink3.symlink.symlink_data; 00128 break; 00129 } 00130 00131 nfs_FhandleToStr(preq->rq_vers, 00132 &(parg->arg_symlink2.from.dir), 00133 &(parg->arg_symlink3.where.dir), 00134 NULL, 00135 str); 00136 LogDebug(COMPONENT_NFSPROTO, 00137 "REQUEST PROCESSING: Calling nfs_Symlink handle: %s name: %s target: %s", 00138 str, str_symlink_name, str_target_path); 00139 } 00140 00141 if(preq->rq_vers == NFS_V3) 00142 { 00143 /* to avoid setting it on each error case */ 00144 pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; 00145 pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; 00146 ppre_attr = NULL; 00147 } 00148 00149 /* Convert directory file handle into a vnode */ 00150 if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, 00151 &(parg->arg_symlink2.from.dir), 00152 &(parg->arg_symlink3.where.dir), 00153 NULL, 00154 &(pres->res_stat2), 00155 &(pres->res_symlink3.status), 00156 NULL, 00157 &parent_attr, 00158 pcontext, &rc)) == NULL) 00159 { 00160 /* Stale NFS FH ? */ 00161 goto out;; 00162 } 00163 00164 /* get directory attributes before action (for V3 reply) */ 00165 ppre_attr = &parent_attr; 00166 00167 /* Extract the filetype */ 00168 parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); 00169 00170 /* 00171 * Sanity checks: new directory name must be non-null; parent must be 00172 * a directory. 00173 */ 00174 if(parent_filetype != DIRECTORY) 00175 { 00176 switch (preq->rq_vers) 00177 { 00178 case NFS_V2: 00179 pres->res_stat2 = NFSERR_NOTDIR; 00180 break; 00181 00182 case NFS_V3: 00183 pres->res_symlink3.status = NFS3ERR_NOTDIR; 00184 break; 00185 } 00186 00187 rc = NFS_REQ_OK; 00188 goto out; 00189 } 00190 00191 #ifdef _USE_QUOTA 00192 /* if quota support is active, then we should check is the FSAL allows inode creation or not */ 00193 fsal_status = FSAL_check_quota( pexport->fullpath, 00194 FSAL_QUOTA_INODES, 00195 FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; 00196 if( FSAL_IS_ERROR( fsal_status ) ) 00197 { 00198 00199 switch (preq->rq_vers) 00200 { 00201 case NFS_V2: 00202 pres->res_stat2 = NFSERR_DQUOT ; 00203 break; 00204 00205 case NFS_V3: 00206 pres->res_symlink3.status = NFS3ERR_DQUOT; 00207 break; 00208 } 00209 00210 rc = NFS_REQ_OK; 00211 goto out; 00212 } 00213 #endif /* _USE_QUOTA */ 00214 00215 00216 switch (preq->rq_vers) 00217 { 00218 case NFS_V2: 00219 str_symlink_name = parg->arg_symlink2.from.name; 00220 str_target_path = parg->arg_symlink2.to; 00221 break; 00222 00223 case NFS_V3: 00224 str_symlink_name = parg->arg_symlink3.where.name; 00225 str_target_path = parg->arg_symlink3.symlink.symlink_data; 00226 break; 00227 } 00228 00229 if(str_symlink_name == NULL || 00230 *str_symlink_name == '\0'|| 00231 str_target_path == NULL || 00232 *str_target_path == '\0' || 00233 FSAL_IS_ERROR(FSAL_str2name(str_symlink_name, FSAL_MAX_NAME_LEN, &symlink_name)) || 00234 FSAL_IS_ERROR(FSAL_str2path 00235 (str_target_path, FSAL_MAX_PATH_LEN, &create_arg.link_content))) 00236 { 00237 cache_status = CACHE_INODE_INVALID_ARGUMENT; 00238 } 00239 else 00240 { 00241 /* Make the symlink */ 00242 if((symlink_pentry = cache_inode_create(parent_pentry, 00243 &symlink_name, 00244 SYMBOLIC_LINK, 00245 mode, 00246 &create_arg, 00247 &attr_symlink, 00248 pcontext, &cache_status)) != NULL) 00249 { 00250 switch (preq->rq_vers) 00251 { 00252 case NFS_V2: 00253 pres->res_stat2 = NFS_OK; 00254 break; 00255 00256 case NFS_V3: 00257 /* Build file handle */ 00258 pfsal_handle = &symlink_pentry->handle; 00259 00260 /* Some clients (like the Spec NFS benchmark) set attributes with the NFSPROC3_SYMLINK request */ 00261 if(nfs3_Sattr_To_FSALattr(&attributes_symlink, 00262 &parg->arg_symlink3.symlink.symlink_attributes) == 0) 00263 { 00264 pres->res_create3.status = NFS3ERR_INVAL; 00265 rc = NFS_REQ_OK; 00266 goto out; 00267 } 00268 00269 /* Mode is managed above (in cache_inode_create), there is no need 00270 * to manage it */ 00271 if(attributes_symlink.asked_attributes & FSAL_ATTR_MODE) 00272 attributes_symlink.asked_attributes &= ~FSAL_ATTR_MODE; 00273 00274 /* Some clients (like Solaris 10) try to set the size of the file to 0 00275 * at creation time. The FSAL create empty file, so we ignore this */ 00276 if(attributes_symlink.asked_attributes & FSAL_ATTR_SIZE) 00277 attributes_symlink.asked_attributes &= ~FSAL_ATTR_SIZE; 00278 00279 if(attributes_symlink.asked_attributes & FSAL_ATTR_SPACEUSED) 00280 attributes_symlink.asked_attributes &= ~FSAL_ATTR_SPACEUSED; 00281 00282 /* Are there attributes to be set (additional to the mode) ? */ 00283 if(attributes_symlink.asked_attributes != 0ULL && 00284 attributes_symlink.asked_attributes != FSAL_ATTR_MODE) 00285 { 00286 /* A call to cache_inode_setattr is required */ 00287 if(cache_inode_setattr(symlink_pentry, 00288 &attributes_symlink, 00289 pcontext, &cache_status) != CACHE_INODE_SUCCESS) 00290 { 00291 /* If we are here, there was an error */ 00292 nfs_SetFailedStatus(pcontext, pexport, 00293 preq->rq_vers, 00294 cache_status, 00295 &pres->res_dirop2.status, 00296 &pres->res_symlink3.status, 00297 NULL, NULL, 00298 parent_pentry, 00299 ppre_attr, 00300 &(pres->res_symlink3.SYMLINK3res_u.resok. 00301 dir_wcc), NULL, NULL, NULL); 00302 00303 if(nfs_RetryableError(cache_status)) { 00304 rc = NFS_REQ_DROP; 00305 goto out; 00306 } 00307 00308 rc = NFS_REQ_OK; 00309 goto out; 00310 } 00311 } 00312 00313 if ((pres->res_symlink3.status = 00314 (nfs3_AllocateFH(&pres->res_symlink3.SYMLINK3res_u 00315 .resok.obj.post_op_fh3_u.handle))) 00316 != NFS3_OK) { 00317 pres->res_symlink3.status = NFS3ERR_IO; 00318 rc = NFS_REQ_OK; 00319 goto out; 00320 } 00321 00322 if(nfs3_FSALToFhandle 00323 (&pres->res_symlink3.SYMLINK3res_u.resok.obj.post_op_fh3_u.handle, 00324 pfsal_handle, pexport) == 0) 00325 { 00326 gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj. 00327 post_op_fh3_u.handle.data.data_val); 00328 00329 pres->res_symlink3.status = NFS3ERR_BADHANDLE; 00330 rc = NFS_REQ_OK; 00331 goto out; 00332 } 00333 00334 /* The the parent pentry attributes for building Wcc Data */ 00335 if(cache_inode_getattr(parent_pentry, 00336 &attr_parent_after, 00337 pcontext, 00338 &cache_status_parent) 00339 != CACHE_INODE_SUCCESS) 00340 { 00341 gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj. 00342 post_op_fh3_u.handle.data.data_val); 00343 00344 pres->res_symlink3.status = NFS3ERR_BADHANDLE; 00345 rc = NFS_REQ_OK; 00346 goto out; 00347 } 00348 00349 /* Set Post Op Fh3 structure */ 00350 pres->res_symlink3.SYMLINK3res_u.resok.obj.handle_follows = TRUE; 00351 00352 /* Build entry attributes */ 00353 nfs_SetPostOpAttr(pexport, 00354 &attr_symlink, 00355 &(pres->res_symlink3.SYMLINK3res_u 00356 .resok.obj_attributes)); 00357 00358 /* Build Weak Cache Coherency data */ 00359 nfs_SetWccData(pexport, 00360 ppre_attr, 00361 &attr_parent_after, 00362 &(pres->res_symlink3.SYMLINK3res_u.resok.dir_wcc)); 00363 00364 pres->res_symlink3.status = NFS3_OK; 00365 break; 00366 } /* switch */ 00367 00368 rc = NFS_REQ_OK; 00369 goto out; 00370 } 00371 } 00372 00373 /* If we are here, there was an error */ 00374 if(nfs_RetryableError(cache_status)) 00375 { 00376 rc = NFS_REQ_DROP; 00377 goto out; 00378 } 00379 00380 nfs_SetFailedStatus(pcontext, pexport, 00381 preq->rq_vers, 00382 cache_status, 00383 &pres->res_stat2, 00384 &pres->res_symlink3.status, 00385 NULL, NULL, 00386 parent_pentry, 00387 ppre_attr, 00388 &(pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc), 00389 NULL, NULL, NULL); 00390 00391 rc = NFS_REQ_OK; 00392 00393 out: 00394 /* return references */ 00395 if (parent_pentry) 00396 cache_inode_put(parent_pentry); 00397 00398 if (symlink_pentry) 00399 cache_inode_put(symlink_pentry); 00400 00401 return (rc); 00402 00403 } /* nfs_Symlink */ 00404 00413 void nfs_Symlink_Free(nfs_res_t * resp) 00414 { 00415 if((resp->res_symlink3.status == NFS3_OK) && 00416 (resp->res_symlink3.SYMLINK3res_u.resok.obj.handle_follows == TRUE)) 00417 gsh_free(resp->res_symlink3.SYMLINK3res_u.resok.obj 00418 .post_op_fh3_u.handle.data.data_val); 00419 } /* nfs_Symlink_Free */