/** * 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_status_t XFSFSAL_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 */ ) { xfsfsal_dir_t * p_dir_descriptor = (xfsfsal_dir_t * ) dir_descriptor; xfsfsal_cookie_t start_position; xfsfsal_cookie_t * p_end_position = (xfsfsal_cookie_t *) end_position; fsal_status_t st; fsal_count_t max_dir_entries; char buff[BUF_SIZE]; struct linux_dirent *dp = NULL; int bpos = 0; int tmpfd = 0; char d_type; struct stat buffstat; int errsv = 0, rc = 0; memset(buff, 0, BUF_SIZE); /*****************/ /* 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; 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.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 = 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); /** @todo not used for the moment. Waiting for information on symlink management */ bpos += dp->d_reclen; /* LogFullDebug(COMPONENT_FSAL, "\tino=%8ld|%8lx off=%d|%x reclen=%d|%x name=%s|%d", dp->d_ino, dp->d_ino, (int)dp->d_off, (int)dp->d_off, dp->d_reclen, dp->d_reclen, dp->d_name, (int)dp->d_name[0] ) ; */ 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); d_type = DT_UNKNOWN; if((tmpfd = openat(p_dir_descriptor->fd, dp->d_name, O_RDONLY | O_NOFOLLOW, 0600)) < 0) { if(errno != ELOOP) /* ( p_dir_descriptor->fd, dp->d_name) is not a symlink */ Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readdir); else d_type = DT_LNK; } /* get object handle */ TakeTokenFSCall(); if(d_type != DT_LNK) { st = fsal_internal_fd2handle((fsal_op_context_t *)&(p_dir_descriptor->context), tmpfd, &(p_pdirent[*p_nb_entries].handle)); close(tmpfd); } else { 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_inum2handle(&p_dir_descriptor->context, buffstat.st_ino, &(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(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); /************************ * Fills the attributes * ************************/ if(d_type != DT_LNK) { p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = XFSFSAL_getattrs((xfsfsal_handle_t *) (&(p_pdirent[*p_nb_entries].handle)), (xfsfsal_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); } } //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off; ((xfsfsal_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(xfsfsal_cookie_t)); (*p_nb_entries)++; } /* for */ } /* While */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }
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_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_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); }
/** * 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 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); }
/** * 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_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_lookup : * Looks up for an object into a directory. * * Note : if parent handle and filename are NULL, * this retrieves root's handle. * * \param parent_directory_handle (input) * Handle of the parent directory to search the object in. * \param filename (input) * The name of the object to find. * \param p_context (input) * Authentication context for the operation (user,...). * \param object_handle (output) * The handle of the object corresponding to filename. * \param object_attributes (optional input/output) * Pointer to the attributes of the object we found. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * It can be NULL (increases performances). * * \return - ERR_FSAL_NO_ERROR, if no error. * - Another error code else. * */ fsal_status_t LUSTREFSAL_lookup(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat buffstat; fsal_path_t pathfsal; /* sanity checks * note : object_attributes is optionnal * parent_directory_handle may be null for getting FS root. */ if(!p_object_handle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* filename AND parent handle are NULL => lookup "/" */ if((p_parent_directory_handle && !p_filename) || (!p_parent_directory_handle && p_filename)) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* get information about root */ if(!p_parent_directory_handle) { /* get handle for the mount point */ FSAL_str2path(((lustrefsal_op_context_t *)p_context)->export_context->mount_point, ((lustrefsal_op_context_t *)p_context)->export_context->mnt_len, &pathfsal); TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get attributes, if asked */ if(p_object_attributes) { status = LUSTREFSAL_getattrs(p_object_handle, p_context, p_object_attributes); 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); } } /* Done */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); } /* retrieve directory attributes */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &pathfsal); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get directory metadata */ TakeTokenFSCall(); rc = lstat(pathfsal.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_lookup); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_lookup); } /* Be careful about junction crossing, symlinks, hardlinks,... */ switch (posix2fsal_type(buffstat.st_mode)) { case FSAL_TYPE_DIR: // OK break; case FSAL_TYPE_JUNCTION: // This is a junction Return(ERR_FSAL_XDEV, 0, INDEX_FSAL_lookup); case FSAL_TYPE_FILE: case FSAL_TYPE_LNK: case FSAL_TYPE_XATTR: // not a directory Return(ERR_FSAL_NOTDIR, 0, INDEX_FSAL_lookup); default: Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_lookup); } LogFullDebug(COMPONENT_FSAL, "lookup of %s/%s\n", pathfsal.path, p_filename->name); /* check rights to enter into the directory */ status = fsal_internal_testAccess(p_context, FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); status = fsal_internal_appendNameToPath(&pathfsal, p_filename); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get file handle, it it exists */ TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get object attributes */ if(p_object_attributes) { status = LUSTREFSAL_getattrs(p_object_handle, p_context, p_object_attributes); 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); } } /* lookup complete ! */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); }
/** * 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 XFSFSAL_open(xfsfsal_handle_t * p_filehandle, /* IN */ xfsfsal_op_context_t * p_context, /* IN */ fsal_openflags_t openflags, /* IN */ xfsfsal_file_t * p_file_descriptor, /* OUT */ fsal_attrib_list_t * p_file_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; int fd = 0 ; struct stat buffstat; int posix_flags = 0; /* sanity checks. * note : file_attributes is optional. */ if(!p_filehandle || !p_context || !p_file_descriptor) Return(ERR_FSAL_FAULT, 0, 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(); status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, posix_flags); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_open); /* retrieve file attributes for checking access rights */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_open); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_open); } #if 0 /* No required, the open would have failed if not permitted */ status = fsal_internal_testAccess(p_context, openflags & FSAL_O_RDONLY ? FSAL_R_OK : FSAL_W_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) { close(fd); ReturnStatus(status, INDEX_FSAL_open); } #endif TakeTokenFSCall(); p_file_descriptor->fd = fd; errsv = errno; ReleaseTokenFSCall(); /* 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); }