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 00036 #ifdef HAVE_CONFIG_H 00037 #include "config.h" 00038 #endif 00039 00040 #ifdef _SOLARIS 00041 #include "solaris_port.h" 00042 #endif 00043 00044 #include <stdio.h> 00045 #include <string.h> 00046 #include <pthread.h> 00047 #include <fcntl.h> 00048 #include <sys/file.h> /* for having FNDELAY */ 00049 #include "HashData.h" 00050 #include "HashTable.h" 00051 #include "log.h" 00052 #include "ganesha_rpc.h" 00053 #include "nfs23.h" 00054 #include "nfs4.h" 00055 #include "mount.h" 00056 #include "nfs_core.h" 00057 #include "cache_inode.h" 00058 #include "nfs_exports.h" 00059 #include "nfs_creds.h" 00060 #include "nfs_proto_functions.h" 00061 #include "nfs_proto_tools.h" 00062 #include "nfs_tools.h" 00063 #include "nfs_file_handle.h" 00064 00078 #define arg_CREATE4 op->nfs_argop4_u.opcreate 00079 #define res_CREATE4 resp->nfs_resop4_u.opcreate 00080 00081 int nfs4_op_create(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) 00082 { 00083 char __attribute__ ((__unused__)) funcname[] = "nfs4_op_create"; 00084 00085 cache_entry_t * pentry_parent = NULL; 00086 cache_entry_t * pentry_new = NULL; 00087 fsal_attrib_list_t attr_parent; 00088 fsal_attrib_list_t attr_new; 00089 fsal_attrib_list_t sattr; 00090 fsal_handle_t * pnewfsal_handle = NULL; 00091 nfs_fh4 newfh4; 00092 cache_inode_status_t cache_status; 00093 int convrc = 0; 00094 fsal_accessmode_t mode = 0777; 00095 fsal_name_t name; 00096 #ifdef _USE_QUOTA 00097 fsal_status_t fsal_status ; 00098 #endif 00099 cache_inode_create_arg_t create_arg; 00100 unsigned int i = 0; 00101 00102 memset(&create_arg, 0, sizeof(create_arg)); 00103 00104 resp->resop = NFS4_OP_CREATE; 00105 res_CREATE4.status = NFS4_OK; 00106 00107 /* Do basic checks on a filehandle */ 00108 res_CREATE4.status = nfs4_sanity_check_FH(data, 0LL); 00109 if(res_CREATE4.status != NFS4_OK) 00110 return res_CREATE4.status; 00111 00112 #ifdef _USE_QUOTA 00113 /* if quota support is active, then we should check is the FSAL allows inode creation or not */ 00114 fsal_status = FSAL_check_quota( data->pexport->fullpath, 00115 FSAL_QUOTA_INODES, 00116 FSAL_OP_CONTEXT_TO_UID( data->pcontext ) ) ; 00117 if( FSAL_IS_ERROR( fsal_status ) ) 00118 { 00119 res_CREATE4.status = NFS4ERR_DQUOT ; 00120 return res_CREATE4.status; 00121 } 00122 #endif /* _USE_QUOTA */ 00123 00124 /* Pseudo Fs is explictely a Read-Only File system */ 00125 if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) 00126 { 00127 res_CREATE4.status = NFS4ERR_ROFS; 00128 return res_CREATE4.status; 00129 } 00130 00131 if (nfs_export_check_security(data->reqp, data->pexport) == FALSE) 00132 { 00133 res_CREATE4.status = NFS4ERR_PERM; 00134 return res_CREATE4.status; 00135 } 00136 00137 /* Ask only for supported attributes */ 00138 if(!nfs4_Fattr_Supported(&arg_CREATE4.createattrs)) 00139 { 00140 res_CREATE4.status = NFS4ERR_ATTRNOTSUPP; 00141 return res_CREATE4.status; 00142 } 00143 00144 /* Do not use READ attr, use WRITE attr */ 00145 if(!nfs4_Fattr_Check_Access(&arg_CREATE4.createattrs, FATTR4_ATTR_WRITE)) 00146 { 00147 res_CREATE4.status = NFS4ERR_INVAL; 00148 return res_CREATE4.status; 00149 } 00150 00151 /* Check for name to long */ 00152 if(arg_CREATE4.objname.utf8string_len > FSAL_MAX_NAME_LEN) 00153 { 00154 res_CREATE4.status = NFS4ERR_NAMETOOLONG; 00155 return res_CREATE4.status; 00156 } 00157 00158 /* 00159 * This operation is used to create a non-regular file, 00160 * this means: - a symbolic link 00161 * - a block device file 00162 * - a character device file 00163 * - a socket file 00164 * - a fifo 00165 * - a directory 00166 * 00167 * You can't use this operation to create a regular file, you have to use NFS4_OP_OPEN for this 00168 */ 00169 00170 /* Convert the UFT8 objname to a regular string */ 00171 if(arg_CREATE4.objname.utf8string_len == 0) 00172 { 00173 res_CREATE4.status = NFS4ERR_INVAL; 00174 return res_CREATE4.status; 00175 } 00176 00177 if(utf82str(name.name, sizeof(name.name), &arg_CREATE4.objname) == -1) 00178 { 00179 res_CREATE4.status = NFS4ERR_INVAL; 00180 return res_CREATE4.status; 00181 } 00182 name.len = strlen(name.name); 00183 00184 /* Sanuty check: never create a directory named '.' or '..' */ 00185 if(arg_CREATE4.objtype.type == NF4DIR) 00186 { 00187 if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) 00188 || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) 00189 { 00190 res_CREATE4.status = NFS4ERR_BADNAME; 00191 return res_CREATE4.status; 00192 } 00193 00194 } 00195 00196 /* Filename should contain not slash */ 00197 for(i = 0; i < name.len; i++) 00198 { 00199 if(name.name[i] == '/') 00200 { 00201 res_CREATE4.status = NFS4ERR_BADCHAR; 00202 return res_CREATE4.status; 00203 } 00204 } 00205 /* Convert current FH into a cached entry, the current_pentry (assocated with the current FH will be used for this */ 00206 pentry_parent = data->current_entry; 00207 00208 /* The currentFH must point to a directory (objects are always created within a directory) */ 00209 if(data->current_filetype != DIRECTORY) 00210 { 00211 res_CREATE4.status = NFS4ERR_NOTDIR; 00212 return res_CREATE4.status; 00213 } 00214 00215 /* get attributes of parent directory, for 'change4' info replyed */ 00216 if((cache_status = cache_inode_getattr(pentry_parent, 00217 &attr_parent, 00218 data->pcontext, 00219 &cache_status)) != CACHE_INODE_SUCCESS) 00220 { 00221 res_CREATE4.status = nfs4_Errno(cache_status); 00222 return res_CREATE4.status; 00223 } 00224 00225 res_CREATE4.CREATE4res_u.resok4.cinfo.before 00226 = cache_inode_get_changeid4(pentry_parent); 00227 00228 /* Convert the incoming fattr4 to a vattr structure, if such arguments are supplied */ 00229 if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0) 00230 { 00231 /* Arguments were supplied, extract them */ 00232 convrc = nfs4_Fattr_To_FSAL_attr(&sattr, &(arg_CREATE4.createattrs)); 00233 00234 if(convrc != NFS4_OK) 00235 { 00236 res_CREATE4.status = convrc; 00237 return res_CREATE4.status; 00238 } 00239 } 00240 00241 /* Create either a symbolic link or a directory */ 00242 switch (arg_CREATE4.objtype.type) 00243 { 00244 case NF4LNK: 00245 /* Convert the name to link from into a regular string */ 00246 if(arg_CREATE4.objtype.createtype4_u.linkdata.utf8string_len == 0) 00247 { 00248 res_CREATE4.status = NFS4ERR_INVAL; 00249 return res_CREATE4.status; 00250 } 00251 else 00252 { 00253 if(utf82str 00254 (create_arg.link_content.path, sizeof(create_arg.link_content.path), 00255 &arg_CREATE4.objtype.createtype4_u.linkdata) == -1) 00256 { 00257 res_CREATE4.status = NFS4ERR_INVAL; 00258 return res_CREATE4.status; 00259 } 00260 create_arg.link_content.len = strlen(create_arg.link_content.path); 00261 } 00262 00263 /* do the symlink operation */ 00264 if((pentry_new = cache_inode_create(pentry_parent, 00265 &name, 00266 SYMBOLIC_LINK, 00267 mode, 00268 &create_arg, 00269 &attr_new, 00270 data->pcontext, &cache_status)) == NULL) 00271 { 00272 res_CREATE4.status = nfs4_Errno(cache_status); 00273 return res_CREATE4.status; 00274 } 00275 00276 /* If entry exists pentry_new is not null but cache_status was set */ 00277 if(cache_status == CACHE_INODE_ENTRY_EXISTS) 00278 { 00279 res_CREATE4.status = NFS4ERR_EXIST; 00280 cache_inode_put(pentry_new); 00281 return res_CREATE4.status; 00282 } 00283 00284 break; 00285 case NF4DIR: 00286 /* Create a new directory */ 00287 00288 /* The create_arg structure contains the information "newly created directory" 00289 * to be passed to cache_inode_new_entry from cache_inode_create */ 00290 create_arg.newly_created_dir = TRUE ; 00291 00292 if((pentry_new = cache_inode_create(pentry_parent, 00293 &name, 00294 DIRECTORY, 00295 mode, 00296 &create_arg, 00297 &attr_new, 00298 data->pcontext, &cache_status)) == NULL) 00299 { 00300 res_CREATE4.status = nfs4_Errno(cache_status); 00301 return res_CREATE4.status; 00302 } 00303 00304 /* If entry exists pentry_new is not null but cache_status was set */ 00305 if(cache_status == CACHE_INODE_ENTRY_EXISTS) 00306 { 00307 res_CREATE4.status = NFS4ERR_EXIST; 00308 cache_inode_put(pentry_new); 00309 return res_CREATE4.status; 00310 } 00311 break; 00312 00313 case NF4SOCK: 00314 00315 /* Create a new socket file */ 00316 if((pentry_new = cache_inode_create(pentry_parent, 00317 &name, 00318 SOCKET_FILE, 00319 mode, 00320 NULL, 00321 &attr_new, 00322 data->pcontext, &cache_status)) == NULL) 00323 { 00324 res_CREATE4.status = nfs4_Errno(cache_status); 00325 return res_CREATE4.status; 00326 } 00327 00328 /* If entry exists pentry_new is not null but cache_status was set */ 00329 if(cache_status == CACHE_INODE_ENTRY_EXISTS) 00330 { 00331 res_CREATE4.status = NFS4ERR_EXIST; 00332 cache_inode_put(pentry_new); 00333 return res_CREATE4.status; 00334 } 00335 break; 00336 00337 case NF4FIFO: 00338 00339 /* Create a new socket file */ 00340 if((pentry_new = cache_inode_create(pentry_parent, 00341 &name, 00342 FIFO_FILE, 00343 mode, 00344 NULL, 00345 &attr_new, 00346 data->pcontext, &cache_status)) == NULL) 00347 { 00348 res_CREATE4.status = nfs4_Errno(cache_status); 00349 return res_CREATE4.status; 00350 } 00351 00352 /* If entry exists pentry_new is not null but cache_status was set */ 00353 if(cache_status == CACHE_INODE_ENTRY_EXISTS) 00354 { 00355 res_CREATE4.status = NFS4ERR_EXIST; 00356 cache_inode_put(pentry_new); 00357 return res_CREATE4.status; 00358 } 00359 break; 00360 00361 case NF4CHR: 00362 00363 create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1; 00364 create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2; 00365 00366 /* Create a new socket file */ 00367 if((pentry_new = cache_inode_create(pentry_parent, 00368 &name, 00369 CHARACTER_FILE, 00370 mode, 00371 &create_arg, 00372 &attr_new, 00373 data->pcontext, &cache_status)) == NULL) 00374 { 00375 res_CREATE4.status = nfs4_Errno(cache_status); 00376 return res_CREATE4.status; 00377 } 00378 00379 /* If entry exists pentry_new is not null but cache_status was set */ 00380 if(cache_status == CACHE_INODE_ENTRY_EXISTS) 00381 { 00382 res_CREATE4.status = NFS4ERR_EXIST; 00383 cache_inode_put(pentry_new); 00384 return res_CREATE4.status; 00385 } 00386 break; 00387 00388 case NF4BLK: 00389 00390 create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1; 00391 create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2; 00392 00393 /* Create a new socket file */ 00394 if((pentry_new = cache_inode_create(pentry_parent, 00395 &name, 00396 BLOCK_FILE, 00397 mode, 00398 &create_arg, 00399 &attr_new, 00400 data->pcontext, &cache_status)) == NULL) 00401 { 00402 res_CREATE4.status = nfs4_Errno(cache_status); 00403 return res_CREATE4.status; 00404 } 00405 00406 /* If entry exists pentry_new is not null but cache_status was set */ 00407 if(cache_status == CACHE_INODE_ENTRY_EXISTS) 00408 { 00409 res_CREATE4.status = NFS4ERR_EXIST; 00410 cache_inode_put(pentry_new); 00411 return res_CREATE4.status; 00412 } 00413 break; 00414 00415 default: 00416 /* Should never happen, but return NFS4ERR_BADTYPE in this case */ 00417 res_CREATE4.status = NFS4ERR_BADTYPE; 00418 return res_CREATE4.status; 00419 break; 00420 } /* switch( arg_CREATE4.objtype.type ) */ 00421 00422 /* Now produce the filehandle to this file */ 00423 pnewfsal_handle = &pentry_new->handle; 00424 00425 /* Allocation of a new file handle */ 00426 if(nfs4_AllocateFH(&newfh4) != NFS4_OK) 00427 { 00428 res_CREATE4.status = NFS4ERR_SERVERFAULT; 00429 cache_inode_put(pentry_new); 00430 return res_CREATE4.status; 00431 } 00432 00433 /* Building the new file handle */ 00434 if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) 00435 { 00436 res_CREATE4.status = NFS4ERR_SERVERFAULT; 00437 cache_inode_put(pentry_new); 00438 return res_CREATE4.status; 00439 } 00440 00441 /* This new fh replaces the current FH */ 00442 data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; 00443 memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len); 00444 00445 /* No do not need newfh any more */ 00446 gsh_free(newfh4.nfs_fh4_val); 00447 00448 /* Set the mode if requested */ 00449 /* Use the same fattr mask for reply, if one attribute was not settable, NFS4ERR_ATTRNOTSUPP was replyied */ 00450 res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len = 00451 arg_CREATE4.createattrs.attrmask.bitmap4_len; 00452 00453 if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0) 00454 { 00455 if((cache_status = cache_inode_setattr(pentry_new, 00456 &sattr, 00457 data->pcontext, 00458 &cache_status)) != CACHE_INODE_SUCCESS) 00459 00460 { 00461 res_CREATE4.status = nfs4_Errno(cache_status); 00462 cache_inode_put(pentry_new); 00463 return res_CREATE4.status; 00464 } 00465 00466 /* Allocate a new bitmap */ 00467 res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val = 00468 gsh_calloc(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len, 00469 sizeof(uint32_t)); 00470 00471 if(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val == NULL) 00472 { 00473 res_CREATE4.status = NFS4ERR_SERVERFAULT; 00474 cache_inode_put(pentry_new); 00475 return res_CREATE4.status; 00476 } 00477 memcpy(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val, 00478 arg_CREATE4.createattrs.attrmask.bitmap4_val, 00479 res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len 00480 * sizeof(uint32_t)); 00481 } 00482 00483 /* Get the change info on parent directory after the operation was successfull */ 00484 if((cache_status = cache_inode_getattr(pentry_parent, 00485 &attr_parent, 00486 data->pcontext, 00487 &cache_status)) != CACHE_INODE_SUCCESS) 00488 { 00489 res_CREATE4.status = nfs4_Errno(cache_status); 00490 cache_inode_put(pentry_new); 00491 return res_CREATE4.status; 00492 } 00493 memset(&(res_CREATE4.CREATE4res_u.resok4.cinfo.after), 0, sizeof(changeid4)); 00494 res_CREATE4.CREATE4res_u.resok4.cinfo.after 00495 = cache_inode_get_changeid4(pentry_parent); 00496 00497 /* Operation is supposed to be atomic .... */ 00498 res_CREATE4.CREATE4res_u.resok4.cinfo.atomic = FALSE; 00499 00500 LogFullDebug(COMPONENT_NFS_V4, 00501 "CREATE CINFO before = %"PRIu64" after = %"PRIu64" atomic = %d", 00502 res_CREATE4.CREATE4res_u.resok4.cinfo.before, 00503 res_CREATE4.CREATE4res_u.resok4.cinfo.after, 00504 res_CREATE4.CREATE4res_u.resok4.cinfo.atomic); 00505 00506 /* @todo : BUGAZOMEU: fair ele free dans cette fonction */ 00507 00508 /* Keep the vnode entry for the file in the compound data */ 00509 00510 if (data->current_entry) { 00511 cache_inode_put(data->current_entry); 00512 } 00513 data->current_entry = pentry_new; 00514 data->current_filetype = pentry_new->type; 00515 00516 /* If you reach this point, then no error occured */ 00517 res_CREATE4.status = NFS4_OK; 00518 00519 return res_CREATE4.status; 00520 } /* nfs4_op_create */ 00521 00532 void nfs4_op_create_Free(CREATE4res * resp) 00533 { 00534 if(resp->status == NFS4_OK) 00535 gsh_free(resp->CREATE4res_u.resok4.attrset.bitmap4_val); 00536 00537 return; 00538 } /* nfs4_op_create_Free */