/** * FSAL_link: * Create a hardlink. * * \param exttarget (input): * Handle of the target object. * \param extdir (input): * Pointer to the directory handle where * the hardlink is to be created. * \param link_name (input): * Pointer to the name of the hardlink to be created. * \param extcontext (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the directory to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param attributes (optionnal input/output): * The post_operation attributes of the linked object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (target or dir does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ... * * NB: if getting postop attributes failed, * the function does not return an error * but the FSAL_ATTR_RDATTR_ERR bit is set in * the attributes->asked_attributes field. */ fsal_status_t CEPHFSAL_link(fsal_handle_t * exttarget, fsal_handle_t * extdir, fsal_name_t * link_name, fsal_op_context_t * extcontext, fsal_attrib_list_t * attributes) { int rc; struct stat st; char strname[FSAL_MAX_NAME_LEN]; cephfsal_handle_t* target = (cephfsal_handle_t*) exttarget; cephfsal_handle_t* dir = (cephfsal_handle_t*) extdir; cephfsal_op_context_t* context = (cephfsal_op_context_t*) context; struct ceph_mount_info *cmount = context->export_context->cmount; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : attributes is optional. */ if(!target || !dir || !context || !link_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); memset(target, 0, sizeof(cephfsal_handle_t)); /* Tests if hardlinking is allowed by configuration. */ if(!global_fs_info.link_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link); FSAL_name2str(link_name, strname, FSAL_MAX_NAME_LEN); TakeTokenFSCall(); rc = ceph_ll_link(cmount, VINODE(target), VINODE(dir), strname, &st, uid, gid); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_link); if(attributes) { fsal_status_t status; status = posix2fsal_attributes(&st, attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(attributes->asked_attributes); FSAL_SET_MASK(attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); }
fsal_status_t FSAL_rename_access_default(fsal_op_context_t * pcontext, /* IN */ fsal_attrib_list_t * pattrsrc, /* IN */ fsal_attrib_list_t * pattrdest, /* IN */ fsal_attrib_list_t * pattrobj) /* IN */ { fsal_status_t fsal_status; if(!pcontext || !pattrsrc || !pattrdest || !pattrobj) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename_access); /* Sticky Bit on the parent directory? */ if(pattrsrc->mode & FSAL_MODE_SVTX) { /* The user must own the file or the parent directory. */ if( ( pattrsrc->owner != FSAL_OP_CONTEXT_TO_UID(pcontext) ) || ( pattrobj->owner != FSAL_OP_CONTEXT_TO_UID(pcontext) ) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename_access); } /* Sticky Bit on the destination directory? */ if(pattrdest->mode & FSAL_MODE_SVTX) { /* The user must own the file or the destination directory. */ if( ( pattrdest->owner != FSAL_OP_CONTEXT_TO_UID(pcontext) ) || ( pattrobj->owner != FSAL_OP_CONTEXT_TO_UID(pcontext) ) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename_access); } /* The user must be able to lookup and write the parent directory. */ fsal_status = FSAL_test_access_default(pcontext, ( FSAL_W_OK | FSAL_X_OK ), pattrsrc); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_rename_access); /* The user must be able to lookup and write the destination directory. */ fsal_status = FSAL_test_access_default(pcontext, ( FSAL_W_OK | FSAL_X_OK ), pattrdest); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_rename_access); /* If this point is reached, then access is granted */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename_access); } /* FSAL_rename_access */
/** * FSAL_opendir : * Opens a directory for reading its content. * * \param exthandle (input) * the handle of the directory to be opened. * \param extcontext (input) * Permission context for the operation (user, export context...). * \param extdescriptor (output) * pointer to an allocated structure that will receive * directory stream informations, on successfull completion. * \param attributes (optional output) * On successfull completion,the structure pointed * by dir_attributes receives the new directory attributes. * Can be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_ACCESS (user does not have read permission on directory) * - ERR_FSAL_STALE (exthandle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_IO, ... */ fsal_status_t CEPHFSAL_opendir(fsal_handle_t * exthandle, fsal_op_context_t * extcontext, fsal_dir_t * extdescriptor, fsal_attrib_list_t * dir_attributes) { cephfsal_handle_t* handle = (cephfsal_handle_t*) exthandle; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; cephfsal_dir_t* descriptor = (cephfsal_dir_t*) extdescriptor; fsal_status_t status; int rc; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); struct ceph_dir_result *dh; /* sanity checks * note : dir_attributes is optional. */ if(!handle || !context || !descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir); TakeTokenFSCall(); /* XXX ceph_ll_opendir has void in the interface, but Client::ll_opendir * is using dir_result_t. */ rc = ceph_ll_opendir(context->export_context->cmount, VINODE(handle), (void *) &dh, uid, gid); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_opendir); descriptor->dh = dh; descriptor->vi = VINODE(handle); descriptor->ctx = *context; if(dir_attributes) { status = CEPHFSAL_getattrs(exthandle, extcontext, dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(dir_attributes->asked_attributes); FSAL_SET_MASK(dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); }
/** * FSAL_getattrs: * Get attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param context (input): * Authentication context for the operation (user, export...). * \param object_attributes (mandatory input/output): * The retrieved attributes for the object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (object_handle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Another error code if an error occured. */ fsal_status_t CEPHFSAL_getattrs(fsal_handle_t * exthandle, fsal_op_context_t * extcontext, fsal_attrib_list_t * object_attributes) { int rc; struct stat st; fsal_status_t status; cephfsal_handle_t* filehandle = (cephfsal_handle_t*) exthandle; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : object_attributes is mandatory in FSAL_getattrs. */ if(!filehandle || !context || !object_attributes) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs); TakeTokenFSCall(); rc = ceph_ll_getattr(context->export_context->cmount, VINODE(filehandle), &st, uid, gid); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_getattrs); /* convert attributes */ status = posix2fsal_attributes(&st, object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs); } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs); }
int nfs_Create(nfs_arg_t *parg, exportlist_t *pexport, fsal_op_context_t *pcontext, nfs_worker_data_t *pworker, struct svc_req *preq, nfs_res_t *pres) { char *str_file_name = NULL; fsal_name_t file_name; fsal_accessmode_t mode = 0; cache_entry_t *file_pentry = NULL; cache_entry_t *parent_pentry = NULL; fsal_attrib_list_t parent_attr; fsal_attrib_list_t attr; fsal_attrib_list_t attr_parent_after; fsal_attrib_list_t attr_newfile; fsal_attrib_list_t attributes_create; fsal_attrib_list_t *ppre_attr; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; cache_inode_status_t cache_status_lookup; cache_inode_file_type_t parent_filetype; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: str_file_name = parg->arg_create2.where.name; break; case NFS_V3: str_file_name = parg->arg_create3.where.name; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_create2.where.dir), &(parg->arg_create3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Create handle: %s name: %s", str, str_file_name); } if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_create3.where.dir)))) { rc = nfs3_Create_Xattr(parg, pexport, pcontext, preq, pres); goto out; } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_create3.CREATE3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_create3.CREATE3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_create2.where.dir), &(parg->arg_create3.where.dir), NULL, &(pres->res_dirop2.status), &(pres->res_create3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: new file name must be non-null; parent must be a * directory. */ if(parent_filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_NOTDIR; break; case NFS_V3: pres->res_create3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } switch (preq->rq_vers) { case NFS_V2: str_file_name = parg->arg_create2.where.name; if(parg->arg_create2.attributes.mode != (unsigned int)-1) { mode = unix2fsal_mode(parg->arg_create2.attributes.mode); } else { mode = 0; } break; case NFS_V3: str_file_name = parg->arg_create3.where.name; if(parg->arg_create3.how.mode == EXCLUSIVE) { /* * Client has not provided mode information. * If the create works, the client will issue * a separate setattr request to fix up the * file's mode, so pick arbitrary value for now. */ mode = 0; } else if(parg->arg_create3.how.createhow3_u.obj_attributes.mode.set_it == TRUE) mode = unix2fsal_mode(parg->arg_create3.how.createhow3_u.obj_attributes.mode. set_mode3_u.mode); else mode = 0; break; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_DQUOT ; break; case NFS_V3: pres->res_create3.status = NFS3ERR_DQUOT; break; } rc = NFS_REQ_OK ; goto out; } #endif /* _USE_QUOTA */ // if(str_file_name == NULL || strlen(str_file_name) == 0) if(str_file_name == NULL || *str_file_name == '\0' ) { if(preq->rq_vers == NFS_V2) pres->res_dirop2.status = NFSERR_IO; if(preq->rq_vers == NFS_V3) pres->res_create3.status = NFS3ERR_INVAL; } else { if((cache_status = cache_inode_error_convert(FSAL_str2name(str_file_name, FSAL_MAX_NAME_LEN, &file_name))) == CACHE_INODE_SUCCESS) { /* * Lookup file to see if it exists. If so, use it. Otherwise * create a new one. */ file_pentry = cache_inode_lookup(parent_pentry, &file_name, &attr, pcontext, &cache_status_lookup); if((cache_status_lookup == CACHE_INODE_NOT_FOUND) || ((cache_status_lookup == CACHE_INODE_SUCCESS) && (parg->arg_create3.how.mode == UNCHECKED))) { /* Create the file */ if((parg->arg_create3.how.mode == UNCHECKED) && (cache_status_lookup == CACHE_INODE_SUCCESS)) { cache_status = CACHE_INODE_SUCCESS; attr_newfile = attr; } else file_pentry = cache_inode_create(parent_pentry, &file_name, REGULAR_FILE, mode, NULL, &attr_newfile, pcontext, &cache_status); if(file_pentry != NULL) { /* * Look at sattr to see if some attributes are to be set at creation time */ attributes_create.asked_attributes = 0ULL; switch (preq->rq_vers) { case NFS_V2: if(nfs2_Sattr_To_FSALattr(&attributes_create, &parg->arg_create2.attributes) == 0) { pres->res_dirop2.status = NFSERR_IO; rc = NFS_REQ_OK; goto out; break; } break; case NFS_V3: if(nfs3_Sattr_To_FSALattr(&attributes_create, &parg->arg_create3.how.createhow3_u. obj_attributes) == 0) { pres->res_create3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } break; } /* Mode is managed above (in cache_inode_create), there is no need * to manage it */ if(attributes_create.asked_attributes & FSAL_ATTR_MODE) attributes_create.asked_attributes &= ~FSAL_ATTR_MODE; /* Some clients (like Solaris 10) try to set the size of the file to 0 * at creation time. The FSAL create empty file, so we ignore this */ if(attributes_create.asked_attributes & FSAL_ATTR_SIZE) attributes_create.asked_attributes &= ~FSAL_ATTR_SIZE; if(attributes_create.asked_attributes & FSAL_ATTR_SPACEUSED) attributes_create.asked_attributes &= ~FSAL_ATTR_SPACEUSED; /* Are there attributes to be set (additional to the mode) ? */ if(attributes_create.asked_attributes != 0ULL && attributes_create.asked_attributes != FSAL_ATTR_MODE) { /* A call to cache_inode_setattr is required */ if(cache_inode_setattr(file_pentry, &attributes_create, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { /* If we are here, there was an error */ nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail. dir_wcc), NULL, NULL, NULL); if(nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } rc = NFS_REQ_OK; goto out; } /* Get the resulting attributes from the Cache Inode */ if(cache_inode_getattr(file_pentry, &attr_newfile, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { /* If we are here, there was an error */ nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail. dir_wcc), NULL, NULL, NULL); if(nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } rc = NFS_REQ_OK; goto out; } } switch (preq->rq_vers) { case NFS_V2: /* Build file handle */ if(nfs2_FSALToFhandle( &(pres->res_dirop2.DIROP2res_u.diropok.file), &file_pentry->handle, pexport) == 0) pres->res_dirop2.status = NFSERR_IO; else { if(!nfs2_FSALattr_To_Fattr( pexport, &attr_newfile, &(pres->res_dirop2.DIROP2res_u. diropok.attributes))) pres->res_dirop2.status = NFSERR_IO; else pres->res_dirop2.status = NFS_OK; } break; case NFS_V3: /* Build file handle */ pres->res_create3.status = nfs3_AllocateFH(&pres->res_create3.CREATE3res_u .resok.obj.post_op_fh3_u.handle); if (pres->res_create3.status != NFS3_OK) { rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ if(nfs3_FSALToFhandle( &(pres->res_create3.CREATE3res_u.resok .obj.post_op_fh3_u.handle), &file_pentry->handle, pexport) == 0) { gsh_free(pres->res_create3.CREATE3res_u.resok.obj. post_op_fh3_u.handle.data.data_val); pres->res_create3.status = NFS3ERR_BADHANDLE; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ pres->res_create3.CREATE3res_u.resok.obj.handle_follows = TRUE; /* Get the attributes of the parent after the operation */ attr_parent_after = parent_pentry->attributes; /* Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr_newfile, &(pres->res_create3.CREATE3res_u.resok. obj_attributes)); /* * Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &(pres->res_create3.CREATE3res_u .resok.dir_wcc)); pres->res_create3.status = NFS3_OK; break; } /* switch */ rc = NFS_REQ_OK; goto out; } } else { if(cache_status_lookup == CACHE_INODE_SUCCESS) { /* Trying to create a file that already exists */ cache_status = CACHE_INODE_ENTRY_EXISTS; switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_EXIST; break; case NFS_V3: pres->res_create3.status = NFS3ERR_EXIST; break; } } else { /* Server fault */ cache_status = cache_status_lookup; switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_IO; break; case NFS_V3: pres->res_create3.status = NFS3ERR_INVAL; break; } } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail.dir_wcc), NULL, NULL, NULL); rc = NFS_REQ_OK; goto out; } /* if( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */ } } /* Set the exit status */ nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail.dir_wcc), NULL, NULL, NULL); /* If we are here, there was an error */ if(nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } rc = NFS_REQ_OK; out: /* return references */ if (file_pentry) cache_inode_put(file_pentry); if (parent_pentry) cache_inode_put(parent_pentry); return (rc); } /* nfs_Create */
/** * FSAL_lookup : * Looks up for an object into a directory. * * Note : if parent handle and filename are NULL, * this retrieves root's handle. * * \param parent_directory_handle (input) * Handle of the parent directory to search the object in. * \param filename (input) * The name of the object to find. * \param p_context (input) * Authentication context for the operation (user,...). * \param object_handle (output) * The handle of the object corresponding to filename. * \param object_attributes (optional input/output) * Pointer to the attributes of the object we found. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * It can be NULL (increases performances). * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (parent_directory_handle does not address an existing object) * - ERR_FSAL_NOTDIR (parent_directory_handle does not address a directory) * - ERR_FSAL_NOENT (the object designated by p_filename does not exist) * - ERR_FSAL_XDEV (tried to operate a lookup on a filesystem junction. * Use FSAL_lookupJunction instead) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_IO, ... * */ fsal_status_t CEPHFSAL_lookup(fsal_handle_t * extparent, fsal_name_t * filename, fsal_op_context_t * extcontext, fsal_handle_t * exthandle, fsal_attrib_list_t * object_attributes) { int rc; struct stat st; fsal_status_t status; cephfsal_handle_t* parent = (cephfsal_handle_t*) extparent; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; cephfsal_handle_t* handle = (cephfsal_handle_t*) exthandle; char str[FSAL_MAX_NAME_LEN+1]; struct ceph_mount_info *cmount = context->export_context->cmount; /* sanity checks * note : object_attributes is optionnal * parent_directory_handle may be null for getting FS root. */ if(!handle || !context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); memset(handle, 0, sizeof(cephfsal_handle_t)); /* retrieves root handle */ if(!parent) { /* check that filename is NULL, * else, parent should not * be NULL. */ if(filename != NULL) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* Ceph seems to have a constant identifying the root inode. Possible source of bugs, so check here if trouble */ VINODE(handle).ino.val = CEPH_INO_ROOT; VINODE(handle).snapid.val = CEPH_NOSNAP; if(object_attributes) { status = CEPHFSAL_getattrs(exthandle, extcontext, object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } } else /* this is a real lookup(parent, name) */ { /* the filename should not be null */ if(filename == NULL) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); FSAL_name2str(filename, str, FSAL_MAX_NAME_LEN); /* Ceph returns POSIX errors, so let's use them */ rc = ceph_ll_lookup(cmount, VINODE(parent), str, &st, FSAL_OP_CONTEXT_TO_UID(context), FSAL_OP_CONTEXT_TO_GID(context)); if(rc) { Return(posix2fsal_error(rc), 0, INDEX_FSAL_lookup); } rc = stat2fsal_fh(cmount, &st, handle); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); if(object_attributes) { /* convert attributes */ status = posix2fsal_attributes(&st, object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); } } } /* lookup complete ! */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); }
int nfs3_Mknod(nfs_arg_t *parg, exportlist_t *pexport, fsal_op_context_t *pcontext, nfs_worker_data_t *pworker, struct svc_req *preq, nfs_res_t * pres) { cache_entry_t *parent_pentry = NULL; fsal_attrib_list_t parent_attr; fsal_attrib_list_t *ppre_attr; fsal_attrib_list_t attr_parent_after; cache_inode_file_type_t parent_filetype; cache_inode_file_type_t nodetype; char *str_file_name = NULL; fsal_name_t file_name; cache_inode_status_t cache_status; cache_inode_status_t cache_status_lookup; fsal_accessmode_t mode = 0; cache_entry_t *node_pentry = NULL; fsal_attrib_list_t attr; cache_inode_create_arg_t create_arg; fsal_handle_t *pfsal_handle; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif memset(&create_arg, 0, sizeof(create_arg)); if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; sprint_fhandle3(str, &(parg->arg_mknod3.where.dir)); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_Mknod handle: %s name: %s", str, parg->arg_mknod3.where.name); } /* to avoid setting them on each error case */ pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; /* retrieve parent entry */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, NULL, &(parg->arg_mknod3.where.dir), NULL, NULL, &(pres->res_mknod3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: new node name must be non-null; parent must be a * directory. */ if(parent_filetype != DIRECTORY) { pres->res_mknod3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } str_file_name = parg->arg_mknod3.where.name; switch (parg->arg_mknod3.what.type) { case NF3CHR: case NF3BLK: if(parg->arg_mknod3.what.mknoddata3_u.device.dev_attributes.mode.set_it) mode = (fsal_accessmode_t) parg->arg_mknod3.what.mknoddata3_u.device.dev_attributes. mode.set_mode3_u.mode; else mode = (fsal_accessmode_t) 0; create_arg.dev_spec.major = parg->arg_mknod3.what.mknoddata3_u.device.spec.specdata1; create_arg.dev_spec.minor = parg->arg_mknod3.what.mknoddata3_u.device.spec.specdata2; break; case NF3FIFO: case NF3SOCK: if(parg->arg_mknod3.what.mknoddata3_u.pipe_attributes.mode.set_it) mode = (fsal_accessmode_t) parg->arg_mknod3.what.mknoddata3_u.pipe_attributes.mode. set_mode3_u.mode; else mode = (fsal_accessmode_t) 0; create_arg.dev_spec.major = 0; create_arg.dev_spec.minor = 0; break; default: pres->res_mknod3.status = NFS3ERR_BADTYPE; rc = NFS_REQ_OK; goto out; } switch (parg->arg_mknod3.what.type) { case NF3CHR: nodetype = CHARACTER_FILE; break; case NF3BLK: nodetype = BLOCK_FILE; break; case NF3FIFO: nodetype = FIFO_FILE; break; case NF3SOCK: nodetype = SOCKET_FILE; break; default: pres->res_mknod3.status = NFS3ERR_BADTYPE; rc = NFS_REQ_OK; goto out; } //if(str_file_name == NULL || strlen(str_file_name) == 0) if(str_file_name == NULL || *str_file_name == '\0' ) { pres->res_mknod3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { pres->res_mknod3.status = NFS3ERR_DQUOT; return NFS_REQ_OK; } #endif /* _USE_QUOTA */ /* convert node name */ if((cache_status = cache_inode_error_convert(FSAL_str2name(str_file_name, 0, &file_name))) == CACHE_INODE_SUCCESS) { /* * Lookup node to see if it exists. If so, use it. Otherwise * create a new one. */ node_pentry = cache_inode_lookup(parent_pentry, &file_name, &attr, pcontext, &cache_status_lookup); if(cache_status_lookup == CACHE_INODE_NOT_FOUND) { /* Create the node */ if((node_pentry = cache_inode_create(parent_pentry, &file_name, nodetype, mode, &create_arg, &attr, pcontext, &cache_status)) != NULL) { MKNOD3resok *rok = &pres->res_mknod3.MKNOD3res_u.resok; /* * Get the FSAL handle for this entry */ pfsal_handle = &node_pentry->handle; /* Build file handle */ pres->res_mknod3.status = nfs3_AllocateFH(&rok->obj.post_op_fh3_u.handle); if(pres->res_mknod3.status != NFS3_OK) return NFS_REQ_OK; if(nfs3_FSALToFhandle(&rok->obj.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { gsh_free(rok->obj.post_op_fh3_u.handle.data.data_val); pres->res_mknod3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ rok->obj.handle_follows = TRUE; /* Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr, &rok->obj_attributes); /* Get the attributes of the parent after the operation */ if(cache_inode_getattr(parent_pentry, &attr_parent_after, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { pres->res_mknod3.status = nfs3_Errno(cache_status); rc = NFS_REQ_OK; goto out; } /* Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &rok->dir_wcc); pres->res_mknod3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; } /* mknod sucess */ } /* not found */ else { /* object already exists or failure during lookup */ if(cache_status_lookup == CACHE_INODE_SUCCESS) { /* Trying to create an entry that already exists */ pres->res_mknod3.status = NFS3ERR_EXIST; } else { /* Server fault */ pres->res_mknod3.status = NFS3ERR_INVAL; } nfs_SetWccData(pexport, NULL, NULL, &(pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc)); rc = NFS_REQ_OK; goto out; } } /* If we are here, there was an error */ rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, NULL, &pres->res_mknod3.status, NULL, ppre_attr, &(pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (parent_pentry) cache_inode_put(parent_pentry); if (node_pentry) cache_inode_put(node_pentry); return (rc); } /* nfs3_Mknod */
int nfs_Mkdir(nfs_arg_t *parg, exportlist_t *pexport, fsal_op_context_t *pcontext, nfs_worker_data_t *pworker, struct svc_req *preq, nfs_res_t *pres) { char *str_dir_name = NULL; fsal_accessmode_t mode = 0; cache_entry_t *dir_pentry = NULL; cache_entry_t *parent_pentry = NULL; fsal_attrib_list_t parent_attr; fsal_attrib_list_t attr; fsal_attrib_list_t *ppre_attr; fsal_attrib_list_t attr_parent_after; cache_inode_file_type_t parent_filetype; fsal_handle_t *pfsal_handle; fsal_name_t dir_name; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; cache_inode_status_t cache_status_lookup; cache_inode_create_arg_t create_arg; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif memset(&create_arg, 0, sizeof(create_arg)); if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: str_dir_name = parg->arg_mkdir2.where.name; break; case NFS_V3: str_dir_name = parg->arg_mkdir3.where.name; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_mkdir2.where.dir), &(parg->arg_mkdir3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Mkdir handle: %s name: %s", str, str_dir_name); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_mkdir2.where.dir), &(parg->arg_mkdir3.where.dir), NULL, &(pres->res_dirop2.status), &(pres->res_mkdir3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: */ if(parent_filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_NOTDIR; break; case NFS_V3: pres->res_mkdir3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_DQUOT; break; case NFS_V3: pres->res_mkdir3.status = NFS3ERR_DQUOT; break; } rc = NFS_REQ_OK ; goto out; } #endif /* _USE_QUOTA */ switch (preq->rq_vers) { case NFS_V2: str_dir_name = parg->arg_mkdir2.where.name; if(parg->arg_mkdir2.attributes.mode != (unsigned int)-1) { mode = (fsal_accessmode_t) parg->arg_mkdir2.attributes.mode; } else { mode = (fsal_accessmode_t) 0; } break; case NFS_V3: str_dir_name = parg->arg_mkdir3.where.name; if(parg->arg_mkdir3.attributes.mode.set_it == TRUE) mode = (fsal_accessmode_t) parg->arg_mkdir3.attributes.mode.set_mode3_u.mode; else mode = (fsal_accessmode_t) 0; break; } //if(str_dir_name == NULL || strlen(str_dir_name) == 0) if(str_dir_name == NULL || *str_dir_name == '\0' ) { if(preq->rq_vers == NFS_V2) pres->res_dirop2.status = NFSERR_IO; if(preq->rq_vers == NFS_V3) pres->res_mkdir3.status = NFS3ERR_INVAL; } else { /* Make the directory */ if((cache_status = cache_inode_error_convert(FSAL_str2name(str_dir_name, 0, &dir_name))) == CACHE_INODE_SUCCESS) { /* * Lookup file to see if it exists. If so, use it. Otherwise * create a new one. */ dir_pentry = cache_inode_lookup(parent_pentry, &dir_name, &attr, pcontext, &cache_status_lookup); if(cache_status_lookup == CACHE_INODE_NOT_FOUND) { /* The create_arg structure contains the information "newly created directory" * to be passed to cache_inode_new_entry from cache_inode_create */ create_arg.newly_created_dir = TRUE; /* Create the directory */ if((dir_pentry = cache_inode_create(parent_pentry, &dir_name, DIRECTORY, mode, &create_arg, &attr, pcontext, &cache_status)) != NULL) { /* * Get the FSAL handle for this entry */ pfsal_handle = &dir_pentry->handle; if(preq->rq_vers == NFS_V2) { DIROP2resok *d2ok = &pres->res_dirop2.DIROP2res_u.diropok; /* Build file handle */ if(!nfs2_FSALToFhandle(&d2ok->file, pfsal_handle, pexport)) pres->res_dirop2.status = NFSERR_IO; else { /* * Build entry * attributes */ if(nfs2_FSALattr_To_Fattr(pexport, &attr, &d2ok->attributes) == 0) pres->res_dirop2.status = NFSERR_IO; else pres->res_dirop2.status = NFS_OK; } } else { MKDIR3resok *d3ok = &pres->res_mkdir3.MKDIR3res_u.resok; /* Build file handle */ pres->res_mkdir3.status = nfs3_AllocateFH(&d3ok->obj.post_op_fh3_u.handle); if(pres->res_mkdir3.status != NFS3_OK) { rc = NFS_REQ_OK; goto out; } if(nfs3_FSALToFhandle(&d3ok->obj.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { gsh_free(d3ok->obj.post_op_fh3_u.handle.data.data_val); pres->res_mkdir3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ d3ok->obj.handle_follows = TRUE; /* * Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr, &d3ok->obj_attributes); /* Get the attributes of the parent after the operation */ if(cache_inode_getattr(parent_pentry, &attr_parent_after, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { pres->res_mkdir3.status = nfs3_Errno(cache_status); rc = NFS_REQ_OK; goto out; } /* * Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &d3ok->dir_wcc); pres->res_mkdir3.status = NFS3_OK; } rc = NFS_REQ_OK; goto out; } } /* If( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */ else { switch (preq->rq_vers) { case NFS_V2: if(cache_status_lookup == CACHE_INODE_SUCCESS) pres->res_dirop2.status = NFSERR_EXIST; else pres->res_dirop2.status = NFSERR_IO; break; case NFS_V3: if(cache_status_lookup == CACHE_INODE_SUCCESS) pres->res_mkdir3.status = NFS3ERR_EXIST; else pres->res_mkdir3.status = NFS3ERR_INVAL; nfs_SetWccData(pexport, ppre_attr, NULL, &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc)); break; } rc = NFS_REQ_OK; goto out; } } } /* If we are here, there was an error */ rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_mkdir3.status, NULL, ppre_attr, &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (dir_pentry) cache_inode_put(dir_pentry); if (parent_pentry) cache_inode_put(parent_pentry); return (rc); }
int nfs_Symlink(nfs_arg_t *parg, exportlist_t *pexport, fsal_op_context_t *pcontext, nfs_worker_data_t *pworker, struct svc_req *preq, nfs_res_t *pres) { char *str_symlink_name = NULL; fsal_name_t symlink_name; char *str_target_path = NULL; cache_inode_create_arg_t create_arg; fsal_accessmode_t mode = 0777; cache_entry_t *symlink_pentry = NULL; cache_entry_t *parent_pentry; cache_inode_file_type_t parent_filetype; fsal_attrib_list_t parent_attr; fsal_attrib_list_t attr_symlink; fsal_attrib_list_t attributes_symlink; fsal_attrib_list_t attr_parent_after; fsal_attrib_list_t *ppre_attr; cache_inode_status_t cache_status; cache_inode_status_t cache_status_parent; fsal_handle_t *pfsal_handle; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif memset(&create_arg, 0, sizeof(create_arg)); if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: str_symlink_name = parg->arg_symlink2.from.name; str_target_path = parg->arg_symlink2.to; break; case NFS_V3: str_symlink_name = parg->arg_symlink3.where.name; str_target_path = parg->arg_symlink3.symlink.symlink_data; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_symlink2.from.dir), &(parg->arg_symlink3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Symlink handle: %s name: %s target: %s", str, str_symlink_name, str_target_path); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } /* Convert directory file handle into a vnode */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_symlink2.from.dir), &(parg->arg_symlink3.where.dir), NULL, &(pres->res_stat2), &(pres->res_symlink3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out;; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: new directory name must be non-null; parent must be * a directory. */ if(parent_filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_NOTDIR; break; case NFS_V3: pres->res_symlink3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_DQUOT ; break; case NFS_V3: pres->res_symlink3.status = NFS3ERR_DQUOT; break; } rc = NFS_REQ_OK; goto out; } #endif /* _USE_QUOTA */ switch (preq->rq_vers) { case NFS_V2: str_symlink_name = parg->arg_symlink2.from.name; str_target_path = parg->arg_symlink2.to; break; case NFS_V3: str_symlink_name = parg->arg_symlink3.where.name; str_target_path = parg->arg_symlink3.symlink.symlink_data; break; } if(str_symlink_name == NULL || *str_symlink_name == '\0'|| str_target_path == NULL || *str_target_path == '\0' || FSAL_IS_ERROR(FSAL_str2name(str_symlink_name, 0, &symlink_name)) || FSAL_IS_ERROR(FSAL_str2path(str_target_path, 0, &create_arg.link_content))) { cache_status = CACHE_INODE_INVALID_ARGUMENT; } else { /* Make the symlink */ if((symlink_pentry = cache_inode_create(parent_pentry, &symlink_name, SYMBOLIC_LINK, mode, &create_arg, &attr_symlink, pcontext, &cache_status)) != NULL) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* Build file handle */ pfsal_handle = &symlink_pentry->handle; /* Some clients (like the Spec NFS benchmark) set attributes with the NFSPROC3_SYMLINK request */ if(nfs3_Sattr_To_FSALattr(&attributes_symlink, &parg->arg_symlink3.symlink.symlink_attributes) == 0) { pres->res_create3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } /* Mode is managed above (in cache_inode_create), there is no need * to manage it */ if(attributes_symlink.asked_attributes & FSAL_ATTR_MODE) attributes_symlink.asked_attributes &= ~FSAL_ATTR_MODE; /* Some clients (like Solaris 10) try to set the size of the file to 0 * at creation time. The FSAL create empty file, so we ignore this */ if(attributes_symlink.asked_attributes & FSAL_ATTR_SIZE) attributes_symlink.asked_attributes &= ~FSAL_ATTR_SIZE; if(attributes_symlink.asked_attributes & FSAL_ATTR_SPACEUSED) attributes_symlink.asked_attributes &= ~FSAL_ATTR_SPACEUSED; /* If owner or owner_group are set, and the credential was * squashed, then we must squash the set owner and owner_group. */ squash_setattr(&pworker->export_perms, &pworker->user_credentials, &attributes_symlink); /* Are there attributes to be set (additional to the mode) ? */ if(attributes_symlink.asked_attributes != 0ULL && attributes_symlink.asked_attributes != FSAL_ATTR_MODE) { /* A call to cache_inode_setattr is required */ if(cache_inode_setattr(symlink_pentry, &attributes_symlink, pcontext, FALSE, &cache_status) != CACHE_INODE_SUCCESS) { goto out_error; } } if ((pres->res_symlink3.status = (nfs3_AllocateFH(&pres->res_symlink3.SYMLINK3res_u .resok.obj.post_op_fh3_u.handle))) != NFS3_OK) { pres->res_symlink3.status = NFS3ERR_IO; rc = NFS_REQ_OK; goto out; } if(nfs3_FSALToFhandle (&pres->res_symlink3.SYMLINK3res_u.resok.obj.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj. post_op_fh3_u.handle.data.data_val); pres->res_symlink3.status = NFS3ERR_BADHANDLE; rc = NFS_REQ_OK; goto out; } /* The the parent pentry attributes for building Wcc Data */ if(cache_inode_getattr(parent_pentry, &attr_parent_after, pcontext, &cache_status_parent) != CACHE_INODE_SUCCESS) { gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj. post_op_fh3_u.handle.data.data_val); pres->res_symlink3.status = NFS3ERR_BADHANDLE; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ pres->res_symlink3.SYMLINK3res_u.resok.obj.handle_follows = TRUE; /* Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr_symlink, &(pres->res_symlink3.SYMLINK3res_u .resok.obj_attributes)); /* Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &(pres->res_symlink3.SYMLINK3res_u.resok.dir_wcc)); pres->res_symlink3.status = NFS3_OK; break; } /* switch */ rc = NFS_REQ_OK; goto out; } } out_error: rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, &pres->res_stat2, &pres->res_symlink3.status, NULL, ppre_attr, &(pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (parent_pentry) cache_inode_put(parent_pentry); if (symlink_pentry) cache_inode_put(symlink_pentry); return (rc); } /* nfs_Symlink */
/** * FSAL_test_access_default : * Tests whether the user identified by the p_context structure * can access the object as indicated by the access_type parameter. * This function tests access rights using cached attributes * given as parameter (no calls to filesystem). * Thus, it cannot test FSAL_F_OK flag, and asking such a flag * will result in a ERR_FSAL_INVAL error. * * \param p_context (input): * Authentication context for the operation (user,...). * \param access_type (input): * Indicates the permissions to test. * This is an inclusive OR of the permissions * to be checked for the user identified by cred. * Permissions constants are : * - FSAL_R_OK : test for read permission * - FSAL_W_OK : test for write permission * - FSAL_X_OK : test for exec permission * - FSAL_F_OK : test for file existence * \param object_attributes (mandatory input): * The cached attributes for the object to test rights on. * The following attributes MUST be filled : * owner, group, mode, ACLs. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error, permission granted) * - ERR_FSAL_ACCESS (object permissions doesn't fit asked access type) * - ERR_FSAL_INVAL (FSAL_test_access is not able to test such a permission) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Another error code if an error occured. */ fsal_status_t FSAL_test_access_default(fsal_op_context_t * p_context, /* IN */ fsal_accessflags_t access_type, /* IN */ fsal_attrib_list_t * object_attributes /* IN */ ) { fsal_accessflags_t missing_access; int is_grp; fsal_count_t i; gid_t * alt_groups; fsal_count_t nb_alt_groups; /* sanity checks. */ if(!object_attributes || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_test_access); /* If the FSAL_F_OK flag is set, returns ERR INVAL */ if(access_type & FSAL_F_OK) Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_test_access); /* ----- here is a code sample for this function ---- */ /* test root access */ if(FSAL_OP_CONTEXT_TO_UID(p_context) == 0) Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_test_access); /* unsatisfied permissions */ missing_access = access_type; /* Test if file belongs to user. */ if(FSAL_OP_CONTEXT_TO_UID(p_context) == object_attributes->owner) { if(object_attributes->mode & FSAL_MODE_RUSR) missing_access &= ~FSAL_R_OK; if(object_attributes->mode & FSAL_MODE_WUSR) missing_access &= ~FSAL_W_OK; if(object_attributes->mode & FSAL_MODE_XUSR) missing_access &= ~FSAL_X_OK; if(missing_access == 0) Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_test_access); else Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_test_access); } /* Test if the file belongs to user's group. */ is_grp = (FSAL_OP_CONTEXT_TO_GID(p_context) == object_attributes->group); if(!is_grp && FSAL_OP_CONTEXT_TO_ALT_GROUPS(p_context) != NULL) { nb_alt_groups = FSAL_OP_CONTEXT_TO_NBGROUPS(p_context); alt_groups = FSAL_OP_CONTEXT_TO_ALT_GROUPS(p_context); /* Test if file belongs to user's alt groups */ for(i = 0; i < nb_alt_groups; i++) { is_grp = (alt_groups[i] == object_attributes->group); if(is_grp) break; } } /* finally apply group rights */ if(is_grp) { if(object_attributes->mode & FSAL_MODE_RGRP) missing_access &= ~FSAL_R_OK; if(object_attributes->mode & FSAL_MODE_WGRP) missing_access &= ~FSAL_W_OK; if(object_attributes->mode & FSAL_MODE_XGRP) missing_access &= ~FSAL_X_OK; if(missing_access == 0) Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_test_access); else Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_test_access); } /* test other perms */ if(object_attributes->mode & FSAL_MODE_ROTH) missing_access &= ~FSAL_R_OK; if(object_attributes->mode & FSAL_MODE_WOTH) missing_access &= ~FSAL_W_OK; if(object_attributes->mode & FSAL_MODE_XOTH) missing_access &= ~FSAL_X_OK; /** @todo: ACLs. */ if(missing_access == 0) Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_test_access); else Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_test_access); }
/** * FSAL_test_setattr_access_default : * test if a client identified by cred can access setattr on the object * knowing its attributes and parent's attributes. * The following fields of the object_attributes structures MUST be filled : * acls (if supported), mode, owner, group. * This doesn't make any call to the filesystem, * as a result, this doesn't ensure that the file exists, nor that * the permissions given as parameters are the actual file permissions : * this must be ensured by the cache_inode layer, using FSAL_getattrs, * for example. * * \param cred (in zfsfsal_cred_t *) user's identifier. * \param candidate_attributes the attributes we want to set on the object * \param object_attributes (in fsal_attrib_list_t *) the cached attributes * for the object. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_ACCESS (Permission denied) * - ERR_FSAL_FAULT (null pointer parameter) * - ERR_FSAL_INVAL (missing attributes : mode, group, user,...) * - ERR_FSAL_SERVERFAULT (unexpected error) */ fsal_status_t FSAL_setattr_access_default(fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * candidate_attributes, /* IN */ fsal_attrib_list_t * object_attributes /* IN */ ) { fsal_status_t fsal_status; int in_grp; int i; fsal_count_t nb_alt_groups; gid_t * alt_groups; in_grp = 0; /* * CHMOD * */ /* We just ignore symlinks. */ if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_MODE) && (object_attributes->type != FSAL_TYPE_LNK)) { /* User must be root or owner of the file */ if( (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) =! object_attributes->owner) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* * CHOWN * */ if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_OWNER)) { /* User must be root or (be the owner and the user he wants to set) */ if( (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && ( ( FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner ) || ( FSAL_OP_CONTEXT_TO_UID(p_context) != candidate_attributes->owner ) ) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_GROUP)) { /* User must ( be root or owner ) */ if( (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); /* He must also be in the group he wants to set */ in_grp = ( FSAL_OP_CONTEXT_TO_GID(p_context) == candidate_attributes->group ); if(!in_grp && FSAL_OP_CONTEXT_TO_ALT_GROUPS(p_context) != NULL) { nb_alt_groups = FSAL_OP_CONTEXT_TO_NBGROUPS(p_context); alt_groups = FSAL_OP_CONTEXT_TO_ALT_GROUPS(p_context); /* Test user's alt groups */ for(i = 0; i < nb_alt_groups; i++) { in_grp = (alt_groups[i] == object_attributes->group); if(in_grp) break; } } if(!in_grp) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* * UTIME * */ /* Is it allowed to change time? */ if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME) && !global_fs_info.cansettime) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); /* Atime: user must be owner or be root or have read access */ if( FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_ATIME) && (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner)) { fsal_status = FSAL_test_access_default(p_context, FSAL_R_OK, object_attributes); if(FSAL_IS_ERROR(fsal_status)) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* Mtime: user must be owner or be root or have write access */ if( FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_MTIME) && (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner)) { fsal_status = FSAL_test_access_default(p_context, FSAL_W_OK, object_attributes); if(FSAL_IS_ERROR(fsal_status)) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* If this point is reached, then access is granted. */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattr_access); } /* FSAL_test_setattr_access */
/** * * MFSL_mkdir : posts an asynchronous mkdir and sets the cached attributes in return. * * Posts an asynchronous setattr and sets the cached attributes in return. * If an object is not asynchronous, then the content of object attributes structure for result will be used to populate it. * * @param target_handle [IN] mfsl object to be operated on (object to be hard linked). * @param dir_handle [IN] mfsl object to be operated on (destination directory for the link). * @param p_context [IN] associated fsal context * @param p_mfsl_context [INOUT] associated mfsl context * @param attrib_set [IN] attributes to be set * @param tgt_attributes [INOUT] resulting attributes for target * @param dir_attributes [INOUT] resulting attributes for directory * * @return the same as FSAL_link */ fsal_status_t MFSL_mkdir(mfsl_object_t * parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* IN */ fsal_op_context_t * p_context, /* IN */ mfsl_context_t * p_mfsl_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ mfsl_object_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * parent_attributes /* IN */ ) { fsal_status_t fsal_status; mfsl_async_op_desc_t *pasyncopdesc = NULL; mfsl_object_specific_data_t *newdir_pasyncdata = NULL; mfsl_object_t *pnewdir_handle = NULL; mfsl_precreated_object_t *pprecreated = NULL; fsal_status = MFSAL_mkdir_check_perms(parent_directory_handle, p_dirname, p_context, p_mfsl_context, parent_attributes); if(FSAL_IS_ERROR(fsal_status)) return fsal_status; P(p_mfsl_context->lock); GetFromPool(pasyncopdesc, &p_mfsl_context->pool_async_op, mfsl_async_op_desc_t); GetFromPool(newdir_pasyncdata, &p_mfsl_context->pool_spec_data, mfsl_object_specific_data_t); V(p_mfsl_context->lock); if(pasyncopdesc == NULL) MFSL_return(ERR_FSAL_INVAL, 0); if(gettimeofday(&pasyncopdesc->op_time, NULL) != 0) { /* Could'not get time of day... Stopping, this may need a major failure */ LogMajor(COMPONENT_MFSL, "MFSL_link: cannot get time of day... exiting"); exit(1); } /* Now get a pre-allocated directory from the synclet data */ P(p_mfsl_context->lock); GetFromPool(pprecreated, &p_mfsl_context->pool_dirs, mfsl_precreated_object_t); V(p_mfsl_context->lock); pnewdir_handle = &(pprecreated->mobject); LogDebug(COMPONENT_MFSL, "Creating asyncop %p", pasyncopdesc); pasyncopdesc->op_type = MFSL_ASYNC_OP_MKDIR; pasyncopdesc->op_args.mkdir.pmfsl_obj_dirdest = parent_directory_handle; pasyncopdesc->op_args.mkdir.precreate_name = pprecreated->name; pasyncopdesc->op_args.mkdir.dirname = *p_dirname; pasyncopdesc->op_args.mkdir.mode = accessmode; pasyncopdesc->op_args.mkdir.owner = FSAL_OP_CONTEXT_TO_UID(p_context); pasyncopdesc->op_args.mkdir.group = FSAL_OP_CONTEXT_TO_GID(p_context); pasyncopdesc->op_res.mkdir.attr.asked_attributes = object_attributes->asked_attributes; pasyncopdesc->op_res.mkdir.attr.supported_attributes = object_attributes->supported_attributes; if(FSAL_IS_ERROR(fsal_status)) return fsal_status; pasyncopdesc->op_func = MFSL_mkdir_async_op; //pasyncopdesc->fsal_op_context = p_context ; pasyncopdesc->fsal_op_context = synclet_data[pasyncopdesc->related_synclet_index].root_fsal_context; pasyncopdesc->ptr_mfsl_context = (caddr_t) p_mfsl_context; fsal_status = MFSL_async_post(pasyncopdesc); if(FSAL_IS_ERROR(fsal_status)) return fsal_status; /* Update the asynchronous metadata */ newdir_pasyncdata->async_attr = pprecreated->attr; newdir_pasyncdata->async_attr.type = FSAL_TYPE_DIR; newdir_pasyncdata->async_attr.filesize = DEV_BSIZE; newdir_pasyncdata->async_attr.spaceused = DEV_BSIZE; newdir_pasyncdata->async_attr.numlinks = 2; newdir_pasyncdata->async_attr.owner = pasyncopdesc->op_args.mkdir.owner; newdir_pasyncdata->async_attr.group = pasyncopdesc->op_args.mkdir.group; newdir_pasyncdata->async_attr.ctime.seconds = pasyncopdesc->op_time.tv_sec; newdir_pasyncdata->async_attr.ctime.nseconds = pasyncopdesc->op_time.tv_usec; /** @todo: there may be a coefficient to be applied here */ newdir_pasyncdata->deleted = FALSE; if(!mfsl_async_set_specdata(pnewdir_handle, newdir_pasyncdata)) MFSL_return(ERR_FSAL_SERVERFAULT, 0); /* Return the correct attributes */ *object_attributes = newdir_pasyncdata->async_attr; *object_handle = pprecreated->mobject; object_handle->health = MFSL_ASYNC_NEVER_SYNCED; /* Do not forget that the parent directory becomes asynchronous too */ parent_directory_handle->health = MFSL_ASYNC_ASYNCHRONOUS; MFSL_return(ERR_FSAL_NO_ERROR, 0); } /* MFSL_mkdir */
fsal_status_t CEPHFSAL_setattrs(fsal_handle_t * exthandle, fsal_op_context_t * extcontext, fsal_attrib_list_t * attrib_set, fsal_attrib_list_t * object_attributes) { cephfsal_handle_t* filehandle = (cephfsal_handle_t*) exthandle; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; struct stat st; fsal_attrib_list_t attrs; int rc, mask=0; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : object_attributes is optional. */ if(!filehandle || !context || !attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* local copy of attributes */ attrs = *attrib_set; /* First, check that FSAL attributes changes are allowed. */ /* Is it allowed to change times ? */ if(!global_fs_info.cansettime) { if(attrs.asked_attributes & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME)) { /* handled as an unsettable attribute. */ Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs); } } /* apply umask, if mode attribute is to be changed */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { attrs.mode &= (~global_fs_info.umask); } /* Build flags and struct stat */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { mask |= CEPH_SETATTR_MODE; st.st_mode = fsal2unix_mode(attrs.mode); } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER)) { mask |= CEPH_SETATTR_UID; st.st_uid = attrs.owner; } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP)) { mask |= CEPH_SETATTR_UID; st.st_gid = attrs.group; } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)) { mask |= CEPH_SETATTR_ATIME; st.st_atime = attrs.atime.seconds; } if (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)) { mask |= CEPH_SETATTR_MTIME; st.st_mtime = attrs.mtime.seconds; } if (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_CTIME)) { mask |= CEPH_SETATTR_CTIME; st.st_ctime = attrs.ctime.seconds; } TakeTokenFSCall(); rc = ceph_ll_setattr(context->export_context->cmount, VINODE(filehandle), &st, mask, uid, gid); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_getattrs); if(object_attributes) { fsal_status_t status; status = CEPHFSAL_getattrs(exthandle, extcontext, object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
fsal_status_t CEPHFSAL_rename(fsal_handle_t * extold_parent, fsal_name_t * old_name, fsal_handle_t * extnew_parent, fsal_name_t * new_name, fsal_op_context_t * extcontext, fsal_attrib_list_t * src_dir_attributes, fsal_attrib_list_t * tgt_dir_attributes) { int rc; cephfsal_handle_t* old_parent = (cephfsal_handle_t*) extold_parent; cephfsal_handle_t* new_parent = (cephfsal_handle_t*) extnew_parent; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; char oldstr[FSAL_MAX_NAME_LEN+1]; char newstr[FSAL_MAX_NAME_LEN+1]; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!old_parent || !new_parent || !old_name || !new_name || !context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); if(src_dir_attributes) { fsal_status_t status = CEPHFSAL_getattrs(extold_parent, extcontext, src_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes); FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } if(tgt_dir_attributes) { fsal_status_t status; /* optimization when src=tgt : */ if(!CEPHFSAL_handlecmp(extold_parent, extnew_parent, &status) && src_dir_attributes) { /* If source dir = target dir, we just copy the attributes. * to avoid doing another getattr. */ (*tgt_dir_attributes) = (*src_dir_attributes); } else { status = CEPHFSAL_getattrs(extnew_parent, extcontext, tgt_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } } FSAL_name2str(old_name, oldstr, FSAL_MAX_NAME_LEN); FSAL_name2str(new_name, newstr, FSAL_MAX_NAME_LEN); rc = ceph_ll_rename(context->export_context->cmount, VINODE(old_parent), oldstr, VINODE(new_parent), newstr, uid, gid); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_rename); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/** * FSAL_create: * Create a regular file. * * \param extparent (input): * Handle of the parent directory where the file is to be created. * \param filename (input): * Pointer to the name of the file to be created. * \param context (input): * Authentication context for the operation (user, export...). * \param accessmode (input): * Mode for the file to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param object_handle (output): * Pointer to the handle of the created file. * \param object_attributes (optionnal input/output): * The postop attributes of the created file. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * Can be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (parent_directory_handle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ... * * NB: if getting postop attributes failed, * the function does not return an error * but the FSAL_ATTR_RDATTR_ERR bit is set in * the object_attributes->asked_attributes field. */ fsal_status_t CEPHFSAL_create(fsal_handle_t * extparent, fsal_name_t * filename, fsal_op_context_t * extcontext, fsal_accessmode_t accessmode, fsal_handle_t * object_handle, fsal_attrib_list_t * object_attributes) { int rc; mode_t mode; struct Fh *fd; struct stat st; char strname[FSAL_MAX_NAME_LEN]; cephfsal_handle_t* parent = (cephfsal_handle_t*) extparent; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; struct ceph_mount_info *cmount = context->export_context->cmount; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : object_attributes is optional. */ if(!parent || !context || !object_handle || !filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); memset(object_handle, 0, sizeof(cephfsal_handle_t)); mode = fsal2unix_mode(accessmode); mode = mode & ~global_fs_info.umask; FSAL_name2str(filename, strname, FSAL_MAX_NAME_LEN); TakeTokenFSCall(); rc = ceph_ll_create(cmount, VINODE(parent), strname, mode, 0, &fd, &st, uid, gid); ceph_ll_close(cmount, fd); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); rc = stat2fsal_fh(cmount, &st, (cephfsal_handle_t*) object_handle); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); if(object_attributes) { fsal_status_t status; status = posix2fsal_attributes(&st, object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }