fsal_status_t FSAL_proxy_truncate_stateless(proxyfsal_handle_t * filehandle, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_size_t length, /* IN */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; fsal_status_t fsal_status; fsal_attrib_list_t open_attrs; bitmap4 inbitmap; bitmap4 convert_bitmap; uint32_t inbitmap_val[2]; uint32_t bitmap_res[2]; uint32_t bitmap_set[2]; uint32_t bitmap_conv_val[2]; #define FSAL_TRUNCATE_STATELESS_NB_OP_ALLOC 3 nfs_argop4 argoparray[FSAL_TRUNCATE_STATELESS_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_TRUNCATE_STATELESS_NB_OP_ALLOC]; fsal_attrib_list_t fsal_attr_set; fattr4 fattr_set; fsal_proxy_internal_fattr_t fattr_internal; struct timeval timeout = { 25, 0 }; /* sanity checks. * note : object_attributes is optional. */ if(!filehandle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate); if(filehandle->data.object_type_reminder != FSAL_TYPE_FILE) { Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate); } /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Truncate" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, filehandle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate); /* Get prepared for truncate */ fsal_attr_set.asked_attributes = FSAL_ATTR_SIZE; fsal_attr_set.filesize = length; convert_bitmap.bitmap4_val = bitmap_conv_val; convert_bitmap.bitmap4_len = 2; fsal_interval_proxy_fsalattr2bitmap4(&fsal_attr_set, &convert_bitmap); if(nfs4_FSALattr_To_Fattr(NULL, /* no exportlist required here */ &fsal_attr_set, &fattr_set, NULL, /* no compound data required here */ NULL, /* No fh here, filehandle is not a settable attribute */ &convert_bitmap) == -1) Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_truncate); inbitmap.bitmap4_val = inbitmap_val; inbitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&inbitmap); #define FSAL_TRUNCATE_STATELESS_IDX_OP_PUTFH 0 #define FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR 1 #define FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR 2 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_SETATTR(argnfs4, fattr_set); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, inbitmap); /* For ATTR_SIZE, stateid is needed, we use the stateless "all-0's" stateid here */ argnfs4.argarray.argarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR].nfs_argop4_u. opsetattr.stateid.seqid = 0; memset(argnfs4.argarray.argarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR]. nfs_argop4_u.opsetattr.stateid.other, 0, 12); resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR].nfs_resop4_u. opsetattr.attrsset.bitmap4_val = bitmap_set; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR].nfs_resop4_u. opsetattr.attrsset.bitmap4_len = 2; TakeTokenFSCall(); COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, 0, INDEX_FSAL_truncate); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_truncate); /* >> interpret error code << */ /* >> Optionnaly retrieve post op attributes * If your filesystem truncate call can't return them, * you can proceed like this : << */ if(object_attributes) { if(nfs4_Fattr_To_FSAL_attr(object_attributes, &resnfs4.resarray.resarray_val [FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR]. nfs_resop4_u.opgetattr.GETATTR4res_u.resok4. obj_attributes) != 1) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate); } } /* No error occured */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_truncate); } /* FSAL_proxy_truncate_stateless */
fsal_status_t PROXYFSAL_rename(fsal_handle_t * old_parent, /* IN */ fsal_name_t * p_old_name, /* IN */ fsal_handle_t * new_parent, /* IN */ fsal_name_t * p_new_name, /* IN */ fsal_op_context_t *context, /* IN */ fsal_attrib_list_t * src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh_old; nfs_fh4 nfs4fh_new; bitmap4 bitmap_old; uint32_t bitmap_val_old[2]; bitmap4 bitmap_new; uint32_t bitmap_val_new[2]; component4 oldname; char oldnameval[MAXNAMLEN]; component4 newname; char newnameval[MAXNAMLEN]; proxyfsal_handle_t * old_parentdir_handle = (proxyfsal_handle_t *)old_parent; proxyfsal_handle_t * new_parentdir_handle = (proxyfsal_handle_t *)new_parent; proxyfsal_op_context_t * p_context = (proxyfsal_op_context_t *)context; #define FSAL_RENAME_NB_OP_ALLOC 7 nfs_argop4 argoparray[FSAL_RENAME_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_RENAME_NB_OP_ALLOC]; uint32_t bitmap_res_old[2]; uint32_t bitmap_res_new[2]; fsal_proxy_internal_fattr_t fattr_internal_new; fsal_proxy_internal_fattr_t fattr_internal_old; struct timeval timeout = TIMEOUTRPC; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!old_parentdir_handle || !new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal_new); fsal_internal_proxy_setup_fattr(&fattr_internal_old); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Rename" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; /* Prepare the structures */ bitmap_old.bitmap4_val = bitmap_val_old; bitmap_old.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap_old); if(fsal_internal_proxy_extract_fh(&nfs4fh_old, old_parent) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); memset((char *)&oldname, 0, sizeof(component4)); oldname.utf8string_val = oldnameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_old_name, &oldname) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); bitmap_new.bitmap4_val = bitmap_val_new; bitmap_new.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap_new); if(fsal_internal_proxy_extract_fh(&nfs4fh_new, new_parent) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); memset((char *)&newname, 0, sizeof(component4)); newname.utf8string_val = newnameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_new_name, &newname) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); #define FSAL_RENAME_IDX_OP_PUTFH_OLD 0 #define FSAL_RENAME_IDX_OP_SAVEFH 1 #define FSAL_RENAME_IDX_OP_PUTFH_NEW 2 #define FSAL_RENAME_IDX_OP_RENAME 3 #define FSAL_RENAME_IDX_OP_GETATTR_NEW 4 #define FSAL_RENAME_IDX_OP_RESTOREFH 5 #define FSAL_RENAME_IDX_OP_GETATTR_OLD 6 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_old); COMPOUNDV4_ARG_ADD_OP_SAVEFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_new); COMPOUNDV4_ARG_ADD_OP_RENAME(argnfs4, oldname, newname); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap_new); COMPOUNDV4_ARG_ADD_OP_RESTOREFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap_old); resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res_new; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal_new; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal_new); resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res_old; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal_old; resnfs4.resarray.resarray_val[FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal_old); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_rename); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_rename); /* >> get last parent post op attributes if asked * For example : << */ if(src_dir_attributes) { if(nfs4_Fattr_To_FSAL_attr(src_dir_attributes, &resnfs4.resarray.resarray_val [FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes); FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rename); } } /* >> get new parent post op attributes if asked * For example : << */ if(tgt_dir_attributes) { if(nfs4_Fattr_To_FSAL_attr(tgt_dir_attributes, &resnfs4.resarray.resarray_val [FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rename); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
int nfs4_op_setattr(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SETATTR4args * const arg_SETATTR4 = &op->nfs_argop4_u.opsetattr; SETATTR4res * const res_SETATTR4 = &resp->nfs_resop4_u.opsetattr; struct attrlist sattr; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; const char *tag = "SETATTR"; state_t *state_found = NULL; state_t *state_open = NULL; cache_entry_t *entry = NULL; bool anonymous_started = false; resp->resop = NFS4_OP_SETATTR; res_SETATTR4->status = NFS4_OK; /* Do basic checks on a filehandle */ res_SETATTR4->status = nfs4_sanity_check_FH(data, NO_FILE_TYPE, false); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; /* Don't allow attribute change while we are in grace period. * Required for delegation reclaims and may be needed for other * reclaimable states as well. */ if (nfs_in_grace()) { res_SETATTR4->status = NFS4ERR_GRACE; return res_SETATTR4->status; } /* Get only attributes that are allowed to be read */ if (!nfs4_Fattr_Check_Access (&arg_SETATTR4->obj_attributes, FATTR4_ATTR_WRITE)) { res_SETATTR4->status = NFS4ERR_INVAL; return res_SETATTR4->status; } /* Ask only for supported attributes */ if (!nfs4_Fattr_Supported(&arg_SETATTR4->obj_attributes)) { res_SETATTR4->status = NFS4ERR_ATTRNOTSUPP; return res_SETATTR4->status; } /* Convert the fattr4 in the request to a fsal sattr structure */ res_SETATTR4->status = nfs4_Fattr_To_FSAL_attr(&sattr, &arg_SETATTR4->obj_attributes, data); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; /* Trunc may change Xtime so we have to start with trunc and * finish by the mtime and atime */ if ((FSAL_TEST_MASK(sattr.mask, ATTR_SIZE)) || (FSAL_TEST_MASK(sattr.mask, ATTR4_SPACE_RESERVED))) { /* Setting the size of a directory is prohibited */ if (data->current_filetype == DIRECTORY) { res_SETATTR4->status = NFS4ERR_ISDIR; return res_SETATTR4->status; } /* Object should be a file */ if (data->current_entry->type != REGULAR_FILE) { res_SETATTR4->status = NFS4ERR_INVAL; return res_SETATTR4->status; } entry = data->current_entry; /* Check stateid correctness and get pointer to state */ res_SETATTR4->status = nfs4_Check_Stateid(&arg_SETATTR4->stateid, data->current_entry, &state_found, data, STATEID_SPECIAL_ANY, 0, false, tag); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; /* NB: After this point, if state_found == NULL, then * the stateid is all-0 or all-1 */ if (state_found != NULL) { switch (state_found->state_type) { case STATE_TYPE_SHARE: state_open = state_found; /* Note this causes an extra refcount, but it * simplifies logic below. */ inc_state_t_ref(state_open); break; case STATE_TYPE_LOCK: state_open = state_found->state_data.lock.openstate; inc_state_t_ref(state_open); break; case STATE_TYPE_DELEG: state_open = NULL; break; default: res_SETATTR4->status = NFS4ERR_BAD_STATEID; return res_SETATTR4->status; } /* This is a size operation, this means that * the file MUST have been opened for writing */ if (state_open != NULL && (state_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) == 0) { /* Bad open mode, return NFS4ERR_OPENMODE */ res_SETATTR4->status = NFS4ERR_OPENMODE; return res_SETATTR4->status; } } else { /* Special stateid, no open state, check to * see if any share conflicts */ state_open = NULL; /* Special stateid, no open state, check to see if * any share conflicts The stateid is all-0 or all-1 */ res_SETATTR4->status = nfs4_Errno_state( state_share_anonymous_io_start( entry, OPEN4_SHARE_ACCESS_WRITE, SHARE_BYPASS_NONE)); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; anonymous_started = true; } } const time_t S_NSECS = 1000000000UL; /* Set the atime and mtime (ctime is not setable) */ /* A carry into seconds considered invalid */ if (sattr.atime.tv_nsec >= S_NSECS) { res_SETATTR4->status = NFS4ERR_INVAL; goto done; } if (sattr.mtime.tv_nsec >= S_NSECS) { res_SETATTR4->status = NFS4ERR_INVAL; goto done; } /* If owner or owner_group are set, and the credential was * squashed, then we must squash the set owner and owner_group. */ squash_setattr(&sattr); /* If a SETATTR comes with an open stateid, and size is being * set, then the open MUST be for write (checked above), so * is_open_write is simple at this stage, it's just a check that * we have an open owner. */ cache_status = cache_inode_setattr(data->current_entry, &sattr, state_open != NULL); if (cache_status != CACHE_INODE_SUCCESS) { res_SETATTR4->status = nfs4_Errno(cache_status); goto done; } /* Set the replyed structure */ res_SETATTR4->attrsset = arg_SETATTR4->obj_attributes.attrmask; /* Exit with no error */ res_SETATTR4->status = NFS4_OK; done: if (anonymous_started) state_share_anonymous_io_done(entry, OPEN4_SHARE_ACCESS_WRITE); if (state_found != NULL) dec_state_t_ref(state_found); if (state_open != NULL) dec_state_t_ref(state_open); return res_SETATTR4->status; } /* nfs4_op_setattr */
static void open4_ex_create_args(OPEN4args *arg, compound_data_t *data, OPEN4res *res_OPEN4, void *verifier, enum fsal_create_mode *createmode, struct attrlist *sattr) { createhow4 *createhow = &arg->openhow.openflag4_u.how; fattr4 *arg_attrs = NULL; *createmode = nfs4_createmode_to_fsal(createhow->mode); if (createhow->mode == EXCLUSIVE4_1) { memcpy(verifier, createhow->createhow4_u.ch_createboth.cva_verf, sizeof(fsal_verifier_t)); } else if (createhow->mode == EXCLUSIVE4) { memcpy(verifier, createhow->createhow4_u.createverf, sizeof(fsal_verifier_t)); } /* Select the correct attributes */ if (createhow->mode == GUARDED4 || createhow->mode == UNCHECKED4) arg_attrs = &createhow->createhow4_u.createattrs; else if (createhow->mode == EXCLUSIVE4_1) arg_attrs = &createhow->createhow4_u.ch_createboth.cva_attrs; if (arg_attrs != NULL) { /* Check if asked attributes are correct */ if (!nfs4_Fattr_Supported(arg_attrs)) { res_OPEN4->status = NFS4ERR_ATTRNOTSUPP; return; } if (!nfs4_Fattr_Check_Access(arg_attrs, FATTR4_ATTR_WRITE)) { res_OPEN4->status = NFS4ERR_INVAL; return; } /* Convert the attributes */ if (arg_attrs->attrmask.bitmap4_len != 0) { /* Convert fattr4 so nfs4_sattr */ res_OPEN4->status = nfs4_Fattr_To_FSAL_attr(sattr, arg_attrs, data); if (res_OPEN4->status != NFS4_OK) return; } if (createhow->mode == EXCLUSIVE4_1) { /** @todo FSF: this needs to be corrected in case FSAL * uses different attributes for the * verifier. */ /* Check that we aren't trying to set the verifier * attributes. */ if (FSAL_TEST_MASK(sattr->valid_mask, ATTR_ATIME) || FSAL_TEST_MASK(sattr->valid_mask, ATTR_MTIME)) { res_OPEN4->status = NFS4ERR_INVAL; return; } } /* If owner or owner_group are set, and the credential was * squashed, then we must squash the set owner and owner_group. */ squash_setattr(sattr); } if (!(sattr->valid_mask & ATTR_MODE)) { /* Make sure mode is set, even for exclusive create. */ sattr->mode = 0600; sattr->valid_mask |= ATTR_MODE; } }
fsal_status_t PROXYFSAL_lookup(proxyfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ proxyfsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; component4 name; char nameval[MAXNAMLEN]; fsal_attrib_list_t attributes; unsigned int index_getfh = 0; unsigned int index_getattr = 0; #define FSAL_LOOKUP_NB_OP_ALLOC 4 nfs_argop4 argoparray[FSAL_LOOKUP_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_LOOKUP_NB_OP_ALLOC]; uint32_t bitmap_res[2]; fsal_proxy_internal_fattr_t fattr_internal; char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN]; struct timeval timeout = TIMEOUTRPC; /* sanity checks * note : object_attributes is optionnal * parent_directory_handle may be null for getting FS root. */ if(!object_handle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; argnfs4.argarray.argarray_len = 0; /* >> retrieve root handle filehandle here << */ bitmap.bitmap4_val = bitmap_val; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); if(!parent_directory_handle) { /* check that p_filename is NULL, * else, parent_directory_handle should not * be NULL. */ if(p_filename != NULL) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup Root" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; #define FSAL_LOOKUP_IDX_OP_PUTROOTFH 0 #define FSAL_LOOKUP_IDX_OP_GETATTR_ROOT 1 #define FSAL_LOOKUP_IDX_OP_GETFH_ROOT 2 COMPOUNDV4_ARG_ADD_OP_PUTROOTFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); index_getattr = FSAL_LOOKUP_IDX_OP_GETATTR_ROOT; index_getfh = FSAL_LOOKUP_IDX_OP_GETFH_ROOT; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR_ROOT].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR_ROOT].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR_ROOT].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR_ROOT].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETFH_ROOT].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETFH_ROOT].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; } else /* this is a real lookup(parent, name) */ { PRINT_HANDLE("PROXYFSAL_lookup parent", parent_directory_handle); /* the filename should not be null */ if(p_filename == NULL) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* >> Be careful about junction crossing, symlinks, hardlinks,... * You may check the parent type if it's sored into the handle << */ switch (parent_directory_handle->data.object_type_reminder) { case FSAL_TYPE_DIR: /* OK */ break; case FSAL_TYPE_JUNCTION: /* This is a junction */ Return(ERR_FSAL_XDEV, 0, INDEX_FSAL_lookup); case FSAL_TYPE_FILE: case FSAL_TYPE_LNK: case FSAL_TYPE_XATTR: /* not a directory */ Return(ERR_FSAL_NOTDIR, 0, INDEX_FSAL_lookup); default: Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_lookup); } /* >> Call your filesystem lookup function here << */ if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_filename, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); if(!FSAL_namecmp(p_filename, (fsal_name_t *) & FSAL_DOT)) { /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup current" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; #define FSAL_LOOKUP_IDX_OP_DOT_PUTFH 0 #define FSAL_LOOKUP_IDX_OP_DOT_GETATTR 1 #define FSAL_LOOKUP_IDX_OP_DOT_GETFH 2 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); index_getattr = FSAL_LOOKUP_IDX_OP_DOT_GETATTR; index_getfh = FSAL_LOOKUP_IDX_OP_DOT_GETFH; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_GETFH].nfs_resop4_u. opgetfh.GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_GETFH].nfs_resop4_u. opgetfh.GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; } else if(!FSAL_namecmp(p_filename, (fsal_name_t *) & FSAL_DOT_DOT)) { /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup parent" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; #define FSAL_LOOKUP_IDX_OP_DOT_DOT_PUTFH 0 #define FSAL_LOOKUP_IDX_OP_DOT_DOT_LOOKUPP 1 #define FSAL_LOOKUP_IDX_OP_DOT_DOT_GETATTR 2 #define FSAL_LOOKUP_IDX_OP_DOT_DOT_GETFH 3 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_LOOKUPP(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); index_getattr = FSAL_LOOKUP_IDX_OP_DOT_DOT_GETATTR; index_getfh = FSAL_LOOKUP_IDX_OP_DOT_DOT_GETFH; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_DOT_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_DOT_GETFH].nfs_resop4_u. opgetfh.GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_DOT_DOT_GETFH].nfs_resop4_u. opgetfh.GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; } else { /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup name" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; #define FSAL_LOOKUP_IDX_OP_PUTFH 0 #define FSAL_LOOKUP_IDX_OP_LOOKUP 1 #define FSAL_LOOKUP_IDX_OP_GETATTR 2 #define FSAL_LOOKUP_IDX_OP_GETFH 3 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_LOOKUP(argnfs4, name); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); index_getattr = FSAL_LOOKUP_IDX_OP_GETATTR; index_getfh = FSAL_LOOKUP_IDX_OP_GETFH; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_LOOKUP_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; } } TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_lookup); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_lookup); /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(&attributes, &resnfs4.resarray.resarray_val[index_getattr].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_lookup); } if(object_attributes) { memcpy(object_attributes, &attributes, sizeof(attributes)); } /* Build the handle */ if(fsal_internal_proxy_create_fh (&resnfs4.resarray.resarray_val[index_getfh].nfs_resop4_u.opgetfh.GETFH4res_u. resok4.object, attributes.type, attributes.fileid, object_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); PRINT_HANDLE("PROXYFSAL_lookup object found", object_handle); /* Return attributes if asked */ if(object_attributes) { memcpy(object_attributes, &attributes, sizeof(attributes)); } /* lookup complete ! */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); }
fsal_status_t PROXYFSAL_readlink(proxyfsal_handle_t * linkhandle, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_path_t * p_link_content, /* OUT */ fsal_attrib_list_t * link_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; fsal_attrib_list_t attributes; #define FSAL_READLINK_NB_OP_ALLOC 4 nfs_argop4 argoparray[FSAL_READLINK_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_READLINK_NB_OP_ALLOC]; uint32_t bitmap_res[2]; fsal_proxy_internal_fattr_t fattr_internal; char padpath[FSAL_MAX_PATH_LEN]; struct timeval timeout = TIMEOUTRPC; /* sanity checks. * note : link_attributes is optional. */ if(!linkhandle || !p_context || !p_link_content) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Readlink" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; /* >> retrieve root handle filehandle here << */ bitmap.bitmap4_val = bitmap_val; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); if(fsal_internal_proxy_extract_fh(&nfs4fh, linkhandle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink); #define FSAL_READLINK_IDX_OP_PUTFH 0 #define FSAL_READLINK_IDX_OP_READLINK 1 #define FSAL_READLINK_IDX_OP_GETATTR 2 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_READLINK(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_READLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_READLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_READLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_READLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); resnfs4.resarray.resarray_val[FSAL_READLINK_IDX_OP_READLINK].nfs_resop4_u.opreadlink. READLINK4res_u.resok4.link.utf8string_val = (char *)padpath; resnfs4.resarray.resarray_val[FSAL_READLINK_IDX_OP_READLINK].nfs_resop4_u.opreadlink. READLINK4res_u.resok4.link.utf8string_len = FSAL_MAX_PATH_LEN; TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_readlink); } ReleaseTokenFSCall(); /* >> convert error code and return on error << */ if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_readlink); /* >> convert fs output to fsal_path_t * for example, if this is a char * (link_content_out) : */ if(fsal_internal_proxy_fsal_utf8_2_path(p_link_content, &(resnfs4.resarray.resarray_val [FSAL_READLINK_IDX_OP_READLINK]. nfs_resop4_u.opreadlink.READLINK4res_u.resok4. link)) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink); /* retrieves object attributes, if asked */ if(link_attributes) { /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(&attributes, &resnfs4.resarray. resarray_val[FSAL_READLINK_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(link_attributes->asked_attributes); FSAL_SET_MASK(link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_readlink); } memcpy(link_attributes, &attributes, sizeof(attributes)); } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readlink); }
int nfs4_op_create(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_entry_t *pentry_parent = NULL; cache_entry_t *pentry_new = NULL; fsal_attrib_list_t attr_parent; fsal_attrib_list_t attr_new; fsal_attrib_list_t sattr; fsal_handle_t *pnewfsal_handle = NULL; nfs_fh4 newfh4; cache_inode_status_t cache_status; int convrc = 0; fsal_accessmode_t mode = 0600; fsal_name_t name; cache_inode_create_arg_t create_arg; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_create"; unsigned int i = 0; resp->resop = NFS4_OP_CREATE; res_CREATE4.status = NFS4_OK; /* If the filehandle is Empty */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_CREATE4.status = NFS4ERR_NOFILEHANDLE; return res_CREATE4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_CREATE4.status = NFS4ERR_BADHANDLE; return res_CREATE4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_CREATE4.status = NFS4ERR_FHEXPIRED; return res_CREATE4.status; } /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_CREATE4.status = NFS4ERR_ROFS; return res_CREATE4.status; } /* Ask only for supported attributes */ if(!nfs4_Fattr_Supported(&arg_CREATE4.createattrs)) { res_CREATE4.status = NFS4ERR_ATTRNOTSUPP; return res_CREATE4.status; } /* Do not use READ attr, use WRITE attr */ if(!nfs4_Fattr_Check_Access(&arg_CREATE4.createattrs, FATTR4_ATTR_WRITE)) { res_CREATE4.status = NFS4ERR_INVAL; return res_CREATE4.status; } /* Check for name to long */ if(arg_CREATE4.objname.utf8string_len > FSAL_MAX_NAME_LEN) { res_CREATE4.status = NFS4ERR_NAMETOOLONG; return res_CREATE4.status; } /* * This operation is used to create a non-regular file, * this means: - a symbolic link * - a block device file * - a character device file * - a socket file * - a fifo * - a directory * * You can't use this operation to create a regular file, you have to use NFS4_OP_OPEN for this */ /* Convert the UFT8 objname to a regular string */ if(arg_CREATE4.objname.utf8string_len == 0) { res_CREATE4.status = NFS4ERR_INVAL; return res_CREATE4.status; } if(utf82str(name.name, &arg_CREATE4.objname) == -1) { res_CREATE4.status = NFS4ERR_INVAL; return res_CREATE4.status; } name.len = strlen(name.name); /* Sanuty check: never create a directory named '.' or '..' */ if(arg_CREATE4.objtype.type == NF4DIR) { if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) { res_CREATE4.status = NFS4ERR_BADNAME; return res_CREATE4.status; } } /* Filename should contain not slash */ for(i = 0; i < name.len; i++) { if(name.name[i] == '/') { res_CREATE4.status = NFS4ERR_BADCHAR; return res_CREATE4.status; } } /* Convert current FH into a cached entry, the current_pentry (assocated with the current FH will be used for this */ pentry_parent = data->current_entry; /* The currentFH must point to a directory (objects are always created within a directory) */ if(data->current_filetype != DIR_BEGINNING && data->current_filetype != DIR_CONTINUE) { res_CREATE4.status = NFS4ERR_NOTDIR; return res_CREATE4.status; } /* get attributes of parent directory, for 'change4' info replyed */ if((cache_status = cache_inode_getattr(pentry_parent, &attr_parent, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* Change info for client cache coherency, pentry internal_md is used for that */ memset(&(res_CREATE4.CREATE4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_CREATE4.CREATE4res_u.resok4.cinfo.before = (changeid4) pentry_parent->internal_md.mod_time; /* Convert the incoming fattr4 to a vattr structure, if such arguments are supplied */ if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0) { /* Arguments were supplied, extract them */ convrc = nfs4_Fattr_To_FSAL_attr(&sattr, &(arg_CREATE4.createattrs)); if(convrc == 0) { res_CREATE4.status = NFS4ERR_ATTRNOTSUPP; return res_CREATE4.status; } if(convrc == -1) { res_CREATE4.status = NFS4ERR_BADXDR; return res_CREATE4.status; } } /* Create either a symbolic link or a directory */ switch (arg_CREATE4.objtype.type) { case NF4LNK: /* Convert the name to link from into a regular string */ if(arg_CREATE4.objtype.createtype4_u.linkdata.utf8string_len == 0) { res_CREATE4.status = NFS4ERR_INVAL; return res_CREATE4.status; } else { if(utf82str (create_arg.link_content.path, &arg_CREATE4.objtype.createtype4_u.linkdata) == -1) { res_CREATE4.status = NFS4ERR_INVAL; return res_CREATE4.status; } create_arg.link_content.len = strlen(create_arg.link_content.path); } /* do the symlink operation */ if((pentry_new = cache_inode_create(pentry_parent, &name, SYMBOLIC_LINK, mode, &create_arg, &attr_new, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* If entry exists pentry_new is not null but cache_status was set */ if(cache_status == CACHE_INODE_ENTRY_EXISTS) { res_CREATE4.status = NFS4ERR_EXIST; return res_CREATE4.status; } break; case NF4DIR: /* Create a new directory */ /* do the symlink operation */ if((pentry_new = cache_inode_create(pentry_parent, &name, DIR_BEGINNING, mode, &create_arg, &attr_new, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* If entry exists pentry_new is not null but cache_status was set */ if(cache_status == CACHE_INODE_ENTRY_EXISTS) { res_CREATE4.status = NFS4ERR_EXIST; return res_CREATE4.status; } break; case NF4SOCK: /* Create a new socket file */ if((pentry_new = cache_inode_create(pentry_parent, &name, SOCKET_FILE, mode, NULL, &attr_new, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* If entry exists pentry_new is not null but cache_status was set */ if(cache_status == CACHE_INODE_ENTRY_EXISTS) { res_CREATE4.status = NFS4ERR_EXIST; return res_CREATE4.status; } break; case NF4FIFO: /* Create a new socket file */ if((pentry_new = cache_inode_create(pentry_parent, &name, FIFO_FILE, mode, NULL, &attr_new, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* If entry exists pentry_new is not null but cache_status was set */ if(cache_status == CACHE_INODE_ENTRY_EXISTS) { res_CREATE4.status = NFS4ERR_EXIST; return res_CREATE4.status; } break; case NF4CHR: create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1; create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2; /* Create a new socket file */ if((pentry_new = cache_inode_create(pentry_parent, &name, CHARACTER_FILE, mode, &create_arg, &attr_new, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* If entry exists pentry_new is not null but cache_status was set */ if(cache_status == CACHE_INODE_ENTRY_EXISTS) { res_CREATE4.status = NFS4ERR_EXIST; return res_CREATE4.status; } break; case NF4BLK: create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1; create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2; /* Create a new socket file */ if((pentry_new = cache_inode_create(pentry_parent, &name, BLOCK_FILE, mode, &create_arg, &attr_new, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* If entry exists pentry_new is not null but cache_status was set */ if(cache_status == CACHE_INODE_ENTRY_EXISTS) { res_CREATE4.status = NFS4ERR_EXIST; return res_CREATE4.status; } break; default: /* Should never happen, but return NFS4ERR_BADTYPE in this case */ res_CREATE4.status = NFS4ERR_BADTYPE; return res_CREATE4.status; break; } /* switch( arg_CREATE4.objtype.type ) */ /* Now produce the filehandle to this file */ if((pnewfsal_handle = cache_inode_get_fsal_handle(pentry_new, &cache_status)) == NULL) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* Allocation of a new file handle */ if(nfs4_AllocateFH(&newfh4) != NFS4_OK) { res_CREATE4.status = NFS4ERR_SERVERFAULT; return res_CREATE4.status; } /* Building the new file handle */ if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) { res_CREATE4.status = NFS4ERR_SERVERFAULT; return res_CREATE4.status; } /* This new fh replaces the current FH */ data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len); /* No do not need newfh any more */ Mem_Free((char *)newfh4.nfs_fh4_val); /* Set the mode if requested */ /* Use the same fattr mask for reply, if one attribute was not settable, NFS4ERR_ATTRNOTSUPP was replyied */ res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len = arg_CREATE4.createattrs.attrmask.bitmap4_len; if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0) { if((cache_status = cache_inode_setattr(pentry_new, &sattr, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } /* Allocate a new bitmap */ res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val = (unsigned int *)Mem_Alloc(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len * sizeof(u_int)); if(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val == NULL) { res_CREATE4.status = NFS4ERR_SERVERFAULT; return res_CREATE4.status; } memset(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val, 0, res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len); memcpy(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val, arg_CREATE4.createattrs.attrmask.bitmap4_val, res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len * sizeof(u_int)); } /* Get the change info on parent directory after the operation was successfull */ if((cache_status = cache_inode_getattr(pentry_parent, &attr_parent, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_CREATE4.status = nfs4_Errno(cache_status); return res_CREATE4.status; } memset(&(res_CREATE4.CREATE4res_u.resok4.cinfo.after), 0, sizeof(changeid4)); res_CREATE4.CREATE4res_u.resok4.cinfo.after = (changeid4) pentry_parent->internal_md.mod_time; /* Operation is supposed to be atomic .... */ res_CREATE4.CREATE4res_u.resok4.cinfo.atomic = TRUE; LogFullDebug(COMPONENT_NFS_V4, " CREATE CINFO before = %llu after = %llu atomic = %d\n", res_CREATE4.CREATE4res_u.resok4.cinfo.before, res_CREATE4.CREATE4res_u.resok4.cinfo.after, res_CREATE4.CREATE4res_u.resok4.cinfo.atomic); /* @todo : BUGAZOMEU: fair ele free dans cette fonction */ /* Keep the vnode entry for the file in the compound data */ data->current_entry = pentry_new; data->current_filetype = pentry_new->internal_md.type; /* If you reach this point, then no error occured */ res_CREATE4.status = NFS4_OK; return res_CREATE4.status; } /* nfs4_op_create */
int nfs41_op_open(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_entry_t *pentry_parent = NULL; cache_entry_t *pentry_lookup = NULL; cache_entry_t *pentry_newfile = NULL; fsal_handle_t *pnewfsal_handle = NULL; fsal_attrib_list_t attr_parent; fsal_attrib_list_t attr; fsal_attrib_list_t attr_newfile; fsal_attrib_list_t sattr; fsal_openflags_t openflags = 0; cache_inode_status_t cache_status; nfsstat4 rc; int retval; fsal_name_t filename; bool_t AttrProvided = FALSE; fsal_accessmode_t mode = 0600; nfs_fh4 newfh4; nfs_client_id_t nfs_clientid; nfs_worker_data_t *pworker = NULL; int convrc = 0; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_open"; cache_inode_state_data_t candidate_data; cache_inode_state_type_t candidate_type; cache_inode_state_t *pfile_state = NULL; cache_inode_state_t *pstate_found_iterate = NULL; cache_inode_state_t *pstate_previous_iterate = NULL; cache_inode_state_t *pstate_found_same_owner = NULL; cache_inode_open_owner_name_t owner_name; cache_inode_open_owner_name_t *powner_name = NULL; cache_inode_open_owner_t *powner = NULL; bool_t open_owner_known = FALSE; resp->resop = NFS4_OP_OPEN; res_OPEN4.status = NFS4_OK; uint32_t tmp_attr[2]; uint_t tmp_int = 2; int pnfs_status; cache_inode_create_arg_t create_arg; pworker = (nfs_worker_data_t *) data->pclient->pworker; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_OPEN4.status = NFS4ERR_NOFILEHANDLE; return res_OPEN4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_OPEN4.status = NFS4ERR_BADHANDLE; return res_OPEN4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_OPEN4.status = NFS4ERR_FHEXPIRED; return res_OPEN4.status; } /* This can't be done on the pseudofs */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_OPEN4.status = NFS4ERR_ROFS; return res_OPEN4.status; } /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_open_xattr(op, data, resp); /* If data->current_entry is empty, repopulate it */ if(data->current_entry == NULL) { if((data->current_entry = nfs_FhandleToCache(NFS_V4, NULL, NULL, &(data->currentFH), NULL, NULL, &(res_OPEN4.status), &attr, data->pcontext, data->pclient, data->ht, &retval)) == NULL) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } } /* Set parent */ pentry_parent = data->current_entry; /* First switch is based upon claim type */ switch (arg_OPEN4.claim.claim) { case CLAIM_DELEGATE_CUR: case CLAIM_DELEGATE_PREV: /* Check for name length */ if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN) { res_OPEN4.status = NFS4ERR_NAMETOOLONG; return res_OPEN4.status; } /* get the filename from the argument, it should not be empty */ if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0) { res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; } res_OPEN4.status = NFS4ERR_NOTSUPP; return res_OPEN4.status; break; case CLAIM_NULL: /* Check for name length */ if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN) { res_OPEN4.status = NFS4ERR_NAMETOOLONG; return res_OPEN4.status; } /* get the filename from the argument, it should not be empty */ if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0) { res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; } /* Check if asked attributes are correct */ if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 || arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4) { if(!nfs4_Fattr_Supported (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs)) { res_OPEN4.status = NFS4ERR_ATTRNOTSUPP; return res_OPEN4.status; } /* Do not use READ attr, use WRITE attr */ if(!nfs4_Fattr_Check_Access (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs, FATTR4_ATTR_WRITE)) { res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; } } /* Check if filename is correct */ if((cache_status = cache_inode_error_convert(FSAL_buffdesc2name ((fsal_buffdesc_t *) & arg_OPEN4.claim.open_claim4_u. file, &filename))) != CACHE_INODE_SUCCESS) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } /* Check parent */ pentry_parent = data->current_entry; /* Parent must be a directory */ if((pentry_parent->internal_md.type != DIR_BEGINNING) && (pentry_parent->internal_md.type != DIR_CONTINUE)) { /* Parent object is not a directory... */ if(pentry_parent->internal_md.type == SYMBOLIC_LINK) res_OPEN4.status = NFS4ERR_SYMLINK; else res_OPEN4.status = NFS4ERR_NOTDIR; return res_OPEN4.status; } /* What kind of open is it ? */ LogFullDebug(COMPONENT_NFS_V4, " OPEN: Claim type = %d Open Type = %d Share Deny = %d Share Access = %d \n", arg_OPEN4.claim.claim, arg_OPEN4.openhow.opentype, arg_OPEN4.share_deny, arg_OPEN4.share_access); /* It this a known client id ? */ LogDebug(COMPONENT_NFS_V4, "OPEN Client id = %llx", arg_OPEN4.owner.clientid); /* Is this open_owner known ? */ if(!nfs_convert_open_owner(&arg_OPEN4.owner, &owner_name)) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } if(!nfs_open_owner_Get_Pointer(&owner_name, &powner)) { /* This open owner is not known yet, allocated and set up a new one */ GET_PREALLOC(powner, data->pclient->pool_open_owner, data->pclient->nb_pre_state_v4, cache_inode_open_owner_t, next); GET_PREALLOC(powner_name, data->pclient->pool_open_owner_name, data->pclient->nb_pre_state_v4, cache_inode_open_owner_name_t, next); if(powner == NULL || powner_name == NULL) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } memcpy((char *)powner_name, (char *)&owner_name, sizeof(cache_inode_open_owner_name_t)); /* set up the content of the open_owner */ powner->confirmed = FALSE; powner->seqid = 1; /* NFSv4.1 specific, initial seqid is 1 */ powner->related_owner = NULL; powner->next = NULL; powner->clientid = arg_OPEN4.owner.clientid; powner->owner_len = arg_OPEN4.owner.owner.owner_len; memcpy((char *)powner->owner_val, (char *)arg_OPEN4.owner.owner.owner_val, arg_OPEN4.owner.owner.owner_len); powner->owner_val[powner->owner_len] = '\0'; pthread_mutex_init(&powner->lock, NULL); if(!nfs_open_owner_Set(powner_name, powner)) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } } /* Status of parent directory before the operation */ if((cache_status = cache_inode_getattr(pentry_parent, &attr_parent, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_OPEN4.OPEN4res_u.resok4.cinfo.before = (changeid4) pentry_parent->internal_md.mod_time; /* CLient may have provided fattr4 to set attributes at creation time */ if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 || arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4) { if(arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.attrmask. bitmap4_len != 0) { /* Convert fattr4 so nfs4_sattr */ convrc = nfs4_Fattr_To_FSAL_attr(&sattr, &(arg_OPEN4.openhow.openflag4_u.how. createhow4_u.createattrs)); if(convrc == 0) { res_OPEN4.status = NFS4ERR_ATTRNOTSUPP; return res_OPEN4.status; } if(convrc == -1) { res_OPEN4.status = NFS4ERR_BADXDR; return res_OPEN4.status; } AttrProvided = TRUE; } } /* Second switch is based upon "openhow" */ switch (arg_OPEN4.openhow.opentype) { case OPEN4_CREATE: /* a new file is to be created */ /* Does a file with this name already exist ? */ pentry_lookup = cache_inode_lookup(pentry_parent, &filename, &attr_newfile, data->ht, data->pclient, data->pcontext, &cache_status); if(cache_status != CACHE_INODE_NOT_FOUND) { /* if open is UNCHECKED, return NFS4_OK (RFC3530 page 172) */ if(arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4 && (cache_status == CACHE_INODE_SUCCESS)) { /* If the file is opened for write, OPEN4 while deny share write access, * in this case, check caller has write access to the file */ if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE) { if(cache_inode_access(pentry_lookup, FSAL_W_OK, data->ht, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } openflags = FSAL_O_WRONLY; } /* Same check on read: check for readability of a file before opening it for read */ if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ) { if(cache_inode_access(pentry_lookup, FSAL_R_OK, data->ht, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } openflags = FSAL_O_RDONLY; } if(AttrProvided == TRUE) /* Set the attribute if provided */ { if((cache_status = cache_inode_setattr(pentry_lookup, &sattr, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } res_OPEN4.OPEN4res_u.resok4.attrset = arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs. attrmask; } else res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0; /* Same check on write */ if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE) { if(cache_inode_access(pentry_lookup, FSAL_W_OK, data->ht, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } openflags = FSAL_O_RDWR; } /* Set the state for the related file */ /* Prepare state management structure */ candidate_type = CACHE_INODE_STATE_SHARE; candidate_data.share.share_deny = arg_OPEN4.share_deny; candidate_data.share.share_access = arg_OPEN4.share_access; if(cache_inode_add_state(pentry_lookup, candidate_type, &candidate_data, powner, data->pclient, data->pcontext, &pfile_state, &cache_status) != CACHE_INODE_SUCCESS) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_SHARE_DENIED; return res_OPEN4.status; } /* Open the file */ if(cache_inode_open_by_name(pentry_parent, &filename, pentry_lookup, data->pclient, openflags, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_SHARE_DENIED; res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2; if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val = (uint32_t *) Mem_Alloc(res_OPEN4.OPEN4res_u.resok4.attrset. bitmap4_len * sizeof(uint32_t))) == NULL) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0, sizeof(changeid4)); res_OPEN4.OPEN4res_u.resok4.cinfo.after = (changeid4) pentry_parent->internal_md.mod_time; res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE; res_OPEN4.OPEN4res_u.resok4.stateid.seqid = pfile_state->seqid; memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other, pfile_state->stateid_other, 12); /* No delegation */ res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = OPEN_DELEGATE_NONE; res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX; /* Now produce the filehandle to this file */ if((pnewfsal_handle = cache_inode_get_fsal_handle(pentry_lookup, &cache_status)) == NULL) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } /* Allocation of a new file handle */ if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK) { res_OPEN4.status = rc; return res_OPEN4.status; } /* Building a new fh */ if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } /* This new fh replaces the current FH */ data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len); data->current_entry = pentry_lookup; data->current_filetype = REGULAR_FILE; res_OPEN4.status = NFS4_OK; return res_OPEN4.status; } /* if open is EXCLUSIVE, but verifier is the same, return NFS4_OK (RFC3530 page 173) */ if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4) { if((pentry_lookup != NULL) && (pentry_lookup->internal_md.type == REGULAR_FILE)) { pstate_found_iterate = NULL; pstate_previous_iterate = NULL; do { cache_inode_state_iterate(pentry_lookup, &pstate_found_iterate, pstate_previous_iterate, data->pclient, data->pcontext, &cache_status); if(cache_status == CACHE_INODE_STATE_ERROR) break; if(cache_status == CACHE_INODE_INVALID_ARGUMENT) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; } /* Check is open_owner is the same */ if(pstate_found_iterate != NULL) { if((pstate_found_iterate->state_type == CACHE_INODE_STATE_SHARE) && !memcmp(arg_OPEN4.owner.owner.owner_val, pstate_found_iterate->powner->owner_val, pstate_found_iterate->powner->owner_len) && !memcmp(pstate_found_iterate->state_data.share. oexcl_verifier, arg_OPEN4.openhow.openflag4_u.how. createhow4_u.createverf, NFS4_VERIFIER_SIZE)) { /* A former open EXCLUSIVE with same owner and verifier was found, resend it */ res_OPEN4.OPEN4res_u.resok4.stateid.seqid = pstate_found_iterate->seqid; memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other, pstate_found_iterate->stateid_other, 12); memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0, sizeof(changeid4)); res_OPEN4.OPEN4res_u.resok4.cinfo.after = (changeid4) pentry_parent->internal_md.mod_time; res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE; /* No delegation */ res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = OPEN_DELEGATE_NONE; res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX; /* Now produce the filehandle to this file */ if((pnewfsal_handle = cache_inode_get_fsal_handle(pentry_lookup, &cache_status)) == NULL) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } /* Allocation of a new file handle */ if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK) { res_OPEN4.status = rc; return res_OPEN4.status; } /* Building a new fh */ if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } /* This new fh replaces the current FH */ data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len); data->current_entry = pentry_lookup; data->current_filetype = REGULAR_FILE; /* regular exit */ res_OPEN4.status = NFS4_OK; return res_OPEN4.status; } } /* if( pstate_found_iterate != NULL ) */ pstate_previous_iterate = pstate_found_iterate; } while(pstate_found_iterate != NULL); } } /* Managing GUARDED4 mode */ if(cache_status != CACHE_INODE_SUCCESS) res_OPEN4.status = nfs4_Errno(cache_status); else res_OPEN4.status = NFS4ERR_EXIST; /* File already exists */ return res_OPEN4.status; } /* if( cache_status != CACHE_INODE_NOT_FOUND ), if file already exists basically */ LogFullDebug(COMPONENT_NFS_V4, " OPEN open.how = %d\n", arg_OPEN4.openhow.openflag4_u.how.mode); create_arg.use_pnfs = FALSE; #ifdef _USE_PNFS /* set the file has "managed via pNFS" */ if(data->pexport->options & EXPORT_OPTION_USE_PNFS) create_arg.use_pnfs = TRUE; #endif /* _USE_PNFS */ /* Create the file, if we reach this point, it does not exist, we can create it */ if((pentry_newfile = cache_inode_create(pentry_parent, &filename, REGULAR_FILE, mode, &create_arg, &attr_newfile, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { /* If the file already exists, this is not an error if open mode is UNCHECKED */ if(cache_status != CACHE_INODE_ENTRY_EXISTS) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } else { /* If this point is reached, then the file already exists, cache_status == CACHE_INODE_ENTRY_EXISTS and pentry_newfile == NULL This probably means EXCLUSIVE4 mode is used and verifier matches. pentry_newfile is then set to pentry_lookup */ pentry_newfile = pentry_lookup; } } /* Prepare state management structure */ candidate_type = CACHE_INODE_STATE_SHARE; candidate_data.share.share_deny = arg_OPEN4.share_deny; candidate_data.share.share_access = arg_OPEN4.share_access; candidate_data.share.lockheld = 0; /* If file is opened under mode EXCLUSIVE4, open verifier should be kept to detect non vicious double open */ if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4) { strncpy(candidate_data.share.oexcl_verifier, arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createverf, NFS4_VERIFIER_SIZE); } if(cache_inode_add_state(pentry_newfile, candidate_type, &candidate_data, powner, data->pclient, data->pcontext, &pfile_state, &cache_status) != CACHE_INODE_SUCCESS) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_SHARE_DENIED; return res_OPEN4.status; } if(AttrProvided == TRUE) /* Set the attribute if provided */ { if((cache_status = cache_inode_setattr(pentry_newfile, &sattr, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } } /* Set the openflags variable */ if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE) openflags |= FSAL_O_RDONLY; if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_READ) openflags |= FSAL_O_WRONLY; if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE) openflags = FSAL_O_RDWR; if(arg_OPEN4.share_access != 0) openflags = FSAL_O_RDWR; /* @todo : BUGAZOMEU : Something better later */ /* Open the file */ if(cache_inode_open_by_name(pentry_parent, &filename, pentry_newfile, data->pclient, openflags, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } break; case OPEN4_NOCREATE: /* It was not a creation, but a regular open */ /* The filehandle to the new file replaces the current filehandle */ if(pentry_newfile == NULL) { if((pentry_newfile = cache_inode_lookup(pentry_parent, &filename, &attr_newfile, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } } /* OPEN4 is to be done on a file */ if(pentry_newfile->internal_md.type != REGULAR_FILE) { if(pentry_newfile->internal_md.type == DIR_BEGINNING || pentry_newfile->internal_md.type == DIR_CONTINUE) { res_OPEN4.status = NFS4ERR_ISDIR; return res_OPEN4.status; } else if(pentry_newfile->internal_md.type == SYMBOLIC_LINK) { res_OPEN4.status = NFS4ERR_SYMLINK; return res_OPEN4.status; } else { res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; } } /* If the file is opened for write, OPEN4 while deny share write access, * in this case, check caller has write access to the file */ if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE) { if(cache_inode_access(pentry_newfile, FSAL_W_OK, data->ht, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } openflags = FSAL_O_WRONLY; } /* Same check on read: check for readability of a file before opening it for read */ if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ) { if(cache_inode_access(pentry_newfile, FSAL_R_OK, data->ht, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } openflags = FSAL_O_RDONLY; } /* Same check on write */ if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE) { if(cache_inode_access(pentry_newfile, FSAL_W_OK, data->ht, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } openflags = FSAL_O_RDWR; } /* Try to find if the same open_owner already has acquired a stateid for this file */ pstate_found_iterate = NULL; pstate_previous_iterate = NULL; do { cache_inode_state_iterate(pentry_newfile, &pstate_found_iterate, pstate_previous_iterate, data->pclient, data->pcontext, &cache_status); if(cache_status == CACHE_INODE_STATE_ERROR) break; /* Get out of the loop */ if(cache_status == CACHE_INODE_INVALID_ARGUMENT) { res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; } /* Check is open_owner is the same */ if(pstate_found_iterate != NULL) { if((pstate_found_iterate->state_type == CACHE_INODE_STATE_SHARE) && (pstate_found_iterate->powner->clientid == arg_OPEN4.owner.clientid) && ((pstate_found_iterate->powner->owner_len == arg_OPEN4.owner.owner.owner_len) && (!memcmp (arg_OPEN4.owner.owner.owner_val, pstate_found_iterate->powner->owner_val, pstate_found_iterate->powner->owner_len)))) { /* We'll be re-using the found state */ pstate_found_same_owner = pstate_found_iterate; } else { /* This is a different owner, check for possible conflicts */ if(memcmp(arg_OPEN4.owner.owner.owner_val, pstate_found_iterate->powner->owner_val, pstate_found_iterate->powner->owner_len)) { switch (pstate_found_iterate->state_type) { case CACHE_INODE_STATE_SHARE: if((pstate_found_iterate->state_data.share. share_access & OPEN4_SHARE_ACCESS_WRITE) && (arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)) { res_OPEN4.status = NFS4ERR_SHARE_DENIED; return res_OPEN4.status; } break; } } } /* In all cases opening in read access a read denied file or write access to a write denied file * should fail, even if the owner is the same, see discussion in 14.2.16 and 8.9 */ if(pstate_found_iterate->state_type == CACHE_INODE_STATE_SHARE) { /* deny read access on read denied file */ if((pstate_found_iterate->state_data.share. share_deny & OPEN4_SHARE_DENY_READ) && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); powner->seqid += 1; res_OPEN4.status = NFS4ERR_SHARE_DENIED; return res_OPEN4.status; } /* deny write access on write denied file */ if((pstate_found_iterate->state_data.share. share_deny & OPEN4_SHARE_DENY_WRITE) && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_SHARE_DENIED; return res_OPEN4.status; } } } /* if( pstate_found_iterate != NULL ) */ pstate_previous_iterate = pstate_found_iterate; } while(pstate_found_iterate != NULL); if(pstate_found_same_owner != NULL) { pfile_state = pstate_found_same_owner; pfile_state->seqid += 1; P(powner->lock); powner->seqid += 1; V(powner->lock); } else { /* Set the state for the related file */ /* Prepare state management structure */ candidate_type = CACHE_INODE_STATE_SHARE; candidate_data.share.share_deny = arg_OPEN4.share_deny; candidate_data.share.share_access = arg_OPEN4.share_access; if(cache_inode_add_state(pentry_newfile, candidate_type, &candidate_data, powner, data->pclient, data->pcontext, &pfile_state, &cache_status) != CACHE_INODE_SUCCESS) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_SHARE_DENIED; return res_OPEN4.status; } } /* Open the file */ if(cache_inode_open_by_name(pentry_parent, &filename, pentry_newfile, data->pclient, openflags, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { /* Seqid has to be incremented even in this case */ P(powner->lock); powner->seqid += 1; V(powner->lock); res_OPEN4.status = NFS4ERR_ACCESS; return res_OPEN4.status; } break; default: /* Seqid has to be incremented even in this case */ if(powner != NULL) { P(powner->lock); powner->seqid += 1; V(powner->lock); } res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; break; } /* switch( arg_OPEN4.openhow.opentype ) */ break; case CLAIM_PREVIOUS: break; default: /* Seqid has to be incremented even in this case */ if(powner != NULL) { P(powner->lock); powner->seqid += 1; V(powner->lock); } res_OPEN4.status = NFS4ERR_INVAL; return res_OPEN4.status; break; } /* switch( arg_OPEN4.claim.claim ) */ /* Now produce the filehandle to this file */ if((pnewfsal_handle = cache_inode_get_fsal_handle(pentry_newfile, &cache_status)) == NULL) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } /* Allocation of a new file handle */ if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK) { res_OPEN4.status = rc; return res_OPEN4.status; } /* Building a new fh */ if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } /* This new fh replaces the current FH */ data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len); data->current_entry = pentry_newfile; data->current_filetype = REGULAR_FILE; /* No do not need newfh any more */ Mem_Free((char *)newfh4.nfs_fh4_val); /* Status of parent directory after the operation */ if((cache_status = cache_inode_getattr(pentry_parent, &attr_parent, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_OPEN4.status = nfs4_Errno(cache_status); return res_OPEN4.status; } res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2; if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val = (uint32_t *) Mem_Alloc(res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len * sizeof(uint32_t))) == NULL) { res_OPEN4.status = NFS4ERR_SERVERFAULT; return res_OPEN4.status; } res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val[0] = 0; /* No Attributes set */ res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val[1] = 0; /* No Attributes set */ if(arg_OPEN4.openhow.opentype == OPEN4_CREATE) { tmp_int = 2; tmp_attr[0] = FATTR4_SIZE; tmp_attr[1] = FATTR4_MODE; nfs4_list_to_bitmap4(&(res_OPEN4.OPEN4res_u.resok4.attrset), &tmp_int, tmp_attr); res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2; } res_OPEN4.OPEN4res_u.resok4.cinfo.after = (changeid4) pentry_parent->internal_md.mod_time; res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE; res_OPEN4.OPEN4res_u.resok4.stateid.seqid = powner->seqid; memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other, pfile_state->stateid_other, 12); /* No delegation */ res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = OPEN_DELEGATE_NONE; res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX; /* regular exit */ res_OPEN4.status = NFS4_OK; return res_OPEN4.status; } /* nfs41_op_open */
fsal_status_t PROXYFSAL_symlink(proxyfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_linkname, /* IN */ fsal_path_t * p_linkcontent, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN (ignored) */ proxyfsal_handle_t * link_handle, /* OUT */ fsal_attrib_list_t * link_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; uint32_t bitmap_mkdir[2]; uint32_t bitmap_getattr_res[2]; uint32_t bitmap_conv_val[2]; fattr4 input_attr; bitmap4 convert_bitmap; component4 name; char nameval[MAXNAMLEN]; component4 linkname; char linknameval[MAXNAMLEN]; char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN]; fsal_proxy_internal_fattr_t fattr_internal; fsal_attrib_list_t create_mode_attr; fsal_attrib_list_t attributes; #define FSAL_SYMLINK_NB_OP_ALLOC 4 #define FSAL_SYMLINK_VAL_BUFFER 1024 nfs_argop4 argoparray[FSAL_SYMLINK_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_SYMLINK_NB_OP_ALLOC]; char fattr_val[FSAL_SYMLINK_VAL_BUFFER]; struct timeval timeout = TIMEOUTRPC; /* sanity checks. * note : link_attributes is optional. */ if(!parent_directory_handle || !p_context || !link_handle || !p_linkname || !p_linkcontent) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); /* Tests if symlinking is allowed by configuration. */ if(!global_fs_info.symlink_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_symlink); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Symlink" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; input_attr.attrmask.bitmap4_val = bitmap_val; input_attr.attrmask.bitmap4_len = 2; input_attr.attr_vals.attrlist4_val = fattr_val; input_attr.attr_vals.attrlist4_len = FSAL_SYMLINK_VAL_BUFFER; fsal_internal_proxy_setup_fattr(&fattr_internal); convert_bitmap.bitmap4_val = bitmap_conv_val; convert_bitmap.bitmap4_len = 2; memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_linkname, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); memset((char *)&linkname, 0, sizeof(component4)); linkname.utf8string_val = linknameval; if(fsal_internal_proxy_fsal_path_2_utf8(p_linkcontent, &linkname) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); bitmap.bitmap4_val = bitmap_mkdir; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); create_mode_attr.asked_attributes = FSAL_ATTR_MODE; create_mode_attr.mode = accessmode; fsal_interval_proxy_fsalattr2bitmap4(&create_mode_attr, &convert_bitmap); if(nfs4_FSALattr_To_Fattr(NULL, /* no exportlist required here */ &create_mode_attr, &input_attr, NULL, /* no compound data required here */ NULL, /* No fh here, filehandle is not a settable attribute */ &convert_bitmap) == -1) Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_symlink); #define FSAL_SYMLINK_IDX_OP_PUTFH 0 #define FSAL_SYMLINK_IDX_OP_SYMLINK 1 #define FSAL_SYMLINK_IDX_OP_GETFH 2 #define FSAL_SYMLINK_IDX_OP_GETATTR 3 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_SYMLINK(argnfs4, name, linkname, input_attr); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_SYMLINK].nfs_resop4_u.opcreate. CREATE4res_u.resok4.attrset.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_SYMLINK].nfs_resop4_u.opcreate. CREATE4res_u.resok4.attrset.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_getattr_res; resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, 0, INDEX_FSAL_symlink); } ReleaseTokenFSCall(); /* >> convert error code, and return on error << */ if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_symlink); /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(&attributes, &resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR]. nfs_resop4_u.opgetattr.GETATTR4res_u.resok4. obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(attributes.asked_attributes); FSAL_SET_MASK(attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_symlink); } if(link_attributes) { memcpy(link_attributes, &attributes, sizeof(attributes)); } if(fsal_internal_proxy_create_fh (& (resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object), FSAL_TYPE_LNK, attributes.fileid, link_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink); }
fsal_status_t PROXYFSAL_unlink(proxyfsal_handle_t * parentdir_handle, /* IN */ fsal_name_t * p_object_name, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * parentdir_attributes /* [IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; component4 name; char nameval[MAXNAMLEN]; #define FSAL_UNLINK_NB_OP_ALLOC 3 nfs_argop4 argoparray[FSAL_UNLINK_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_UNLINK_NB_OP_ALLOC]; uint32_t bitmap_res[2]; fsal_proxy_internal_fattr_t fattr_internal; struct timeval timeout = TIMEOUTRPC; /* sanity checks. * note : parentdir_attributes are optional. * parentdir_handle is mandatory, * because, we do not allow to delete FS root ! */ if(!parentdir_handle || !p_context || !p_object_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Unlink" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; /* >> retrieve root handle filehandle here << */ bitmap.bitmap4_val = bitmap_val; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); if(fsal_internal_proxy_extract_fh(&nfs4fh, parentdir_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink); memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_object_name, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink); #define FSAL_UNLINK_IDX_OP_PUTFH 0 #define FSAL_UNLINK_IDX_OP_REMOVE 1 #define FSAL_UNLINK_IDX_OP_GETATTR 2 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_REMOVE(argnfs4, name); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_UNLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_UNLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_UNLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_UNLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_unlink); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_unlink); /* >> get post op attributes for the parent, if they are asked, * and your filesystem didn't return them << */ if(parentdir_attributes) { if(nfs4_Fattr_To_FSAL_attr(parentdir_attributes, &resnfs4.resarray. resarray_val[FSAL_UNLINK_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(parentdir_attributes->asked_attributes); FSAL_SET_MASK(parentdir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_unlink); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_unlink); }
/** * FSAL_create: * Create a regular file. * * \param parent_directory_handle (input): * Handle of the parent directory where the file is to be created. * \param p_filename (input): * Pointer to the name of the file to be created. * \param cred (input): * Authentication context for the operation (user, export...). * \param accessmode (input): * Mode for the file to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param object_handle (output): * Pointer to the handle of the created file. * \param object_attributes (optionnal input/output): * The postop attributes of the created file. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * Can be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (parent_directory_handle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ... * * NB: if getting postop attributes failed, * the function does not return an error * but the FSAL_ATTR_RDATTR_ERR bit is set in * the object_attributes->asked_attributes field. */ fsal_status_t PROXYFSAL_create(proxyfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ proxyfsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; uint32_t bitmap_conv_val[2]; uint32_t bitmap_create[2]; uint32_t bitmap_getattr_res[2]; fattr4 input_attr; bitmap4 convert_bitmap; component4 name; char nameval[MAXNAMLEN]; char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN]; fsal_status_t fsal_status; proxyfsal_file_t fd; #define FSAL_CREATE_NB_OP_ALLOC 4 #define FSAL_CREATE_VAL_BUFFER 1024 fsal_proxy_internal_fattr_t fattr_internal; fsal_attrib_list_t create_mode_attr; fsal_attrib_list_t attributes; nfs_argop4 argoparray[FSAL_CREATE_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_CREATE_NB_OP_ALLOC]; char fattr_val[FSAL_CREATE_VAL_BUFFER]; struct timeval timeout = { 25, 0 }; char owner_val[FSAL_PROXY_OWNER_LEN]; unsigned int owner_len = 0; /* sanity checks. * note : object_attributes is optional. */ if(!parent_directory_handle || !p_context || !object_handle || !p_filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); PRINT_HANDLE("FSAL_create", parent_directory_handle); /* Create the owner */ snprintf(owner_val, FSAL_PROXY_OWNER_LEN, "GANESHA/PROXY: pid=%u ctx=%p file=%llu", getpid(), p_context, (unsigned long long int)p_context->file_counter); owner_len = strnlen(owner_val, FSAL_PROXY_OWNER_LEN); p_context->file_counter += 1; /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Mkdir" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; input_attr.attrmask.bitmap4_val = bitmap_val; input_attr.attrmask.bitmap4_len = 2; input_attr.attr_vals.attrlist4_val = fattr_val; input_attr.attr_vals.attrlist4_len = FSAL_CREATE_VAL_BUFFER; fsal_internal_proxy_setup_fattr(&fattr_internal); convert_bitmap.bitmap4_val = bitmap_conv_val; convert_bitmap.bitmap4_len = 2; memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_filename, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); if(isFullDebug(COMPONENT_FSAL)) { char outstr[1024]; nfs4_sprint_fhandle(&nfs4fh, outstr); LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) parent handle=%s\n", outstr); } bitmap.bitmap4_val = bitmap_create; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); create_mode_attr.asked_attributes = FSAL_ATTR_MODE; create_mode_attr.mode = accessmode; fsal_interval_proxy_fsalattr2bitmap4(&create_mode_attr, &convert_bitmap); if(nfs4_FSALattr_To_Fattr(NULL, /* no exportlist required here */ &create_mode_attr, &input_attr, NULL, /* no compound data required here */ NULL, /* No fh here, filehandle is not a settable attribute */ &convert_bitmap) == -1) Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_create); #define FSAL_CREATE_IDX_OP_PUTFH 0 #define FSAL_CREATE_IDX_OP_OPEN_CREATE 1 #define FSAL_CREATE_IDX_OP_GETFH 2 #define FSAL_CREATE_IDX_OP_GETATTR 3 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_OPEN_CREATE(argnfs4, name, input_attr, p_context->clientid, owner_val, owner_len); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.attrset.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.attrset.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_getattr_res; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_create); } ReleaseTokenFSCall(); /* >> convert error code, and return on error << */ if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_create); /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(&attributes, &resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR]. nfs_resop4_u.opgetattr.GETATTR4res_u.resok4. obj_attributes) != 1) { FSAL_CLEAR_MASK(attributes.asked_attributes); FSAL_SET_MASK(attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_create); } /* Return attributes if asked */ if(object_attributes) { memcpy(object_attributes, &attributes, sizeof(attributes)); } if(isFullDebug(COMPONENT_FSAL)) { char outstr[1024]; nfs4_sprint_fhandle(&nfs4fh, outstr); LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) created file handle=%s\n", outstr); } if(fsal_internal_proxy_create_fh (& (resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object), FSAL_TYPE_FILE, attributes.fileid, object_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* Keep the information into the file descriptor as well */ memcpy((char *)&fd.fhandle, (char *)object_handle, sizeof(fd.fhandle)); fd.openflags = FSAL_O_RDWR; fd.current_offset = 0; fd.pcontext = p_context; /* Keep the returned stateid for later use */ fd.stateid.seqid = resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.stateid.seqid; memcpy((char *)fd.stateid.other, resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u. opopen.OPEN4res_u.resok4.stateid.other, 12); /* See if a OPEN_CONFIRM is required */ if(resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM) { fsal_status = FSAL_proxy_open_confirm(&fd); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create); } #ifdef _FSAL_CREATE_CLOSE_FILE /* The craeted file is still opened, to preserve the correct seqid for later use, we close it */ fsal_status = FSAL_close(&fd); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create); #endif /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); } /* FSAL_create */
/** * FSAL_link: * Create a hardlink. * * \param target_handle (input): * Handle of the target object. * \param dir_handle (input): * Pointer to the directory handle where * the hardlink is to be created. * \param p_link_name (input): * Pointer to the name of the hardlink to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the directory to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param attributes (optionnal input/output): * The post_operation attributes of the linked object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (target_handle or dir_handle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ... * * NB: if getting postop attributes failed, * the function does not return an error * but the FSAL_ATTR_RDATTR_ERR bit is set in * the attributes->asked_attributes field. */ fsal_status_t PROXYFSAL_link(proxyfsal_handle_t * target_handle, /* IN */ proxyfsal_handle_t * dir_handle, /* IN */ fsal_name_t * p_link_name, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh_target; nfs_fh4 nfs4fh_dest; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; component4 name; char nameval[MAXNAMLEN]; fsal_proxy_internal_fattr_t fattr_internal; struct timeval timeout = { 25, 0 }; /* sanity checks. * note : attributes is optional. */ if(!target_handle || !dir_handle || !p_context || !p_link_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); /* Tests if hardlinking is allowed by configuration. */ if(!global_fs_info.link_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link); #define FSAL_LINK_NB_OP_ALLOC 6 nfs_argop4 argoparray[FSAL_LINK_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_LINK_NB_OP_ALLOC]; /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Link" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; bitmap.bitmap4_val = bitmap_val; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); if(fsal_internal_proxy_extract_fh(&nfs4fh_target, target_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); if(fsal_internal_proxy_extract_fh(&nfs4fh_dest, dir_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_link_name, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); #define FSAL_LINK_IDX_OP_PUTFH_TARGET 0 #define FSAL_LINK_IDX_OP_SAVEFH 1 #define FSAL_LINK_IDX_OP_PUTFH_DEST 2 #define FSAL_LINK_IDX_OP_LINK 3 #define FSAL_LINK_IDX_OP_RESTOREFH 4 #define FSAL_LINK_IDX_OP_GETATTR 5 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_target); COMPOUNDV4_ARG_ADD_OP_SAVEFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_dest); COMPOUNDV4_ARG_ADD_OP_LINK(argnfs4, name); COMPOUNDV4_ARG_ADD_OP_RESTOREFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_link); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_link); if(attributes) { /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(attributes, &resnfs4.resarray. resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != 1) { FSAL_CLEAR_MASK(attributes->asked_attributes); FSAL_SET_MASK(attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_link); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); }
fsal_status_t PROXYFSAL_truncate(fsal_handle_t * file_hdl, /* IN */ fsal_op_context_t * context, /* IN */ fsal_size_t length, /* IN */ fsal_file_t * file_descriptor, /* [IN|OUT] */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; uint64_t fileid; fsal_status_t fsal_status; fsal_attrib_list_t open_attrs; bitmap4 inbitmap; bitmap4 convert_bitmap; uint32_t inbitmap_val[2]; uint32_t bitmap_res[2]; uint32_t bitmap_set[2]; uint32_t bitmap_conv_val[2]; proxyfsal_handle_t * filehandle = (proxyfsal_handle_t *)file_hdl; proxyfsal_op_context_t * p_context = (proxyfsal_op_context_t *)context; #define FSAL_TRUNCATE_NB_OP_ALLOC 3 nfs_argop4 argoparray[FSAL_TRUNCATE_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_TRUNCATE_NB_OP_ALLOC]; fsal_attrib_list_t fsal_attr_set; fattr4 fattr_set; fsal_proxy_internal_fattr_t fattr_internal; struct timeval timeout = TIMEOUTRPC; /* sanity checks. * note : object_attributes is optional. */ if(!filehandle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate); if(filehandle->data.object_type_reminder != FSAL_TYPE_FILE) { Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate); } if(file_descriptor == NULL) { /* Use the stateless version */ fsal_status = FSAL_proxy_truncate_stateless(file_hdl, context, length, object_attributes); Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate); } /* First, we need to get the fileid on a filehandle base */ fsal_status = FSAL_DigestHandle(context->export_context, FSAL_DIGEST_FILEID4, file_hdl, (caddr_t) & fileid); if(FSAL_IS_ERROR(fsal_status)) { Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate); } /* Then we have of open the file by fileid */ open_attrs.asked_attributes = FSAL_ATTRS_POSIX; fsal_status = FSAL_open_by_fileid(file_hdl, fileid, context, FSAL_O_RDWR, file_descriptor, &open_attrs); if(FSAL_IS_ERROR(fsal_status)) { Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate); } /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Truncate" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, file_hdl) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate); /* Get prepared for truncate */ fsal_attr_set.asked_attributes = FSAL_ATTR_SIZE; fsal_attr_set.filesize = length; convert_bitmap.bitmap4_val = bitmap_conv_val; convert_bitmap.bitmap4_len = 2; fsal_interval_proxy_fsalattr2bitmap4(&fsal_attr_set, &convert_bitmap); if(nfs4_FSALattr_To_Fattr(NULL, /* no exportlist required here */ &fsal_attr_set, &fattr_set, NULL, /* no compound data required here */ NULL, /* No fh here, filehandle is not a settable attribute */ &convert_bitmap) == -1) Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_truncate); inbitmap.bitmap4_val = inbitmap_val; inbitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&inbitmap); #define FSAL_TRUNCATE_IDX_OP_PUTFH 0 #define FSAL_TRUNCATE_IDX_OP_SETATTR 1 #define FSAL_TRUNCATE_IDX_OP_GETATTR 2 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_SETATTR(argnfs4, fattr_set); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, inbitmap); /* For ATTR_SIZE, stateid is needed */ argnfs4.argarray.argarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_argop4_u.opsetattr. stateid.seqid = ((proxyfsal_file_t *)file_descriptor)->stateid.seqid; memcpy(argnfs4.argarray.argarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_argop4_u. opsetattr.stateid.other, ((proxyfsal_file_t *)file_descriptor)->stateid.other, 12); resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_resop4_u.opsetattr. attrsset.bitmap4_val = bitmap_set; resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_resop4_u.opsetattr. attrsset.bitmap4_len = 2; TakeTokenFSCall(); COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, 0, INDEX_FSAL_truncate); } ReleaseTokenFSCall(); if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_truncate); /* >> interpret error code << */ /* >> Optionnaly retrieve post op attributes * If your filesystem truncate call can't return them, * you can proceed like this : << */ if(object_attributes) { if(nfs4_Fattr_To_FSAL_attr(object_attributes, &resnfs4.resarray. resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate); } } /* Close the previously opened filedescriptor */ fsal_status = FSAL_close_by_fileid(file_descriptor, fileid); if(FSAL_IS_ERROR(fsal_status)) { Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate); } /* No error occured */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_truncate); }
/** * PROXYFSAL_access : * Tests whether the user or entity identified by the p_context structure * can access the object identified by object_handle, * as indicated by the access_type parameter. * * \param object_handle (input): * The handle of the object to test permissions on. * \param p_context (input): * Authentication context for the operation (export entry, user,...). * \param access_type (input): * Indicates the permissions to be tested. * This is an inclusive OR of the permissions * to be checked for the user specified by p_context. * Permissions constants are : * - FSAL_R_OK : test for read permission * - FSAL_W_OK : test for write permission * - FSAL_X_OK : test for exec permission * - FSAL_F_OK : test for file existence * \param object_attributes (optional 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). * Can be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error, asked permission is granted) * - ERR_FSAL_ACCESS (object permissions doesn't fit asked access type) * - ERR_FSAL_STALE (object_handle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes when something anormal occurs. */ fsal_status_t PROXYFSAL_access(fsal_handle_t * object_handle, /* IN */ fsal_op_context_t *context, /* IN */ fsal_accessflags_t access_type, /* IN */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; uint32_t accessflag = 0; proxyfsal_op_context_t * p_context = (proxyfsal_op_context_t *)context; fsal_proxy_internal_fattr_t fattr_internal; struct timeval __attribute__ ((__unused__)) timeout = TIMEOUTRPC; nfs_fh4 nfs4fh; #define FSAL_ACCESS_NB_OP_ACCESS 3 nfs_argop4 argoparray[FSAL_ACCESS_NB_OP_ACCESS]; nfs_resop4 resoparray[FSAL_ACCESS_NB_OP_ACCESS]; /* sanity checks. * note : object_attributes is optional in PROXYFSAL_access. */ if(!object_handle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_access); /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; fsal_internal_proxy_setup_fattr(&fattr_internal); argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Access" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; bitmap.bitmap4_val = bitmap_val; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); /* Set up access flags */ if(access_type & FSAL_R_OK) accessflag |= ACCESS4_READ; if(access_type & FSAL_X_OK) accessflag |= ACCESS4_LOOKUP; if(access_type & FSAL_W_OK) accessflag |= (ACCESS4_MODIFY & ACCESS4_EXTEND); if(access_type & FSAL_F_OK) accessflag |= ACCESS4_LOOKUP; /* >> convert your fsal access type to your FS access type << */ /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, object_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_access); #define FSAL_ACCESS_IDX_OP_PUTFH 0 #define FSAL_ACCESS_IDX_OP_ACCESS 1 #define FSAL_ACCESS_IDX_OP_GETATTR 2 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_ACCESS(argnfs4, accessflag); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_ACCESS_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_ACCESS_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_ACCESS_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_ACCESS_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, resnfs4.status, INDEX_FSAL_access); } ReleaseTokenFSCall(); /* >> convert the returned code, an return it on error << */ if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_access); /* get attributes if object_attributes is not null. * If an error occures during getattr operation, * an error bit is set in the output structure. */ if(object_attributes) { /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(object_attributes, &resnfs4.resarray. resarray_val[FSAL_ACCESS_IDX_OP_GETATTR].nfs_resop4_u. opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_access); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_access); }