/** * FSAL_setattrs: * Set attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param cred (input): * Authentication context for the operation (user,...). * \param attrib_set (mandatory input): * The attributes to be set for the object. * It defines the attributes that the caller * wants to set and their values. * \param object_attributes (optionnal input/output): * The post operation 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). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t LUSTREFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_attrib_set, /* IN */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; unsigned int i; fsal_status_t status; fsal_attrib_list_t attrs; fsal_path_t fsalpath; struct stat buffstat; /* sanity checks. * note : object_attributes is optional. */ if(!p_filehandle || !p_context || !p_attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* local copy of attributes */ attrs = *p_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); } /* convert handle into path */ status = fsal_internal_Handle2FidPath(p_context, p_filehandle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); /* get current attributes */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc != 0) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); } /*********** * CHMOD * ***********/ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { /* The POSIX chmod call don't affect the symlink object, but * the entry it points to. So we must ignore it. */ if(!S_ISLNK(buffstat.st_mode)) { /* For modifying mode, user must be root or the owner */ if((p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", buffstat.st_uid, p_context->credential.user); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } TakeTokenFSCall(); rc = chmod(fsalpath.path, fsal2unix_mode(attrs.mode)); errsv = errno; ReleaseTokenFSCall(); if(rc) { Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); } } } /*********** * CHOWN * ***********/ /* Only root can change uid and A normal user must be in the group he wants to set */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER)) { /* For modifying owner, user must be root or current owner==wanted==client */ if((p_context->credential.user != 0) && ((p_context->credential.user != buffstat.st_uid) || (p_context->credential.user != attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", buffstat.st_uid, p_context->credential.user, attrs.owner); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP)) { /* For modifying group, user must be root or current owner */ if((p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid)) Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); int in_grp = 0; /* set in_grp */ if(p_context->credential.group == attrs.group) in_grp = 1; else for(i = 0; i < p_context->credential.nbgroups; i++) { if((in_grp = (attrs.group == p_context->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(p_context->credential.user != 0 && !in_grp) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", buffstat.st_gid, p_context->credential.group, attrs.group); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)", fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)attrs.owner : -1, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)attrs.group : -1); TakeTokenFSCall(); rc = lchown(fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)attrs.owner : -1, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)attrs.group : -1); ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } /*********** * UTIME * ***********/ /* user must be the owner or have read access to modify 'atime' */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) && (p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid) && ((status = fsal_internal_testAccess(p_context, FSAL_R_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) ReturnStatus(status, INDEX_FSAL_setattrs); /* user must be the owner or have write access to modify 'mtime' */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) && (p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid) && ((status = fsal_internal_testAccess(p_context, FSAL_W_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) ReturnStatus(status, INDEX_FSAL_setattrs); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { struct utimbuf timebuf; timebuf.actime = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs. atime.seconds : buffstat.st_atime); timebuf.modtime = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs. mtime.seconds : buffstat.st_mtime); TakeTokenFSCall(); rc = utime(fsalpath.path, &timebuf); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = LUSTREFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
fsal_status_t ZFSFSAL_rename(fsal_handle_t * old_parentdir_handle, /* IN */ fsal_name_t * p_old_name, /* IN */ fsal_handle_t * new_parentdir_handle, /* IN */ fsal_name_t * p_new_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc; creden_t cred; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!old_parentdir_handle || !new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); /* Hook to prenvet moving thing from or to a snapshot */ if(((zfsfsal_handle_t *)old_parentdir_handle)->data.i_snap != 0 || ((zfsfsal_handle_t *)new_parentdir_handle)->data.i_snap != 0) { LogDebug(COMPONENT_FSAL, "Trying to rename an object from/to a snapshot"); Return(ERR_FSAL_ROFS, 0, INDEX_FSAL_rename); } cred.uid = p_context->credential.user; cred.gid = p_context->credential.group; TakeTokenFSCall(); rc = libzfswrap_rename(((zfsfsal_op_context_t *)p_context)->export_context->p_vfs, &cred, ((zfsfsal_handle_t *)old_parentdir_handle)->data.zfs_handle, p_old_name->name, ((zfsfsal_handle_t *)new_parentdir_handle)->data.zfs_handle, p_new_name->name); ReleaseTokenFSCall(); /* >> interpret the returned error << */ if(rc) Return(posix2fsal_error(rc), 0, INDEX_FSAL_rename); /* >> get last parent post op attributes if asked * For example : << */ if(src_dir_attributes) { fsal_status_t st; st = ZFSFSAL_getattrs(old_parentdir_handle, p_context, src_dir_attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes); FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* >> get new parent post op attributes if asked * For example : << */ if(tgt_dir_attributes) { fsal_status_t st; /* optimization when src=tgt : */ if(!ZFSFSAL_handlecmp(old_parentdir_handle, new_parentdir_handle, &st) && 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 { /* get attributes */ st = ZFSFSAL_getattrs(new_parentdir_handle, p_context, tgt_dir_attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/** * FSAL_symlink: * Create a symbolic link. * * \param parent_directory_handle (input): * Handle of the parent directory where the link is to be created. * \param p_linkname (input): * Name of the link to be created. * \param p_linkcontent (input): * Content of the link to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (ignored input): * Mode of the link to be created. * It has no sense in HPSS nor UNIX filesystems. * \param link_handle (output): * Pointer to the handle of the created symlink. * \param link_attributes (optionnal input/output): * Attributes of the newly created symlink. * 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) * - Another error code if an error occured. */ fsal_status_t LUSTREFSAL_symlink(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_linkname, /* IN */ fsal_path_t * p_linkcontent, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN (ignored) */ fsal_handle_t * p_link_handle, /* OUT */ fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; fsal_path_t fsalpath; struct stat buffstat; int setgid_bit = FALSE; /* sanity checks. * note : link_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_link_handle || !p_linkname || !p_linkcontent) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); /* Tests if symlinking is allowed by configuration. */ if(!global_fs_info.symlink_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_symlink); /* build the new path and check the permissions on the parent directory */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* retrieve directory metadata, for checking access */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_symlink); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); } if(buffstat.st_mode & S_ISGID) setgid_bit = TRUE; status = fsal_internal_testAccess(p_context, FSAL_W_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* build symlink path */ status = fsal_internal_appendNameToPath(&fsalpath, p_linkname); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* create the symlink on the filesystem. */ TakeTokenFSCall(); rc = symlink(p_linkcontent->path, fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); /* Get symlink handle */ TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &fsalpath, p_link_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* chown the symlink to the current user/group */ TakeTokenFSCall(); rc = lchown(fsalpath.path, p_context->credential.user, setgid_bit ? -1 : p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); /* get attributes if asked */ if(p_link_attributes) { status = LUSTREFSAL_getattrs(p_link_handle, p_context, p_link_attributes); /* On error, we set a flag in the returned attributes */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_link_attributes->asked_attributes); FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink); }
fsal_status_t VFSFSAL_truncate(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_size_t length, /* IN */ fsal_file_t * file_descriptor, /* Unused in this FSAL */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int fd; fsal_status_t st; /* sanity checks. * note : object_attributes is optional. */ if(!p_filehandle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate); /* get the path of the file and its handle */ TakeTokenFSCall(); st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDWR); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_truncate); /* Executes the POSIX truncate operation */ TakeTokenFSCall(); rc = ftruncate(fd, length); errsv = errno; ReleaseTokenFSCall(); close(fd); /* convert return code */ if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_truncate); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_truncate); } /* Optionally retrieve attributes */ if(p_object_attributes) { fsal_status_t st; st = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* No error occurred */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_truncate); }
/** * FSAL_opendir : * Opens a directory for reading its content. * * \param dir_handle (input) * the handle of the directory to be opened. * \param p_context (input) * Permission context for the operation (user, export context...). * \param dir_descriptor (output) * pointer to an allocated structure that will receive * directory stream informations, on successfull completion. * \param dir_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 (dir_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_IO, ... */ fsal_status_t FUSEFSAL_opendir(fsal_handle_t * dir_hdl, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_dir_t * dir_desc, /* OUT */ fsal_attrib_list_t * dir_attributes /* [ IN/OUT ] */ ) { int rc; char object_path[FSAL_MAX_PATH_LEN]; fusefsal_dir_t * dir_descriptor = (fusefsal_dir_t *)dir_desc; fusefsal_handle_t * dir_handle = (fusefsal_handle_t *)dir_hdl; /* sanity checks * note : dir_attributes is optionnal. */ if(!dir_handle || !p_context || !dir_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir); /* get the full path for this directory */ rc = NamespacePath(dir_handle->data.inode, dir_handle->data.device, dir_handle->data.validator, object_path); if(rc) Return(ERR_FSAL_STALE, rc, INDEX_FSAL_opendir); memset(dir_descriptor, 0, sizeof(fsal_dir_t)); /* set context for the next operation, so it can be retrieved by FS thread */ fsal_set_thread_context(p_context); /* check opendir call */ if(p_fs_ops->opendir) { TakeTokenFSCall(); rc = p_fs_ops->opendir(object_path, &(dir_descriptor->dir_info)); ReleaseTokenFSCall(); if(rc) Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_opendir); } else { /* ignoring opendir */ memset(&(dir_descriptor->dir_info), 0, sizeof(struct ganefuse_file_info)); } /* fill the dir descriptor structure */ dir_descriptor->dir_handle = *dir_handle; /* backup context */ dir_descriptor->context = *(fusefsal_op_context_t *)p_context; /* optionaly get attributes */ if(dir_attributes) { fsal_status_t status; status = FUSEFSAL_getattrs(dir_hdl, p_context, dir_attributes); /* on error, we set a special bit in the mask. */ 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_create: * Create a regular file. * * \param parent_directory_handle (input): * Handle of the parent directory where the file is to be created. * \param p_filename (input): * Pointer to the name of the file to be created. * \param cred (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 PROXYFSAL_create(proxyfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ proxyfsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; uint32_t bitmap_conv_val[2]; uint32_t bitmap_create[2]; uint32_t bitmap_getattr_res[2]; fattr4 input_attr; bitmap4 convert_bitmap; component4 name; char nameval[MAXNAMLEN]; char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN]; fsal_status_t fsal_status; proxyfsal_file_t fd; #define FSAL_CREATE_NB_OP_ALLOC 4 #define FSAL_CREATE_VAL_BUFFER 1024 fsal_proxy_internal_fattr_t fattr_internal; fsal_attrib_list_t create_mode_attr; fsal_attrib_list_t attributes; nfs_argop4 argoparray[FSAL_CREATE_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_CREATE_NB_OP_ALLOC]; char fattr_val[FSAL_CREATE_VAL_BUFFER]; struct timeval timeout = { 25, 0 }; char owner_val[FSAL_PROXY_OWNER_LEN]; unsigned int owner_len = 0; /* sanity checks. * note : object_attributes is optional. */ if(!parent_directory_handle || !p_context || !object_handle || !p_filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); PRINT_HANDLE("FSAL_create", parent_directory_handle); /* Create the owner */ snprintf(owner_val, FSAL_PROXY_OWNER_LEN, "GANESHA/PROXY: pid=%u ctx=%p file=%llu", getpid(), p_context, (unsigned long long int)p_context->file_counter); owner_len = strnlen(owner_val, FSAL_PROXY_OWNER_LEN); p_context->file_counter += 1; /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Mkdir" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; input_attr.attrmask.bitmap4_val = bitmap_val; input_attr.attrmask.bitmap4_len = 2; input_attr.attr_vals.attrlist4_val = fattr_val; input_attr.attr_vals.attrlist4_len = FSAL_CREATE_VAL_BUFFER; fsal_internal_proxy_setup_fattr(&fattr_internal); convert_bitmap.bitmap4_val = bitmap_conv_val; convert_bitmap.bitmap4_len = 2; memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_filename, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); if(isFullDebug(COMPONENT_FSAL)) { char outstr[1024]; nfs4_sprint_fhandle(&nfs4fh, outstr); LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) parent handle=%s\n", outstr); } bitmap.bitmap4_val = bitmap_create; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); create_mode_attr.asked_attributes = FSAL_ATTR_MODE; create_mode_attr.mode = accessmode; fsal_interval_proxy_fsalattr2bitmap4(&create_mode_attr, &convert_bitmap); if(nfs4_FSALattr_To_Fattr(NULL, /* no exportlist required here */ &create_mode_attr, &input_attr, NULL, /* no compound data required here */ NULL, /* No fh here, filehandle is not a settable attribute */ &convert_bitmap) == -1) Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_create); #define FSAL_CREATE_IDX_OP_PUTFH 0 #define FSAL_CREATE_IDX_OP_OPEN_CREATE 1 #define FSAL_CREATE_IDX_OP_GETFH 2 #define FSAL_CREATE_IDX_OP_GETATTR 3 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_OPEN_CREATE(argnfs4, name, input_attr, p_context->clientid, owner_val, owner_len); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.attrset.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.attrset.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_getattr_res; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_create); } ReleaseTokenFSCall(); /* >> convert error code, and return on error << */ if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_create); /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(&attributes, &resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR]. nfs_resop4_u.opgetattr.GETATTR4res_u.resok4. obj_attributes) != 1) { FSAL_CLEAR_MASK(attributes.asked_attributes); FSAL_SET_MASK(attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_create); } /* Return attributes if asked */ if(object_attributes) { memcpy(object_attributes, &attributes, sizeof(attributes)); } if(isFullDebug(COMPONENT_FSAL)) { char outstr[1024]; nfs4_sprint_fhandle(&nfs4fh, outstr); LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) created file handle=%s\n", outstr); } if(fsal_internal_proxy_create_fh (& (resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object), FSAL_TYPE_FILE, attributes.fileid, object_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* Keep the information into the file descriptor as well */ memcpy((char *)&fd.fhandle, (char *)object_handle, sizeof(fd.fhandle)); fd.openflags = FSAL_O_RDWR; fd.current_offset = 0; fd.pcontext = p_context; /* Keep the returned stateid for later use */ fd.stateid.seqid = resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.stateid.seqid; memcpy((char *)fd.stateid.other, resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u. opopen.OPEN4res_u.resok4.stateid.other, 12); /* See if a OPEN_CONFIRM is required */ if(resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM) { fsal_status = FSAL_proxy_open_confirm(&fd); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create); } #ifdef _FSAL_CREATE_CLOSE_FILE /* The craeted file is still opened, to preserve the correct seqid for later use, we close it */ fsal_status = FSAL_close(&fd); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create); #endif /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); } /* FSAL_create */
fsal_status_t HPSSFSAL_readdir(hpssfsal_dir_t * dir_descriptor, /* IN */ fsal_op_context_t * p_context, /* IN */ hpssfsal_cookie_t start_position, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * pdirent, /* OUT */ hpssfsal_cookie_t * end_position, /* OUT */ fsal_count_t * nb_entries, /* OUT */ fsal_boolean_t * end_of_dir /* OUT */ ) { int rc, returned, i; fsal_status_t st; fsal_attrib_mask_t handle_attr_mask; fsal_count_t current_nb_entries, missing_entries, max_dir_entries; /* hpss_ReadRawAttrsHandle arguments. */ u_signed64 curr_start_position; unsigned32 buff_size_in; unsigned32 bool_getattr_in; unsigned32 bool_eod_out; u_signed64 last_offset_out; //ns_DirEntry_t outbuff[FSAL_READDIR_SIZE]; ns_DirEntry_t * outbuff = NULL ; /* sanity checks */ if(!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); if((outbuff = gsh_calloc(FSAL_READDIR_SIZE, sizeof(ns_DirEntry_t))) == NULL) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); /* handle provides : suppattr, type, fileid */ /** @todo : does handle provide mounted_on_fileid ? */ handle_attr_mask = FSAL_ATTR_SUPPATTR | FSAL_ATTR_TYPE | FSAL_ATTR_FILEID; /* if the handle cannot provide the requested attributes, * we have to retrieve file attributes. */ if(get_attr_mask & (~handle_attr_mask)) bool_getattr_in = TRUE; else bool_getattr_in = FALSE; /* init values */ curr_start_position = start_position.data; bool_eod_out = 0; current_nb_entries = 0; max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); /* while we haven't filled the output buffer * and the end of dir has not been reached : */ while((current_nb_entries < max_dir_entries) && (!bool_eod_out)) { missing_entries = max_dir_entries - current_nb_entries; /* If the requested count is smaller than the default FSAL_READDIR_SIZE, * we use a smaller output buffer. */ if(missing_entries < FSAL_READDIR_SIZE) buff_size_in = missing_entries * sizeof(ns_DirEntry_t); else buff_size_in = FSAL_READDIR_SIZE * sizeof(ns_DirEntry_t); /* call to hpss clapi */ TakeTokenFSCall(); rc = HPSSFSAL_ReadRawAttrsHandle(&(dir_descriptor->dir_handle.data.ns_handle), curr_start_position, &dir_descriptor->context.credential.hpss_usercred, buff_size_in, bool_getattr_in, ReturnInconsistentDirent, &bool_eod_out, &last_offset_out, outbuff); ReleaseTokenFSCall(); if(rc < 0) { gsh_free( outbuff ) ; Return(hpss2fsal_error(rc), -rc, INDEX_FSAL_readdir); } else returned = rc; /* Fills the fsal dirent list. */ for(i = 0; i < returned; i++) { memset( (char *)&(pdirent[current_nb_entries].handle), 0, sizeof( hpssfsal_handle_t ) ) ; pdirent[current_nb_entries].handle.data.ns_handle = outbuff[i].ObjHandle; pdirent[current_nb_entries].handle.data.obj_type = hpss2fsal_type(outbuff[i].ObjHandle.Type); st = FSAL_str2name((char *)outbuff[i].Name, HPSS_MAX_FILE_NAME, &pdirent[current_nb_entries].name); /** @todo : test returned status */ pdirent[current_nb_entries].cookie.data = outbuff[i].ObjOffset; /* set asked attributes */ pdirent[current_nb_entries].attributes.asked_attributes = get_attr_mask; if(bool_getattr_in) { /* convert HPSS attributes to fsal attributes */ st = hpss2fsal_attributes(&outbuff[i].ObjHandle, &outbuff[i].Attrs, &pdirent[current_nb_entries].attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(pdirent[current_nb_entries].attributes. asked_attributes); FSAL_SET_MASK(pdirent[current_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } } else if(get_attr_mask) { /* extract asked attributes from file handle */ st = hpssHandle2fsalAttributes(&outbuff[i].ObjHandle, &pdirent[current_nb_entries].attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(pdirent[current_nb_entries].attributes. asked_attributes); FSAL_SET_MASK(pdirent[current_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* set the previous' next */ if(current_nb_entries) pdirent[current_nb_entries - 1].nextentry = &(pdirent[current_nb_entries]); /* current's next */ pdirent[current_nb_entries].nextentry = NULL; /* increment entries count */ current_nb_entries++; curr_start_position = last_offset_out; } } /* At this point, 2 cases : * - the requested count is reached * - the end of dir is reached. * However, the treatment is the same. */ /* setting output vars. */ /* if no item was read, the offset keeps the same. */ end_position->data = (current_nb_entries == 0 ? start_position.data : last_offset_out); *nb_entries = current_nb_entries; *end_of_dir = (bool_eod_out ? TRUE : FALSE); LogDebug(COMPONENT_FSAL, "%s() returned %u entries, end_of_dir=%d", __func__, *nb_entries, *end_of_dir); gsh_free( outbuff ) ; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); /* @todo badly set fsal_log ? */ }
/** * 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); }
/** * * cache_inode_renew_entry: Renews the attributes for an entry. * * Sets the attributes for an entry located in the cache by its address. Attributes are provided * with compliance to the underlying FSAL semantics. Attributes that are set are returned in "*pattr". * * @param pentry_parent [IN] entry for the parent directory to be managed. * @param pattr [OUT] renewed attributes for the entry that we have found. * @param pclient [INOUT] ressource allocated by the client for the nfs management. * @param pcontext [IN] FSAL credentials * @param pstatus [OUT] returned status. * * @return CACHE_INODE_SUCCESS if operation is a success \n @return Other errors shows a FSAL error. * */ cache_inode_status_t cache_inode_renew_entry(cache_entry_t * pentry, fsal_attrib_list_t * pattr, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { fsal_handle_t *pfsal_handle = NULL; fsal_status_t fsal_status; fsal_attrib_list_t object_attributes; fsal_path_t link_content; time_t current_time = time(NULL); time_t entry_time = pentry->internal_md.refresh_time; /* If we do nothing (no expiration) then everything is all right */ *pstatus = CACHE_INODE_SUCCESS; if(isFullDebug(COMPONENT_CACHE_INODE)) { char *type; char grace[20], grace2[20]; unsigned int elapsed = (unsigned int)current_time - (unsigned int)entry_time; int print = 1; cache_inode_expire_to_str(pclient->expire_type_attr, pclient->grace_period_attr, grace); switch(pentry->internal_md.type) { case UNASSIGNED: type = "UNASSIGNED"; break; case REGULAR_FILE: type = "REGULAR_FILE"; break; case CHARACTER_FILE: type = "CHARACTER_FILE"; break; case BLOCK_FILE: type = "BLOCK_FILE"; break; case SYMBOLIC_LINK: print = 0; cache_inode_expire_to_str(pclient->expire_type_link, pclient->grace_period_link, grace2); LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for SYMBOLIC_LINK elapsed time=%u, grace_period_attr=%s, grace_period_link=%s", pentry, elapsed, grace, grace2); break; case SOCKET_FILE: type = "SOCKET_FILE"; break; case FIFO_FILE: type = "FIFO_FILE"; break; case DIRECTORY: print = 0; cache_inode_expire_to_str(pclient->expire_type_dirent, pclient->grace_period_dirent, grace2); LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for DIRECTORY elapsed time=%u, grace_period_attr=%s, grace_period_dirent=%s, has_been_readdir=%u", pentry, elapsed, grace, grace2, pentry->object.dir.has_been_readdir); break; case FS_JUNCTION: type = "FS_JUNCTION"; break; case RECYCLED: type = "RECYCLED"; break; default: type = "UNKNOWN"; break; } if(print) { LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for %s elapsed time=%u, grace_period_attr=%s", pentry, type, elapsed, grace); } } /* An entry that is a regular file with an associated File Content Entry won't * expire until data exists in File Content Cache, to avoid attributes incoherency */ /* @todo: BUGAZOMEU: I got serious doubts on the following blocks: possible trouble if using data caching */ if(pentry->internal_md.type == REGULAR_FILE && pentry->object.file.pentry_content != NULL) { /* Successfull exit without having nothing to do ... */ LogDebug(COMPONENT_CACHE_INODE, "Entry %p is a REGULAR_FILE with associated data cached %p, no expiration", pentry, pentry->object.file.pentry_content); *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry use getattr/mtime checking %d, is dir " "beginning %d, has bit in mask %d, has been readdir %d state %d", pclient->getattr_dir_invalidation, pentry->internal_md.type == DIRECTORY, (int) FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME), pentry->object.dir.has_been_readdir, pentry->internal_md.valid_state); /* Do we use getattr/mtime checking */ if(pclient->getattr_dir_invalidation && pentry->internal_md.type == DIRECTORY && FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME) /*&& pentry->object.dir.has_been_readdir == CACHE_INODE_YES*/) { /* This checking is to be done ... */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry testing directory mtime"); pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: returning %d (%s) from FSAL_getattrs for getattr/mtime checking", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry=%p, type=%d, Cached Time=%d, FSAL Time=%d", pentry, pentry->internal_md.type, pentry->object.dir.attributes.mtime.seconds, object_attributes.mtime.seconds); /* Compare the FSAL mtime and the cached mtime */ if(pentry->object.dir.attributes.mtime.seconds < object_attributes.mtime.seconds) { /* Cached directory content is obsolete, it must be renewed */ cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the directory content as "to be renewed" */ /* Next call to cache_inode_readdir will repopulate the dirent array */ pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: cached directory content for entry %p must be renewed, due to getattr mismatch", pentry); if(cache_inode_invalidate_all_cached_dirent(pentry, ht, pclient, pstatus) != CACHE_INODE_SUCCESS) { /* Should never happen */ LogCrit(COMPONENT_CACHE_INODE, "cache_inode_invalidate_all_cached_dirent returned %d (%s)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } } /* if( pentry->object.dir.attributes.mtime < object_attributes.asked_attributes.mtime ) */ } /* if( pclient->getattr_dir_invalidation && ... */ /* Check for dir content expiration and/or staleness */ if(pentry->internal_md.type == DIRECTORY && pclient->expire_type_dirent != CACHE_INODE_EXPIRE_NEVER && pentry->object.dir.has_been_readdir == CACHE_INODE_YES && ((current_time - entry_time >= pclient->grace_period_dirent) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Case 1: cached directory entries for entry %p must be renewed" " (has been readdir)", pentry); if(isFullDebug(COMPONENT_CACHE_INODE)) { char name[1024]; struct avltree_node *d_node; cache_inode_dir_entry_t *d_dirent; int i = 0; d_node = avltree_first(&pentry->object.dir.dentries); do { d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t, node_n); if (d_dirent->pentry->internal_md.valid_state == VALID) { FSAL_name2str(&(d_dirent->name), name, 1023); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry %d %s", i, name); } i++; } while ((d_node = avltree_next(d_node))); } /* Do the getattr if it had not being done before */ if(pfsal_handle == NULL) { pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (1)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } } cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the directory content as "to be renewed" */ /* Next call to cache_inode_readdir will repopulate the dirent array */ pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type == DIRECTORY && ... */ /* if the directory has not been readdir, only update its attributes */ else if(pentry->internal_md.type == DIRECTORY && pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER && pentry->object.dir.has_been_readdir != CACHE_INODE_YES && ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Case 2: cached directory entries for entry %p must be renewed (has not been readdir)", pentry); if(isFullDebug(COMPONENT_CACHE_INODE)) { char name[1024]; struct avltree_node *d_node; cache_inode_dir_entry_t *d_dirent; int i = 0; d_node = avltree_first(&pentry->object.dir.dentries); do { d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t, node_n); if (d_dirent->pentry->internal_md.valid_state == VALID) { FSAL_name2str(&(d_dirent->name), name, 1023); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry %d %s", i, name); } i++; } while ((d_node = avltree_next(d_node))); } pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (2)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* else if( pentry->internal_md.type == DIRECTORY && ... */ /* Check for attributes expiration in other cases */ else if(pentry->internal_md.type != DIRECTORY && pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER && ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Attributes for entry %p must be renewed", pentry); switch (pentry->internal_md.type) { case REGULAR_FILE: pfsal_handle = &pentry->object.file.handle; break; case SYMBOLIC_LINK: assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; break; case SOCKET_FILE: case FIFO_FILE: case CHARACTER_FILE: case BLOCK_FILE: pfsal_handle = &pentry->object.special_obj.handle; break; case DIRECTORY: case FS_JUNCTION: case UNASSIGNED: case RECYCLED: LogCrit(COMPONENT_CACHE_INODE, "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s", pentry->internal_md.type, __LINE__, __FILE__); *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; #ifdef _USE_MFSL fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, &object_attributes); #else fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, &object_attributes); #endif if(FSAL_IS_ERROR(fsal_status) && fsal_status.major == ERR_FSAL_NOT_OPENED) { //TODO: LOOKATME !!!!! fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for non directories", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* Keep the new attribute in cache */ cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type != DIR_CONTINUE && ... */ /* Check for link content expiration */ if(pentry->internal_md.type == SYMBOLIC_LINK && pclient->expire_type_link != CACHE_INODE_EXPIRE_NEVER && ((current_time - entry_time >= pclient->grace_period_link) || (pentry->internal_md.valid_state == STALE))) { assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "cached link content for entry %p must be renewed", pentry); FSAL_CLEAR_MASK(object_attributes.asked_attributes); FSAL_SET_MASK(object_attributes.asked_attributes, pclient->attrmask); if( CACHE_INODE_KEEP_CONTENT( pentry->policy ) ) { #ifdef _USE_MFSL fsal_status = MFSL_readlink(&pentry->mobject, pcontext, &pclient->mfsl_context, &link_content, &object_attributes, NULL); #else fsal_status = FSAL_readlink(pfsal_handle, pcontext, &link_content, &object_attributes); #endif } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } } else { assert(pentry->object.symlink); fsal_status = FSAL_pathcpy(&pentry->object.symlink->content, &link_content); /* copy ctor? */ if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1; } } /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type == SYMBOLIC_LINK && ... */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* cache_inode_renew_entry */
fsal_status_t VFSFSAL_readdir(fsal_dir_t * dir_descriptor, /* IN */ fsal_cookie_t startposition, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * p_pdirent, /* OUT */ fsal_cookie_t * end_position, /* OUT */ fsal_count_t * p_nb_entries, /* OUT */ fsal_boolean_t * p_end_of_dir /* OUT */ ) { vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t * ) dir_descriptor; vfsfsal_cookie_t start_position; vfsfsal_cookie_t * p_end_position = (vfsfsal_cookie_t *) end_position; fsal_status_t st; fsal_count_t max_dir_entries; fsal_name_t entry_name; char buff[BUF_SIZE]; struct linux_dirent *dp = NULL; int bpos = 0; char d_type; struct stat buffstat; int rc = 0; memset(buff, 0, BUF_SIZE); memset(&entry_name, 0, sizeof(fsal_name_t)); /*****************/ /* sanity checks */ /*****************/ if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); /***************************/ /* seek into the directory */ /***************************/ start_position.data.cookie = *((off_t*) &startposition.data); rc = errno = 0; lseek(p_dir_descriptor->fd, start_position.data.cookie, SEEK_SET); rc = errno; if(rc) Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); /************************/ /* browse the directory */ /************************/ *p_nb_entries = 0; while(*p_nb_entries < max_dir_entries) { /***********************/ /* read the next entry */ /***********************/ TakeTokenFSCall(); rc = syscall(SYS_getdents, p_dir_descriptor->fd, buff, BUF_SIZE); ReleaseTokenFSCall(); if(rc < 0) { rc = errno; Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); } /* End of directory */ if(rc == 0) { *p_end_of_dir = 1; break; } /***********************************/ /* Get information about the entry */ /***********************************/ for(bpos = 0; bpos < rc;) { dp = (struct linux_dirent *)(buff + bpos); d_type = *(buff + bpos + dp->d_reclen - 1); bpos += dp->d_reclen; if(!(*p_nb_entries < max_dir_entries)) break; /* skip . and .. */ if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; /* build the full path of the file into "fsalpath */ if(FSAL_IS_ERROR (st = FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, &(p_pdirent[*p_nb_entries].name)))) ReturnStatus(st, INDEX_FSAL_readdir); // TODO: there is a race here, because between handle fetch // and open at things might change. we need to figure out if there // is another way to open without the pcontext strncpy(entry_name.name, dp->d_name, sizeof(entry_name.name)); entry_name.len = strlen(entry_name.name); /* get object handle */ TakeTokenFSCall(); if(fstatat(p_dir_descriptor->fd, dp->d_name, &buffstat, AT_SYMLINK_NOFOLLOW) < 0 ) { ReleaseTokenFSCall(); Return(posix2fsal_error(errno), errno, INDEX_FSAL_readdir); } st = fsal_internal_get_handle_at( p_dir_descriptor->fd, dp->d_name, &p_pdirent[*p_nb_entries].handle) ; if(FSAL_IS_ERROR(st)) { ReleaseTokenFSCall(); ReturnStatus(st, INDEX_FSAL_readdir); } p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = posix2fsal_attributes(&buffstat, &p_pdirent[*p_nb_entries].attributes); if(FSAL_IS_ERROR(st)) { ReleaseTokenFSCall(); FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); ReturnStatus(st, INDEX_FSAL_getattrs); } ReleaseTokenFSCall(); //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off; ((vfsfsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = dp->d_off; p_pdirent[*p_nb_entries].nextentry = NULL; if(*p_nb_entries) p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]); //(*p_end_position) = p_pdirent[*p_nb_entries].cookie; memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie, sizeof(vfsfsal_cookie_t)); (*p_nb_entries)++; } /* for */ } /* While */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }
/** * FSAL_opendir : * Opens a directory for reading its content. * * \param dir_handle (input) * the handle of the directory to be opened. * \param cred (input) * Permission context for the operation (user,...). * \param dir_descriptor (output) * pointer to an allocated structure that will receive * directory stream informations, on successfull completion. * \param dir_attributes (optional output) * On successfull completion,the structure pointed * by dir_attributes receives the new directory attributes. * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t VFSFSAL_opendir(fsal_handle_t * p_dir_handle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_dir_t * dir_desc, /* OUT */ fsal_attrib_list_t * p_dir_attributes /* [ IN/OUT ] */ ) { vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t *) dir_desc; int rc, errsv; fsal_status_t status; struct stat buffstat; /* sanity checks * note : dir_attributes is optionnal. */ if(!p_dir_handle || !p_context || !p_dir_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir); /* get the path of the directory */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_dir_handle, &p_dir_descriptor->fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* get directory metadata */ TakeTokenFSCall(); rc = fstat(p_dir_descriptor->fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc != 0) { close(p_dir_descriptor->fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_opendir); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_opendir); } /* Test access rights for this directory */ status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* if everything is OK, fills the dir_desc structure : */ memcpy(&(p_dir_descriptor->context), p_context, sizeof(vfsfsal_op_context_t)); memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(vfsfsal_handle_t)); if(p_dir_attributes) { status = posix2fsal_attributes(&buffstat, p_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_dir_attributes->asked_attributes); FSAL_SET_MASK(p_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } p_dir_descriptor->dir_offset = 0; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); }
fsal_status_t PROXYFSAL_rename(fsal_handle_t * old_parent, /* IN */ fsal_name_t * p_old_name, /* IN */ fsal_handle_t * new_parent, /* IN */ fsal_name_t * p_new_name, /* IN */ fsal_op_context_t *context, /* IN */ fsal_attrib_list_t * src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh_old; nfs_fh4 nfs4fh_new; bitmap4 bitmap_old; uint32_t bitmap_val_old[2]; bitmap4 bitmap_new; uint32_t bitmap_val_new[2]; component4 oldname; char oldnameval[MAXNAMLEN+1]; component4 newname; char newnameval[MAXNAMLEN+1]; proxyfsal_handle_t * old_parentdir_handle = (proxyfsal_handle_t *)old_parent; proxyfsal_handle_t * new_parentdir_handle = (proxyfsal_handle_t *)new_parent; proxyfsal_op_context_t * p_context = (proxyfsal_op_context_t *)context; #define FSAL_RENAME_NB_OP_ALLOC 7 nfs_argop4 argoparray[FSAL_RENAME_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_RENAME_NB_OP_ALLOC]; uint32_t bitmap_res_old[2]; uint32_t bitmap_res_new[2]; fsal_proxy_internal_fattr_t fattr_internal_new; fsal_proxy_internal_fattr_t fattr_internal_old; struct timeval timeout = TIMEOUTRPC; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!old_parentdir_handle || !new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal_new); fsal_internal_proxy_setup_fattr(&fattr_internal_old); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Rename" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; /* Prepare the structures */ bitmap_old.bitmap4_val = bitmap_val_old; bitmap_old.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap_old); if(fsal_internal_proxy_extract_fh(&nfs4fh_old, old_parent) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); memset((char *)&oldname, 0, sizeof(component4)); oldname.utf8string_val = oldnameval; oldname.utf8string_len = sizeof(oldnameval); if(fsal_internal_proxy_fsal_name_2_utf8(p_old_name, &oldname) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); bitmap_new.bitmap4_val = bitmap_val_new; bitmap_new.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap_new); if(fsal_internal_proxy_extract_fh(&nfs4fh_new, new_parent) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); memset((char *)&newname, 0, sizeof(component4)); newname.utf8string_val = newnameval; newname.utf8string_len = sizeof(newnameval); if(fsal_internal_proxy_fsal_name_2_utf8(p_new_name, &newname) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); #define FSAL_RENAME_IDX_OP_PUTFH_OLD 0 #define FSAL_RENAME_IDX_OP_SAVEFH 1 #define FSAL_RENAME_IDX_OP_PUTFH_NEW 2 #define FSAL_RENAME_IDX_OP_RENAME 3 #define FSAL_RENAME_IDX_OP_GETATTR_NEW 4 #define FSAL_RENAME_IDX_OP_RESTOREFH 5 #define FSAL_RENAME_IDX_OP_GETATTR_OLD 6 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_old); COMPOUNDV4_ARG_ADD_OP_SAVEFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_new); COMPOUNDV4_ARG_ADD_OP_RENAME(argnfs4, oldname, newname); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap_new); COMPOUNDV4_ARG_ADD_OP_RESTOREFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap_old); resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res_new; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal_new; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal_new); resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res_old; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal_old; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal_old); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_rename); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_rename); /* >> get last parent post op attributes if asked * For example : << */ if(src_dir_attributes) { if(nfs4_Fattr_To_FSAL_attr(src_dir_attributes, &resnfs4.resarray.resarray_val [FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes, ANON_UID, ANON_GID) != NFS4_OK) { FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes); FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rename); } } /* >> get new parent post op attributes if asked * For example : << */ if(tgt_dir_attributes) { if(nfs4_Fattr_To_FSAL_attr(tgt_dir_attributes, &resnfs4.resarray.resarray_val [FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes, ANON_UID, ANON_GID) != NFS4_OK) { FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rename); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/** * PTFSAL_getattrs: * Get attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param cred (input): * Authentication context for the operation (user,...). * \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) * - Another error code if an error occured. */ fsal_status_t PTFSAL_getattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_object_attributes /* IN/OUT */) { fsal_status_t st; int stat_rc; fsi_stat_struct buffstat; ptfsal_op_context_t * fsi_op_context = (ptfsal_op_context_t *)p_context; ptfsal_export_context_t * fsi_export_context = fsi_op_context->export_context; #ifdef _USE_NFS4_ACL fsal_accessflags_t access_mask = 0; #endif FSI_TRACE(FSI_DEBUG, "Begin-------------------\n"); /* sanity checks. * note : object_attributes is mandatory in PTFSAL_getattrs. */ if (!p_filehandle || !p_context || !p_object_attributes) { Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs); } stat_rc = ptfsal_stat_by_handle(p_filehandle, p_context, &buffstat); if (stat_rc) { Return(ERR_FSAL_INVAL, errno, INDEX_FSAL_getattrs); } /* convert attributes */ st = posix2fsal_attributes(&buffstat, p_object_attributes); FSI_TRACE(FSI_DEBUG, "Handle type=%d st_mode=%o (octal)", p_object_attributes->type, buffstat.st_mode); p_object_attributes->mounted_on_fileid = fsi_export_context->ganesha_export_id; if (FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); ReturnStatus(st, INDEX_FSAL_getattrs); } #ifdef _USE_NFS4_ACL /* Check permission to get attributes and ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_READ_ATTR | FSAL_ACE_PERM_READ_ACL); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) { st = fsal_internal_testAccess(p_context, access_mask, NULL, p_object_attributes); } else { st = fsal_internal_access(p_context, p_filehandle, access_mask, p_object_attributes); } if (FSAL_IS_ERROR(st)) { ReturnStatus(st, INDEX_FSAL_getattrs); } #endif FSI_TRACE(FSI_DEBUG, "End-----------------------------\n"); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs); }
/** * PTFSAL_setattrs: * Set attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param cred (input): * Authentication context for the operation (user,...). * \param attrib_set (mandatory input): * The attributes to be set for the object. * It defines the attributes that the caller * wants to set and their values. * \param object_attributes (optionnal input/output): * The post operation 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). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t PTFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_attrib_set, /* IN */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */) { unsigned int i; fsal_status_t status; ptfsal_xstat_t buffxstat; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t wanted_attrs, current_attrs; mode_t st_mode_in_cache = 0; char fsi_name[PATH_MAX]; int rc; int fd; FSI_TRACE(FSI_DEBUG, "Begin-----------------------------------------\n"); /* sanity checks. * note : object_attributes is optional. */ if (!p_filehandle || !p_context || !p_attrib_set) { Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); } /* local copy of attributes */ wanted_attrs = *p_attrib_set; /* First, check that FSAL attributes changes are allowed. */ if (!global_fs_info.cansettime) { if (wanted_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(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) { wanted_attrs.mode &= (~global_fs_info.umask); } /* get current attributes */ current_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES; status = PTFSAL_getattrs(p_filehandle, p_context, ¤t_attrs); if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); ReturnStatus(status, INDEX_FSAL_setattrs); } /************** * TRUNCATE * **************/ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_SIZE)) { status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); if (FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_setattrs); } status = PTFSAL_truncate( p_filehandle, p_context, wanted_attrs.filesize, &fd, p_object_attributes); if (FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_setattrs); } } /*********** * CHMOD * ***********/ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) { FSI_TRACE(FSI_DEBUG, "Begin chmod------------------\n"); /* The POSIX chmod call don't affect the symlink object, but * the entry it points to. So we must ignore it. */ if (current_attrs.type != FSAL_TYPE_LNK) { /* For modifying mode, user must be root or the owner */ if ((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { FSI_TRACE(FSI_DEBUG, "Permission denied for CHMOD opeartion: " "current owner=%d, credential=%d", current_attrs.owner, p_context->credential.user); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); #endif /* Fill wanted mode. */ buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode); FSI_TRACE(FSI_DEBUG, "current mode = %o, new mode = %o", fsal2unix_mode(current_attrs.mode), buffxstat.buffstat.st_mode); rc = fsi_get_name_from_handle(p_context, p_filehandle->data.handle.f_handle, fsi_name, NULL); if (rc < 0) { FSI_TRACE(FSI_ERR, "Failed to convert file handle back to filename" ); FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", p_filehandle->data.handle.f_handle); Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs); } FSI_TRACE(FSI_DEBUG, "Handle to name: %s for handle %s", fsi_name, p_filehandle->data.handle.f_handle); rc = ptfsal_chmod(p_context, fsi_name, buffxstat.buffstat.st_mode); if (rc == -1) { FSI_TRACE(FSI_ERR, "chmod FAILED"); Return (ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } else { st_mode_in_cache = (buffxstat.buffstat.st_mode | fsal_type2unix(current_attrs.type)); fsi_update_cache_stat(fsi_name, st_mode_in_cache, p_context->export_context->pt_export_id); FSI_TRACE(FSI_INFO, "Chmod SUCCEED with st_mode in cache being %o", st_mode_in_cache); } } FSI_TRACE(FSI_DEBUG, "End chmod-------------------\n"); } /*********** * CHOWN * ***********/ FSI_TRACE(FSI_DEBUG, "Begin chown------------------------------\n"); /* Only root can change uid and A normal user must be in the group * he wants to set */ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { /* For modifying owner, user must be root or current * owner==wanted==client */ if ((p_context->credential.user != 0) && ((p_context->credential.user != current_attrs.owner) || (p_context->credential.user != wanted_attrs.owner))) { FSI_TRACE(FSI_DEBUG, "Permission denied for CHOWN opeartion: " "current owner=%d, credential=%d, new owner=%d", current_attrs.owner, p_context->credential.user, wanted_attrs.owner); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); #endif } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { /* For modifying group, user must be root or current owner */ if ((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } int in_grp = 0; /* set in_grp */ if (p_context->credential.group == wanted_attrs.group) { in_grp = 1; } else { for(i = 0; i < p_context->credential.nbgroups; i++) { if ((in_grp = (wanted_attrs.group == p_context->credential.alt_groups[i]))) break; } } /* it must also be in target group */ if (p_context->credential.user != 0 && !in_grp) { FSI_TRACE(FSI_DEBUG, "Permission denied for CHOWN operation: " "current group=%d, credential=%d, new group=%d", current_attrs.group, p_context->credential.group, wanted_attrs.group); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); #endif } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { /* Fill wanted owner. */ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { buffxstat.buffstat.st_uid = (int)wanted_attrs.owner; } else { buffxstat.buffstat.st_uid = (int)current_attrs.owner; } FSI_TRACE(FSI_DEBUG, "current uid = %d, new uid = %d", current_attrs.owner, buffxstat.buffstat.st_uid); /* Fill wanted group. */ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { buffxstat.buffstat.st_gid = (int)wanted_attrs.group; } else { buffxstat.buffstat.st_gid = (int)current_attrs.group; } FSI_TRACE(FSI_DEBUG, "current gid = %d, new gid = %d", current_attrs.group, buffxstat.buffstat.st_gid); rc = fsi_get_name_from_handle(p_context, p_filehandle->data.handle.f_handle, fsi_name, NULL); if (rc < 0) { FSI_TRACE(FSI_ERR, "Failed to convert file handle back to filename" ); FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", p_filehandle->data.handle.f_handle); Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs); } FSI_TRACE(FSI_DEBUG, "handle to name: %s for handle %s", fsi_name, p_filehandle->data.handle.f_handle); rc = ptfsal_chown(p_context, fsi_name, buffxstat.buffstat.st_uid, buffxstat.buffstat.st_gid); if (rc == -1) { FSI_TRACE(FSI_ERR, "chown FAILED"); Return (ERR_FSAL_PERM, 1, INDEX_FSAL_setattrs); } else { FSI_TRACE(FSI_INFO, "Chown SUCCEED"); } } FSI_TRACE(FSI_DEBUG, "End chown-----------------------------------\n"); /*********** * UTIME * ***********/ FSI_TRACE(FSI_DEBUG, "Begin UTIME-----------------------------------\n"); /* user must be the owner or have read access to modify 'atime' */ access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); } else { status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && (status.major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } /* user must be the owner or have write access to modify 'mtime' */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); } else { status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && (status.major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { /* Fill wanted atime. */ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)) { buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds; FSI_TRACE(FSI_DEBUG, "current atime = %lu, new atime = %lu", (unsigned long)current_attrs.atime.seconds, (unsigned long)buffxstat.buffstat.st_atime); } else { buffxstat.buffstat.st_atime = (time_t) current_attrs.atime.seconds; } FSI_TRACE(FSI_DEBUG, "current atime = %lu, new atime = %lu", (unsigned long)current_attrs.atime.seconds, (unsigned long)buffxstat.buffstat.st_atime); /* Fill wanted mtime. */ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME)) { buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds; } else { buffxstat.buffstat.st_mtime = (time_t) current_attrs.mtime.seconds; } FSI_TRACE(FSI_DEBUG, "current mtime = %lu, new mtime = %lu", (unsigned long)current_attrs.mtime.seconds, (unsigned long)buffxstat.buffstat.st_mtime); rc = fsi_get_name_from_handle(p_context, p_filehandle->data.handle.f_handle, fsi_name, NULL); if (rc < 0) { FSI_TRACE(FSI_ERR, "Failed to convert file handle back to filename " "from cache" ); FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", p_filehandle->data.handle.f_handle); Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs); } FSI_TRACE(FSI_DEBUG, "Handle to name: %s for handle %s", fsi_name, p_filehandle->data.handle.f_handle); rc = ptfsal_ntimes(p_context, fsi_name, buffxstat.buffstat.st_atime, buffxstat.buffstat.st_mtime); if (rc == -1) { FSI_TRACE(FSI_ERR, "ntime FAILED"); Return (ERR_FSAL_PERM, 2, INDEX_FSAL_setattrs); } else { FSI_TRACE(FSI_INFO, "ntime SUCCEED"); } } FSI_TRACE(FSI_DEBUG, "End UTIME------------------------------\n"); #ifdef _USE_NFS4_ACL /*********** * ACL * ***********/ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ACL)) { /* Check permission to set ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); if (wanted_attrs.acl) { LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl); /* Convert FSAL ACL to PTFS NFS4 ACL and fill the buffer. */ status = fsal_acl_2_ptfs_acl(wanted_attrs.acl, &buffxstat); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { LogCrit(COMPONENT_FSAL, "setattr acl is NULL"); Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); } } #endif /* _USE_NFS4_ACL */ /* Optionaly fills output attributes. */ if (p_object_attributes) { status = PTFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } FSI_TRACE(FSI_DEBUG, "End--------------------------------------------\n"); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
/** * FSAL_mkdir: * Create a directory. * * \param parent_directory_handle (input): * Handle of the parent directory where * the subdirectory is to be created. * \param p_dirname (input): * Pointer to the name of the directory to be created. * \param cred (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 object_handle (output): * Pointer to the handle of the created directory. * \param object_attributes (optionnal input/output): * The attributes of the created directory. * 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 (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 PROXYFSAL_mkdir(proxyfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ proxyfsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; uint32_t bitmap_mkdir[2]; uint32_t bitmap_getattr_res[2]; uint32_t bitmap_conv_val[2]; fattr4 input_attr; bitmap4 convert_bitmap; component4 name; char nameval[MAXNAMLEN]; char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN]; fsal_proxy_internal_fattr_t fattr_internal; fsal_attrib_list_t create_mode_attr; fsal_attrib_list_t attributes; #define FSAL_MKDIR_NB_OP_ALLOC 4 #define FSAL_MKDIR_VAL_BUFFER 1024 nfs_argop4 argoparray[FSAL_MKDIR_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_MKDIR_NB_OP_ALLOC]; char fattr_val[FSAL_MKDIR_VAL_BUFFER]; struct timeval timeout = { 25, 0 }; /* sanity checks. * note : object_attributes is optional. */ if(!parent_directory_handle || !p_context || !object_handle || !p_dirname) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); PRINT_HANDLE("FSAL_mkdir", parent_directory_handle); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Mkdir" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; input_attr.attrmask.bitmap4_val = bitmap_val; input_attr.attrmask.bitmap4_len = 2; input_attr.attr_vals.attrlist4_val = fattr_val; input_attr.attr_vals.attrlist4_len = FSAL_MKDIR_VAL_BUFFER; fsal_internal_proxy_setup_fattr(&fattr_internal); convert_bitmap.bitmap4_val = bitmap_conv_val; convert_bitmap.bitmap4_len = 2; memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_dirname, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); bitmap.bitmap4_val = bitmap_mkdir; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); create_mode_attr.asked_attributes = FSAL_ATTR_MODE; create_mode_attr.mode = accessmode; fsal_interval_proxy_fsalattr2bitmap4(&create_mode_attr, &convert_bitmap); if(nfs4_FSALattr_To_Fattr(NULL, /* no exportlist required here */ &create_mode_attr, &input_attr, NULL, /* no compound data required here */ NULL, /* No fh here, filehandle is not a settable attribute */ &convert_bitmap) == -1) Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_mkdir); #define FSAL_MKDIR_IDX_OP_PUTFH 0 #define FSAL_MKDIR_IDX_OP_MKDIR 1 #define FSAL_MKDIR_IDX_OP_GETFH 2 #define FSAL_MKDIR_IDX_OP_GETATTR 3 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_MKDIR(argnfs4, name, input_attr); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_MKDIR].nfs_resop4_u.opcreate. CREATE4res_u.resok4.attrset.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_MKDIR].nfs_resop4_u.opcreate. CREATE4res_u.resok4.attrset.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETFH].nfs_resop4_u.opgetfh.GETFH4res_u. resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETFH].nfs_resop4_u.opgetfh.GETFH4res_u. resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_getattr_res; resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, 0, INDEX_FSAL_mkdir); } ReleaseTokenFSCall(); /* >> convert error code, and return on error << */ if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_mkdir); /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(&attributes, &resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETATTR]. nfs_resop4_u.opgetattr.GETATTR4res_u.resok4. obj_attributes) != 1) { FSAL_CLEAR_MASK(attributes.asked_attributes); FSAL_SET_MASK(attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mkdir); } if(object_attributes) { memcpy(object_attributes, &attributes, sizeof(attributes)); } if(fsal_internal_proxy_create_fh (& (resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object), FSAL_TYPE_DIR, attributes.fileid, object_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); PRINT_HANDLE("FSAL_mkdir new obj", object_handle); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); }
cache_entry_t *cache_inode_get_located(cache_inode_fsal_data_t * pfsdata, cache_entry_t * plocation, cache_inode_policy_t policy, fsal_attrib_list_t * pattr, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { hash_buffer_t key, value; cache_entry_t *pentry = NULL; fsal_status_t fsal_status; cache_inode_create_arg_t create_arg; cache_inode_file_type_t type; int hrc = 0; fsal_attrib_list_t fsal_attributes; cache_inode_fsal_data_t *ppoolfsdata = NULL; memset(&create_arg, 0, sizeof(create_arg)); /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* stats */ /* cache_invalidate calls this with no context or client */ if (pclient) { pclient->stat.nb_call_total += 1; pclient->stat.func_stats.nb_call[CACHE_INODE_GET] += 1; } /* Turn the input to a hash key */ if(cache_inode_fsaldata_2_key(&key, pfsdata, pclient)) { *pstatus = CACHE_INODE_UNAPPROPRIATED_KEY; /* stats */ /* cache_invalidate calls this with no context or client */ if (pclient) { pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; ppoolfsdata = (cache_inode_fsal_data_t *) key.pdata; ReleaseToPool(ppoolfsdata, &pclient->pool_key); } return NULL; } switch (hrc = HashTable_Get(ht, &key, &value)) { case HASHTABLE_SUCCESS: /* Entry exists in the cache and was found */ pentry = (cache_entry_t *) value.pdata; /* return attributes additionally */ *pattr = pentry->attributes; if ( !pclient ) { /* invalidate. Just return it to mark it stale and go on. */ return( pentry ); } break; case HASHTABLE_ERROR_NO_SUCH_KEY: if ( !pclient ) { /* invalidate. Just return */ return( NULL ); } /* Cache miss, allocate a new entry */ /* XXX I do not think this can happen with avl dirent cache */ if(pfsdata->cookie != DIR_START) { /* added for sanity check */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_get: pfsdata->cookie != DIR_START (=%"PRIu64") on object whose type is %u", pfsdata->cookie, cache_inode_fsal_type_convert(fsal_attributes.type)); pfsdata->cookie = DIR_START; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); /* redo the call */ return cache_inode_get(pfsdata, policy, pattr, ht, pclient, pcontext, pstatus); } /* First, call FSAL to know what the object is */ fsal_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(&pfsdata->handle, pcontext, &fsal_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_get: cache_inode_status=%u fsal_status=%u,%u ", *pstatus, fsal_status.major, fsal_status.minor); if(fsal_status.major == ERR_FSAL_STALE) { char handle_str[256]; snprintHandle(handle_str, 256, &pfsdata->handle); LogEvent(COMPONENT_CACHE_INODE, "cache_inode_get: Stale FSAL File Handle %s, fsal_status=(%u,%u)", handle_str, fsal_status.major, fsal_status.minor); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* The type has to be set in the attributes */ if(!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE)) { *pstatus = CACHE_INODE_FSAL_ERROR; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Get the cache_inode file type */ type = cache_inode_fsal_type_convert(fsal_attributes.type); if(type == SYMBOLIC_LINK) { if( CACHE_INODE_KEEP_CONTENT( policy ) ) { FSAL_CLEAR_MASK(fsal_attributes.asked_attributes); FSAL_SET_MASK(fsal_attributes.asked_attributes, pclient->attrmask); fsal_status = FSAL_readlink(&pfsdata->handle, pcontext, &create_arg.link_content, &fsal_attributes); } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_get: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_get: Could not kill entry %p, status = %u, fsal_status=(%u,%u)", pentry, kill_status, fsal_status.major, fsal_status.minor); *pstatus = CACHE_INODE_FSAL_ESTALE; } return NULL; } } /* Add the entry to the cache */ if ( type == 1) LogCrit(COMPONENT_CACHE_INODE,"inode get"); if((pentry = cache_inode_new_entry( pfsdata, &fsal_attributes, type, policy, &create_arg, NULL, /* never used to add a new DIR_CONTINUE within this function */ ht, pclient, pcontext, FALSE, /* This is a population, not a creation */ pstatus ) ) == NULL ) { /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Set the returned attributes */ *pattr = fsal_attributes; /* Now, exit the switch/case and returns */ break; default: /* This should not happened */ *pstatus = CACHE_INODE_INVALID_ARGUMENT; LogCrit(COMPONENT_CACHE_INODE, "cache_inode_get returning CACHE_INODE_INVALID_ARGUMENT - this should not have happened"); if ( !pclient ) { /* invalidate. Just return */ return( NULL ); } /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; break; } /* Want to ASSERT pclient at this point */ *pstatus = CACHE_INODE_SUCCESS; if (pentry->object.symlink != NULL) { int stop_here; stop_here = 1; if (stop_here) { stop_here = 2; } } /* valid the found entry, if this is not feasable, returns nothing to the client */ if( plocation != NULL ) { if( plocation != pentry ) { P_w(&pentry->lock); if((*pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient)) != CACHE_INODE_SUCCESS) { V_w(&pentry->lock); pentry = NULL; } V_w(&pentry->lock); } } /* stats */ pclient->stat.func_stats.nb_success[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return pentry; } /* cache_inode_get_located */
/** * FSAL_link: * Create a hardlink. * * \param target_handle (input): * Handle of the target object. * \param dir_handle (input): * Pointer to the directory handle where * the hardlink is to be created. * \param p_link_name (input): * Pointer to the name of the hardlink to be created. * \param cred (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_handle or dir_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 attributes->asked_attributes field. */ fsal_status_t PROXYFSAL_link(proxyfsal_handle_t * target_handle, /* IN */ proxyfsal_handle_t * dir_handle, /* IN */ fsal_name_t * p_link_name, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh_target; nfs_fh4 nfs4fh_dest; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; component4 name; char nameval[MAXNAMLEN]; fsal_proxy_internal_fattr_t fattr_internal; struct timeval timeout = { 25, 0 }; /* sanity checks. * note : attributes is optional. */ if(!target_handle || !dir_handle || !p_context || !p_link_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); /* Tests if hardlinking is allowed by configuration. */ if(!global_fs_info.link_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link); #define FSAL_LINK_NB_OP_ALLOC 6 nfs_argop4 argoparray[FSAL_LINK_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_LINK_NB_OP_ALLOC]; /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Link" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; bitmap.bitmap4_val = bitmap_val; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); if(fsal_internal_proxy_extract_fh(&nfs4fh_target, target_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); if(fsal_internal_proxy_extract_fh(&nfs4fh_dest, dir_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_link_name, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); #define FSAL_LINK_IDX_OP_PUTFH_TARGET 0 #define FSAL_LINK_IDX_OP_SAVEFH 1 #define FSAL_LINK_IDX_OP_PUTFH_DEST 2 #define FSAL_LINK_IDX_OP_LINK 3 #define FSAL_LINK_IDX_OP_RESTOREFH 4 #define FSAL_LINK_IDX_OP_GETATTR 5 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_target); COMPOUNDV4_ARG_ADD_OP_SAVEFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_dest); COMPOUNDV4_ARG_ADD_OP_LINK(argnfs4, name); COMPOUNDV4_ARG_ADD_OP_RESTOREFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_link); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_link); if(attributes) { /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(attributes, &resnfs4.resarray. resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != 1) { FSAL_CLEAR_MASK(attributes->asked_attributes); FSAL_SET_MASK(attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_link); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); }
/* * Read the ACL in GlusterFS format and convert it into fsal ACL before * storing it in fsalattr */ fsal_status_t glusterfs_get_acl(struct glusterfs_export *glfs_export, struct glfs_object *glhandle, glusterfs_fsal_xstat_t *buffxstat, struct attrlist *fsalattr) { fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 }; fsal_acl_data_t acldata; fsal_acl_status_t aclstatus; fsal_ace_t *pace = NULL; int e_count = 0, i_count = 0, new_count = 0, new_i_count = 0; if (fsalattr->acl != NULL) { /* We should never be passed attributes that have an * ACL attached, but just in case some future code * path changes that assumption, let's release the * old ACL properly. */ int acl_status; acl_status = nfs4_acl_release_entry(fsalattr->acl); if (acl_status != NFS_V4_ACL_SUCCESS) LogCrit(COMPONENT_FSAL, "Failed to release old acl, status=%d", acl_status); fsalattr->acl = NULL; } if (NFSv4_ACL_SUPPORT) { buffxstat->e_acl = glfs_h_acl_get(glfs_export->gl_fs->fs, glhandle, ACL_TYPE_ACCESS); if (!buffxstat->e_acl) { status = gluster2fsal_error(errno); return status; } e_count = ace_count(buffxstat->e_acl); if (buffxstat->is_dir) { buffxstat->i_acl = glfs_h_acl_get(glfs_export->gl_fs->fs, glhandle, ACL_TYPE_DEFAULT); i_count = ace_count(buffxstat->i_acl); } /* Allocating memory for both ALLOW and DENY entries */ acldata.naces = 2 * (e_count + i_count); LogDebug(COMPONENT_FSAL, "No of aces present in fsal_acl_t = %d" , acldata.naces); if (!acldata.naces) return status; FSAL_SET_MASK(buffxstat->attr_valid, XATTR_ACL); acldata.aces = (fsal_ace_t *) nfs4_ace_alloc(acldata.naces); pace = acldata.aces; new_count = posix_acl_2_fsal_acl(buffxstat->e_acl, buffxstat->is_dir, false, &pace); if (new_count < 0) return fsalstat(ERR_FSAL_NO_ACE, -1); if (i_count > 0) { new_i_count = posix_acl_2_fsal_acl(buffxstat->i_acl, true, true, &pace); if (new_i_count > 0) new_count += new_i_count; else LogDebug(COMPONENT_FSAL, "Inherit acl is not set for this directory"); } /* Reallocating acldata into the required size */ acldata.aces = (fsal_ace_t *) gsh_realloc(acldata.aces, new_count*sizeof(fsal_ace_t)); acldata.naces = new_count; fsalattr->acl = nfs4_acl_new_entry(&acldata, &aclstatus); LogDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u", fsalattr->acl, aclstatus); if (fsalattr->acl == NULL) { LogCrit(COMPONENT_FSAL, "failed to create a new acl entry"); return fsalstat(ERR_FSAL_NOMEM, -1); } fsalattr->valid_mask |= ATTR_ACL; } else { /* We were asked for ACL but do not support. */ status = fsalstat(ERR_FSAL_NOTSUPP, 0); } return status; }
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_open: * Open a regular file for reading/writing its data content. * * \param filehandle (input): * Handle of the file to be read/modified. * \param cred (input): * Authentication context for the operation (user,...). * \param openflags (input): * Flags that indicates behavior for file opening and access. * This is an inclusive OR of the following values * ( such of them are not compatible) : * - FSAL_O_RDONLY: opening file for reading only. * - FSAL_O_RDWR: opening file for reading and writing. * - FSAL_O_WRONLY: opening file for writting only. * - FSAL_O_APPEND: always write at the end of the file. * - FSAL_O_TRUNC: truncate the file to 0 on opening. * \param file_descriptor (output): * The file descriptor to be used for FSAL_read/write operations. * \param file_attributes (optionnal input/output): * Post operation attributes. * 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_ACCESS (user doesn't have the permissions for opening the file) * - ERR_FSAL_STALE (filehandle does not address an existing object) * - ERR_FSAL_INVAL (filehandle does not address a regular file, * or open flags are conflicting) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_IO, ... */ fsal_status_t FUSEFSAL_open(fsal_handle_t * file_hdl, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_openflags_t openflags, /* IN */ fsal_file_t * file_desc, /* OUT */ fsal_attrib_list_t * file_attributes /* [ IN/OUT ] */ ) { int rc = 0; char object_path[FSAL_MAX_PATH_LEN]; int file_info_provided = FALSE; fusefsal_handle_t * filehandle = (fusefsal_handle_t *)file_hdl; fusefsal_file_t * file_descriptor = (fusefsal_file_t *)file_desc; /* sanity checks. * note : file_attributes is optional. */ if(!filehandle || !p_context || !file_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_open); /* get the full path for this file */ rc = NamespacePath(filehandle->data.inode, filehandle->data.device, filehandle->data.validator, object_path); if(rc) Return(ERR_FSAL_STALE, rc, INDEX_FSAL_open); memset(file_descriptor, 0, sizeof(fusefsal_file_t)); /* set access mode flags */ file_descriptor->file_info.flags = 0; if(openflags & FSAL_O_RDONLY) file_descriptor->file_info.flags |= O_RDONLY; if(openflags & FSAL_O_WRONLY) file_descriptor->file_info.flags |= O_WRONLY; if(openflags & FSAL_O_RDWR) file_descriptor->file_info.flags |= O_RDWR; /* set context for the next operation, so it can be retrieved by FS thread */ fsal_set_thread_context(p_context); /* check open call */ if(p_fs_ops->open) { LogFullDebug(COMPONENT_FSAL, "Call to open( %s, %#X )", object_path, file_descriptor->file_info.flags); TakeTokenFSCall(); rc = p_fs_ops->open(object_path, &(file_descriptor->file_info)); ReleaseTokenFSCall(); if(rc) Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open); file_info_provided = TRUE; } else { LogFullDebug(COMPONENT_FSAL, "no open command provided"); /* ignoring open */ memset(&(file_descriptor->file_info), 0, sizeof(struct ganefuse_file_info)); } /* check open flags (only FSAL_O_TRUNC and FSAL_O_APPEND are used for FUSE filesystems) */ if(openflags & FSAL_O_TRUNC) { if(file_info_provided && p_fs_ops->ftruncate) { LogFullDebug(COMPONENT_FSAL, "call to ftruncate on file since FSAL_O_TRUNC was set"); /* ftruncate the file */ TakeTokenFSCall(); rc = p_fs_ops->ftruncate(object_path, 0, &(file_descriptor->file_info)); ReleaseTokenFSCall(); if(rc) Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open); } else if(p_fs_ops->truncate) { LogFullDebug(COMPONENT_FSAL, "call to truncate on file since FSAL_O_TRUNC was set"); /* truncate the file */ TakeTokenFSCall(); rc = p_fs_ops->truncate(object_path, 0); ReleaseTokenFSCall(); if(rc) Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open); } /* else: ignoring flag */ } if(openflags & FSAL_O_APPEND) { struct stat stbuf; /* In this case, this only solution is to get file attributes */ if(file_info_provided && p_fs_ops->fgetattr) { rc = p_fs_ops->fgetattr(object_path, &stbuf, &(file_descriptor->file_info)); } else { rc = p_fs_ops->getattr(object_path, &stbuf); } if(rc) Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open); file_descriptor->current_offset = stbuf.st_size; } else { file_descriptor->current_offset = 0; } /* fill the file descriptor structure */ file_descriptor->file_handle = *filehandle; /* backup context */ file_descriptor->context = *(fusefsal_op_context_t *)p_context; if(file_info_provided) LogFullDebug(COMPONENT_FSAL, "FSAL_open: FH=%"PRId64, file_descriptor->file_info.fh); if(file_attributes) { fsal_status_t status; status = FUSEFSAL_getattrs((fsal_handle_t *)filehandle, p_context, file_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(file_attributes->asked_attributes); FSAL_SET_MASK(file_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_open); }
/** * FSAL_readdir : * Read the entries of an opened directory. * * \param dir_descriptor (input): * Pointer to the directory descriptor filled by FSAL_opendir. * \param start_position (input): * Cookie that indicates the first object to be read during * this readdir operation. * This should be : * - FSAL_READDIR_FROM_BEGINNING for reading the content * of the directory from the beginning. * - The end_position parameter returned by the previous * call to FSAL_readdir. * \param get_attr_mask (input) * Specify the set of attributes to be retrieved for directory entries. * \param buffersize (input) * The size (in bytes) of the buffer where * the direntries are to be stored. * \param pdirent (output) * Adresse of the buffer where the direntries are to be stored. * \param end_position (output) * Cookie that indicates the current position in the directory. * \param nb_entries (output) * Pointer to the number of entries read during the call. * \param end_of_dir (output) * Pointer to a boolean that indicates if the end of dir * has been reached during the call. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t LUSTREFSAL_readdir(fsal_dir_t *dir_desc, /* IN */ fsal_cookie_t start_pos, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * p_pdirent, /* OUT */ fsal_cookie_t * p_end_position, /* OUT */ fsal_count_t * p_nb_entries, /* OUT */ fsal_boolean_t * p_end_of_dir /* OUT */ ) { fsal_status_t st; fsal_count_t max_dir_entries; struct dirent *dp; struct dirent dpe; fsal_path_t fsalpath; int rc; lustrefsal_dir_t * p_dir_descriptor = (lustrefsal_dir_t *)dir_desc; lustrefsal_cookie_t start_position; /*****************/ /* sanity checks */ /*****************/ if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); start_position.data.cookie = (off_t)start_pos.data; /***************************/ /* seek into the directory */ /***************************/ errno = 0; if(start_position.data.cookie == 0) { rewinddir(p_dir_descriptor->p_dir); rc = errno; } else { seekdir(p_dir_descriptor->p_dir, start_position.data.cookie); rc = errno; } if(rc) Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); /************************/ /* browse the directory */ /************************/ *p_nb_entries = 0; while(*p_nb_entries < max_dir_entries) { /***********************/ /* read the next entry */ /***********************/ TakeTokenFSCall(); rc = readdir_r(p_dir_descriptor->p_dir, &dpe, &dp); ReleaseTokenFSCall(); if(rc) { rc = errno; Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); } /* End of directory */ if(!dp) { *p_end_of_dir = 1; break; } /***********************************/ /* Get information about the entry */ /***********************************/ /* skip . and .. */ if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; /* build the full path of the file into "fsalpath */ if(FSAL_IS_ERROR (st = FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, &(p_pdirent[*p_nb_entries].name)))) ReturnStatus(st, INDEX_FSAL_readdir); memcpy(&fsalpath, &(p_dir_descriptor->path), sizeof(fsal_path_t)); st = fsal_internal_appendNameToPath(&fsalpath, &(p_pdirent[*p_nb_entries].name)); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); /* get object handle */ TakeTokenFSCall(); st = fsal_internal_Path2Handle((fsal_op_context_t *) &p_dir_descriptor->context, &fsalpath, &(p_pdirent[*p_nb_entries].handle)); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); /************************ * Fills the attributes * ************************/ p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = LUSTREFSAL_getattrs(&(p_pdirent[*p_nb_entries].handle), (fsal_op_context_t *) &p_dir_descriptor->context, &p_pdirent[*p_nb_entries].attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } ((lustrefsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = telldir(p_dir_descriptor->p_dir); p_pdirent[*p_nb_entries].nextentry = NULL; if(*p_nb_entries) p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]); memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie, sizeof(lustrefsal_cookie_t)); (*p_nb_entries)++; } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }
static void fill_dirent(fsal_dirent_t * to_be_filled, fsal_attrib_mask_t getattr_mask, const char *name, const struct stat *stbuf, off_t off) { fsal_status_t status; struct stat tmp_statbuff; int err = FALSE; fusefsal_handle_t *fill_handle = (fusefsal_handle_t *) &to_be_filled->handle; if(stbuf) { if(stbuf->st_ino == 0) { LogDebug(COMPONENT_FSAL, "WARNING in fill_dirent: Filesystem doesn't provide inode numbers !!!"); } fill_handle->data.inode = stbuf->st_ino; fill_handle->data.device = stbuf->st_dev; FSAL_str2name(name, strlen(name) + 1, &(to_be_filled->name)); ((fusefsal_cookie_t *) &to_be_filled->cookie)->data = off; /* local copy for non "const" calls */ tmp_statbuff = *stbuf; /* set attributes */ to_be_filled->attributes.asked_attributes = getattr_mask; status = posix2fsal_attributes(&tmp_statbuff, &to_be_filled->attributes); LogFullDebug(COMPONENT_FSAL, "getattr_mask = %X, recupere = %X, status=%d, inode=%llX.%llu, type=%d, posixmode=%#o, mode=%#o", getattr_mask, to_be_filled->attributes.asked_attributes, status.major, to_be_filled->attributes.fsid.major, to_be_filled->attributes.fileid, to_be_filled->attributes.type, tmp_statbuff.st_mode, to_be_filled->attributes.mode); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(to_be_filled->attributes.asked_attributes); /* set getattr error bit in attr mask */ FSAL_SET_MASK(to_be_filled->attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); err = TRUE; } } /* if any error occured during conversion, * or if values seem to be inconsistent, * proceed a lookup afterward */ if(!stbuf || (stbuf->st_ino == 0) || err || to_be_filled->attributes.type == (fsal_nodetype_t) - 1 || to_be_filled->attributes.mode == 0 || to_be_filled->attributes.numlinks == 0) { FSAL_CLEAR_MASK(to_be_filled->attributes.asked_attributes); /* we only known entry name, we tag it for a later lookup. */ fill_handle->data.inode = INODE_TO_BE_COMPLETED; FSAL_str2name(name, strlen(name) + 1, &(to_be_filled->name)); ((fusefsal_cookie_t *) &to_be_filled->cookie)->data = off; } } /* fill_dirent */
/** * FSAL_opendir : * Opens a directory for reading its content. * * \param dir_handle (input) * the handle of the directory to be opened. * \param cred (input) * Permission context for the operation (user,...). * \param dir_descriptor (output) * pointer to an allocated structure that will receive * directory stream informations, on successfull completion. * \param dir_attributes (optional output) * On successfull completion,the structure pointed * by dir_attributes receives the new directory attributes. * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t LUSTREFSAL_opendir(fsal_handle_t * p_dir_handle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_dir_t *dir_desc, /* OUT */ fsal_attrib_list_t * p_dir_attributes /* [ IN/OUT ] */ ) { int rc; fsal_status_t status; fsal_path_t fsalpath; struct stat buffstat; lustrefsal_dir_t *p_dir_descriptor = (lustrefsal_dir_t *)dir_desc; /* sanity checks * note : dir_attributes is optionnal. */ if(!p_dir_handle || !p_context || !p_dir_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir); /* get the path of the directory */ status = fsal_internal_Handle2FidPath(p_context, p_dir_handle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* get directory metadata */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); ReleaseTokenFSCall(); if(rc != 0) { rc = errno; if(rc == ENOENT) Return(ERR_FSAL_STALE, rc, INDEX_FSAL_opendir); else Return(posix2fsal_error(rc), rc, INDEX_FSAL_opendir); } /* Test access rights for this directory */ status = fsal_internal_testAccess(p_context, FSAL_R_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* if everything is OK, fills the dir_desc structure : */ TakeTokenFSCall(); p_dir_descriptor->p_dir = opendir(fsalpath.path); ReleaseTokenFSCall(); if(!p_dir_descriptor->p_dir) Return(posix2fsal_error(errno), errno, INDEX_FSAL_opendir); memcpy(&(p_dir_descriptor->context), p_context, sizeof(lustrefsal_op_context_t)); memcpy(&(p_dir_descriptor->path), &fsalpath, sizeof(fsal_path_t)); memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(lustrefsal_handle_t)); if(p_dir_attributes) { status = posix2fsal_attributes(&buffstat, p_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_dir_attributes->asked_attributes); FSAL_SET_MASK(p_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); }
fsal_status_t FUSEFSAL_rename(fusefsal_handle_t * old_parentdir_handle, /* IN */ fsal_name_t * p_old_name, /* IN */ fusefsal_handle_t * new_parentdir_handle, /* IN */ fsal_name_t * p_new_name, /* IN */ fusefsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc = 0; char src_dir_path[FSAL_MAX_PATH_LEN]; char tgt_dir_path[FSAL_MAX_PATH_LEN]; char src_obj_path[FSAL_MAX_PATH_LEN]; char tgt_obj_path[FSAL_MAX_PATH_LEN]; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!old_parentdir_handle || !new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); if(!p_fs_ops->rename) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_rename); /* get full path for parent source handle */ rc = NamespacePath(old_parentdir_handle->data.inode, old_parentdir_handle->data.device, old_parentdir_handle->data.validator, src_dir_path); if(rc) Return(ERR_FSAL_STALE, rc, INDEX_FSAL_rename); /* get full path for parent target handle */ rc = NamespacePath(new_parentdir_handle->data.inode, new_parentdir_handle->data.device, new_parentdir_handle->data.validator, tgt_dir_path); if(rc) Return(ERR_FSAL_STALE, rc, INDEX_FSAL_rename); /* build full path for source entry */ FSAL_internal_append_path(src_obj_path, src_dir_path, p_old_name->name); /* build full path for target entry */ FSAL_internal_append_path(tgt_obj_path, tgt_dir_path, p_new_name->name); /* set context for the next operation, so it can be retrieved by FS thread */ fsal_set_thread_context(p_context); TakeTokenFSCall(); rc = p_fs_ops->rename(src_obj_path, tgt_obj_path); ReleaseTokenFSCall(); /* Regarding FALSE parameter of function fuse2fsal_error: * here, if error is ENOENT, we don't know weither the father handle is STALE * or if the source entry does not exist. * We choose returning ENOENT since the parent exists in the namespace, * so it it more likely to exist than the children. */ if(rc) Return(fuse2fsal_error(rc, FALSE), rc, INDEX_FSAL_rename); /* If operation succeeded, impact the namespace */ NamespaceRename(old_parentdir_handle->data.inode, old_parentdir_handle->data.device, old_parentdir_handle->data.validator, p_old_name->name, new_parentdir_handle->data.inode, new_parentdir_handle->data.device, new_parentdir_handle->data.validator, p_new_name->name); /* Last parent post op attributes if asked */ if(src_dir_attributes) { fsal_status_t st; st = FUSEFSAL_getattrs(old_parentdir_handle, p_context, src_dir_attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes); FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* New parent post op attributes if asked */ if(tgt_dir_attributes) { fsal_status_t st; /* optimization when src=tgt : */ if(!FUSEFSAL_handlecmp(old_parentdir_handle, new_parentdir_handle, &st) && 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 { /* get attributes */ st = FUSEFSAL_getattrs(new_parentdir_handle, p_context, tgt_dir_attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
static struct closefd vfs_fsal_open_and_stat(struct fsal_export *exp, struct vfs_fsal_obj_handle *myself, struct stat *stat, int open_flags, fsal_errors_t *fsal_error) { struct fsal_obj_handle *obj_hdl = &myself->obj_handle; struct closefd cfd = { .fd = -1, .close_fd = false }; int retval = 0; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); const char *func = "unknown"; struct vfs_filesystem *vfs_fs = myself->obj_handle.fs->private; switch (obj_hdl->type) { case SOCKET_FILE: case CHARACTER_FILE: case BLOCK_FILE: cfd.fd = vfs_open_by_handle(vfs_fs, myself->u.unopenable.dir, O_PATH | O_NOACCESS, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), O_PATH | O_NOACCESS); return cfd; } cfd.close_fd = true; retval = fstatat(cfd.fd, myself->u.unopenable.name, stat, AT_SYMLINK_NOFOLLOW); func = "fstatat"; break; case REGULAR_FILE: if (myself->u.file.openflags == FSAL_O_CLOSED) { /* no file open at the moment */ cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), open_flags); return cfd; } cfd.close_fd = true; } else { cfd.fd = myself->u.file.fd; } retval = fstat(cfd.fd, stat); func = "fstat"; break; case SYMBOLIC_LINK: open_flags |= (O_PATH | O_RDWR | O_NOFOLLOW); goto vfos_open; case FIFO_FILE: open_flags |= O_NONBLOCK; /* fall through */ case DIRECTORY: default: vfos_open: cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), open_flags); return cfd; } cfd.close_fd = true; retval = vfs_stat_by_handle(cfd.fd, myself->handle, stat, open_flags); func = "vfs_stat_by_handle"; break; } if (retval < 0) { retval = errno; if (cfd.close_fd) { int rc; rc = close(cfd.fd); if (rc < 0) { rc = errno; LogDebug(COMPONENT_FSAL, "close failed with %s", strerror(rc)); } } if (retval == ENOENT) retval = ESTALE; *fsal_error = posix2fsal_error(retval); LogDebug(COMPONENT_FSAL, "%s failed with %s", func, strerror(retval)); cfd.fd = -retval; cfd.close_fd = false; return cfd; } return cfd; } static fsal_status_t getattrs(struct fsal_obj_handle *obj_hdl) { struct vfs_fsal_obj_handle *myself; struct closefd cfd = { .fd = -1, .close_fd = false }; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; fsal_status_t st; int retval = 0; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (obj_hdl->fsal != obj_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s getattr for handle belonging to FSAL %s, ignoring", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); goto out; } cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat, O_RDONLY, &fsal_error); if (cfd.fd >= 0) { st = posix2fsal_attributes(&stat, &obj_hdl->attributes); if (cfd.close_fd) close(cfd.fd); if (FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(obj_hdl->attributes.mask); FSAL_SET_MASK(obj_hdl->attributes.mask, ATTR_RDATTR_ERR); fsal_error = st.major; retval = st.minor; } else { obj_hdl->attributes.fsid = obj_hdl->fs->fsid; } } else { LogDebug(COMPONENT_FSAL, "Failed with %s, fsal_error %s", strerror(-cfd.fd), fsal_error == ERR_FSAL_STALE ? "ERR_FSAL_STALE" : "other"); if (obj_hdl->type == SYMBOLIC_LINK && cfd.fd == -EPERM) { /* You cannot open_by_handle (XFS on linux) a symlink * and it throws an EPERM error for it. * open_by_handle_at does not throw that error for * symlinks so we play a game here. Since there is * not much we can do with symlinks anyway, * say that we did it but don't actually * do anything. In this case, return the stat we got * at lookup time. If you *really* want to tweek things * like owners, get a modern linux kernel... */ fsal_error = ERR_FSAL_NO_ERROR; goto out; } retval = -cfd.fd; } out: return fsalstat(fsal_error, retval); } /* * NOTE: this is done under protection of the attributes rwlock * in the cache entry. */ static fsal_status_t setattrs(struct fsal_obj_handle *obj_hdl, struct attrlist *attrs) { struct vfs_fsal_obj_handle *myself; struct closefd cfd = { .fd = -1, .close_fd = false }; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; int open_flags = O_RDONLY; /* apply umask, if mode attribute is to be changed */ if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) attrs->mode &= ~op_ctx->fsal_export->exp_ops. fs_umask(op_ctx->fsal_export); myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (obj_hdl->fsal != obj_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto hdlerr; } /* This is yet another "you can't get there from here". If this object * is a socket (AF_UNIX), an fd on the socket s useless _period_. * If it is for a symlink, without O_PATH, you will get an ELOOP error * and (f)chmod doesn't work for a symlink anyway - not that it matters * because access checking is not done on the symlink but the final * target. * AF_UNIX sockets are also ozone material. If the socket is already * active listeners et al, you can manipulate the mode etc. If it is * just sitting there as in you made it with a mknod. * (one of those leaky abstractions...) * or the listener forgot to unlink it, it is lame duck. */ if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) open_flags = O_RDWR; cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat, open_flags, &fsal_error); if (cfd.fd < 0) { if (obj_hdl->type == SYMBOLIC_LINK && cfd.fd == -EPERM) { /* You cannot open_by_handle (XFS) a symlink and it * throws an EPERM error for it. open_by_handle_at * does not throw that error for symlinks so we play a * game here. Since there is not much we can do with * symlinks anyway, say that we did it * but don't actually do anything. * If you *really* want to tweek things * like owners, get a modern linux kernel... */ fsal_error = ERR_FSAL_NO_ERROR; goto out; } return fsalstat(fsal_error, cfd.fd); } /** TRUNCATE **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) { if (obj_hdl->type != REGULAR_FILE) { fsal_error = ERR_FSAL_INVAL; goto fileerr; } retval = ftruncate(cfd.fd, attrs->filesize); if (retval != 0) { /* XXX ESXi volume creation pattern reliably * reaches this point and reliably can successfully * ftruncate on reopen. I don't know yet if fd if * we failed to handle a previous error, or what. * I don't see a prior failed op in wireshark. */ if (retval == -1 /* bad fd */) { vfs_close(obj_hdl); if (cfd.close_fd) close(cfd.fd); cfd = vfs_fsal_open_and_stat( op_ctx->fsal_export, myself, &stat, open_flags, &fsal_error); retval = ftruncate(cfd.fd, attrs->filesize); if (retval != 0) goto fileerr; } else goto fileerr; } } /** CHMOD **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) { /* The POSIX chmod call doesn't affect the symlink object, but * the entry it points to. So we must ignore it. */ if (!S_ISLNK(stat.st_mode)) { if (vfs_unopenable_type(obj_hdl->type)) retval = fchmodat(cfd.fd, myself->u.unopenable.name, fsal2unix_mode(attrs->mode), 0); else retval = fchmod(cfd.fd, fsal2unix_mode(attrs->mode)); if (retval != 0) goto fileerr; } } /** CHOWN **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_OWNER | ATTR_GROUP)) { uid_t user = FSAL_TEST_MASK(attrs->mask, ATTR_OWNER) ? (int)attrs->owner : -1; gid_t group = FSAL_TEST_MASK(attrs->mask, ATTR_GROUP) ? (int)attrs->group : -1; if (vfs_unopenable_type(obj_hdl->type)) retval = fchownat(cfd.fd, myself->u.unopenable.name, user, group, AT_SYMLINK_NOFOLLOW); else if (obj_hdl->type == SYMBOLIC_LINK) retval = fchownat(cfd.fd, "", user, group, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH); else retval = fchown(cfd.fd, user, group); if (retval) goto fileerr; } /** UTIME **/ if (FSAL_TEST_MASK (attrs->mask, ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SERVER | ATTR_MTIME_SERVER)) { struct timespec timebuf[2]; if (obj_hdl->type == SYMBOLIC_LINK) goto out; /* Setting time on symlinks is illegal */ /* Atime */ if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME_SERVER)) { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME)) { timebuf[0] = attrs->atime; } else { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_OMIT; } /* Mtime */ if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME_SERVER)) { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME)) { timebuf[1] = attrs->mtime; } else { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_OMIT; } if (vfs_unopenable_type(obj_hdl->type)) retval = vfs_utimesat(cfd.fd, myself->u.unopenable.name, timebuf, AT_SYMLINK_NOFOLLOW); else retval = vfs_utimes(cfd.fd, timebuf); if (retval != 0) goto fileerr; } goto out; fileerr: retval = errno; fsal_error = posix2fsal_error(retval); out: if (cfd.close_fd) close(cfd.fd); hdlerr: return fsalstat(fsal_error, retval); } /* file_unlink * unlink the named file in the directory */ static fsal_status_t file_unlink(struct fsal_obj_handle *dir_hdl, const char *name) { struct vfs_fsal_obj_handle *myself; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; struct stat stat; int fd; int retval = 0; myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (dir_hdl->fsal != dir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", dir_hdl->fsal->name, dir_hdl->fs->fsal != NULL ? dir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto out; } fd = vfs_fsal_open(myself, O_PATH | O_NOACCESS, &fsal_error); if (fd < 0) { retval = -fd; goto out; } retval = fstatat(fd, name, &stat, AT_SYMLINK_NOFOLLOW); if (retval < 0) { retval = errno; LogDebug(COMPONENT_FSAL, "fstatat %s failed %s", name, strerror(retval)); if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); goto errout; } fsal_set_credentials(op_ctx->creds); retval = unlinkat(fd, name, (S_ISDIR(stat.st_mode)) ? AT_REMOVEDIR : 0); if (retval < 0) { retval = errno; if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); } fsal_restore_ganesha_credentials(); errout: close(fd); out: return fsalstat(fsal_error, retval); } /* handle_digest * fill in the opaque f/s file handle part. * we zero the buffer to length first. This MAY already be done above * at which point, remove memset here because the caller is zeroing * the whole struct. */ static fsal_status_t handle_digest(const struct fsal_obj_handle *obj_hdl, fsal_digesttype_t output_type, struct gsh_buffdesc *fh_desc) { const struct vfs_fsal_obj_handle *myself; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (obj_hdl->fsal != obj_hdl->fs->fsal) { /* Log, but allow digest */ LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); } switch (output_type) { case FSAL_DIGEST_NFSV3: case FSAL_DIGEST_NFSV4: if (fh_desc->len < myself->handle->handle_len) { LogMajor(COMPONENT_FSAL, "Space too small for handle. need %d, have %lu", (int) myself->handle->handle_len, fh_desc->len); return fsalstat(ERR_FSAL_TOOSMALL, 0); } memcpy(fh_desc->addr, myself->handle->handle_data, myself->handle->handle_len); break; default: return fsalstat(ERR_FSAL_SERVERFAULT, 0); } fh_desc->len = myself->handle->handle_len; return fsalstat(ERR_FSAL_NO_ERROR, 0); } /** * handle_to_key * return a handle descriptor into the handle in this object handle * @TODO reminder. make sure things like hash keys don't point here * after the handle is released. */ static void handle_to_key(struct fsal_obj_handle *obj_hdl, struct gsh_buffdesc *fh_desc) { struct vfs_fsal_obj_handle *myself; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); fh_desc->addr = myself->handle->handle_data; fh_desc->len = myself->handle->handle_len; } /* * release * release our export first so they know we are gone */ static void release(struct fsal_obj_handle *obj_hdl) { struct vfs_fsal_obj_handle *myself; object_file_type_t type = obj_hdl->type; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (type == REGULAR_FILE) { fsal_status_t st = vfs_close(obj_hdl); if (FSAL_IS_ERROR(st)) { LogCrit(COMPONENT_FSAL, "Could not close hdl 0x%p, error %s(%d)", obj_hdl, strerror(st.minor), st.minor); } } fsal_obj_handle_fini(obj_hdl); if (type == SYMBOLIC_LINK) { if (myself->u.symlink.link_content != NULL) gsh_free(myself->u.symlink.link_content); } else if (vfs_unopenable_type(type)) { if (myself->u.unopenable.name != NULL) gsh_free(myself->u.unopenable.name); if (myself->u.unopenable.dir != NULL) gsh_free(myself->u.unopenable.dir); } gsh_free(myself); } void vfs_handle_ops_init(struct fsal_obj_ops *ops) { ops->release = release; ops->lookup = lookup; ops->readdir = read_dirents; ops->create = create; ops->mkdir = makedir; ops->mknode = makenode; ops->symlink = makesymlink; ops->readlink = readsymlink; ops->test_access = fsal_test_access; ops->getattrs = getattrs; ops->setattrs = setattrs; ops->link = linkfile; ops->rename = renamefile; ops->unlink = file_unlink; ops->open = vfs_open; ops->status = vfs_status; ops->read = vfs_read; ops->write = vfs_write; ops->commit = vfs_commit; ops->lock_op = vfs_lock_op; ops->close = vfs_close; ops->lru_cleanup = vfs_lru_cleanup; ops->handle_digest = handle_digest; ops->handle_to_key = handle_to_key; /* xattr related functions */ ops->list_ext_attrs = vfs_list_ext_attrs; ops->getextattr_id_by_name = vfs_getextattr_id_by_name; ops->getextattr_value_by_name = vfs_getextattr_value_by_name; ops->getextattr_value_by_id = vfs_getextattr_value_by_id; ops->setextattr_value = vfs_setextattr_value; ops->setextattr_value_by_id = vfs_setextattr_value_by_id; ops->getextattr_attrs = vfs_getextattr_attrs; ops->remove_extattr_by_id = vfs_remove_extattr_by_id; ops->remove_extattr_by_name = vfs_remove_extattr_by_name; } /* export methods that create object handles */ /* lookup_path * modeled on old api except we don't stuff attributes. * KISS */ fsal_status_t vfs_lookup_path(struct fsal_export *exp_hdl, const char *path, struct fsal_obj_handle **handle) { int dir_fd = -1; struct stat stat; struct vfs_fsal_obj_handle *hdl; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; struct fsal_filesystem *fs; struct fsal_dev__ dev; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); *handle = NULL; /* poison it */ dir_fd = open_dir_by_path_walk(-1, path, &stat); if (dir_fd < 0) { LogCrit(COMPONENT_FSAL, "Could not open directory for path %s", path); retval = -dir_fd; goto errout; } dev = posix2fsal_devt(stat.st_dev); fs = lookup_dev(&dev); if (fs == NULL) { LogInfo(COMPONENT_FSAL, "Could not find file system for path %s", path); retval = ENOENT; goto errout; } if (fs->fsal != exp_hdl->fsal) { LogInfo(COMPONENT_FSAL, "File system for path %s did not belong to FSAL %s", path, exp_hdl->fsal->name); retval = EACCES; goto errout; } LogDebug(COMPONENT_FSAL, "filesystem %s for path %s", fs->path, path); retval = vfs_fd_to_handle(dir_fd, fs, fh); if (retval < 0) { retval = errno; LogCrit(COMPONENT_FSAL, "Could not get handle for path %s, error %s", path, strerror(retval)); goto errout; } /* allocate an obj_handle and fill it up */ hdl = alloc_handle(-1, fh, fs, &stat, NULL, "", exp_hdl); if (hdl == NULL) { retval = ENOMEM; LogCrit(COMPONENT_FSAL, "Could not allocate handle for path %s", path); goto errout; } close(dir_fd); *handle = &hdl->obj_handle; return fsalstat(ERR_FSAL_NO_ERROR, 0); errout: if (dir_fd >= 0) close(dir_fd); fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); } fsal_status_t vfs_check_handle(struct fsal_export *exp_hdl, struct gsh_buffdesc *hdl_desc, struct fsal_filesystem **fs, vfs_file_handle_t *fh, bool *dummy) { fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; struct fsal_fsid__ fsid; enum fsid_type fsid_type; *fs = NULL; if (!vfs_valid_handle(hdl_desc)) return fsalstat(ERR_FSAL_BADHANDLE, 0); memcpy(fh->handle_data, hdl_desc->addr, hdl_desc->len); fh->handle_len = hdl_desc->len; *dummy = vfs_is_dummy_handle(fh); retval = vfs_extract_fsid(fh, &fsid_type, &fsid); if (retval == 0) { *fs = lookup_fsid(&fsid, fsid_type); if (*fs == NULL) { LogInfo(COMPONENT_FSAL, "Could not map " "fsid=0x%016"PRIx64".0x%016"PRIx64 " to filesytem", fsid.major, fsid.minor); retval = ESTALE; fsal_error = posix2fsal_error(retval); goto errout; } if (((*fs)->fsal != exp_hdl->fsal) && !(*dummy)) { LogInfo(COMPONENT_FSAL, "fsid=0x%016"PRIx64".0x%016"PRIx64 " in handle not a %s filesystem", fsid.major, fsid.minor, exp_hdl->fsal->name); retval = ESTALE; fsal_error = posix2fsal_error(retval); goto errout; } LogDebug(COMPONENT_FSAL, "Found filesystem %s for handle for FSAL %s", (*fs)->path, (*fs)->fsal != NULL ? (*fs)->fsal->name : "(none)"); } else { LogDebug(COMPONENT_FSAL, "Could not map handle to fsid"); fsal_error = ERR_FSAL_BADHANDLE; goto errout; } errout: return fsalstat(fsal_error, retval); }
fsal_status_t FSAL_setattrs(fsal_handle_t * filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * attrib_set, /* IN */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { GHOSTFS_setattr_mask_t set_mask = 0; GHOSTFS_Attrs_t ghost_attrs; int rc; memset(&ghost_attrs, 0, sizeof(GHOSTFS_Attrs_t)); /* For logging */ SetFuncID(INDEX_FSAL_setattrs); #define SETTABLE_ATTRIBUTES ( FSAL_ATTR_SIZE |\ FSAL_ATTR_MODE |\ FSAL_ATTR_OWNER |\ FSAL_ATTR_GROUP |\ FSAL_ATTR_ATIME |\ FSAL_ATTR_MTIME ) /* sanity checks. * note : object_attributes is optional. */ if(!filehandle || !p_context || !attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* first convert attributes and mask */ if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_SIZE)) { set_mask |= SETATTR_SIZE; ghost_attrs.size = attrib_set->filesize; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MODE)) { set_mask |= SETATTR_MODE; ghost_attrs.mode = fsal2ghost_mode(attrib_set->mode); } /* ghostfs does not check chown restrictions, * so we check this for it. */ if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_OWNER)) { if(p_context->credential.user != 0) Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); set_mask |= SETATTR_UID; ghost_attrs.uid = attrib_set->owner; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_GROUP)) { if(p_context->credential.user != 0) Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); set_mask |= SETATTR_GID; ghost_attrs.gid = attrib_set->group; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_ATIME)) { set_mask |= SETATTR_ATIME; ghost_attrs.atime = attrib_set->atime.seconds; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MTIME)) { set_mask |= SETATTR_MTIME; ghost_attrs.mtime = attrib_set->mtime.seconds; } if(attrib_set->asked_attributes & ~SETTABLE_ATTRIBUTES) { LogFullDebug(COMPONENT_FSAL, "FSAL: To be set %llX, Settable %llX", (unsigned long long)object_attributes->asked_attributes, (unsigned long long)SETTABLE_ATTRIBUTES); Return(ERR_FSAL_ATTRNOTSUPP, 0, INDEX_FSAL_setattrs); } /* appel a setattr */ rc = GHOSTFS_SetAttrs((GHOSTFS_handle_t) (*filehandle), set_mask, ghost_attrs); if(rc) Return(ghost2fsal_error(rc), rc, INDEX_FSAL_setattrs); if(object_attributes) { fsal_status_t status = FSAL_getattrs(filehandle, p_context, 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_open: * Open a regular file for reading/writing its data content. * * \param filehandle (input): * Handle of the file to be read/modified. * \param cred (input): * Authentication context for the operation (user,...). * \param openflags (input): * Flags that indicates behavior for file opening and access. * This is an inclusive OR of the following values * ( such of them are not compatible) : * - FSAL_O_RDONLY: opening file for reading only. * - FSAL_O_RDWR: opening file for reading and writing. * - FSAL_O_WRONLY: opening file for writting only. * - FSAL_O_APPEND: always write at the end of the file. * - FSAL_O_TRUNC: truncate the file to 0 on opening. * \param file_descriptor (output): * The file descriptor to be used for FSAL_read/write operations. * \param file_attributes (optionnal input/output): * Post operation attributes. * 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. * - Another error code if an error occured during this call. */ fsal_status_t POSIXFSAL_open(posixfsal_handle_t * p_filehandle, /* IN */ posixfsal_op_context_t * p_context, /* IN */ fsal_openflags_t openflags, /* IN */ posixfsal_file_t * p_file_descriptor, /* OUT */ fsal_attrib_list_t * p_file_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; fsal_path_t fsalpath; struct stat buffstat; #ifdef _FSAL_POSIX_USE_STREAM char posix_flags[4]; /* stores r, r+, w, w+, a, or a+ */ #else int posix_flags; #endif /* sanity checks. * note : file_attributes is optional. */ if(!p_filehandle || !p_context || !p_file_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_open); status = fsal_internal_getPathFromHandle(p_context, p_filehandle, 0, &fsalpath, &buffstat); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_open); status = fsal_internal_testAccess(p_context, (openflags & FSAL_O_RDONLY ? FSAL_R_OK : FSAL_W_OK) | FSAL_OWNER_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_open); /* convert fsal open flags to posix open flags */ rc = fsal2posix_openflags(openflags, &posix_flags); /* flags conflicts. */ if(rc) { LogEvent(COMPONENT_FSAL, "Invalid/conflicting flags : %#X", openflags); Return(rc, 0, INDEX_FSAL_open); } TakeTokenFSCall(); #ifdef _FSAL_POSIX_USE_STREAM p_file_descriptor->p_file = fopen(fsalpath.path, posix_flags); errsv = errno; ReleaseTokenFSCall(); if(!(p_file_descriptor->p_file)) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_open); #else p_file_descriptor->filefd = open(fsalpath.path, posix_flags); errsv = errno; ReleaseTokenFSCall(); #endif /* set the read-only flag of the file descriptor */ p_file_descriptor->ro = openflags & FSAL_O_RDONLY; /* output attributes */ if(p_file_attributes) { status = posix2fsal_attributes(&buffstat, p_file_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_file_attributes->asked_attributes); FSAL_SET_MASK(p_file_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_open); }
/** * FSAL_readlink: * Read the content of a symbolic link. * * \param linkhandle (input): * Handle of the link to be read. * \param cred (input): * Authentication context for the operation (user,...). * \param p_link_content (output): * Pointer to an fsal path structure where * the link content is to be stored.. * \param link_attributes (optionnal input/output): * The post operation attributes of the symlink link. * 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) * - Another error code if an error occured. */ fsal_status_t LUSTREFSAL_readlink(fsal_handle_t * p_linkhandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_path_t * p_link_content, /* OUT */ fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; char link_content_out[FSAL_MAX_PATH_LEN]; fsal_path_t fsalpath; /* sanity checks. * note : link_attributes is optional. */ if(!p_linkhandle || !p_context || !p_link_content) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink); status = fsal_internal_Handle2FidPath(p_context, p_linkhandle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_readlink); memset(link_content_out, 0, FSAL_MAX_PATH_LEN); /* Read the link on the filesystem */ TakeTokenFSCall(); rc = readlink(fsalpath.path, link_content_out, FSAL_MAX_PATH_LEN); errsv = errno; ReleaseTokenFSCall(); /* rc is the length for the symlink content or -1 on error !!! */ if(rc < 0) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readlink); /* convert char * to fsal_path_t */ status = FSAL_str2path(link_content_out, FSAL_MAX_PATH_LEN, p_link_content); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_readlink); /* retrieves object attributes, if asked */ if(p_link_attributes) { status = LUSTREFSAL_getattrs(p_linkhandle, p_context, p_link_attributes); /* On error, we set a flag in the returned attributes */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_link_attributes->asked_attributes); FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readlink); }
/** * FSAL_readdir : * Read the entries of an opened directory. * * \param dir_descriptor (input): * Pointer to the directory descriptor filled by FSAL_opendir. * \param start_position (input): * Cookie that indicates the first object to be read during * this readdir operation. * This should be : * - FSAL_READDIR_FROM_BEGINNING for reading the content * of the directory from the beginning. * - The end_position parameter returned by the previous * call to FSAL_readdir. * \param get_attr_mask (input) * Specify the set of attributes to be retrieved for directory entries. * \param buffersize (input) * The size (in bytes) of the buffer where * the direntries are to be stored. * \param pdirent (output) * Adresse of the buffer where the direntries are to be stored. * \param end_position (output) * Cookie that indicates the current position in the directory. * \param nb_entries (output) * Pointer to the number of entries read during the call. * \param end_of_dir (output) * Pointer to a boolean that indicates if the end of dir * has been reached during the call. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_IO, ... */ fsal_status_t SNMPFSAL_readdir(fsal_dir_t * dir_desc, /* IN */ fsal_cookie_t start_pos, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * pdirent, /* OUT */ fsal_cookie_t * end_pos, /* OUT */ fsal_count_t * nb_entries, /* OUT */ fsal_boolean_t * end_of_dir /* OUT */ ) { fsal_count_t max_dir_entries; fsal_count_t cur_nb_entries; fsal_boolean_t bool_eod; snmpfsal_cookie_t last_listed; fsal_request_desc_t req_opt; netsnmp_variable_list *p_curr_var; struct tree *cur_node; struct tree *nearest_node; int rc; snmpfsal_dir_t * dir_descriptor = (snmpfsal_dir_t *)dir_desc; snmpfsal_cookie_t start_position; snmpfsal_cookie_t * end_position = (snmpfsal_cookie_t *)end_pos; /* sanity checks */ if(!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); /* The readdir call is a sequence of GET/GETNEXT operations : * The first call, is a get on the hypothetic next brother * => if it exists, we add it to the dirents, and try to get the next child. * => if it doesnt exist, we make a getnext on it. * then, when a next branch is discovered, the next item to be tested * is the next hypothetic child. */ /* initial cookie */ memcpy(&start_position.data, &start_pos.data, sizeof(snmpfsal_cookie_t)); if(start_position.data.oid_len == 0) /* readdir from begginning */ { FSAL_OID_DUP(&last_listed, dir_descriptor->node_handle.data.oid_tab, dir_descriptor->node_handle.data.oid_len); /* first try to get .0 child */ last_listed.data.oid_tab[last_listed.data.oid_len] = 0; last_listed.data.oid_len++; } else /* readdir from another entry */ { FSAL_OID_DUP(&last_listed, start_position.data.oid_tab, start_position.data.oid_len); } /* calculate the requested dircount */ max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); /* init counters and outputs */ memset(pdirent, 0, buffersize); bool_eod = FALSE; cur_nb_entries = 0; if(max_dir_entries == 0) Return(ERR_FSAL_TOOSMALL, 0, INDEX_FSAL_readdir); while(!bool_eod && cur_nb_entries < max_dir_entries) { snmpfsal_handle_t *dir_entry = (snmpfsal_handle_t *) &pdirent[cur_nb_entries].handle; snmpfsal_cookie_t *dir_cookie = (snmpfsal_cookie_t *) &pdirent[cur_nb_entries].cookie; /* First, we proceed a GET request */ req_opt.request_type = SNMP_MSG_GET; TakeTokenFSCall(); rc = IssueSNMPQuery(dir_descriptor->p_context, last_listed.data.oid_tab, last_listed.data.oid_len, &req_opt); ReleaseTokenFSCall(); if(rc != SNMP_ERR_NOERROR && snmp2fsal_error(rc) != ERR_FSAL_NOENT) { LogDebug(COMPONENT_FSAL, "SNMP GET request failed: error=%d, snmp_errno=%d, errno=%d, msg=%s", rc, snmp_errno, errno, snmp_api_errstring(rc)); Return(snmp2fsal_error(rc), rc, INDEX_FSAL_readdir); } else if(snmp2fsal_error(rc) != ERR_FSAL_NOENT) { p_curr_var = GetNextResponse(dir_descriptor->p_context); /* Then test if the object exists */ if(p_curr_var != NULL && p_curr_var->type != SNMP_NOSUCHOBJECT && p_curr_var->type != SNMP_NOSUCHINSTANCE && p_curr_var->type != SNMP_ENDOFMIBVIEW) { FSAL_OID_DUP(dir_entry, p_curr_var->name, p_curr_var->name_length); dir_entry->data.object_type_reminder = FSAL_NODETYPE_LEAF; /* object cookie is the hypothetic next object at the same level */ FSAL_OID_DUP(dir_cookie, p_curr_var->name, p_curr_var->name_length); FSAL_OID_INC(dir_cookie); cur_node = GetMIBNode(dir_descriptor->p_context, dir_entry, FALSE); /* build the label */ rc = snmp_object2name(p_curr_var, cur_node, dir_entry, &pdirent[cur_nb_entries].name); if(rc) Return(rc, 0, INDEX_FSAL_readdir); /* when a node does not exist, we take its nearest parent's rights */ if(cur_node == NULL) nearest_node = GetMIBNode(dir_descriptor->p_context, dir_entry, TRUE); else nearest_node = cur_node; if(isFullDebug(COMPONENT_FSAL)) { LogFullDebug(COMPONENT_FSAL, "FOUND A DIRECT CHILD (LEAF) = %s, parent_oid_len=%zu, oid_len=%zu, index=%d", pdirent[cur_nb_entries].name.name, dir_descriptor->node_handle.data.oid_len, p_curr_var->name_length, p_curr_var->index); if(nearest_node) LogFullDebug(COMPONENT_FSAL, "type = %#X, last oid=%ld", nearest_node->type, p_curr_var->name[p_curr_var->name_length - 1]); } /* set entry attributes */ if(get_attr_mask) { pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask; rc = snmp2fsal_attributes(dir_entry, p_curr_var, nearest_node, &pdirent[cur_nb_entries].attributes); if(rc != ERR_FSAL_NO_ERROR) { FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes. asked_attributes); FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* link entries together */ pdirent[cur_nb_entries].nextentry = NULL; if(cur_nb_entries > 0) pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries]; /* copy hypothetic next entry to cookie and increment nb_entries */ FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab, dir_cookie->data.oid_len); cur_nb_entries++; /* restart a sequence from GET request */ continue; } } /* the entry has not been found, we can look for the next child */ req_opt.request_type = SNMP_MSG_GETNEXT; TakeTokenFSCall(); rc = IssueSNMPQuery(dir_descriptor->p_context, last_listed.data.oid_tab, last_listed.data.oid_len, &req_opt); ReleaseTokenFSCall(); if(rc != SNMP_ERR_NOERROR && snmp2fsal_error(rc) != ERR_FSAL_NOENT) { LogDebug(COMPONENT_FSAL, "SNMP GETNEXT request failed: error=%d, snmp_errno=%d, errno=%d, msg=%s", rc, snmp_errno, errno, snmp_api_errstring(rc)); Return(snmp2fsal_error(rc), rc, INDEX_FSAL_readdir); } else if(snmp2fsal_error(rc) == ERR_FSAL_NOENT) { bool_eod = TRUE; break; } p_curr_var = GetNextResponse(dir_descriptor->p_context); if(p_curr_var == NULL || p_curr_var->type == SNMP_NOSUCHOBJECT || p_curr_var->type == SNMP_NOSUCHINSTANCE || p_curr_var->type == SNMP_ENDOFMIBVIEW) { bool_eod = TRUE; break; } /* check if the response is under the root (else, end of dir is reached) */ if(IsSNMPChild (dir_descriptor->node_handle.data.oid_tab, dir_descriptor->node_handle.data.oid_len, p_curr_var->name, p_curr_var->name_length)) { /* if the object is exactly 1 level under the dir, we insert it in the list */ if(p_curr_var->name_length == dir_descriptor->node_handle.data.oid_len + 1) { FSAL_OID_DUP(dir_entry, p_curr_var->name, p_curr_var->name_length); dir_entry->data.object_type_reminder = FSAL_NODETYPE_LEAF; /* object cookie is the hypothetic next object */ FSAL_OID_DUP(dir_cookie, p_curr_var->name, p_curr_var->name_length); FSAL_OID_INC(dir_cookie); cur_node = GetMIBNode(dir_descriptor->p_context, dir_entry, FALSE); /* build the label */ rc = snmp_object2name(p_curr_var, cur_node, dir_entry, &pdirent[cur_nb_entries].name); if(rc) Return(rc, 0, INDEX_FSAL_readdir); /* when a node does not exist, we take its nearest parent's rights */ if(cur_node == NULL) nearest_node = GetMIBNode(dir_descriptor->p_context, dir_entry, TRUE); else nearest_node = cur_node; if(isFullDebug(COMPONENT_FSAL)) { LogFullDebug(COMPONENT_FSAL, "FOUND A DIRECT CHILD (LEAF) = %s, parent_oid_len=%zu, oid_len=%zu, index=%d", pdirent[cur_nb_entries].name.name, dir_descriptor->node_handle.data.oid_len, p_curr_var->name_length, p_curr_var->index); if(nearest_node) LogFullDebug(COMPONENT_FSAL, "type = %#X, last oid=%ld", nearest_node->type, p_curr_var->name[p_curr_var->name_length - 1]); } /* set entry attributes */ if(get_attr_mask) { pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask; rc = snmp2fsal_attributes(dir_entry, p_curr_var, nearest_node, &pdirent[cur_nb_entries].attributes); if(rc != ERR_FSAL_NO_ERROR) { FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes. asked_attributes); FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* link entries together */ pdirent[cur_nb_entries].nextentry = NULL; if(cur_nb_entries > 0) pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries]; /* copy hypothetic next entry to cookie and increment nb_entries */ FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab, dir_cookie->data.oid_len); cur_nb_entries++; /* restart a sequence from GET request */ continue; } else /* directory item */ { /* it the returned subdirectory is "smaller" than the cookie, we skip it * and incrment the cookie. */ if(fsal_oid_cmp(p_curr_var->name, last_listed.data.oid_tab, last_listed.data.oid_len) < 0) { FSAL_OID_INC(&last_listed); continue; } /* we found a new subsirectory */ FSAL_OID_DUP(dir_entry, p_curr_var->name, dir_descriptor->node_handle.data.oid_len + 1); dir_entry->data.object_type_reminder = FSAL_NODETYPE_NODE; /* object cookie is the next potentiel object at this level */ FSAL_OID_DUP(dir_cookie, dir_entry->data.oid_tab, dir_entry->data.oid_len); FSAL_OID_INC(dir_cookie); /* try to get the associated MIB node */ cur_node = GetMIBNode(dir_descriptor->p_context, dir_entry, FALSE); /* build the label */ rc = snmp_object2name(NULL, cur_node, dir_entry, &pdirent[cur_nb_entries].name); if(rc) Return(rc, 0, INDEX_FSAL_readdir); /* when a node does not exist, we take its nearest parent's rights */ if(cur_node == NULL) nearest_node = GetMIBNode(dir_descriptor->p_context, dir_entry, TRUE); else nearest_node = cur_node; LogFullDebug(COMPONENT_FSAL, "FOUND A NEW SUBDIR = %s (%ld) (cookie->%ld)", pdirent[cur_nb_entries].name.name, dir_entry->data.oid_tab[dir_descriptor->node_handle.data.oid_len], dir_cookie->data.oid_tab[dir_cookie->data.oid_len - 1]); /* set entry attributes */ if(get_attr_mask) { pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask; rc = snmp2fsal_attributes(dir_entry, NULL, nearest_node, &pdirent[cur_nb_entries].attributes); if(rc != ERR_FSAL_NO_ERROR) { FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes. asked_attributes); FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* link entries together */ pdirent[cur_nb_entries].nextentry = NULL; if(cur_nb_entries > 0) pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries]; /* copy last listed item to cookie and increment nb_entries */ FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab, dir_cookie->data.oid_len); cur_nb_entries++; /* end of subdir processing */ } } else /* no more objects in the directory tree */ { bool_eod = TRUE; break; } /* loop until the requested count is reached * or the end of dir is reached. */ } /* setting output vars : end_position, nb_entries, end_of_dir */ *end_of_dir = bool_eod; memset(end_position, 0, sizeof(snmpfsal_cookie_t)); FSAL_OID_DUP(end_position, last_listed.data.oid_tab, last_listed.data.oid_len); *nb_entries = cur_nb_entries; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }