/** * @brief Create a regular file. * * @param dir_hdl Handle of parent directory where the file is to be created. * @param filename Pointer to the name of the file to be created. * @param op_ctx Authentication context for the operation (user,...). * @param accessmode Mode for the file to be created. * @param gpfs_fh Pointer to the handle of the created file. * @param fsal_attr Attributes of the created file. * @return ERR_FSAL_NO_ERROR on success, otherwise error * */ fsal_status_t GPFSFSAL_create(struct fsal_obj_handle *dir_hdl, const char *filename, const struct req_op_context *op_ctx, uint32_t accessmode, struct gpfs_file_handle *gpfs_fh, struct attrlist *fsal_attr) { fsal_status_t status; mode_t unix_mode; /* note : fsal_attr is optional. */ if (!dir_hdl || !op_ctx || !gpfs_fh || !filename) return fsalstat(ERR_FSAL_FAULT, 0); /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~op_ctx->fsal_export->exp_ops. fs_umask(op_ctx->fsal_export); LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); /* call to filesystem */ fsal_set_credentials(op_ctx->creds); status = fsal_internal_create(dir_hdl, filename, unix_mode | S_IFREG, 0, gpfs_fh, NULL); fsal_restore_ganesha_credentials(); if (FSAL_IS_ERROR(status)) return status; /* retrieve file attributes */ return GPFSFSAL_getattrs(op_ctx->fsal_export, dir_hdl->fs->private_data, op_ctx, gpfs_fh, fsal_attr); }
/** * 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 ZFSFSAL_mkdir(zfsfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* IN */ zfsfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ zfsfsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; mode_t unix_mode; /* 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); /* convert fsal args to ZFS args */ unix_mode = fsal2unix_mode(accessmode); /* Applying FSAL umask */ unix_mode = unix_mode & ~global_fs_info.umask; TakeTokenFSCall(); /* Create the directory */ inogen_t object; rc = libzfswrap_mkdir(p_context->export_context->p_vfs, &p_context->user_credential.cred, parent_directory_handle->data.zfs_handle, p_dirname->name, unix_mode, &object); ReleaseTokenFSCall(); /* >> interpret returned error << */ if(rc) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); /* set output handle */ object_handle->data.zfs_handle = object; object_handle->data.type = FSAL_TYPE_DIR; if(object_attributes) { /**@TODO: skip this => libzfswrap_mkdir might return attributes */ fsal_status_t status = ZFSFSAL_getattrs(object_handle, 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); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); }
/** * 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 ZFSFSAL_create(zfsfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ zfsfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ zfsfsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; /* 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); /* >> convert fsal args to your fs args. * Don't forget applying FSAL umask : * mode = mode & ~global_fs_info.umask << */ TakeTokenFSCall(); inogen_t object; rc = libzfswrap_create(p_context->export_context->p_vfs, &p_context->user_credential.cred, parent_directory_handle->data.zfs_handle, p_filename->name, fsal2unix_mode(accessmode), &object); ReleaseTokenFSCall(); /* >> interpret returned error << */ if(rc) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); /* >> set output handle << */ object_handle->data.zfs_handle = object; object_handle->data.type = FSAL_TYPE_FILE; if(object_attributes) { fsal_status_t status = ZFSFSAL_getattrs(object_handle, 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); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
/** * @brief Create a directory. * * @param dir_hdl Handle of the parent directory * @param dir_name Pointer to the name of the directory to be created. * @param op_ctx Authentication context for the operation (user,...). * @param accessmode Mode for the directory to be created. * @param gpfs_fh Pointer to the handle of the created directory. * @param fsal_attr Attributes of the created directory. * @return ERR_FSAL_NO_ERROR on success, error otherwise * */ fsal_status_t GPFSFSAL_mkdir(struct fsal_obj_handle *dir_hdl, const char *dir_name, const struct req_op_context *op_ctx, uint32_t accessmode, struct gpfs_file_handle *gpfs_fh, struct attrlist *obj_attr) { mode_t unix_mode; fsal_status_t status; /* note : obj_attr is optional. */ if (!dir_hdl || !op_ctx || !gpfs_fh || !dir_name) return fsalstat(ERR_FSAL_FAULT, 0); /* convert FSAL mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export); /* build new entry path */ /* creates the directory and get its handle */ fsal_set_credentials(op_ctx->creds); status = fsal_internal_create(dir_hdl, dir_name, unix_mode | S_IFDIR, 0, gpfs_fh, NULL); fsal_restore_ganesha_credentials(); if (FSAL_IS_ERROR(status)) return status; /* retrieve file attributes */ return GPFSFSAL_getattrs(op_ctx->fsal_export, dir_hdl->fs->private_data, op_ctx, gpfs_fh, obj_attr); }
fsal_status_t vfs_open2(struct fsal_obj_handle *obj_hdl, struct state_t *state, fsal_openflags_t openflags, enum fsal_create_mode createmode, const char *name, struct attrlist *attrib_set, fsal_verifier_t verifier, struct fsal_obj_handle **new_obj, struct attrlist *attrs_out, bool *caller_perm_check) { int posix_flags = 0; int fd, dir_fd; int retval = 0; mode_t unix_mode; fsal_status_t status = {0, 0}; struct vfs_fd *my_fd = NULL; struct vfs_fsal_obj_handle *myself, *hdl = NULL; struct stat stat; vfs_file_handle_t *fh = NULL; bool truncated; bool created = false; if (state != NULL) my_fd = (struct vfs_fd *)(state + 1); myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); LogAttrlist(COMPONENT_FSAL, NIV_FULL_DEBUG, "attrib_set ", attrib_set, false); fsal2posix_openflags(openflags, &posix_flags); truncated = (posix_flags & O_TRUNC) != 0; LogFullDebug(COMPONENT_FSAL, truncated ? "Truncate" : "No truncate"); if (createmode >= FSAL_EXCLUSIVE) { /* Now fixup attrs for verifier if exclusive create */ set_common_verifier(attrib_set, verifier); } if (name == NULL) { /* This is an open by handle */ 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) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", obj_hdl->fsal->name, obj_hdl->fs->fsal->name); return fsalstat(posix2fsal_error(EXDEV), EXDEV); } if (state != NULL) { /* Prepare to take the share reservation, but only if we * are called with a valid state (if state is NULL the * caller is a stateless create such as NFS v3 CREATE). */ /* This can block over an I/O operation. */ PTHREAD_RWLOCK_wrlock(&obj_hdl->lock); /* Check share reservation conflicts. */ status = check_share_conflict(&myself->u.file.share, openflags, false); if (FSAL_IS_ERROR(status)) { PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; } /* Take the share reservation now by updating the * counters. */ update_share_counters(&myself->u.file.share, FSAL_O_CLOSED, openflags); PTHREAD_RWLOCK_unlock(&obj_hdl->lock); } else { /* We need to use the global fd to continue, and take * the lock to protect it. */ my_fd = &hdl->u.file.fd; PTHREAD_RWLOCK_wrlock(&obj_hdl->lock); } status = vfs_open_my_fd(myself, openflags, posix_flags, my_fd); if (FSAL_IS_ERROR(status)) { if (state == NULL) { /* Release the lock taken above, and return * since there is nothing to undo. */ PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; } else { /* Error - need to release the share */ goto undo_share; } } if (createmode >= FSAL_EXCLUSIVE || truncated) { /* Refresh the attributes */ struct stat stat; retval = fstat(my_fd->fd, &stat); if (retval == 0) { LogFullDebug(COMPONENT_FSAL, "New size = %" PRIx64, stat.st_size); } else { if (errno == EBADF) errno = ESTALE; status = fsalstat(posix2fsal_error(errno), errno); } /* Now check verifier for exclusive, but not for * FSAL_EXCLUSIVE_9P. */ if (!FSAL_IS_ERROR(status) && createmode >= FSAL_EXCLUSIVE && createmode != FSAL_EXCLUSIVE_9P && !check_verifier_stat(&stat, verifier)) { /* Verifier didn't match, return EEXIST */ status = fsalstat(posix2fsal_error(EEXIST), EEXIST); } } if (state == NULL) { /* If no state, release the lock taken above and return * status. */ PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; } if (!FSAL_IS_ERROR(status)) { /* Return success. */ return status; } (void) vfs_close_my_fd(my_fd); undo_share: /* Can only get here with state not NULL and an error */ /* On error we need to release our share reservation * and undo the update of the share counters. * This can block over an I/O operation. */ PTHREAD_RWLOCK_wrlock(&obj_hdl->lock); update_share_counters(&myself->u.file.share, openflags, FSAL_O_CLOSED); PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; } /* In this path where we are opening by name, we can't check share * reservation yet since we don't have an object_handle yet. If we * indeed create the object handle (there is no race with another * open by name), then there CAN NOT be a share conflict, otherwise * the share conflict will be resolved when the object handles are * merged. */ #ifdef ENABLE_VFS_DEBUG_ACL if (createmode != FSAL_NO_CREATE) { /* Need to ammend attributes for inherited ACL, these will be * set later. We also need to test for permission to create * since there might be an ACL. */ struct attrlist attrs; fsal_accessflags_t access_type; access_type = FSAL_MODE_MASK_SET(FSAL_W_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE); status = obj_hdl->obj_ops.test_access(obj_hdl, access_type, NULL, NULL, false); if (FSAL_IS_ERROR(status)) return status; fsal_prepare_attrs(&attrs, ATTR_ACL); status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs); if (FSAL_IS_ERROR(status)) return status; status.major = fsal_inherit_acls(attrib_set, attrs.acl, FSAL_ACE_FLAG_FILE_INHERIT); /* Done with the attrs */ fsal_release_attrs(&attrs); if (FSAL_IS_ERROR(status)) return status; } #endif /* ENABLE_VFS_DEBUG_ACL */ if (createmode != FSAL_NO_CREATE) { /* Now add in O_CREAT and O_EXCL. */ posix_flags |= O_CREAT; /* And if we are at least FSAL_GUARDED, do an O_EXCL create. */ if (createmode >= FSAL_GUARDED) posix_flags |= O_EXCL; /* Fetch the mode attribute to use in the openat system call. */ unix_mode = fsal2unix_mode(attrib_set->mode) & ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export); /* Don't set the mode if we later set the attributes */ FSAL_UNSET_MASK(attrib_set->mask, ATTR_MODE); } if (createmode == FSAL_UNCHECKED && (attrib_set->mask != 0)) { /* If we have FSAL_UNCHECKED and want to set more attributes * than the mode, we attempt an O_EXCL create first, if that * succeeds, then we will be allowed to set the additional * attributes, otherwise, we don't know we created the file * and this can NOT set the attributes. */ posix_flags |= O_EXCL; } dir_fd = vfs_fsal_open(myself, O_PATH | O_NOACCESS, &status.major); if (dir_fd < 0) return fsalstat(status.major, -dir_fd); /** @todo: not sure what this accomplishes... */ retval = vfs_stat_by_handle(dir_fd, &stat); if (retval < 0) { retval = errno; status = fsalstat(posix2fsal_error(retval), retval); goto direrr; } /* Become the user because we are creating an object in this dir. */ if (createmode != FSAL_NO_CREATE) fsal_set_credentials(op_ctx->creds); if ((posix_flags & O_CREAT) != 0) fd = openat(dir_fd, name, posix_flags, unix_mode); else fd = openat(dir_fd, name, posix_flags); if (fd == -1 && errno == EEXIST && createmode == FSAL_UNCHECKED) { /* We tried to create O_EXCL to set attributes and failed. * Remove O_EXCL and retry. We still try O_CREAT again just in * case file disappears out from under us. * * Note that because we have dropped O_EXCL, later on we will * not assume we created the file, and thus will not set * additional attributes. We don't need to separately track * the condition of not wanting to set attributes. */ posix_flags &= ~O_EXCL; fd = openat(dir_fd, name, posix_flags, unix_mode); } /* Preserve errno */ retval = errno; /* If we were creating, restore credentials now. */ if (createmode != FSAL_NO_CREATE) fsal_restore_ganesha_credentials(); if (fd < 0) { status = fsalstat(posix2fsal_error(retval), retval); goto direrr; } /* Remember if we were responsible for creating the file. * Note that in an UNCHECKED retry we MIGHT have re-created the * file and won't remember that. Oh well, so in that rare case we * leak a partially created file if we have a subsequent error in here. * Also notify caller to do permission check if we DID NOT create the * file. Note it IS possible in the case of a race between an UNCHECKED * open and an external unlink, we did create the file, but we will * still force a permission check. Of course that permission check * SHOULD succeed since we also won't set the mode the caller requested * and the default file create permissions SHOULD allow the owner * read/write. */ created = (posix_flags & O_EXCL) != 0; *caller_perm_check = !created; vfs_alloc_handle(fh); retval = vfs_name_to_handle(dir_fd, obj_hdl->fs, name, fh); if (retval < 0) { retval = errno; status = fsalstat(posix2fsal_error(retval), retval); goto fileerr; } retval = fstat(fd, &stat); if (retval < 0) { retval = errno; status = fsalstat(posix2fsal_error(retval), retval); goto fileerr; } /* allocate an obj_handle and fill it up */ hdl = alloc_handle(dir_fd, fh, obj_hdl->fs, &stat, myself->handle, name, op_ctx->fsal_export); if (hdl == NULL) { status = fsalstat(posix2fsal_error(ENOMEM), ENOMEM); goto fileerr; } /* If we didn't have a state above, use the global fd. At this point, * since we just created the global fd, no one else can have a * reference to it, and thus we can mamnipulate unlocked which is * handy since we can then call setattr2 which WILL take the lock * without a double locking deadlock. */ if (my_fd == NULL) my_fd = &hdl->u.file.fd; my_fd->fd = fd; my_fd->openflags = openflags; *new_obj = &hdl->obj_handle; if (created && attrib_set->mask != 0) { /* Set attributes using our newly opened file descriptor as the * share_fd if there are any left to set (mode and truncate * have already been handled). * * Note that we only set the attributes if we were responsible * for creating the file and we have attributes to set. * * Note if we have ENABLE_VFS_DEBUG_ACL an inherited ACL might * be part of the attributes we are setting here. */ status = (*new_obj)->obj_ops.setattr2(*new_obj, false, state, attrib_set); if (FSAL_IS_ERROR(status)) { /* Release the handle we just allocated. */ (*new_obj)->obj_ops.release(*new_obj); *new_obj = NULL; goto fileerr; } if (attrs_out != NULL) { status = (*new_obj)->obj_ops.getattrs(*new_obj, attrs_out); if (FSAL_IS_ERROR(status) && (attrs_out->mask & ATTR_RDATTR_ERR) == 0) { /* Get attributes failed and caller expected * to get the attributes. Otherwise continue * with attrs_out indicating ATTR_RDATTR_ERR. */ goto fileerr; } } } else if (attrs_out != NULL) { /* Since we haven't set any attributes other than what was set * on create (if we even created), just use the stat results * we used to create the fsal_obj_handle. */ posix2fsal_attributes(&stat, attrs_out); /* Make sure ATTR_RDATTR_ERR is cleared on success. */ attrs_out->mask &= ~ATTR_RDATTR_ERR; } close(dir_fd); if (state != NULL) { /* Prepare to take the share reservation, but only if we are * called with a valid state (if state is NULL the caller is * a stateless create such as NFS v3 CREATE). */ /* This can block over an I/O operation. */ PTHREAD_RWLOCK_wrlock(&(*new_obj)->lock); /* Take the share reservation now by updating the counters. */ update_share_counters(&hdl->u.file.share, FSAL_O_CLOSED, openflags); PTHREAD_RWLOCK_unlock(&(*new_obj)->lock); } return fsalstat(ERR_FSAL_NO_ERROR, 0); fileerr: close(fd); /* Delete the file if we actually created it. */ if (created) unlinkat(dir_fd, name, 0); direrr: close(dir_fd); return fsalstat(posix2fsal_error(retval), retval); }
/** * @brief Set attributes on an object * * This function sets attributes on an object. Which attributes are * set is determined by attrib_set->mask. The FSAL must manage bypass * or not of share reservations, and a state may be passed. * * @param[in] obj_hdl File on which to operate * @param[in] state state_t to use for this operation * @param[in] attrib_set Attributes to set * * @return FSAL status. */ fsal_status_t vfs_setattr2(struct fsal_obj_handle *obj_hdl, bool bypass, struct state_t *state, struct attrlist *attrib_set) { struct vfs_fsal_obj_handle *myself; fsal_status_t status = {0, 0}; int retval = 0; fsal_openflags_t openflags = FSAL_O_ANY; bool has_lock = false; bool need_fsync = false; bool closefd = false; int my_fd; const char *func; /* apply umask, if mode attribute is to be changed */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) attrib_set->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)"); return fsalstat(posix2fsal_error(EXDEV), EXDEV); } #ifdef ENABLE_VFS_DEBUG_ACL #ifdef ENABLE_RFC_ACL if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE) && !FSAL_TEST_MASK(attrib_set->mask, ATTR_ACL)) { /* Set ACL from MODE */ struct attrlist attrs; fsal_prepare_attrs(&attrs, ATTR_ACL); status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs); if (FSAL_IS_ERROR(status)) return status; status = fsal_mode_to_acl(attrib_set, attrs.acl); /* Done with the attrs */ fsal_release_attrs(&attrs); } else { /* If ATTR_ACL is set, mode needs to be adjusted no matter what. * See 7530 s 6.4.1.3 */ if (!FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) attrib_set->mode = myself->mode; status = fsal_acl_to_mode(attrib_set); } if (FSAL_IS_ERROR(status)) return status; #endif /* ENABLE_RFC_ACL */ #endif /* 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. */ /* Test if size is being set, make sure file is regular and if so, * require a read/write file descriptor. */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) { if (obj_hdl->type != REGULAR_FILE) { LogFullDebug(COMPONENT_FSAL, "Setting size on non-regular file"); return fsalstat(ERR_FSAL_INVAL, EINVAL); } openflags = FSAL_O_RDWR; } /* Get a usable file descriptor. Share conflict is only possible if * size is being set. */ status = find_fd(&my_fd, obj_hdl, bypass, state, openflags, &has_lock, &need_fsync, &closefd, false); if (FSAL_IS_ERROR(status)) { if (obj_hdl->type == SYMBOLIC_LINK && status.major == ERR_FSAL_PERM) { /* 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... */ status = fsalstat(ERR_FSAL_NO_ERROR, 0); } LogFullDebug(COMPONENT_FSAL, "find_fd status=%s", fsal_err_txt(status)); goto out; } /** TRUNCATE **/ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) { retval = ftruncate(my_fd, attrib_set->filesize); if (retval != 0) { /** @todo FSF: is this still necessary? * * XXX ESXi volume creation pattern reliably * reached this point in the past, however now that we * only use the already open file descriptor if it is * open read/write, this may no longer fail. * If there is some other error from ftruncate, then * we will needlessly retry, but without more detail * of the original failure, we can't be sure. * Fortunately permission checking is done by * Ganesha before calling here, so we won't get an * EACCES since this call is done as root. We could * get EFBIG, EPERM, or EINVAL. */ /** @todo FSF: re-open if we really still need this */ retval = ftruncate(my_fd, attrib_set->filesize); if (retval != 0) { func = "truncate"; goto fileerr; } } } /** CHMOD **/ if (FSAL_TEST_MASK(attrib_set->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 (obj_hdl->type != SYMBOLIC_LINK) { if (vfs_unopenable_type(obj_hdl->type)) retval = fchmodat( my_fd, myself->u.unopenable.name, fsal2unix_mode(attrib_set->mode), 0); else retval = fchmod( my_fd, fsal2unix_mode(attrib_set->mode)); if (retval != 0) { func = "chmod"; goto fileerr; } } } /** CHOWN **/ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER | ATTR_GROUP)) { uid_t user = FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER) ? (int)attrib_set->owner : -1; gid_t group = FSAL_TEST_MASK(attrib_set->mask, ATTR_GROUP) ? (int)attrib_set->group : -1; if (vfs_unopenable_type(obj_hdl->type)) retval = fchownat(my_fd, myself->u.unopenable.name, user, group, AT_SYMLINK_NOFOLLOW); else if (obj_hdl->type == SYMBOLIC_LINK) retval = fchownat(my_fd, "", user, group, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH); else retval = fchown(my_fd, user, group); if (retval) { func = "chown"; goto fileerr; } } /** UTIME **/ if (FSAL_TEST_MASK(attrib_set->mask, ATTRS_SET_TIME)) { struct timespec timebuf[2]; if (obj_hdl->type == SYMBOLIC_LINK) goto out; /* Setting time on symlinks is illegal */ /* Atime */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME_SERVER)) { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME)) { timebuf[0] = attrib_set->atime; } else { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_OMIT; } /* Mtime */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME_SERVER)) { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME)) { timebuf[1] = attrib_set->mtime; } else { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_OMIT; } if (vfs_unopenable_type(obj_hdl->type)) retval = vfs_utimesat(my_fd, myself->u.unopenable.name, timebuf, AT_SYMLINK_NOFOLLOW); else retval = vfs_utimes(my_fd, timebuf); if (retval != 0) { func = "utimes"; goto fileerr; } } /** SUBFSAL **/ if (myself->sub_ops && myself->sub_ops->setattrs) { status = myself->sub_ops->setattrs( myself, my_fd, attrib_set->mask, attrib_set); if (FSAL_IS_ERROR(status)) goto out; } errno = 0; fileerr: retval = errno; if (retval != 0) { LogDebug(COMPONENT_FSAL, "%s returned %s", func, strerror(retval)); } status = fsalstat(posix2fsal_error(retval), retval); out: if (closefd) close(my_fd); if (has_lock) PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; }
static fsal_status_t lustre_makedir(struct fsal_obj_handle *dir_hdl, const char *name, struct attrlist *attrib, struct fsal_obj_handle **handle) { struct lustre_fsal_obj_handle *myself, *hdl; char dirpath[MAXPATHLEN]; char newpath[MAXPATHLEN]; struct stat stat; mode_t unix_mode; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int rc = 0; struct lustre_file_handle *fh = alloca(sizeof(struct lustre_file_handle)); *handle = NULL; /* poison it */ if (!dir_hdl->ops->handle_is(dir_hdl, DIRECTORY)) { LogCrit(COMPONENT_FSAL, "Parent handle is not a directory. hdl = 0x%p", dir_hdl); return fsalstat(ERR_FSAL_NOTDIR, 0); } memset(fh, 0, sizeof(struct lustre_file_handle)); myself = container_of(dir_hdl, struct lustre_fsal_obj_handle, obj_handle); unix_mode = fsal2unix_mode(attrib->mode) & ~op_ctx->fsal_export->ops->fs_umask(op_ctx->fsal_export); lustre_handle_to_path(dir_hdl->fs->path, myself->handle, dirpath); rc = lstat(dirpath, &stat); if (rc < 0) { rc = errno; goto direrr; } /* create it with no access because we are root when we do this */ snprintf(newpath, MAXPATHLEN, "%s/%s", dirpath, name); rc = CRED_WRAP(op_ctx->creds, int, mkdir, newpath, unix_mode); if (rc < 0) { rc = errno; goto direrr; } rc = get_stat_by_handle_at(dir_hdl->fs->path, myself->handle, name, fh, &stat); if (rc < 0) goto fileerr; /* allocate an obj_handle and fill it up */ hdl = alloc_handle(fh, dir_hdl->fs, &stat, NULL, NULL, NULL, op_ctx->fsal_export); if (hdl != NULL) { *handle = &hdl->obj_handle; } else { fsal_error = ERR_FSAL_NOMEM; goto errout; } return fsalstat(ERR_FSAL_NO_ERROR, 0); direrr: rc = errno; fsal_error = posix2fsal_error(rc); return fsalstat(fsal_error, rc); fileerr: fsal_error = posix2fsal_error(rc); rmdir(newpath); /* remove the evidence on errors */ errout: return fsalstat(fsal_error, rc); }
/** * FSAL_mkdir: * Create a directory. * * \param dir_hdl (input): * Handle of the parent directory where * the subdirectory is to be created. * \param p_context (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 p_object_handle (output): * Pointer to the handle of the created directory. * \param p_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 PTFSAL_mkdir(struct fsal_obj_handle *dir_hdl, /* IN */ const char *p_dirname, /* IN */ const struct req_op_context *p_context, /* IN */ uint32_t accessmode, /* IN */ ptfsal_handle_t *p_object_handle, /* OUT */ struct attrlist *p_object_attributes) { /* IN/OUT */ int rc, errsv; int setgid_bit = 0; mode_t unix_mode; fsal_status_t status; struct attrlist parent_dir_attrs; char newPath[PATH_MAX]; struct pt_fsal_obj_handle *pt_hdl; FSI_TRACE(FSI_INFO, "MKDIR BEGIN-------------------------\n"); /* sanity checks. * note : object_attributes is optional. */ if (!dir_hdl || !p_context || !p_object_handle || !p_dirname) return fsalstat(ERR_FSAL_FAULT, 0); pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle); /* convert FSAL mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~p_context->fsal_export->exp_ops. fs_umask(p_context->fsal_export); /* get directory metadata */ parent_dir_attrs.mask = p_context->fsal_export->exp_ops. fs_supported_attrs(p_context->fsal_export); status = PTFSAL_getattrs(p_context->fsal_export, p_context, pt_hdl->handle, &parent_dir_attrs); if (FSAL_IS_ERROR(status)) return status; /* 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; rc = ptfsal_mkdir(pt_hdl, p_dirname, p_context, unix_mode, p_object_handle); errsv = errno; if (rc) return fsalstat(posix2fsal_error(errsv), errsv); if (FSAL_IS_ERROR(status)) return status; /* the directory has been created */ /* chown the dir to the current user/group */ if (p_context->creds->caller_uid != geteuid()) { FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__); /* 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 */ if (fsi_get_name_from_handle (p_context, p_context->fsal_export, pt_hdl->handle, (char *)newPath, NULL) < 0) { FSI_TRACE(FSI_DEBUG, "Failed to get name from handle %s", (char *)p_object_handle->data.handle. f_handle); return fsalstat(posix2fsal_error(errsv), errsv); } rc = ptfsal_chown(p_context, p_context->fsal_export, newPath, p_context->creds->caller_uid, setgid_bit ? -1 : (int)p_context->creds-> caller_gid); errsv = errno; if (rc) return fsalstat(posix2fsal_error(errsv), errsv); } /* retrieve file attributes */ if (p_object_attributes) { FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__); status = PTFSAL_getattrs(p_context->fsal_export, p_context, p_object_handle, p_object_attributes); /* on error, we set a special bit in the mask. */ if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->mask); FSAL_SET_MASK(p_object_attributes->mask, ATTR_RDATTR_ERR); } } FSI_TRACE(FSI_INFO, "MKDIR END ------------------\n"); FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__); /* OK */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * FSAL_mknode: * Create a special object in the filesystem. * Not supported upon HPSS. * * \return ERR_FSAL_NOTSUPP. */ fsal_status_t GPFSFSAL_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; fsal_status_t status; int fd, newfd; mode_t unix_mode = 0; dev_t unix_dev = 0; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; /* 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 */ status = fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_RDONLY | O_DIRECTORY); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* retrieve directory attributes */ parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(parentdir_handle, p_context, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* Check the user can write in the directory, and check weither 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_mknode); /* creates the node, then stats it */ rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev); errsv = errno; if(rc) { close(fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } /* WARNING: * After creating the new node, the node name could have been changed. * This is a race condition. However only root creates new nodes. This * is an unlikely race condition, but hopefully can be fixed someday. */ if(FSAL_IS_ERROR(status = fsal_internal_get_handle_at(fd, p_node_name, p_object_handle))) { close(fd); ReturnStatus(status, INDEX_FSAL_mknode); } if(FSAL_IS_ERROR(status = fsal_internal_handle2fd_at(fd, p_object_handle, &newfd, O_RDONLY | O_NOFOLLOW))) { close(fd); ReturnStatus(status, INDEX_FSAL_mknode); } /* the node has been created */ /* chown the file to the current user/group */ if(p_context->credential.user != geteuid()) { /* 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; 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 = GPFSFSAL_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_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 POSIXFSAL_create(fsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { posixfsal_handle_t * p_parent_directory_handle = (posixfsal_handle_t *) parent_directory_handle; posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context; posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) p_object_handle; int rc, fd, errsv; int setgid_bit = 0; fsal_status_t status; fsal_path_t fsalpath; struct stat buffstat; fsal_posixdb_fileinfo_t info; 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); /* build the destination path */ status = fsal_internal_getPathFromHandle(p_context, p_parent_directory_handle, 1, &fsalpath, &buffstat); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, 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)) Return(status.major, status.minor, INDEX_FSAL_create); status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_filename); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_create); /* call to API */ TakeTokenFSCall(); /* create the file */ fd = open(fsalpath.path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode); /* error if the file already exists */ errsv = errno; if(fd == -1) goto releaseToken; /* close the file descriptor */ rc = close(fd); errsv = errno; if(rc) goto releaseToken; /* stat the new file */ rc = lstat(fsalpath.path, &buffstat); errsv = errno; releaseToken: ReleaseTokenFSCall(); if(fd == -1 || rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); /* add the file to the database */ if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info))) Return(status.major, status.minor, INDEX_FSAL_create); if(FSAL_IS_ERROR (status = fsal_internal_posixdb_add_entry(p_context->p_conn, p_filename, &info, p_parent_directory_handle, p_object_handle))) Return(status.major, status.minor, 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 = lchown(fsalpath.path, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); buffstat.st_uid = p_context->credential.user; buffstat.st_gid = p_context->credential.group; } /* add the file to the database */ if(p_object_attributes) { /* convert POSIX attributes to fsal attributes */ status = posix2fsal_attributes(&buffstat, 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); }
/** * @brief Create a special object in the filesystem. * * @param dir_hdl Handle of the parent dir where the file is to be created. * @param node_name Pointer to the name of the file to be created. * @param op_ctx Authentication context for the operation (user,...). * @param accessmode Mode for the file to be created. * @param node_type Type of file to create. * @param dev Device id of file to create. * @param gpfs_fh Pointer to the handle of the created file. * @param fsal_attr Attributes of the created file. * @return ERR_FSAL_NO_ERROR on success, error otherwise * */ fsal_status_t GPFSFSAL_mknode(struct fsal_obj_handle *dir_hdl, const char *node_name, const struct req_op_context *op_ctx, uint32_t accessmode, mode_t nodetype, fsal_dev_t *dev, struct gpfs_file_handle *gpfs_fh, struct attrlist *fsal_attr) { fsal_status_t status; mode_t unix_mode = 0; dev_t unix_dev = 0; /* note : fsal_attr is optional. */ if (!dir_hdl || !op_ctx || !node_name) return fsalstat(ERR_FSAL_FAULT, 0); unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~op_ctx->fsal_export->exp_ops. fs_umask(op_ctx->fsal_export); switch (nodetype) { case BLOCK_FILE: if (!dev) return fsalstat(ERR_FSAL_FAULT, 0); unix_mode |= S_IFBLK; unix_dev = (dev->major << 20) | (dev->minor & 0xFFFFF); break; case CHARACTER_FILE: if (!dev) return fsalstat(ERR_FSAL_FAULT, 0); unix_mode |= S_IFCHR; unix_dev = (dev->major << 20) | (dev->minor & 0xFFFFF); break; case SOCKET_FILE: unix_mode |= S_IFSOCK; break; case FIFO_FILE: unix_mode |= S_IFIFO; break; default: LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype); return fsalstat(ERR_FSAL_INVAL, 0); } fsal_set_credentials(op_ctx->creds); status = fsal_internal_mknode(dir_hdl, node_name, unix_mode, unix_dev, gpfs_fh, NULL); fsal_restore_ganesha_credentials(); if (FSAL_IS_ERROR(status)) return status; /* Fills the attributes */ return GPFSFSAL_getattrs(op_ctx->fsal_export, dir_hdl->fs->private_data, op_ctx, gpfs_fh, fsal_attr); }
/** * FSAL_mknode: * Create a special object in the filesystem. * Not supported upon HPSS. * * \return ERR_FSAL_NOTSUPP. */ fsal_status_t GPFSFSAL_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 ] */ ) { fsal_status_t status; /* int flags=(O_RDONLY|O_NOFOLLOW); */ mode_t unix_mode = 0; dev_t unix_dev = 0; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; /* 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; /* flags = (O_RDONLY | O_NOFOLLOW | O_NONBLOCK); */ break; default: LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode); } /* retrieve directory attributes */ parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(parentdir_handle, p_context, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* Check the user can write in the directory */ /* 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); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); else status = fsal_internal_access(p_context, parentdir_handle, access_mask, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); fsal_set_credentials(p_context); TakeTokenFSCall(); status = fsal_internal_create(p_context, parentdir_handle, p_node_name, unix_mode, unix_dev, p_object_handle, NULL); ReleaseTokenFSCall(); fsal_restore_ganesha_credentials(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* Fills the attributes if needed */ if(node_attributes) { status = GPFSFSAL_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_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 PTFSAL_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 errsv; int setgid_bit = 0; fsal_status_t status; mode_t unix_mode; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; int open_rc; ptfsal_handle_t * p_fsi_handle = (ptfsal_handle_t *)p_object_handle; FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n"); /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) { FSI_TRACE(FSI_DEBUG, "BAD Happen!"); 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); /* retrieve directory metadata */ parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES; status = PTFSAL_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); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); } else { status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask, &parent_dir_attrs); } if(FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_create); } // Create the file, return handle open_rc = ptfsal_open(p_parent_directory_handle, p_filename, p_context, unix_mode, p_object_handle); if (open_rc < 0) { errsv = errno; Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } FSI_TRACE(FSI_DEBUG, "New Handle = %s", (char *)p_fsi_handle->data.handle.f_handle); /* retrieve file attributes */ if(p_object_attributes) { status = PTFSAL_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); } } FSI_TRACE(FSI_DEBUG, "End to create file************************\n"); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
/** * 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 PTFSAL_mkdir(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* 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; mode_t unix_mode; fsal_status_t status; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; char newPath[PATH_MAX]; FSI_TRACE(FSI_INFO,"MKDIR BEGIN-------------------------\n"); /* 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 unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; /* get directory metadata */ parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES; status = PTFSAL_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_SUBDIRECTORY); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); } else { status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask, &parent_dir_attrs); } if(FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_mkdir); } rc = ptfsal_mkdir(p_parent_directory_handle, p_dirname, p_context, unix_mode, p_object_handle); errsv = errno; if(rc) { Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } if(FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_mkdir); } /* the directory has been created */ /* chown the dir to the current user/group */ if(p_context->credential.user != geteuid()) { FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__); /* 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 */ if(fsi_get_name_from_handle( p_context, (char *)p_object_handle->data.handle.f_handle, (char *)newPath, NULL) < 0) { FSI_TRACE(FSI_DEBUG, "Failed to get name from handle %s", (char *)p_object_handle->data.handle.f_handle); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } rc = ptfsal_chown(p_context, newPath, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; if(rc) { Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } } /* retrieve file attributes */ if(p_object_attributes) { FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__); status = PTFSAL_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); } } FSI_TRACE(FSI_INFO,"MKDIR END ------------------\n"); FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); }
/** * 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); }
static fsal_status_t lustre_makenode(struct fsal_obj_handle *dir_hdl, const char *name, object_file_type_t nodetype, /* IN */ fsal_dev_t *dev, /* IN */ struct attrlist *attrib, struct fsal_obj_handle **handle) { struct lustre_fsal_obj_handle *myself, *hdl; char dirpath[MAXPATHLEN]; char newpath[MAXPATHLEN]; struct stat stat; mode_t unix_mode; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int rc = 0; dev_t unix_dev = 0; struct lustre_file_handle *dir_fh = NULL; const char *sock_name = NULL; struct lustre_file_handle *fh = alloca(sizeof(struct lustre_file_handle)); *handle = NULL; /* poison it */ if (!dir_hdl->ops->handle_is(dir_hdl, DIRECTORY)) { LogCrit(COMPONENT_FSAL, "Parent handle is not a directory. hdl = 0x%p", dir_hdl); return fsalstat(ERR_FSAL_NOTDIR, 0); } memset(fh, 0, sizeof(struct lustre_file_handle)); myself = container_of(dir_hdl, struct lustre_fsal_obj_handle, obj_handle); unix_mode = fsal2unix_mode(attrib->mode) & ~op_ctx->fsal_export->ops->fs_umask(op_ctx->fsal_export); switch (nodetype) { case BLOCK_FILE: if (!dev) { fsal_error = ERR_FSAL_FAULT; goto errout; } unix_dev = CRED_WRAP(op_ctx->creds, dev_t, makedev, dev->major, dev->minor); break; case CHARACTER_FILE: if (!dev) { fsal_error = ERR_FSAL_FAULT; goto errout; } unix_dev = CRED_WRAP(op_ctx->creds, dev_t, makedev, dev->major, dev->minor); break; case FIFO_FILE: break; case SOCKET_FILE: dir_fh = myself->handle; sock_name = name; break; default: LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype); fsal_error = ERR_FSAL_INVAL; goto errout; } lustre_handle_to_path(dir_hdl->fs->path, myself->handle, dirpath); rc = lstat(dirpath, &stat); if (rc < 0) { rc = errno; goto errout; } /* create it with no access because we are root when we do this */ snprintf(newpath, MAXPATHLEN, "%s/%s", dirpath, name); rc = CRED_WRAP(op_ctx->creds, int, mknod, newpath, unix_mode, unix_dev); if (rc < 0) { rc = errno; goto direrr; } rc = get_stat_by_handle_at(dir_hdl->fs->path, myself->handle, name, fh, &stat); if (rc < 0) goto direrr; /* allocate an obj_handle and fill it up */ hdl = alloc_handle(fh, dir_hdl->fs, &stat, NULL, dir_fh, sock_name, op_ctx->fsal_export); if (hdl == NULL) { fsal_error = ERR_FSAL_NOMEM; goto unlinkout; } *handle = &hdl->obj_handle; return fsalstat(ERR_FSAL_NO_ERROR, 0); direrr: fsal_error = posix2fsal_error(rc); unlinkout: unlink(newpath); errout: return fsalstat(fsal_error, rc); }
/** * GPFSFSAL_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 GPFSFSAL_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; /* Buffer that will be passed to gpfs_ganesha API. */ gpfsfsal_xstat_t buffxstat; /* Indicate if stat or acl or both should be changed. */ int attr_valid = 0; /* Indiate which attribute in stat should be changed. */ int attr_changed = 0; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t wanted_attrs, current_attrs; /* 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; /* It does not make sense to setattr on a symlink */ /* if(p_filehandle->type == DT_LNK) return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set, p_object_attributes); */ /* First, check that FSAL attributes changes are allowed. */ /* Is it allowed to change times ? */ 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 = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_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); } /*********** * CHMOD * ***********/ if(FSAL_TEST_MASK(wanted_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(current_attrs.type != FSAL_TYPE_LNK) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* For modifying mode, user must be root or the owner */ if((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { LogFullDebug(COMPONENT_FSAL, "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 } #endif attr_valid |= XATTR_STAT; attr_changed |= XATTR_MODE; /* Fill wanted mode. */ buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode); LogDebug(COMPONENT_FSAL, "current mode = %o, new mode = %o", fsal2unix_mode(current_attrs.mode), buffxstat.buffstat.st_mode); } } /*********** * CHOWN * ***********/ /* 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)) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* 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))) { LogFullDebug(COMPONENT_FSAL, "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 } #endif } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* 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) { LogFullDebug(COMPONENT_FSAL, "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 } #endif } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { /* LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)", fsalpath.path, FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)wanted_attrs.owner : -1, FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)wanted_attrs.group : -1);*/ attr_valid |= XATTR_STAT; attr_changed |= FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ? XATTR_UID : XATTR_GID; /* Fill wanted owner. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { buffxstat.buffstat.st_uid = (int)wanted_attrs.owner; LogDebug(COMPONENT_FSAL, "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; LogDebug(COMPONENT_FSAL, "current gid = %d, new gid = %d", current_attrs.group, buffxstat.buffstat.st_gid); } } /*********** * UTIME * ***********/ /* 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(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs)).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(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs)).major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { attr_valid |= XATTR_STAT; /* Fill wanted atime. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)) { attr_changed |= XATTR_ATIME; buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds; LogDebug(COMPONENT_FSAL, "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)) { attr_changed |= XATTR_CTIME; buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds; LogDebug(COMPONENT_FSAL, "current mtime = %lu, new mtime = %lu", (unsigned long)current_attrs.mtime.seconds, (unsigned long)buffxstat.buffstat.st_mtime); } } #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); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); if(wanted_attrs.acl) { attr_valid |= XATTR_ACL; LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl); /* Convert FSAL ACL to GPFS NFS4 ACL and fill the buffer. */ status = fsal_acl_2_gpfs_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 */ /* If there is any change in stat or acl or both, send it down to file system. */ if((attr_valid == XATTR_STAT && attr_changed !=0) || attr_valid == XATTR_ACL) { status = fsal_set_xstat_by_handle(p_context, p_filehandle, attr_valid, attr_changed, &buffxstat); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = GPFSFSAL_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_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 GPFSFSAL_mkdir(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* 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 setgid_bit = 0; */ mode_t unix_mode; fsal_status_t status; 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_dirname) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); /* convert FSAL mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; /* get 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_mkdir); /* 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_SUBDIRECTORY); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); else status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* build new entry path */ /* creates the directory and get its handle */ fsal_set_credentials(p_context); TakeTokenFSCall(); status = fsal_internal_create(p_context, p_parent_directory_handle, p_dirname, unix_mode | S_IFDIR, 0, p_object_handle, NULL); ReleaseTokenFSCall(); fsal_restore_ganesha_credentials(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* 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_mkdir); }
/** * 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 POSIXFSAL_mkdir(fsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* IN */ fsal_op_context_t * context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { posixfsal_handle_t * p_parent_directory_handle = (posixfsal_handle_t *) parent_directory_handle; posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context; posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) object_handle; int rc, errsv; int setgid_bit = 0; struct stat buffstat; mode_t unix_mode; fsal_status_t status; fsal_path_t fsalpath; fsal_posixdb_fileinfo_t info; /* 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; /* build the destination path */ status = fsal_internal_getPathFromHandle(p_context, p_parent_directory_handle, 1, &fsalpath, &buffstat); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_mkdir); /* 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)) Return(status.major, status.minor, INDEX_FSAL_mkdir); status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_dirname); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_mkdir); /* creates the directory and stats it */ TakeTokenFSCall(); rc = mkdir(fsalpath.path, unix_mode); if(!rc) rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); /* add the directory to the database */ if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info))) Return(status.major, status.minor, INDEX_FSAL_mkdir); if(FSAL_IS_ERROR (status = fsal_internal_posixdb_add_entry(p_context->p_conn, p_dirname, &info, p_parent_directory_handle, p_object_handle))) Return(status.major, status.minor, 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 = lchown(fsalpath.path, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); buffstat.st_uid = p_context->credential.user; buffstat.st_gid = p_context->credential.group; } /* Fills the attributes if needed */ if(p_object_attributes) { status = posix2fsal_attributes(&buffstat, 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); }
/** * 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 ] */ ) { fsal_status_t status; 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); /* 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 */ /* 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); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); else status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* call to filesystem */ fsal_set_credentials(p_context); TakeTokenFSCall(); status = fsal_internal_create(p_context, p_parent_directory_handle, p_filename, unix_mode | S_IFREG, 0, p_object_handle, NULL); ReleaseTokenFSCall(); fsal_restore_ganesha_credentials(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, 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); } } // error injection to test DRC //sleep(61); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
fsal_status_t GPFSFSAL_rename(fsal_handle_t * p_old_parentdir_handle, /* IN */ fsal_name_t * p_old_name, /* IN */ fsal_handle_t * p_new_parentdir_handle, /* IN */ fsal_name_t * p_new_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * p_tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat buffstat; int old_parent_fd, new_parent_fd; int src_equal_tgt = FALSE; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t src_dir_attrs, tgt_dir_attrs; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!p_old_parentdir_handle || !p_new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); /* Get directory access path by fid */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_old_parentdir_handle, &old_parent_fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve directory metadata for checking access rights */ src_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_old_parentdir_handle, p_context, &src_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* optimisation : don't do the job twice if source dir = dest dir */ if(!FSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status)) { new_parent_fd = old_parent_fd; src_equal_tgt = TRUE; tgt_dir_attrs = src_dir_attrs; } else { TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_new_parentdir_handle, &new_parent_fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(old_parent_fd); ReturnStatus(status, INDEX_FSAL_rename); } /* retrieve destination attrs */ tgt_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_new_parentdir_handle, p_context, &tgt_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); } /* check access rights */ /* 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_DELETE_CHILD); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, &src_dir_attrs); else status = fsal_internal_access(p_context, p_old_parentdir_handle, access_mask, &src_dir_attrs); if(FSAL_IS_ERROR(status)) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); ReturnStatus(status, INDEX_FSAL_rename); } if(!src_equal_tgt) { access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE | FSAL_ACE_PERM_ADD_SUBDIRECTORY); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, &tgt_dir_attrs); else status = fsal_internal_access(p_context, p_new_parentdir_handle, access_mask, &tgt_dir_attrs); if(FSAL_IS_ERROR(status)) { close(old_parent_fd); close(new_parent_fd); ReturnStatus(status, INDEX_FSAL_rename); } } /* build file paths */ TakeTokenFSCall(); rc = fstatat(old_parent_fd, p_old_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } /* Check sticky bits */ /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */ if((fsal2unix_mode(src_dir_attrs.mode) & S_ISVTX) && src_dir_attrs.owner != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); } /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */ if(fsal2unix_mode(tgt_dir_attrs.mode) & S_ISVTX) { TakeTokenFSCall(); rc = fstatat(new_parent_fd, p_new_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); errsv = errno; ReleaseTokenFSCall(); if(rc < 0) { if(errsv != ENOENT) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } } else { if(tgt_dir_attrs.owner != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); } } } /************************************* * Rename the file on the filesystem * *************************************/ TakeTokenFSCall(); rc = renameat(old_parent_fd, p_old_name->name, new_parent_fd, p_new_name->name); errsv = errno; ReleaseTokenFSCall(); close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); /*********************** * Fill the attributes * ***********************/ if(p_src_dir_attributes) { status = GPFSFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_src_dir_attributes->asked_attributes); FSAL_SET_MASK(p_src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } if(p_tgt_dir_attributes) { status = GPFSFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(p_tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/** * FSAL_mknode: * Create a special object in the filesystem. * Not supported upon HPSS. * * \return ERR_FSAL_NOTSUPP. */ fsal_status_t POSIXFSAL_mknode(fsal_handle_t * parentdir_hdl, /* IN */ fsal_name_t * p_node_name, /* IN */ fsal_op_context_t * context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_nodetype_t nodetype, /* IN */ fsal_dev_t * dev, /* IN */ fsal_handle_t * object_handle, /* OUT (handle to the created node) */ fsal_attrib_list_t * node_attributes /* [ IN/OUT ] */ ) { posixfsal_handle_t * parentdir_handle = (posixfsal_handle_t *) parentdir_hdl; posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context; posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) object_handle; int rc, errsv; int setgid_bit = 0; struct stat buffstat; fsal_status_t status; fsal_path_t fsalpath; fsal_posixdb_fileinfo_t info; 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 destination path */ status = fsal_internal_getPathFromHandle(p_context, parentdir_handle, 1, &fsalpath, &buffstat); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, 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)) Return(status.major, status.minor, INDEX_FSAL_mknode); status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_node_name); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_mknode); /* creates the node, then stats it */ TakeTokenFSCall(); rc = mknod(fsalpath.path, unix_mode, unix_dev); if(!rc) rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); /* add the object to the database */ if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info))) Return(status.major, status.minor, INDEX_FSAL_mknode); if(FSAL_IS_ERROR (status = fsal_internal_posixdb_add_entry(p_context->p_conn, p_node_name, &info, parentdir_handle, p_object_handle))) Return(status.major, status.minor, INDEX_FSAL_mknode); /* the node 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 = lchown(fsalpath.path, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); buffstat.st_uid = p_context->credential.user; buffstat.st_gid = p_context->credential.group; } /* Fills the attributes if needed */ if(node_attributes) { status = posix2fsal_attributes(&buffstat, 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); }
static fsal_status_t makedir(struct fsal_obj_handle *dir_hdl, const struct req_op_context *opctx, const char *name, struct attrlist *attrib, struct fsal_obj_handle **handle) { int rc = 0; fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 }; struct stat sb; struct glfs_object *glhandle = NULL; unsigned char globjhdl[GLAPI_HANDLE_LENGTH]; struct glusterfs_handle *objhandle = NULL; struct glusterfs_export *glfs_export = container_of(dir_hdl->export, struct glusterfs_export, export); struct glusterfs_handle *parenthandle = container_of(dir_hdl, struct glusterfs_handle, handle); #ifdef GLTIMING struct timespec s_time, e_time; now(&s_time); #endif rc = setglustercreds(glfs_export, &opctx->creds->caller_uid, &opctx->creds->caller_gid, opctx->creds->caller_glen, opctx->creds->caller_garray); if (rc != 0) { status = gluster2fsal_error(EPERM); LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials"); goto out; } /* FIXME: what else from attrib should we use? */ glhandle = glfs_h_mkdir(glfs_export->gl_fs, parenthandle->glhandle, name, fsal2unix_mode(attrib->mode), &sb); rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL); if (rc != 0) { status = gluster2fsal_error(EPERM); LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials"); goto out; } if (glhandle == NULL) { status = gluster2fsal_error(errno); goto out; } rc = glfs_h_extract_handle(glhandle, globjhdl, GLAPI_HANDLE_LENGTH); if (rc < 0) { status = gluster2fsal_error(errno); goto out; } rc = construct_handle(glfs_export, &sb, glhandle, globjhdl, GLAPI_HANDLE_LENGTH, &objhandle); if (rc != 0) { status = gluster2fsal_error(rc); goto out; } *handle = &objhandle->handle; *attrib = objhandle->handle.attributes; out: if (status.major != ERR_FSAL_NO_ERROR) { gluster_cleanup_vars(glhandle); } #ifdef GLTIMING now(&e_time); latency_update(&s_time, &e_time, lat_makedir); #endif return status; }
/** * 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 GPFSFSAL_mkdir(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* 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; mode_t unix_mode; fsal_status_t status; int fd, newfd; 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_dirname) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); /* convert FSAL mode to unix 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_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* get 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_SUBDIRECTORY); status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); 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); } ReleaseTokenFSCall(); /**** * There is a race here between mkdir creation and the open, not * sure there is any way to close it in practice. */ /* get the new handle */ TakeTokenFSCall(); status = fsal_internal_get_handle_at(fd, p_dirname, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); ReturnStatus(status, INDEX_FSAL_mkdir); } TakeTokenFSCall(); status = fsal_internal_handle2fd_at(fd, p_object_handle, &newfd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); ReturnStatus(status, INDEX_FSAL_mkdir); } /* the directory has been created */ /* chown the dir 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 = 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_mkdir); }
static fsal_status_t makenode(struct fsal_obj_handle *dir_hdl, const struct req_op_context *opctx, const char *name, object_file_type_t nodetype, fsal_dev_t * dev, struct attrlist *attrib, struct fsal_obj_handle **handle) { int rc = 0; fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 }; struct stat sb; struct glfs_object *glhandle = NULL; unsigned char globjhdl[GLAPI_HANDLE_LENGTH]; struct glusterfs_handle *objhandle = NULL; dev_t ndev = { 0, }; struct glusterfs_export *glfs_export = container_of(dir_hdl->export, struct glusterfs_export, export); struct glusterfs_handle *parenthandle = container_of(dir_hdl, struct glusterfs_handle, handle); mode_t create_mode; #ifdef GLTIMING struct timespec s_time, e_time; now(&s_time); #endif switch (nodetype) { case BLOCK_FILE: if (!dev) return fsalstat(ERR_FSAL_INVAL, 0); /* FIXME: This needs a feature flag test? */ ndev = makedev(dev->major, dev->minor); create_mode = S_IFBLK; break; case CHARACTER_FILE: if (!dev) return fsalstat(ERR_FSAL_INVAL, 0); ndev = makedev(dev->major, dev->minor); create_mode = S_IFCHR; break; case FIFO_FILE: create_mode = S_IFIFO; break; case SOCKET_FILE: create_mode = S_IFSOCK; break; default: LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype); return fsalstat(ERR_FSAL_INVAL, 0); } rc = setglustercreds(glfs_export, &opctx->creds->caller_uid, &opctx->creds->caller_gid, opctx->creds->caller_glen, opctx->creds->caller_garray); if (rc != 0) { status = gluster2fsal_error(EPERM); LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials"); goto out; } /* FIXME: what else from attrib should we use? */ glhandle = glfs_h_mknod(glfs_export->gl_fs, parenthandle->glhandle, name, create_mode | fsal2unix_mode(attrib->mode), ndev, &sb); rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL); if (rc != 0) { status = gluster2fsal_error(EPERM); LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials"); goto out; } if (glhandle == NULL) { status = gluster2fsal_error(errno); goto out; } rc = glfs_h_extract_handle(glhandle, globjhdl, GLAPI_HANDLE_LENGTH); if (rc < 0) { status = gluster2fsal_error(errno); goto out; } rc = construct_handle(glfs_export, &sb, glhandle, globjhdl, GLAPI_HANDLE_LENGTH, &objhandle); if (rc != 0) { status = gluster2fsal_error(rc); goto out; } *handle = &objhandle->handle; *attrib = objhandle->handle.attributes; out: if (status.major != ERR_FSAL_NO_ERROR) { gluster_cleanup_vars(glhandle); } #ifdef GLTIMING now(&e_time); latency_update(&s_time, &e_time, lat_makenode); #endif return status; }
/** * 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); }
static fsal_status_t setattrs(struct fsal_obj_handle *obj_hdl, const struct req_op_context *opctx, struct attrlist *attrs) { int rc = 0; fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 }; struct stat sb; int mask = 0; struct glusterfs_export *glfs_export = container_of(obj_hdl->export, struct glusterfs_export, export); struct glusterfs_handle *objhandle = container_of(obj_hdl, struct glusterfs_handle, handle); #ifdef GLTIMING struct timespec s_time, e_time; now(&s_time); #endif memset(&sb, 0, sizeof(struct stat)); if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) { rc = glfs_h_truncate(glfs_export->gl_fs, objhandle->glhandle, attrs->filesize); if (rc != 0) { status = gluster2fsal_error(errno); goto out; } } if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) { mask |= GLAPI_SET_ATTR_MODE; sb.st_mode = fsal2unix_mode(attrs->mode); } if (FSAL_TEST_MASK(attrs->mask, ATTR_OWNER)) { mask |= GLAPI_SET_ATTR_UID; sb.st_uid = attrs->owner; } if (FSAL_TEST_MASK(attrs->mask, ATTR_GROUP)) { mask |= GLAPI_SET_ATTR_GID; sb.st_gid = attrs->group; } if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME)) { mask |= GLAPI_SET_ATTR_ATIME; sb.st_atim = attrs->atime; } if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME_SERVER)) { mask |= GLAPI_SET_ATTR_ATIME; struct timespec timestamp; rc = clock_gettime(CLOCK_REALTIME, ×tamp); if (rc != 0) { status = gluster2fsal_error(errno); goto out; } sb.st_atim = timestamp; } if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME)) { mask |= GLAPI_SET_ATTR_MTIME; sb.st_mtim = attrs->mtime; } if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME_SERVER)) { mask |= GLAPI_SET_ATTR_MTIME; struct timespec timestamp; rc = clock_gettime(CLOCK_REALTIME, ×tamp); if (rc != 0) { status = gluster2fsal_error(rc); goto out; } sb.st_mtim = timestamp; } rc = glfs_h_setattrs(glfs_export->gl_fs, objhandle->glhandle, &sb, mask); if (rc != 0) { status = gluster2fsal_error(errno); goto out; } out: #ifdef GLTIMING now(&e_time); latency_update(&s_time, &e_time, lat_setattrs); #endif return status; }
/** * FSAL_create: * Create a regular file. * * \param parent_hdl (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 p_context (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 p_object_handle (output): * Pointer to the handle of the created file. * \param p_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 PTFSAL_create(struct fsal_obj_handle *dir_hdl, /* IN */ const char *p_filename, /* IN */ const struct req_op_context *p_context, /* IN */ uint32_t accessmode, /* IN */ ptfsal_handle_t *p_object_handle, /* OUT */ struct attrlist *p_object_attributes) { /* IN/OUT */ int errsv; fsal_status_t status; struct pt_fsal_obj_handle *pt_hdl; mode_t unix_mode; int open_rc; ptfsal_handle_t *p_fsi_handle = (ptfsal_handle_t *) p_object_handle; FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n"); /* sanity checks. * note : object_attributes is optional. */ if (!dir_hdl || !p_context || !p_object_handle || !p_filename) return fsalstat(ERR_FSAL_FAULT, 0); pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle); /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~p_context->fsal_export->exp_ops. fs_umask(p_context->fsal_export); LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); open_rc = ptfsal_open(pt_hdl, p_filename, p_context, unix_mode, p_object_handle); if (open_rc < 0) { errsv = errno; return fsalstat(posix2fsal_error(errsv), errsv); } FSI_TRACE(FSI_DEBUG, "New Handle = %s", (char *)p_fsi_handle->data.handle.f_handle); /* retrieve file attributes */ if (p_object_attributes) { status = PTFSAL_getattrs(p_context->fsal_export, p_context, p_object_handle, p_object_attributes); /* on error, we set a special bit in the mask. */ if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->mask); FSAL_SET_MASK(p_object_attributes->mask, ATTR_RDATTR_ERR); } } FSI_TRACE(FSI_DEBUG, "End to create file************************\n"); /* OK */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * VFSFSAL_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 VFSFSAL_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 ] */ ) { vfsfsal_op_context_t * vfs_context = (vfsfsal_op_context_t *) p_context; int rc, errsv; unsigned int i; fsal_status_t status; fsal_attrib_list_t attrs; int fd; 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; /* It does not make sense to setattr on a symlink */ /* if(p_filehandle->type == DT_LNK) return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set, p_object_attributes); */ /* 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); } TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { /* Symbolic link are handled here, they are to be opened as O_PATH */ if( status.minor == ELOOP ) { if(p_object_attributes) { status = VFSFSAL_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); } ReturnStatus( status, INDEX_FSAL_setattrs); } /* get current attributes */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc != 0) { close(fd); 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((vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", buffstat.st_uid, vfs_context->credential.user); close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } TakeTokenFSCall(); rc = fchmod(fd, fsal2unix_mode(attrs.mode)); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); 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((vfs_context->credential.user != 0) && ((vfs_context->credential.user != buffstat.st_uid) || (vfs_context->credential.user != attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", buffstat.st_uid, vfs_context->credential.user, attrs.owner); close(fd); 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((vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid)) { close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } int in_grp = 0; /* set in_grp */ if(vfs_context->credential.group == attrs.group) in_grp = 1; else for(i = 0; i < vfs_context->credential.nbgroups; i++) { if((in_grp = (attrs.group == vfs_context->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(vfs_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, vfs_context->credential.group, attrs.group); close(fd); 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 = fchown(fd, 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) { close(fd); 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) && (vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid) && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) { close(fd); 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) && (vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid) && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) { close(fd); ReturnStatus(status, INDEX_FSAL_setattrs); } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { struct timeval timebuf[2]; /* Atime */ timebuf[0].tv_sec = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs. atime.seconds : buffstat.st_atime); timebuf[0].tv_usec = 0; /* Mtime */ timebuf[1].tv_sec = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs. mtime.seconds : buffstat.st_mtime); timebuf[1].tv_usec = 0; TakeTokenFSCall(); rc = futimes(fd, timebuf); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = VFSFSAL_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); } } close(fd); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }