/* * Common code used by fsal_lookup and fsal_readdir - * given the name try to stat an entry. If an entry is * regular file or directory then open it and use fd2handle * to get a real handle, otherwise use inum2handle to fake * a handle. */ fsal_status_t xfsfsal_stat_by_name(fsal_op_context_t * context, int atfd, const char *name, fsal_handle_t *handle, fsal_attrib_list_t * attributes) { int rc; int errsv; struct stat buffstat; fsal_status_t st; TakeTokenFSCall(); rc = fstatat(atfd, name, &buffstat, AT_SYMLINK_NOFOLLOW); errsv = errno; ReleaseTokenFSCall(); if(rc < 0) ReturnCode(posix2fsal_error(errsv), errsv); if(S_ISDIR(buffstat.st_mode) || S_ISREG(buffstat.st_mode)) { int tmpfd; TakeTokenFSCall(); tmpfd = openat(atfd, name, O_RDONLY | O_NOFOLLOW, 0600); errsv = errno; ReleaseTokenFSCall(); if(tmpfd < 0) ReturnCode(posix2fsal_error(errsv), errsv); st = fsal_internal_fd2handle(context, tmpfd, handle); close(tmpfd); } else { st = fsal_internal_inum2handle(context, buffstat.st_ino, handle); } if(FSAL_IS_ERROR(st)) return st; if(attributes) { st = posix2fsal_attributes(&buffstat, attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(attributes->asked_attributes); FSAL_SET_MASK(attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } return st; }
fsal_status_t fsal_internal_Path2Handle(fsal_op_context_t * p_context, /* IN */ fsal_path_t * p_fsalpath, /* IN */ fsal_handle_t * p_handle /* OUT */ ) { int objectfd; fsal_status_t st; if(!p_context || !p_handle || !p_fsalpath) ReturnCode(ERR_FSAL_FAULT, 0); LogFullDebug(COMPONENT_FSAL, "Lookup handle for %s", p_fsalpath->path); if((objectfd = open(p_fsalpath->path, O_RDONLY, 0600)) < 0) ReturnCode(posix2fsal_error(errno), errno); st = fsal_internal_fd2handle(p_context, objectfd, p_handle); close(objectfd); return st; } /* fsal_internal_Path2Handle */
/** * 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,...). * \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 (optional input/output): * The 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). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occurred. */ fsal_status_t GPFSFSAL_create(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc = 0, errsv; int setgid_bit = 0; fsal_status_t status; int fd, newfd; mode_t unix_mode; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* retrieve directory metadata */ parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* Check the user can write in the directory, and check the setgid bit on the directory */ if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) setgid_bit = 1; /* Set both mode and ace4 mask */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE); status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* call to filesystem */ TakeTokenFSCall(); /* create the file. * O_EXCL=> error if the file already exists */ newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode); errsv = errno; if(newfd < 0) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* we no longer need the parent directory open any more */ close(fd); /* close the file descriptor */ /*** * Previously the file handle was closed here. I don't think that we need that, but leaving the commented out logic just in case. rc = close(newfd); errsv = errno; if(rc) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } */ /* get a handle for this new fd, doing this directly ensures no race because we still have the fd open until the end of this function */ status = fsal_internal_fd2handle(newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(newfd); ReturnStatus(status, INDEX_FSAL_create); } /* the file has been created */ /* chown the file to the current user */ if(p_context->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } } /* if we got this far successfully, but the file close fails, we've got a problem, possibly a disk full problem. */ close(newfd); if(rc) Return(posix2fsal_error(errno), errno, INDEX_FSAL_create); /* retrieve file attributes */ if(p_object_attributes) { status = GPFSFSAL_getattrs(p_object_handle, 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); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
fsal_status_t VFSFSAL_readdir(vfsfsal_dir_t * p_dir_descriptor, /* IN */ vfsfsal_cookie_t start_position, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * p_pdirent, /* OUT */ vfsfsal_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; 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 */ /***************************/ 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) { vfsfsal_handle_t *tmp_handle = (vfsfsal_handle_t *) (&(p_pdirent[*p_nb_entries].handle)); st = fsal_internal_fd2handle(&p_dir_descriptor->context, tmpfd, tmp_handle); close(tmpfd); } else { vfsfsal_handle_t *tmp_handle = (vfsfsal_handle_t *) (&(p_pdirent[*p_nb_entries].handle)); 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, tmp_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 = VFSFSAL_getattrs((vfsfsal_handle_t *) (&(p_pdirent[*p_nb_entries].handle)), (vfsfsal_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; ((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_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,...). * \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 (optional input/output): * The 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). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occurred. */ fsal_status_t XFSFSAL_create(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; fsal_status_t status; int fd, newfd; struct stat buffstat; mode_t unix_mode; /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* retrieve directory metadata */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* Check the user can write in the directory, and check the setgid bit on the directory */ if(buffstat.st_mode & S_ISGID) setgid_bit = 1; status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* call to filesystem */ TakeTokenFSCall(); /* create the file. * O_EXCL=> error if the file already exists */ newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode); errsv = errno; if(newfd == -1) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* get the new file handle */ status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); close(newfd); ReturnStatus(status, INDEX_FSAL_create); } /* the file has been created */ /* chown the file to the current user */ if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user, setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } } close(fd); close(newfd); /* retrieve file attributes */ if(p_object_attributes) { status = XFSFSAL_getattrs(p_object_handle, 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); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
/** * FSAL_mknode: * Create a special object in the filesystem. * Not supported upon HPSS. * * \return ERR_FSAL_NOTSUPP. */ fsal_status_t XFSFSAL_mknode(fsal_handle_t * parentdir_handle, /* IN */ fsal_name_t * p_node_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_nodetype_t nodetype, /* IN */ fsal_dev_t * dev, /* IN */ fsal_handle_t * p_object_handle, /* OUT (handle to the created node) */ fsal_attrib_list_t * node_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; struct stat buffstat; fsal_status_t status; int fd, newfd; mode_t unix_mode = 0; dev_t unix_dev = 0; /* sanity checks. * note : link_attributes is optional. */ if(!parentdir_handle || !p_context || !p_node_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; switch (nodetype) { case FSAL_TYPE_BLK: if(!dev) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode |= S_IFBLK; unix_dev = (dev->major << 8) | (dev->minor & 0xFF); break; case FSAL_TYPE_CHR: if(!dev) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode |= S_IFCHR; unix_dev = (dev->major << 8) | (dev->minor & 0xFF); break; case FSAL_TYPE_SOCK: unix_mode |= S_IFSOCK; break; case FSAL_TYPE_FIFO: unix_mode |= S_IFIFO; break; default: LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode); } /* build the directory path */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* retrieve directory attributes */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_mknode); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } /* Check the user can write in the directory, and check weither the setgid bit on the directory */ if(buffstat.st_mode & S_ISGID) setgid_bit = 1; status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* creates the node, then stats it */ TakeTokenFSCall(); rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev); errsv = errno; if(rc) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } /* get the new object handle */ if((newfd = openat(fd, p_node_name->name, O_RDONLY, 0600)) < 0) { errsv = errno; close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); close(newfd); ReturnStatus(status, INDEX_FSAL_mknode); } /* the node has been created */ /* chown the file to the current user/group */ if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user, setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } } close(fd); close(newfd); /* Fills the attributes if needed */ if(node_attributes) { status = XFSFSAL_getattrs(p_object_handle, p_context, node_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(node_attributes->asked_attributes); FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* Finished */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode); }
/** * 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) * - Another error code if an error occured. */ fsal_status_t XFSFSAL_mkdir(xfsfsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* IN */ xfsfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ xfsfsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; struct stat buffstat; mode_t unix_mode; fsal_status_t status; int fd, newfd; /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); /* convert FSAL mode to HPSS mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* get directory metadata */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* Check the user can write in the directory, and check the setgid bit on the directory */ if(buffstat.st_mode & S_ISGID) setgid_bit = 1; status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* build new entry path */ /* creates the directory and get its handle */ TakeTokenFSCall(); rc = mkdirat(fd, p_dirname->name, unix_mode); errsv = errno; if(rc) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } /* get the new handle */ if((newfd = openat(fd, p_dirname->name, O_RDONLY | O_DIRECTORY, 0600)) < 0) { errsv = errno; close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); close(newfd); ReturnStatus(status, INDEX_FSAL_mkdir); } /* the directory has been created */ /* chown the file to the current user/group */ if(p_context->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } } close(fd); close(newfd); /* retrieve file attributes */ if(p_object_attributes) { status = XFSFSAL_getattrs(p_object_handle, 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); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); }
/** * @param exp_hdl Handle * @param path Path * @param handle Reference to handle * * modelled on old api except we don't stuff attributes. * @return Status of operation */ fsal_status_t gpfs_lookup_path(struct fsal_export *exp_hdl, const char *path, struct fsal_obj_handle **handle, struct attrlist *attrs_out) { fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; fsal_status_t fsal_status; int retval = 0; int dir_fd; struct fsal_filesystem *fs; struct gpfs_fsal_obj_handle *hdl; struct attrlist attributes; gpfsfsal_xstat_t buffxstat; struct gpfs_file_handle *fh = alloca(sizeof(struct gpfs_file_handle)); struct fsal_fsid__ fsid; struct gpfs_fsal_export *gpfs_export; memset(fh, 0, sizeof(struct gpfs_file_handle)); fh->handle_size = GPFS_MAX_FH_SIZE; *handle = NULL; /* poison it */ dir_fd = open_dir_by_path_walk(-1, path, &buffxstat.buffstat); fsal_prepare_attrs(&attributes, ATTR_GPFS_ALLOC_HANDLE); if (attrs_out != NULL) attributes.mask |= attrs_out->mask; if (dir_fd < 0) { LogCrit(COMPONENT_FSAL, "Could not open directory for path %s", path); retval = -dir_fd; goto errout; } fsal_status = fsal_internal_fd2handle(dir_fd, fh); if (FSAL_IS_ERROR(fsal_status)) goto fileerr; gpfs_export = container_of(exp_hdl, struct gpfs_fsal_export, export); fsal_status = fsal_get_xstat_by_handle(dir_fd, fh, &buffxstat, NULL, false, (attributes.mask & ATTR_ACL) != 0); if (FSAL_IS_ERROR(fsal_status)) goto fileerr; fsal_status = gpfsfsal_xstat_2_fsal_attributes(&buffxstat, &attributes, gpfs_export->use_acl); LogFullDebug(COMPONENT_FSAL, "fsid=0x%016"PRIx64".0x%016"PRIx64, attributes.fsid.major, attributes.fsid.minor); if (FSAL_IS_ERROR(fsal_status)) goto fileerr; close(dir_fd); gpfs_extract_fsid(fh, &fsid); fs = lookup_fsid(&fsid, GPFS_FSID_TYPE); 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); /* Make sure ATTR_RDATTR_ERR is cleared on success. */ attributes.mask &= ~ATTR_RDATTR_ERR; /* allocate an obj_handle and fill it up */ hdl = alloc_handle(fh, fs, &attributes, NULL, exp_hdl); if (attrs_out != NULL) { /* Copy the attributes to caller, passing ACL ref. */ fsal_copy_attrs(attrs_out, &attributes, true); } else { /* Done with the attrs */ fsal_release_attrs(&attributes); } *handle = &hdl->obj_handle; return fsalstat(ERR_FSAL_NO_ERROR, 0); fileerr: retval = errno; close(dir_fd); errout: /* Done with attributes */ fsal_release_attrs(&attributes); fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); }