int nfs4_op_remove(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_entry_t *parent_entry = NULL; fsal_attrib_list_t attr_parent; fsal_name_t name; cache_inode_status_t cache_status; #ifdef _USE_PNFS pnfs_file_t pnfs_file; #endif char __attribute__ ((__unused__)) funcname[] = "nfs4_op_remove"; resp->resop = NFS4_OP_REMOVE; res_REMOVE4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_NOFILEHANDLE; return res_REMOVE4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_BADHANDLE; return res_REMOVE4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_FHEXPIRED; return res_REMOVE4.status; } /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_ROFS; return res_REMOVE4.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_remove_xattr(op, data, resp); /* Get the parent entry (aka the current one in the compound data) */ parent_entry = data->current_entry; /* We have to keep track of the 'change' file attribute for reply structure */ memset(&(res_REMOVE4.REMOVE4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_REMOVE4.REMOVE4res_u.resok4.cinfo.before = (changeid4) parent_entry->internal_md.mod_time; /* The operation delete object named arg_REMOVE4.target in directory pointed bt cuurentFH */ /* Make sur the currentFH is pointed a directory */ if(data->current_filetype != DIR_BEGINNING && data->current_filetype != DIR_CONTINUE) { res_REMOVE4.status = NFS4ERR_NOTDIR; return res_REMOVE4.status; } /* Check for name length */ if(arg_REMOVE4.target.utf8string_len > FSAL_MAX_NAME_LEN) { res_REMOVE4.status = NFS4ERR_NAMETOOLONG; return res_REMOVE4.status; } /* get the filename from the argument, it should not be empty */ if(arg_REMOVE4.target.utf8string_len == 0) { res_REMOVE4.status = NFS4ERR_INVAL; return res_REMOVE4.status; } /* NFS4_OP_REMOVE can delete files as well as directory, it replaces NFS3_RMDIR and NFS3_REMOVE * because of this, we have to know if object is a directory or not */ if((cache_status = cache_inode_error_convert(FSAL_buffdesc2name ((fsal_buffdesc_t *) & arg_REMOVE4.target, &name))) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } /* Test RM7: remiving '.' should return NFS4ERR_BADNAME */ if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) { res_REMOVE4.status = NFS4ERR_BADNAME; return res_REMOVE4.status; } if((cache_status = cache_inode_remove(parent_entry, &name, &attr_parent, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } /* We have to keep track of the 'change' file attribute for reply structure */ memset(&(res_REMOVE4.REMOVE4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_REMOVE4.REMOVE4res_u.resok4.cinfo.after = (changeid4) parent_entry->internal_md.mod_time; /* Operation was not atomic .... */ res_REMOVE4.REMOVE4res_u.resok4.cinfo.atomic = TRUE; /* If you reach this point, everything was ok */ res_REMOVE4.status = NFS4_OK; return NFS4_OK; } /* nfs4_op_remove */
/** * * cache_inode_lookup_sw: looks up for a name in a directory indicated by a * cached entry. * * Looks up for a name in a directory indicated by a cached entry. The directory * should have been cached before. * * @param pentry_parent [IN] entry for the parent directory to be managed. * @param name [IN] name of the entry that we are looking for in the * cache. * @param pattr [OUT] attributes for the entry that we have found. * @param ht [IN] hash table used for the cache, unused in this * call. * @param pclient [INOUT] ressource allocated by the client for the nfs * management. * @param pcontext [IN] FSAL credentials * @param pstatus [OUT] returned status. * @param use_mutex [IN] if TRUE, mutex management is done, not if equal * to FALSE. * * @return CACHE_INODE_SUCCESS if operation is a success \n * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the * entry * */ cache_entry_t *cache_inode_lookup_sw(cache_entry_t * pentry_parent, fsal_name_t * pname, cache_inode_policy_t policy, fsal_attrib_list_t * pattr, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus, int use_mutex) { cache_inode_dir_entry_t dirent_key[1], *dirent; struct avltree_node *dirent_node; cache_inode_dir_entry_t *new_dir_entry; cache_entry_t *pentry = NULL; fsal_status_t fsal_status; #ifdef _USE_MFSL mfsl_object_t object_handle; #else fsal_handle_t object_handle; #endif fsal_handle_t dir_handle; fsal_attrib_list_t object_attributes; cache_inode_create_arg_t create_arg; cache_inode_file_type_t type; cache_inode_status_t cache_status; cache_inode_fsal_data_t new_entry_fsdata; fsal_accessflags_t access_mask = 0; memset(&create_arg, 0, sizeof(create_arg)); memset( (char *)&new_entry_fsdata, 0, sizeof( new_entry_fsdata ) ) ; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* stats */ (pclient->stat.nb_call_total)++; (pclient->stat.func_stats.nb_call[CACHE_INODE_LOOKUP])++; /* We should not renew entries when !use_mutex (because unless we * make the flag explicit (shared vs. exclusive), we don't know * whether a mutating operation is safe--and, the caller should have * already renewed the entry */ if(use_mutex == TRUE) { P_w(&pentry_parent->lock); cache_status = cache_inode_renew_entry(pentry_parent, pattr, ht, pclient, pcontext, pstatus); if(cache_status != CACHE_INODE_SUCCESS) { V_w(&pentry_parent->lock); inc_func_err_retryable(pclient, CACHE_INODE_GETATTR); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_lookup: returning %d(%s) from cache_inode_renew_entry", *pstatus, cache_inode_err_str(*pstatus)); return NULL; } /* RW Lock goes for writer to reader */ rw_lock_downgrade(&pentry_parent->lock); } if(pentry_parent->internal_md.type != DIRECTORY) { /* Parent is no directory base, return NULL */ *pstatus = CACHE_INODE_NOT_A_DIRECTORY; /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; if(use_mutex == TRUE) V_r(&pentry_parent->lock); return NULL; } /* if name is ".", use the input value */ if(!FSAL_namecmp(pname, (fsal_name_t *) & FSAL_DOT)) { pentry = pentry_parent; } else if(!FSAL_namecmp(pname, (fsal_name_t *) & FSAL_DOT_DOT)) { /* Directory do only have exactly one parent. This a limitation in all FS, * which implies that hard link are forbidden on directories (so that * they exists only in one dir). Because of this, the parent list is * always limited to one element for a dir. Clients SHOULD never * 'lookup( .. )' in something that is no dir. */ pentry = cache_inode_lookupp_no_mutex(pentry_parent, ht, pclient, pcontext, pstatus); } else { /* This is a "regular lookup" (not on "." or "..") */ /* Check is user (as specified by the credentials) is authorized to * lookup the directory or not */ access_mask = FSAL_MODE_MASK_SET(FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR); if(cache_inode_access_no_mutex(pentry_parent, access_mask, ht, pclient, pcontext, pstatus) != CACHE_INODE_SUCCESS) { if(use_mutex == TRUE) V_r(&pentry_parent->lock); (pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_GETATTR])++; return NULL; } /* We first try avltree_lookup by name. If that fails, we dispatch to * the fsal. */ FSAL_namecpy(&dirent_key->name, pname); dirent_node = avltree_lookup(&dirent_key->node_n, &pentry_parent->object.dir.dentries); if (dirent_node) { dirent = avltree_container_of(dirent_node, cache_inode_dir_entry_t, node_n); pentry = dirent->pentry; } if(pentry == NULL) { LogDebug(COMPONENT_CACHE_INODE, "Cache Miss detected"); dir_handle = pentry_parent->handle; object_attributes.asked_attributes = pclient->attrmask; #ifdef _USE_MFSL #ifdef _USE_MFSL_ASYNC if(!mfsl_async_is_object_asynchronous(&pentry_parent->mobject)) { /* If the parent is asynchronous, rely on the content of the cache * inode parent entry. * * /!\ If the fs behind the FSAL is touched in a non-nfs way, * there will be huge incoherencies. */ #endif /* _USE_MFSL_ASYNC */ fsal_status = MFSL_lookup(&pentry_parent->mobject, pname, pcontext, &pclient->mfsl_context, &object_handle, &object_attributes, NULL); #ifdef _USE_MFSL_ASYNC } else { LogMidDebug(COMPONENT_CACHE_INODE, "cache_inode_lookup chose to bypass FSAL and trusted his cache for name=%s", pname->name); fsal_status.major = ERR_FSAL_NOENT; fsal_status.minor = ENOENT; } #endif /* _USE_MFSL_ASYNC */ #else fsal_status = FSAL_lookup(&dir_handle, pname, pcontext, &object_handle, &object_attributes); #endif /* _USE_MFSL */ if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* Stale File Handle to be detected and managed */ if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_lookup: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry_parent, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry_parent, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_pentry_parent: Could not kill entry %p, status = %u", pentry_parent, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } type = cache_inode_fsal_type_convert(object_attributes.type); /* If entry is a symlink, this value for be cached */ if(type == SYMBOLIC_LINK) { if( CACHE_INODE_KEEP_CONTENT( policy ) ) #ifdef _USE_MFSL { fsal_status = MFSL_readlink(&object_handle, pcontext, &pclient->mfsl_context, &create_arg.link_content, &object_attributes, NULL); } #else { fsal_status = FSAL_readlink(&object_handle, pcontext, &create_arg.link_content, &object_attributes); } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* Stale File Handle to be detected and managed */ if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_lookup: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry_parent, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry_parent, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_pentry_parent: Could not kill entry %p, status = %u", pentry_parent, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } } /* Allocation of a new entry in the cache */ #ifdef _USE_MFSL new_entry_fsdata.handle = object_handle.handle; #else new_entry_fsdata.handle = object_handle; #endif new_entry_fsdata.cookie = 0; if((pentry = cache_inode_new_entry( &new_entry_fsdata, &object_attributes, type, policy, &create_arg, NULL, ht, pclient, pcontext, FALSE, /* This is a population and not a creation */ pstatus ) ) == NULL ) { if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } /* Entry was found in the FSAL, add this entry to the parent * directory */ cache_status = cache_inode_add_cached_dirent(pentry_parent, pname, pentry, ht, &new_dir_entry, pclient, pcontext, pstatus); if(cache_status != CACHE_INODE_SUCCESS && cache_status != CACHE_INODE_ENTRY_EXISTS) { if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } } /* cached lookup fail (try fsal) */
int nfs4_op_link(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_link"; cache_entry_t * dir_pentry = NULL; cache_entry_t * file_pentry = NULL; cache_inode_status_t cache_status; fsal_attrib_list_t attr; fsal_name_t newname; resp->resop = NFS4_OP_LINK; res_LINK4.status = NFS4_OK; /* Do basic checks on a filehandle */ res_LINK4.status = nfs4_sanity_check_FH(data, 0LL); if(res_LINK4.status != NFS4_OK) return res_LINK4.status; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->savedFH))) { res_LINK4.status = NFS4ERR_NOFILEHANDLE; return res_LINK4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->savedFH))) { res_LINK4.status = NFS4ERR_BADHANDLE; return res_LINK4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->savedFH))) { res_LINK4.status = NFS4ERR_FHEXPIRED; return res_LINK4.status; } /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_LINK4.status = NFS4ERR_ROFS; return res_LINK4.status; } /* If data->exportp is null, a junction from pseudo fs was traversed, credp and exportp have to be updated */ if(data->pexport == NULL) { res_LINK4.status = nfs4_SetCompoundExport(data); if(res_LINK4.status != NFS4_OK) return res_LINK4.status; } /* * This operation creates a hard link, for the file represented by the saved FH, in directory represented by currentFH under the * name arg_LINK4.target */ /* Crossing device is not allowed */ if(((file_handle_v4_t *) (data->currentFH.nfs_fh4_val))->exportid != ((file_handle_v4_t *) (data->savedFH.nfs_fh4_val))->exportid) { res_LINK4.status = NFS4ERR_XDEV; return res_LINK4.status; } /* If name is empty, return EINVAL */ if(arg_LINK4.newname.utf8string_len == 0) { res_LINK4.status = NFS4ERR_INVAL; return res_LINK4.status; } /* Check for name to long */ if(arg_LINK4.newname.utf8string_len > FSAL_MAX_NAME_LEN) { res_LINK4.status = NFS4ERR_NAMETOOLONG; return res_LINK4.status; } /* Convert the UFT8 objname to a regular string */ if((cache_status = cache_inode_error_convert(FSAL_buffdesc2name ((fsal_buffdesc_t *) & arg_LINK4.newname, &newname))) != CACHE_INODE_SUCCESS) { res_LINK4.status = nfs4_Errno(cache_status); return res_LINK4.status; } /* Sanity check: never create a link named '.' or '..' */ if(!FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT_DOT)) { res_LINK4.status = NFS4ERR_BADNAME; return res_LINK4.status; } /* get info from compound data */ dir_pentry = data->current_entry; /* Destination FH (the currentFH) must be a directory */ if(data->current_filetype != DIRECTORY) { res_LINK4.status = NFS4ERR_NOTDIR; return res_LINK4.status; } /* Target object (the savedFH) must not be a directory */ if(data->saved_filetype == DIRECTORY) { res_LINK4.status = NFS4ERR_ISDIR; return res_LINK4.status; } /* We have to keep track of the 'change' file attribute for reply structure */ if((cache_status = cache_inode_getattr(dir_pentry, &attr, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_LINK4.status = nfs4_Errno(cache_status); return res_LINK4.status; } res_LINK4.LINK4res_u.resok4.cinfo.before = cache_inode_get_changeid4(dir_pentry); /* Convert savedFH into a vnode */ file_pentry = data->saved_entry; /* make the link */ if(cache_inode_link(file_pentry, dir_pentry, &newname, &attr, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_LINK4.status = nfs4_Errno(cache_status); return res_LINK4.status; } res_LINK4.LINK4res_u.resok4.cinfo.after = cache_inode_get_changeid4(dir_pentry); res_LINK4.LINK4res_u.resok4.cinfo.atomic = FALSE; res_LINK4.status = NFS4_OK; return NFS4_OK; } /* nfs4_op_link */
int nfs4_op_lookup(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { fsal_name_t name; char strname[MAXNAMLEN]; #ifndef _NO_XATTRD char objname[MAXNAMLEN]; #endif unsigned int xattr_found = FALSE; cache_entry_t *dir_pentry = NULL; cache_entry_t *file_pentry = NULL; fsal_attrib_list_t attrlookup; cache_inode_status_t cache_status; fsal_handle_t *pfsal_handle = NULL; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lookup"; resp->resop = NFS4_OP_LOOKUP; res_LOOKUP4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_LOOKUP4.status = NFS4ERR_NOFILEHANDLE; return res_LOOKUP4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_LOOKUP4.status = NFS4ERR_BADHANDLE; return res_LOOKUP4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_LOOKUP4.status = NFS4ERR_FHEXPIRED; return res_LOOKUP4.status; } /* Check for empty name */ if(op->nfs_argop4_u.oplookup.objname.utf8string_len == 0 || op->nfs_argop4_u.oplookup.objname.utf8string_val == NULL) { res_LOOKUP4.status = NFS4ERR_INVAL; return res_LOOKUP4.status; } /* Check for name to long */ if(op->nfs_argop4_u.oplookup.objname.utf8string_len > FSAL_MAX_NAME_LEN) { res_LOOKUP4.status = NFS4ERR_NAMETOOLONG; return res_LOOKUP4.status; } /* If Filehandle points to a pseudo fs entry, manage it via pseudofs specific functions */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) return nfs4_op_lookup_pseudo(op, data, resp); #ifndef _NO_XATTRD /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_lookup_xattr(op, data, resp); #endif /* UTF8 strings may not end with \0, but they carry their length */ utf82str(strname, sizeof(strname), &arg_LOOKUP4.objname); #ifndef _NO_XATTRD /* Is this a .xattr.d.<object> name ? */ if(nfs_XattrD_Name(strname, objname)) { strcpy(strname, objname); xattr_found = TRUE; } #endif if((cache_status = cache_inode_error_convert(FSAL_str2name(strname, MAXNAMLEN, &name))) != CACHE_INODE_SUCCESS) { res_LOOKUP4.status = nfs4_Errno(cache_status); return res_LOOKUP4.status; } /* No 'cd .' is allowed return NFS4ERR_BADNAME in this case */ /* No 'cd .. is allowed, return EINVAL in this case. NFS4_OP_LOOKUPP should be use instead */ if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) { res_LOOKUP4.status = NFS4ERR_BADNAME; return res_LOOKUP4.status; } /* Do the lookup in the HPSS Namespace */ file_pentry = NULL; dir_pentry = data->current_entry; /* Sanity check: dir_pentry should be ACTUALLY a directory */ if(dir_pentry->internal_md.type != DIR_BEGINNING && dir_pentry->internal_md.type != DIR_CONTINUE) { /* This is not a directory */ if(dir_pentry->internal_md.type == SYMBOLIC_LINK) res_LOOKUP4.status = NFS4ERR_SYMLINK; else res_LOOKUP4.status = NFS4ERR_NOTDIR; /* Return failed status */ return res_LOOKUP4.status; } /* BUGAZOMEU: Faire la gestion des cross junction traverse */ if((file_pentry = cache_inode_lookup(dir_pentry, &name, &attrlookup, data->ht, data->pclient, data->pcontext, &cache_status)) != NULL) { /* Extract the fsal attributes from the cache inode pentry */ pfsal_handle = cache_inode_get_fsal_handle(file_pentry, &cache_status); if(cache_status != CACHE_INODE_SUCCESS) { res_LOOKUP4.status = NFS4ERR_SERVERFAULT; return res_LOOKUP4.status; } /* Convert it to a file handle */ if(!nfs4_FSALToFhandle(&data->currentFH, pfsal_handle, data)) { res_LOOKUP4.status = NFS4ERR_SERVERFAULT; return res_LOOKUP4.status; } /* Copy this to the mounted on FH (if no junction is traversed */ memcpy((char *)(data->mounted_on_FH.nfs_fh4_val), (char *)(data->currentFH.nfs_fh4_val), data->currentFH.nfs_fh4_len); data->mounted_on_FH.nfs_fh4_len = data->currentFH.nfs_fh4_len; #if 0 print_buff((char *)cache_inode_get_fsal_handle(file_pentry, &cache_status), sizeof(fsal_handle_t)); print_buff((char *)cache_inode_get_fsal_handle(dir_pentry, &cache_status), sizeof(fsal_handle_t)); #endif if(isFullDebug(COMPONENT_NFS_V4)) { LogFullDebug(COMPONENT_NFS_V4, "----> nfs4_op_lookup: name=%s dir_pentry=%p looked up pentry=%p", strname, dir_pentry, file_pentry); LogFullDebug(COMPONENT_NFS_V4, "----> FSAL handle parent puis fils dans nfs4_op_lookup"); print_buff(COMPONENT_NFS_V4, (char *)cache_inode_get_fsal_handle(file_pentry, &cache_status), sizeof(fsal_handle_t)); print_buff(COMPONENT_NFS_V4, (char *)cache_inode_get_fsal_handle(dir_pentry, &cache_status), sizeof(fsal_handle_t)); } LogHandleNFS4("NFS4 LOOKUP CURRENT FH: ", &data->currentFH); /* Keep the pointer within the compound data */ data->current_entry = file_pentry; data->current_filetype = file_pentry->internal_md.type; /* Return successfully */ res_LOOKUP4.status = NFS4_OK; #ifndef _NO_XATTRD /* If this is a xattr ghost directory name, update the FH */ if(xattr_found == TRUE) res_LOOKUP4.status = nfs4_fh_to_xattrfh(&(data->currentFH), &(data->currentFH)); #endif if((data->current_entry->internal_md.type == DIR_BEGINNING) && (data->current_entry->object.dir_begin.referral != NULL)) { if(!nfs4_Set_Fh_Referral(&(data->currentFH))) { res_LOOKUP4.status = NFS4ERR_SERVERFAULT; return res_LOOKUP4.status; } } return NFS4_OK; } /* If the part of the code is reached, then something wrong occured in the lookup process, status is not HPSS_E_NOERROR * and contains the code for the error */ res_LOOKUP4.status = nfs4_Errno(cache_status); return res_LOOKUP4.status; } /* nfs4_op_lookup */
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); }
/** * * cache_inode_readdir_nonamecache: Reads a directory without populating the name cache (no dirents created). * * Reads a directory without populating the name cache (no dirents created). * * @param pentry [IN] entry for the parent directory to be read. * @param cookie [IN] cookie for the readdir operation (basically the offset). * @param nbwanted [IN] Maximum number of directory entries wanted. * @param peod_met [OUT] A flag to know if end of directory was met during this call. * @param dirent_array [OUT] the resulting array of found directory entries. * @param ht [IN] hash table used for the cache, unused in this call. * @param unlock [OUT] the caller shall release read-lock on pentry when done * @param pclient [INOUT] ressource allocated by the client for the nfs management. * @param pcontext [IN] FSAL credentials * @param pstatus [OUT] returned status. * * @return CACHE_INODE_SUCCESS if operation is a success \n * */ static cache_inode_status_t cache_inode_readdir_nonamecache( cache_entry_t * pentry_dir, cache_inode_policy_t policy, uint64_t cookie, unsigned int nbwanted, unsigned int *pnbfound, uint64_t *pend_cookie, cache_inode_endofdir_t *peod_met, cache_inode_dir_entry_t **dirent_array, hash_table_t *ht, int *unlock, cache_inode_client_t *pclient, fsal_op_context_t *pcontext, cache_inode_status_t *pstatus) { fsal_dir_t fsal_dirhandle; fsal_status_t fsal_status; fsal_attrib_list_t dir_attributes; fsal_cookie_t begin_cookie; fsal_cookie_t end_cookie; fsal_count_t iter; fsal_boolean_t fsal_eod; fsal_dirent_t fsal_dirent_array[FSAL_READDIR_SIZE + 20]; cache_inode_fsal_data_t entry_fsdata; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* Only DIRECTORY entries are concerned */ if(pentry_dir->internal_md.type != DIRECTORY) { *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } LogFullDebug(COMPONENT_NFS_READDIR, "About to readdir in cache_inode_readdir_nonamecache: pentry=%p " "cookie=%"PRIu64, pentry_dir, cookie ) ; /* Open the directory */ dir_attributes.asked_attributes = pclient->attrmask; #ifdef _USE_MFSL fsal_status = MFSL_opendir(&pentry_dir->mobject, pcontext, &pclient->mfsl_context, &fsal_dirhandle, &dir_attributes, NULL); #else fsal_status = FSAL_opendir(&pentry_dir->object.dir.handle, pcontext, &fsal_dirhandle, &dir_attributes); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_readdir: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry_dir, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry_dir, WT_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_readdir: Could not kill entry %p, status = %u", pentry_dir, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } return *pstatus; } /* Loop for readding the directory */ // memcpy( &(begin_cookie.data), &cookie, sizeof( uint64_t ) ) ; FSAL_SET_COOKIE_BY_OFFSET( begin_cookie, cookie ) ; fsal_eod = FALSE; #ifdef _USE_MFSL fsal_status = MFSL_readdir( &fsal_dirhandle, begin_cookie, pclient->attrmask, nbwanted * sizeof(fsal_dirent_t), fsal_dirent_array, &end_cookie, (fsal_count_t *)pnbfound, &fsal_eod, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_readdir( &fsal_dirhandle, begin_cookie, pclient->attrmask, nbwanted * sizeof(fsal_dirent_t), fsal_dirent_array, &end_cookie, (fsal_count_t *)pnbfound, &fsal_eod); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); return *pstatus; } for( iter = 0 ; iter < *pnbfound ; iter ++ ) { /* cache_inode_readdir does not return . or .. */ if(!FSAL_namecmp(&(fsal_dirent_array[iter].name), (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&(fsal_dirent_array[iter].name), (fsal_name_t *) & FSAL_DOT_DOT)) continue; /* Get the related pentry without populating the name cache (but eventually populating the attrs cache */ entry_fsdata.handle = fsal_dirent_array[iter].handle; entry_fsdata.cookie = 0; /* XXX needed? */ /* Allocate a dirent to be returned to the client */ /** @todo Make sure this piece of memory once the data are used */ GetFromPool( dirent_array[iter], &pclient->pool_dir_entry, cache_inode_dir_entry_t); if( dirent_array[iter] == NULL ) { *pstatus = CACHE_INODE_MALLOC_ERROR; return *pstatus; } /* fills in the dirent_array */ if( ( dirent_array[iter]->pentry= cache_inode_get( &entry_fsdata, policy, &fsal_dirent_array[iter].attributes, ht, pclient, pcontext, pstatus ) ) == NULL ) return *pstatus ; fsal_status = FSAL_namecpy( &dirent_array[iter]->name, &fsal_dirent_array[iter].name ) ; if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); return *pstatus; } (void) FSAL_cookie_to_uint64( &fsal_dirent_array[iter].handle, pcontext, &fsal_dirent_array[iter].cookie, &dirent_array[iter]->fsal_cookie); dirent_array[iter]->cookie = dirent_array[iter]->fsal_cookie ; } /* for( iter = 0 ; iter < nbfound ; iter ++ ) */ if( fsal_eod == TRUE ) *peod_met = END_OF_DIR ; else *peod_met = TO_BE_CONTINUED ; /* Do not forget to set returned end cookie */ //memcpy( pend_cookie, &(end_cookie.data), sizeof( uint64_t ) ) ; FSAL_SET_POFFSET_BY_COOKIE( end_cookie, pend_cookie ) ; LogFullDebug(COMPONENT_NFS_READDIR, "End of readdir in cache_inode_readdir_nonamecache: pentry=%p " "cookie=%"PRIu64, pentry_dir, *pend_cookie ) ; /* Close the directory */ #ifdef _USE_MFSL fsal_status = MFSL_closedir(&fsal_dirhandle, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_closedir(&fsal_dirhandle); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); return *pstatus; } return CACHE_INODE_SUCCESS ; } /* cache_inode_readdir_nomanecache */
/** * * cache_inode_readdir_populate: fully reads a directory in FSAL and caches * the related entries. * * fully reads a directory in FSAL and caches the related entries. No MT * safety managed here !! * * @param pentry [IN] entry for the parent directory to be read. This must be * a DIRECTORY * @param ht [IN] hash table used for the cache, unused in this call. * @param pclient [INOUT] ressource allocated by the client for the nfs * management. * @param pcontext [IN] FSAL credentials * @param pstatus [OUT] returned status. * */ cache_inode_status_t cache_inode_readdir_populate( cache_entry_t * pentry_dir, cache_inode_policy_t policy, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { fsal_dir_t fsal_dirhandle; fsal_status_t fsal_status; fsal_attrib_list_t dir_attributes; fsal_cookie_t begin_cookie; fsal_cookie_t end_cookie; fsal_count_t nbfound; fsal_count_t iter; fsal_boolean_t fsal_eod; cache_entry_t *pentry = NULL; cache_entry_t *pentry_parent = pentry_dir; fsal_attrib_list_t object_attributes; cache_inode_create_arg_t create_arg; cache_inode_file_type_t type; cache_inode_status_t cache_status; fsal_dirent_t array_dirent[FSAL_READDIR_SIZE + 20]; cache_inode_fsal_data_t new_entry_fsdata; cache_inode_dir_entry_t *new_dir_entry = NULL; uint64_t i = 0; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* Only DIRECTORY entries are concerned */ if(pentry_dir->internal_md.type != DIRECTORY) { *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } #ifdef _USE_MFSL_ASYNC /* If entry is asynchronous (via MFSL), it should not be repopulated until it is synced */ if(MFSL_ASYNC_is_synced(&pentry_dir->mobject) == FALSE) { /* Directory is asynchronous, do not repopulate it and let it * in the state 'has_been_readdir == FALSE' */ *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } #endif /* If directory is already populated , there is no job to do */ if(pentry_dir->object.dir.has_been_readdir == CACHE_INODE_YES) { *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } /* Invalidate all the dirents */ if(cache_inode_invalidate_all_cached_dirent(pentry_dir, ht, pclient, pstatus) != CACHE_INODE_SUCCESS) return *pstatus; /* Open the directory */ dir_attributes.asked_attributes = pclient->attrmask; #ifdef _USE_MFSL fsal_status = MFSL_opendir(&pentry_dir->mobject, pcontext, &pclient->mfsl_context, &fsal_dirhandle, &dir_attributes, NULL); #else fsal_status = FSAL_opendir(&pentry_dir->object.dir.handle, pcontext, &fsal_dirhandle, &dir_attributes); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_readdir: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry_dir, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry_dir, WT_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_readdir: Could not kill entry %p, status = %u", pentry_dir, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } return *pstatus; } /* Loop for readding the directory */ FSAL_SET_COOKIE_BEGINNING(begin_cookie); FSAL_SET_COOKIE_BEGINNING(end_cookie); fsal_eod = FALSE; do { #ifdef _USE_MFSL fsal_status = MFSL_readdir(&fsal_dirhandle, begin_cookie, pclient->attrmask, FSAL_READDIR_SIZE * sizeof(fsal_dirent_t), array_dirent, &end_cookie, &nbfound, &fsal_eod, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_readdir(&fsal_dirhandle, begin_cookie, pclient->attrmask, FSAL_READDIR_SIZE * sizeof(fsal_dirent_t), array_dirent, &end_cookie, &nbfound, &fsal_eod); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); return *pstatus; } for(iter = 0; iter < nbfound; iter++) { LogFullDebug(COMPONENT_NFS_READDIR, "cache readdir populate found entry %s", array_dirent[iter].name.name); /* It is not needed to cache '.' and '..' */ if(!FSAL_namecmp(&(array_dirent[iter].name), (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&(array_dirent[iter].name), (fsal_name_t *) & FSAL_DOT_DOT)) { LogFullDebug(COMPONENT_NFS_READDIR, "cache readdir populate : do not cache . and .."); continue; } /* If dir entry is a symbolic link, its content has to be read */ if((type = cache_inode_fsal_type_convert(array_dirent[iter].attributes.type)) == SYMBOLIC_LINK) { #ifdef _USE_MFSL mfsl_object_t tmp_mfsl; #endif /* Let's read the link for caching its value */ object_attributes.asked_attributes = pclient->attrmask; if( CACHE_INODE_KEEP_CONTENT( pentry_dir->policy ) ) { #ifdef _USE_MFSL tmp_mfsl.handle = array_dirent[iter].handle; fsal_status = MFSL_readlink(&tmp_mfsl, pcontext, &pclient->mfsl_context, &create_arg.link_content, &object_attributes, NULL); #else fsal_status = FSAL_readlink(&array_dirent[iter].handle, pcontext, &create_arg.link_content, &object_attributes); #endif } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_readdir: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry_dir, fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry_dir, WT_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_readdir: Could not kill entry %p, status = %u", pentry_dir, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } return *pstatus; } } /* Try adding the entry, if it exists then this existing entry is returned */ new_entry_fsdata.handle = array_dirent[iter].handle; new_entry_fsdata.cookie = 0; /* XXX needed? */ if((pentry = cache_inode_new_entry( &new_entry_fsdata, &array_dirent[iter].attributes, type, policy, &create_arg, NULL, ht, pclient, pcontext, FALSE, /* This is population and no creation */ pstatus)) == NULL) return *pstatus; cache_status = cache_inode_add_cached_dirent( pentry_parent, &(array_dirent[iter].name), pentry, ht, &new_dir_entry, pclient, pcontext, pstatus); if(cache_status != CACHE_INODE_SUCCESS && cache_status != CACHE_INODE_ENTRY_EXISTS) return *pstatus; /* * Remember the FSAL readdir cookie associated with this dirent. This * is needed for partial directory reads. * * to_uint64 should be a lightweight operation--it is in the current * default implementation. We think the right thing -should- happen * therefore with if _USE_MFSL. * * I'm ignoring the status because the default operation is a memcmp-- * we lready -have- the cookie. */ if (cache_status != CACHE_INODE_ENTRY_EXISTS) { (void) FSAL_cookie_to_uint64(&array_dirent[iter].handle, pcontext, &array_dirent[iter].cookie, &new_dir_entry->fsal_cookie); /* we are filling in all entries, and the cookie avl was * cleared before adding dirents */ new_dir_entry->cookie = i; /* still an offset */ (void) avltree_insert(&new_dir_entry->node_c, &pentry_parent->object.dir.cookies); } /* !exist */ } /* iter */ /* Get prepared for next step */ begin_cookie = end_cookie; /* next offset */ i++; } while(fsal_eod != TRUE); /* Close the directory */ #ifdef _USE_MFSL fsal_status = MFSL_closedir(&fsal_dirhandle, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_closedir(&fsal_dirhandle); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); return *pstatus; } /* End of work */ pentry_dir->object.dir.has_been_readdir = CACHE_INODE_YES; *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } /* cache_inode_readdir_populate */
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 nfs4_op_rename(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_rename"; cache_entry_t * dst_entry = NULL; cache_entry_t * src_entry = NULL; cache_entry_t * tst_entry_dst = NULL; cache_entry_t * tst_entry_src = NULL; fsal_attrib_list_t attr_dst; fsal_attrib_list_t attr_src; fsal_attrib_list_t attr_tst_dst; fsal_attrib_list_t attr_tst_src; cache_inode_status_t cache_status; fsal_status_t fsal_status; fsal_handle_t * handlenew = NULL; fsal_handle_t * handleold = NULL; fsal_name_t oldname; fsal_name_t newname; resp->resop = NFS4_OP_RENAME; res_RENAME4.status = NFS4_OK; /* Do basic checks on a filehandle */ res_RENAME4.status = nfs4_sanity_check_FH(data, 0LL); if(res_RENAME4.status != NFS4_OK) return res_RENAME4.status; /* Do basic checks on saved filehandle */ /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_NOFILEHANDLE; return res_RENAME4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_BADHANDLE; return res_RENAME4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_FHEXPIRED; return res_RENAME4.status; } /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_ROFS; return res_RENAME4.status; } if (nfs_in_grace()) { res_RENAME4.status = NFS4ERR_GRACE; return res_RENAME4.status; } /* get the names from the RPC input */ cache_status = utf8_to_name(&arg_RENAME4.oldname, &oldname); if(cache_status != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); return res_RENAME4.status; } cache_status = utf8_to_name(&arg_RENAME4.newname, &newname); if(cache_status != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); return res_RENAME4.status; } /* Sanuty check: never rename to '.' or '..' */ if(!FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT_DOT)) { res_RENAME4.status = NFS4ERR_BADNAME; return res_RENAME4.status; } /* Sanuty check: never rename to '.' or '..' */ if(!FSAL_namecmp(&oldname, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&oldname, (fsal_name_t *) & FSAL_DOT_DOT)) { res_RENAME4.status = NFS4ERR_BADNAME; return res_RENAME4.status; } /* * This operation renames * - the object in directory pointed by savedFH, named arg_RENAME4.oldname * into * - an object in directory pointed by currentFH, named arg_RENAME4.newname * * Because of this, we will use 2 entry and we have verified both currentFH and savedFH */ /* No Cross Device */ if(((file_handle_v4_t *) (data->currentFH.nfs_fh4_val))->exportid != ((file_handle_v4_t *) (data->savedFH.nfs_fh4_val))->exportid) { res_RENAME4.status = NFS4ERR_XDEV; return res_RENAME4.status; } /* destination must be a directory */ dst_entry = data->current_entry; if(data->current_filetype != DIRECTORY) { res_RENAME4.status = NFS4ERR_NOTDIR; return res_RENAME4.status; } /* Convert saved FH into a vnode */ src_entry = data->saved_entry; /* Source must be a directory */ if(data->saved_filetype != DIRECTORY) { res_RENAME4.status = NFS4ERR_NOTDIR; return res_RENAME4.status; } /* Renaming a file to himself is allowed, returns NFS4_OK */ if(src_entry == dst_entry) { if(!FSAL_namecmp(&oldname, &newname)) { res_RENAME4.status = NFS4_OK; return res_RENAME4.status; } } /* For the change_info4, get the 'change' attributes for both directories */ if((cache_status = cache_inode_getattr(src_entry, &attr_src, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); return res_RENAME4.status; } #ifdef BUGAZOMEU /* Ne devrait pas se produire dans le cas de exportid differents */ /* Both object must resides on the same filesystem, return NFS4ERR_XDEV if not */ if(attr_src.va_rdev != attr_dst.va_rdev) { res_RENAME4.status = NFS4ERR_XDEV; return res_RENAME4.status; } #endif /* Lookup oldfile to see if it exists (refcount +1) */ if((tst_entry_src = cache_inode_lookup(src_entry, &oldname, &attr_tst_src, data->pcontext, &cache_status)) == NULL) { res_RENAME4.status = nfs4_Errno(cache_status); goto release; } /* Lookup file with new name to see if it already exists (refcount +1), * I expect to get NO_ERROR or ENOENT, anything else means an error */ tst_entry_dst = cache_inode_lookup(dst_entry, &newname, &attr_tst_dst, data->pcontext, &cache_status); if((cache_status != CACHE_INODE_SUCCESS) && (cache_status != CACHE_INODE_NOT_FOUND)) { /* Unexpected status at this step, exit with an error */ res_RENAME4.status = nfs4_Errno(cache_status); goto release; } if(cache_status == CACHE_INODE_NOT_FOUND) tst_entry_dst = NULL; /* Just to make sure */ /* Renaming a file to one of its own hardlink is allowed, return NFS4_OK */ if(tst_entry_src == tst_entry_dst) { res_RENAME4.status = NFS4_OK; goto release; } /* Renaming dir into existing file should return NFS4ERR_EXIST */ if ((tst_entry_src->type == DIRECTORY) && ((tst_entry_dst != NULL) && (tst_entry_dst->type == REGULAR_FILE))) { res_RENAME4.status = NFS4ERR_EXIST; goto release; } /* Renaming file into existing dir should return NFS4ERR_EXIST */ if(tst_entry_src->type == REGULAR_FILE) { if(tst_entry_dst != NULL) { if(tst_entry_dst->type == DIRECTORY) { res_RENAME4.status = NFS4ERR_EXIST; goto release; } } } /* Renaming dir1 into existing, nonempty dir2 should return NFS4ERR_EXIST * Renaming file into existing, nonempty dir should return NFS4ERR_EXIST */ if(tst_entry_dst != NULL) { if((tst_entry_dst->type == DIRECTORY) && ((tst_entry_src->type == DIRECTORY) || (tst_entry_src->type == REGULAR_FILE))) { if(cache_inode_is_dir_empty_WithLock(tst_entry_dst) == CACHE_INODE_DIR_NOT_EMPTY) { res_RENAME4.status = NFS4ERR_EXIST; goto release; } } } res_RENAME4.RENAME4res_u.resok4.source_cinfo.before = cache_inode_get_changeid4(src_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.before = cache_inode_get_changeid4(dst_entry); if(cache_status == CACHE_INODE_SUCCESS) { /* New entry already exists, its attributes are in attr_tst_*, check for old entry to see if types are compatible */ handlenew = &tst_entry_dst->handle; handleold = &tst_entry_src->handle; if(!FSAL_handlecmp(handlenew, handleold, &fsal_status)) { /* For the change_info4, get the 'change' attributes for both directories */ res_RENAME4.RENAME4res_u.resok4.source_cinfo.before = cache_inode_get_changeid4(src_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.before = cache_inode_get_changeid4(dst_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.atomic = FALSE; res_RENAME4.RENAME4res_u.resok4.source_cinfo.atomic = FALSE; res_RENAME4.status = NFS4_OK; goto release; } else { /* Destination exists and is something different from source */ if(( tst_entry_src->type == REGULAR_FILE && tst_entry_dst->type == REGULAR_FILE ) || ( tst_entry_src->type == DIRECTORY && tst_entry_dst->type == DIRECTORY )) { if(cache_inode_rename(src_entry, &oldname, dst_entry, &newname, &attr_src, &attr_dst, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); goto release; } } else { res_RENAME4.status = NFS4ERR_EXIST; goto release; } } } else { /* New entry does not already exist, call cache_entry_rename */ if(cache_inode_rename(src_entry, &oldname, dst_entry, &newname, &attr_src, &attr_dst, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); goto release; } } /* If you reach this point, then everything was alright */ /* For the change_info4, get the 'change' attributes for both directories */ res_RENAME4.RENAME4res_u.resok4.source_cinfo.after = cache_inode_get_changeid4(src_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.after = cache_inode_get_changeid4(dst_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.atomic = FALSE; res_RENAME4.RENAME4res_u.resok4.source_cinfo.atomic = FALSE; res_RENAME4.status = nfs4_Errno(cache_status); release: if (tst_entry_src) (void) cache_inode_put(tst_entry_src); if (tst_entry_dst) (void) cache_inode_put(tst_entry_dst); return (res_RENAME4.status); } /* nfs4_op_rename */
int nfs4_op_remove(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_remove"; cache_entry_t * parent_entry = NULL; fsal_attrib_list_t attr_parent; fsal_name_t name; cache_inode_status_t cache_status; resp->resop = NFS4_OP_REMOVE; res_REMOVE4.status = NFS4_OK; /* * Do basic checks on a filehandle * Delete arg_REMOVE4.target in directory pointed by currentFH * Make sure the currentFH is pointed a directory */ res_REMOVE4.status = nfs4_sanity_check_FH(data, DIRECTORY); if(res_REMOVE4.status != NFS4_OK) return res_REMOVE4.status; /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_ROFS; return res_REMOVE4.status; } if (nfs_in_grace()) { res_REMOVE4.status = NFS4ERR_GRACE; return res_REMOVE4.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_remove_xattr(op, data, resp); /* Get the parent entry (aka the current one in the compound data) */ parent_entry = data->current_entry; /* We have to keep track of the 'change' file attribute for reply structure */ memset(&(res_REMOVE4.REMOVE4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_REMOVE4.REMOVE4res_u.resok4.cinfo.before = cache_inode_get_changeid4(parent_entry); /* Check for name length */ if(arg_REMOVE4.target.utf8string_len > FSAL_MAX_NAME_LEN) { res_REMOVE4.status = NFS4ERR_NAMETOOLONG; return res_REMOVE4.status; } /* get the filename from the argument, it should not be empty */ if(arg_REMOVE4.target.utf8string_len == 0) { res_REMOVE4.status = NFS4ERR_INVAL; return res_REMOVE4.status; } /* NFS4_OP_REMOVE can delete files as well as directory, it replaces NFS3_RMDIR and NFS3_REMOVE * because of this, we have to know if object is a directory or not */ if((cache_status = cache_inode_error_convert(FSAL_buffdesc2name ((fsal_buffdesc_t *) & arg_REMOVE4.target, &name))) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } /* Test RM7: remiving '.' should return NFS4ERR_BADNAME */ if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) { res_REMOVE4.status = NFS4ERR_BADNAME; return res_REMOVE4.status; } if((cache_status = cache_inode_remove(parent_entry, &name, &attr_parent, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } res_REMOVE4.REMOVE4res_u.resok4.cinfo.after = cache_inode_get_changeid4(parent_entry); /* Operation was not atomic .... */ res_REMOVE4.REMOVE4res_u.resok4.cinfo.atomic = FALSE; /* If you reach this point, everything was ok */ res_REMOVE4.status = NFS4_OK; return NFS4_OK; } /* nfs4_op_remove */
/** * @brief Get the handle of a file from a fsal_posixdb_child array, knowing its name * * @param p_context * @param p_parent_dir_handle * Handle of the parent directory * @param p_fsalname * Name of the object * @param p_infofs * Information about the file (taken from the filesystem) to be compared to information stored in database * @param p_children * fsal_posixdb_child array (that contains the entries of the directory stored in the db) * @param p_object_handle * Handle of the file. * * @return * ERR_FSAL_NOERR, if no error * Anothere error code else. */ fsal_status_t fsal_internal_getInfoFromChildrenList(posixfsal_op_context_t * p_context, /* IN */ posixfsal_handle_t * p_parent_dir_handle, /* IN */ fsal_name_t * p_fsalname, /* IN */ fsal_posixdb_fileinfo_t * p_infofs, /* IN */ fsal_posixdb_child * p_children, /* IN */ unsigned int children_count, /* IN */ posixfsal_handle_t * p_object_handle) /* OUT */ { fsal_posixdb_status_t stdb; fsal_status_t st; int cmp = -1; /* when no children is available */ unsigned int count; /* sanity check */ if(!p_context || !p_parent_dir_handle || !p_fsalname || (!p_children && children_count) || !p_object_handle) ReturnCode(ERR_FSAL_FAULT, 0); /* check if the filename is in the list */ for(count = 0; count < children_count; count++) { cmp = FSAL_namecmp(p_fsalname, &(p_children[count].name)); if(!cmp) break; /* maybe a sorted list could give better result */ } switch (cmp) { case 0: /* Entry found : check consistency */ if(fsal_posixdb_consistency_check(&(p_children[count].handle.data.info), p_infofs)) { /* Entry not consistent */ /* Delete the Handle entry, then add a new one (with a Parent entry) */ stdb = fsal_posixdb_deleteHandle(p_context->p_conn, &(p_children[count].handle)); if(FSAL_POSIXDB_IS_ERROR(stdb) && FSAL_IS_ERROR(st = posixdb2fsal_error(stdb))) return st; /* don't break, add a new entry */ } else { memcpy(p_object_handle, &(p_children[count].handle), sizeof(posixfsal_handle_t)); break; } default: /* not found ! Add it */ st = fsal_internal_posixdb_add_entry(p_context->p_conn, p_fsalname, p_infofs, p_parent_dir_handle, p_object_handle); if(FSAL_IS_ERROR(st)) return st; } ReturnCode(ERR_FSAL_NO_ERROR, 0); }
int nfs_Rename(nfs_arg_t * parg /* IN */ , exportlist_t * pexport /* IN */ , fsal_op_context_t * pcontext /* IN */ , cache_inode_client_t * pclient /* IN */ , hash_table_t * ht /* INOUT */ , struct svc_req *preq /* IN */ , nfs_res_t * pres /* OUT */ ) { static char __attribute__ ((__unused__)) funcName[] = "nfs_Rename"; char *str_entry_name = NULL; fsal_name_t entry_name; char *str_new_entry_name = NULL; fsal_name_t new_entry_name; cache_entry_t *pentry = NULL; cache_entry_t *new_pentry = NULL; cache_entry_t *parent_pentry = NULL; cache_entry_t *new_parent_pentry = NULL; cache_entry_t *should_not_exists = NULL; cache_entry_t *should_exists = NULL; cache_inode_status_t cache_status; int rc; fsal_attrib_list_t *ppre_attr; fsal_attrib_list_t pre_attr; fsal_attrib_list_t *pnew_pre_attr; fsal_attrib_list_t new_attr; fsal_attrib_list_t new_parent_attr; fsal_attrib_list_t attr; fsal_attrib_list_t tst_attr; cache_inode_file_type_t parent_filetype; cache_inode_file_type_t new_parent_filetype; if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.before.attributes_follow = FALSE; pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.after.attributes_follow = FALSE; pres->res_rename3.RENAME3res_u.resfail.todir_wcc.before.attributes_follow = FALSE; pres->res_rename3.RENAME3res_u.resfail.todir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; pnew_pre_attr = NULL; } /* Convert fromdir file handle into a cache_entry */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_rename2.from.dir), &(parg->arg_rename3.from.dir), NULL, &(pres->res_dirop2.status), &(pres->res_create3.status), NULL, &pre_attr, pcontext, pclient, ht, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* Convert todir file handle into a cache_entry */ if((new_parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_rename2.to.dir), &(parg->arg_rename3.to.dir), NULL, &(pres->res_dirop2.status), &(pres->res_create3.status), NULL, &new_parent_attr, pcontext, pclient, ht, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* get the attr pointers */ ppre_attr = &pre_attr; pnew_pre_attr = &new_parent_attr; /* Get the filetypes */ parent_filetype = cache_inode_fsal_type_convert(pre_attr.type); new_parent_filetype = cache_inode_fsal_type_convert(new_parent_attr.type); /* * Sanity checks: we must manage directories */ if((parent_filetype != DIR_BEGINNING && parent_filetype != DIR_CONTINUE) || (new_parent_filetype != DIR_BEGINNING && new_parent_filetype != DIR_CONTINUE)) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_NOTDIR; break; case NFS_V3: pres->res_rename3.status = NFS3ERR_NOTDIR; break; } return NFS_REQ_OK; } switch (preq->rq_vers) { case NFS_V2: str_entry_name = parg->arg_rename2.from.name; str_new_entry_name = parg->arg_rename2.to.name; break; case NFS_V3: str_entry_name = parg->arg_rename3.from.name; str_new_entry_name = parg->arg_rename3.to.name; break; } pentry = new_pentry = NULL; if(str_entry_name == NULL || strlen(str_entry_name) == 0 || str_new_entry_name == NULL || strlen(str_new_entry_name) == 0 || FSAL_IS_ERROR(FSAL_str2name(str_entry_name, FSAL_MAX_NAME_LEN, &entry_name)) || FSAL_IS_ERROR(FSAL_str2name(str_new_entry_name, FSAL_MAX_NAME_LEN, &new_entry_name))) { cache_status = CACHE_INODE_INVALID_ARGUMENT; } else { /* * Lookup file to see if new entry exists * */ should_not_exists = cache_inode_lookup(new_parent_pentry, &new_entry_name, &tst_attr, ht, pclient, pcontext, &cache_status); if(cache_status == CACHE_INODE_NOT_FOUND) { /* We need to lookup over the old entry also */ should_exists = cache_inode_lookup(parent_pentry, &entry_name, &tst_attr, ht, pclient, pcontext, &cache_status); /* Rename entry */ if(cache_status == CACHE_INODE_SUCCESS) cache_inode_rename(parent_pentry, &entry_name, new_parent_pentry, &new_entry_name, &attr, &new_attr, ht, pclient, pcontext, &cache_status); if(cache_status == CACHE_INODE_SUCCESS) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* * Build Weak Cache Coherency * data */ nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc)); nfs_SetWccData(pcontext, pexport, new_parent_pentry, pnew_pre_attr, &new_attr, &(pres->res_rename3.RENAME3res_u.resok.todir_wcc)); pres->res_rename3.status = NFS3_OK; break; } return NFS_REQ_OK; } } else { /* If name are the same (basically renaming a/file1 to a/file1, this is a non-erroneous situation to be managed */ if(new_parent_pentry == parent_pentry) { if(!FSAL_namecmp(&new_entry_name, &entry_name)) { /* trying to rename a file to himself, this is allowed */ cache_status = CACHE_INODE_SUCCESS; switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* * Build Weak Cache Coherency * data */ nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc)); nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok.todir_wcc)); pres->res_rename3.status = NFS3_OK; break; } return NFS_REQ_OK; } } /* New entry already exists. In this case (see RFC), entry should be compatible: Both are non-directories or * both are directories and 'todir' is empty. If compatible, old 'todir' entry is scratched, if not returns EEXISTS */ if(should_not_exists != NULL) { /* We need to lookup over the old entry also */ if((should_exists = cache_inode_lookup(parent_pentry, &entry_name, &tst_attr, ht, pclient, pcontext, &cache_status)) != NULL) { if(cache_inode_type_are_rename_compatible (should_exists, should_not_exists)) { /* Remove the old entry before renaming it */ if(cache_inode_remove(new_parent_pentry, &new_entry_name, &tst_attr, ht, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { if(cache_inode_rename(parent_pentry, &entry_name, new_parent_pentry, &new_entry_name, &attr, &new_attr, ht, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { /* trying to rename a file to himself, this is allowed */ switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* * Build Weak Cache Coherency * data */ nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok. fromdir_wcc)); nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok. todir_wcc)); pres->res_rename3.status = NFS3_OK; break; } return NFS_REQ_OK; } } } } /* if( cache_inode_type_are_rename_compatible( should_exists, should_not_exists ) ) */ } /* if( ( should_exists = cache_inode_lookup( parent_pentry, .... */ /* If this point is reached, then destination object already exists with that name in the directory and types are not compatible, we should return that the file exists */ cache_status = CACHE_INODE_ENTRY_EXISTS; } /* if( should_not_exists != NULL ) */ } /* If we are here, there was an error */ if(nfs_RetryableError(cache_status)) { return NFS_REQ_DROP; } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_stat2, &pres->res_rename3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc), new_parent_pentry, pnew_pre_attr, &(pres->res_rename3.RENAME3res_u.resfail.todir_wcc)); return NFS_REQ_OK; } /* nfs_Rename */