int pnfs_ds_unlink_file(pnfs_client_t * pnfsclient, pnfs_ds_file_t * pfile) { component4 name; char nameval[MAXNAMLEN]; char filename[MAXNAMLEN]; unsigned int i; int rc = 0; if(!pnfsclient || !pfile) return NFS4ERR_SERVERFAULT; name.utf8string_val = nameval; name.utf8string_len = 0; snprintf(filename, MAXNAMLEN, "%s", pfile->location.str_mds_handle); if(str2utf8(filename, &name) == -1) return NFS4ERR_SERVERFAULT; for(i = 0; i < pnfsclient->nb_ds; i++) { if((rc = pnfs_unlink_ds_partfile(&(pnfsclient->ds_client[i]), name, &(pfile->filepart[i]))) != NFS4_OK) return rc; } return NFS4_OK; } /* pnfs_ds_unlink_file */
int fsal_internal_proxy_fsal_path_2_utf8(fsal_path_t * ppath, utf8string * utf8str) { char tmpstr[FSAL_MAX_PATH_LEN]; fsal_status_t fsal_status; if(ppath == NULL || utf8str == NULL) return FALSE; fsal_status = FSAL_path2str(ppath, tmpstr, FSAL_MAX_NAME_LEN); if(fsal_status.major != ERR_FSAL_NO_ERROR) return FALSE; if(utf8str->utf8string_len == 0) { if((utf8str->utf8string_val = gsh_malloc(ppath->len)) == NULL) return FALSE; else utf8str->utf8string_len = ppath->len; } if(str2utf8(tmpstr, utf8str) == -1) return FALSE; return TRUE; } /* fsal_internal_proxy_fsal_path_2_utf8 */
int fsal_internal_proxy_fsal_name_2_utf8(fsal_name_t * pname, utf8string * utf8str) { char tmpstr[FSAL_MAX_NAME_LEN]; fsal_status_t fsal_status; if(pname == NULL || utf8str == NULL) return FALSE; fsal_status = FSAL_name2str(pname, tmpstr, FSAL_MAX_NAME_LEN); if(fsal_status.major != ERR_FSAL_NO_ERROR) return FALSE; if(utf8str->utf8string_len == 0) { if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(pname->len, "fsal_internal_proxy_fsal_name_2_utf8")) == NULL) return FALSE; else utf8str->utf8string_len = pname->len; } if(str2utf8(tmpstr, utf8str) == -1) return FALSE; return TRUE; } /* fsal_internal_proxy_fsal_name_2_utf8 */
void PR(){ pair * p; tagged * t; obj y = TOS(); if (AFIX(y)) printf ("%ld", OBJ2FIX(y)); else if (ACHAR(y)){ char * utf8 = cpt2utf8(OBJ2CHAR(y)); printf ("%s", utf8); free(utf8); } else if (ASYM(y)) printf ("%s", ((symbol *)y)->value); else if (AFLOAT(y)) printf ("%g", ((flonum*)y)->value); else if (ASTR(y)) printf ("%s", str2utf8 ((string *) y)); else if (AFN(y)) printf ("#<procedure>"); else if (ATBL(y)) pr_tbl((table *) y); else if (ATAG(y)){ t = (tagged *) y; printf ("#3(tagged "); PUSH(t->ctype); PR(); printf (" "); TOS() = t->content; PR(); sp--; printf (")"); } else if (APAIR(y)){ printf ("("); while (APAIR(y)){ p = (pair *) y; PUSH(p->car); PR(); sp--; y = p->cdr; if (APAIR(y)) printf (" "); } if (y != SYM2OBJ("nil")){ PUSH(y); printf (" . "); PR(); sp--; } printf (")"); } }
/** * * gid2utf8: converts a gid to a utf8 string descriptor. * * Converts a gid to a utf8 string descriptor. * * @param gid [IN] the input gid * @param utf8str [OUT] computed UTF8 string descriptor * * @return the length of the utf8 buffer if succesfull, -1 if failed * */ int gid2utf8(gid_t gid, utf8string * utf8str) { char buff[NFS4_MAX_DOMAIN_LEN]; unsigned int len = 0; if(gid2str(gid, buff) == -1) return -1; len = strlen(buff); /* A matching gid was found */ /* Do the conversion to uft8 format */ if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "gid2utf8")) == NULL) return -1; else utf8str->utf8string_len = len; return str2utf8(buff, utf8str); } /* gid2utf8 */
/** * * uid2utf8: converts a uid to a utf8 string descriptor. * * Converts a uid to a utf8 string descriptor. * * @param uid [IN] the input uid * @param utf8str [OUT] computed UTF8 string descriptor * * @return the length of the utf8 buffer if succesfull, -1 if failed * */ int uid2utf8(uid_t uid, utf8string * utf8str) { char buff[NFS4_MAX_DOMAIN_LEN]; unsigned int len = 0; if(uid2str(uid, buff) == -1) return -1; len = strlen(buff); /* A matching uid was found, now do the conversion to utf8 */ if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "uid2utf8")) == NULL) return -1; else utf8str->utf8string_len = len; return str2utf8(buff, utf8str); } /* uid2utf8 */
int pnfs_ds_create_file(pnfs_client_t * pnfsclient, pnfs_ds_loc_t * plocation, pnfs_ds_file_t * pfile) { component4 name; char nameval[MAXNAMLEN]; char filename[MAXNAMLEN]; int rc; unsigned int i = 0; if(!pnfsclient || !pfile || !plocation) return NFS4ERR_SERVERFAULT; name.utf8string_val = nameval; name.utf8string_len = 0; snprintf(filename, MAXNAMLEN, "%s", plocation->str_mds_handle ) ; if(str2utf8(filename, &name) == -1) return NFS4ERR_SERVERFAULT; for(i = 0; i < pnfsclient->nb_ds; i++) { if((rc = pnfs_create_ds_partfile(&(pnfsclient->ds_client[i]), name, plocation, &(pfile->filepart[i]))) != NFS4_OK) return rc; } /* for */ strncpy ( pfile->location.str_mds_handle, plocation->str_mds_handle, MAXNAMLEN ) ; pfile->allocated = TRUE; pfile->stripe = pnfsclient->nb_ds; return NFS4_OK; } /* pnfs_ds_create_file */
/** * nfs4_op_readdir: The NFS4_OP_READDIR. * * Implements the NFS4_OP_READDIR. If fh is a pseudo FH, then call is routed to routine nfs4_op_readdir_pseudo * * @param op [IN] pointer to nfs4_op arguments * @param data [INOUT] Pointer to the compound request's data * @param resp [IN] Pointer to nfs4_op results * * @return NFS4_OK if ok, any other value show an error. * */ int nfs4_op_readdir(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_entry_t *dir_pentry = NULL; cache_entry_t *pentry = NULL; cache_inode_endofdir_t eod_met; fsal_attrib_list_t attrlookup; cache_inode_status_t cache_status; cache_inode_status_t cache_status_attr; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readdir"; unsigned long dircount; unsigned long maxcount; entry4 *entry_nfs_array; cache_inode_dir_entry_t **dirent_array = NULL; verifier4 cookie_verifier; uint64_t cookie = 0; uint64_t end_cookie = 0; fsal_handle_t *entry_FSALhandle; nfs_fh4 entryFH; char val_fh[NFS4_FHSIZE]; entry_name_array_item_t *entry_name_array = NULL; unsigned int estimated_num_entries; unsigned int num_entries; int dir_pentry_unlock = FALSE; unsigned int i = 0; unsigned int outbuffsize = 0 ; unsigned int entrysize = 0 ; bitmap4 RdAttrErrorBitmap = { 1, (uint32_t *) "\0\0\0\b" }; /* 0xB = 11 = FATTR4_RDATTR_ERROR */ attrlist4 RdAttrErrorVals = { 0, NULL }; /* Nothing to be seen here */ resp->resop = NFS4_OP_READDIR; res_READDIR4.status = NFS4_OK; entryFH.nfs_fh4_len = 0; entryFH.nfs_fh4_val = val_fh; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_READDIR4.status = NFS4ERR_NOFILEHANDLE; return res_READDIR4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_READDIR4.status = NFS4ERR_BADHANDLE; return res_READDIR4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_READDIR4.status = NFS4ERR_FHEXPIRED; return res_READDIR4.status; } /* Pseudo Fs management */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) return nfs4_op_readdir_pseudo(op, data, resp); /* Xattrs management */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_readdir_xattr(op, data, resp); /* You can readdir only within a directory */ dir_pentry = data->current_entry; if(data->current_filetype != DIRECTORY) { res_READDIR4.status = NFS4ERR_NOTDIR; return res_READDIR4.status; } /* get the characteristic value for readdir operation */ dircount = arg_READDIR4.dircount; maxcount = arg_READDIR4.maxcount*0.9; cookie = (unsigned int)arg_READDIR4.cookie; /* dircount is considered meaningless by many nfsv4 client (like the CITI * one). we use maxcount instead. */ /* the Linux 3.0, 3.1.0 clients vs. TCP Ganesha comes out 10x slower * with 500 max entries */ #if 0 /* takes 2s to return 2999 entries */ estimated_num_entries = maxcount / sizeof(entry4); #else /* takes 20s to return 2999 entries */ estimated_num_entries = 50; #endif LogFullDebug(COMPONENT_NFS_V4, "--- nfs4_op_readdir ---> dircount=%lu maxcount=%lu arg_cookie=%" PRIu64" cookie=%"PRIu64" estimated_num_entries=%u", dircount, maxcount, arg_READDIR4.cookie, cookie, estimated_num_entries); /* Do not use a cookie of 1 or 2 (reserved values) */ if(cookie == 1 || cookie == 2) { res_READDIR4.status = NFS4ERR_BAD_COOKIE; return res_READDIR4.status; } /* Get only attributes that are allowed to be read */ if(!nfs4_Fattr_Check_Access_Bitmap(&arg_READDIR4.attr_request, FATTR4_ATTR_READ)) { res_READDIR4.status = NFS4ERR_INVAL; return res_READDIR4.status; } /* If maxcount is too short, return NFS4ERR_TOOSMALL */ if(maxcount < sizeof(entry4) || estimated_num_entries == 0) { res_READDIR4.status = NFS4ERR_TOOSMALL; return res_READDIR4.status; } /* * If cookie verifier is used, then an non-trivial value is * returned to the client This value is the mtime of * the pentry. If verifier is unused (as in many NFS * Servers) then only a set of zeros is returned (trivial * value) */ memset(cookie_verifier, 0, NFS4_VERIFIER_SIZE); if(data->pexport->UseCookieVerifier == 1) memcpy(cookie_verifier, &dir_pentry->internal_md.mod_time, sizeof(time_t)); /* Cookie delivered by the server and used by the client SHOULD not ne 0, 1 or 2 (cf RFC3530, page192) * because theses value are reserved for special use. * 0 - cookie for first READDIR * 1 - reserved for . on client handside * 2 - reserved for .. on client handside * Entries '.' and '..' are not returned also * For these reason, there will be an offset of 3 between NFS4 cookie and * HPSS cookie */ if((cookie != 0) && (data->pexport->UseCookieVerifier == 1)) { if(memcmp(cookie_verifier, arg_READDIR4.cookieverf, NFS4_VERIFIER_SIZE) != 0) { res_READDIR4.status = NFS4ERR_BAD_COOKIE; return res_READDIR4.status; } } /* The default behaviour is to consider that eof is not reached, the * returned values by cache_inode_readdir will let us know if eod was * reached or not */ res_READDIR4.READDIR4res_u.resok4.reply.eof = FALSE; /* Get prepared for readdir */ if((dirent_array = (cache_inode_dir_entry_t **) Mem_Alloc( estimated_num_entries * sizeof(cache_inode_dir_entry_t*))) == NULL) { res_READDIR4.status = NFS4ERR_SERVERFAULT; goto out; } /* Perform the readdir operation */ if(cache_inode_readdir(dir_pentry, data->pexport->cache_inode_policy, cookie, estimated_num_entries, &num_entries, &end_cookie, &eod_met, dirent_array, data->ht, &dir_pentry_unlock, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_READDIR4.status = nfs4_Errno(cache_status); goto out; } /* For an empty directory, we will find only . and .., so reply as if the * end is reached */ if(num_entries == 0) { /* only . and .. */ res_READDIR4.READDIR4res_u.resok4.reply.entries = NULL; res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE; memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, NFS4_VERIFIER_SIZE); } else { /* Start computing the outbuffsize */ outbuffsize = sizeof( bool_t) /* eof */ + sizeof( nfsstat4 ) /* READDIR4res::status */ + NFS4_VERIFIER_SIZE /* cookie verifier */ ; /* Allocation of reply structures */ if((entry_name_array = (entry_name_array_item_t *) Mem_Alloc(num_entries * (FSAL_MAX_NAME_LEN + 1))) == NULL) { LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno); res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } memset((char *)entry_name_array, 0, num_entries * (FSAL_MAX_NAME_LEN + 1)); if((entry_nfs_array = (entry4 *) Mem_Alloc(num_entries * sizeof(entry4))) == NULL) { LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno); res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } memset((char *)entry_nfs_array, 0, num_entries * sizeof(entry4)); for(i = 0; i < num_entries; i++) { entry_nfs_array[i].name.utf8string_val = entry_name_array[i]; if(str2utf8(dirent_array[i]->name.name, &entry_nfs_array[i].name) == -1) { res_READDIR4.status = NFS4ERR_SERVERFAULT; goto out; } /* Set the cookie value */ entry_nfs_array[i].cookie = dirent_array[i]->cookie; /* Get the pentry for the object's attributes and filehandle */ if( ( pentry = cache_inode_lookup_no_mutex( dir_pentry, &dirent_array[i]->name, data->pexport->cache_inode_policy, &attrlookup, data->ht, data->pclient, data->pcontext, &cache_status ) ) == NULL ) { Mem_Free((char *)entry_nfs_array); /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */ entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap; entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals; res_READDIR4.status = NFS4ERR_SERVERFAULT; goto out; } /* If file handle is asked in the attributes, provide it */ if(arg_READDIR4.attr_request.bitmap4_val != NULL && (arg_READDIR4.attr_request.bitmap4_val[0] & FATTR4_FILEHANDLE)) { if((entry_FSALhandle = cache_inode_get_fsal_handle(pentry, &cache_status_attr)) == NULL) { /* Faulty Handle or pentry */ Mem_Free((char *)entry_nfs_array); res_READDIR4.status = NFS4ERR_SERVERFAULT; goto out; } if(!nfs4_FSALToFhandle(&entryFH, entry_FSALhandle, data)) { /* Faulty type */ Mem_Free((char *)entry_nfs_array); res_READDIR4.status = NFS4ERR_SERVERFAULT; goto out; } } if(nfs4_FSALattr_To_Fattr(data->pexport, &attrlookup, &(entry_nfs_array[i].attrs), data, &entryFH, &(arg_READDIR4.attr_request)) != 0) { /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */ entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap; entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals; } /* Update the size of the output buffer */ entrysize = sizeof( nfs_cookie4 ) ; /* nfs_cookie4 */ entrysize += sizeof( u_int ) ; /* pathname4::utf8strings_len */ entrysize += entry_nfs_array[i].name.utf8string_len ; entrysize += sizeof( u_int ) ; /* bitmap4_len */ entrysize += entry_nfs_array[i].attrs.attrmask.bitmap4_len ; entrysize += sizeof( u_int ) ; /* attrlist4_len */ entrysize += entry_nfs_array[i].attrs.attr_vals.attrlist4_len ; entrysize += sizeof( caddr_t ) ; outbuffsize += entrysize; LogFullDebug(COMPONENT_NFS_V4, " === nfs4_op_readdir ===> i=%u name=%s cookie=%"PRIu64" " "entrysize=%u buffsize=%u", i, dirent_array[i]->name.name, entry_nfs_array[i].cookie, entrysize, outbuffsize); /* Chain the entries together */ entry_nfs_array[i].nextentry = NULL; if(i != 0) { if( outbuffsize < maxcount ) entry_nfs_array[i - 1].nextentry = &(entry_nfs_array[i]); else { LogFullDebug(COMPONENT_NFS_V4, "=== nfs4_op_readdir ===> " "maxcount reached at %u entries name=%s " "cookie=%llu " "buffsize=%u (return early)", i+1, dirent_array[i]->name.name, (unsigned long long)entry_nfs_array[i].cookie, outbuffsize); entry_nfs_array[i - 1].nextentry = NULL ; break ; } } } /* for i */ if((i == num_entries) && (eod_met == END_OF_DIR)) { LogFullDebug(COMPONENT_NFS_V4, "End of directory reached: num_entries=%d i=%d", num_entries, i); /* This is the end of the directory */ res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE; memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, NFS4_VERIFIER_SIZE); } /* Put the entry's list in the READDIR reply */ res_READDIR4.READDIR4res_u.resok4.reply.entries = entry_nfs_array; } /* Do not forget to set the verifier */ memcpy((char *)res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, NFS4_VERIFIER_SIZE); res_READDIR4.status = NFS4_OK; out: /* release read lock on dir_pentry, if requested */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if (dirent_array) { if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, data->pclient ) ; Mem_Free((char *)dirent_array); } return res_READDIR4.status; } /* nfs4_op_readdir */
int nfs4_op_readlink(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_inode_status_t cache_status; fsal_path_t symlink_path; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readlink"; resp->resop = NFS4_OP_READLINK; res_READLINK4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_NOFILEHANDLE; return NFS4ERR_NOFILEHANDLE; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_BADHANDLE; return NFS4ERR_BADHANDLE; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_FHEXPIRED; return NFS4ERR_FHEXPIRED; } /* You can readlink only on a link ... */ if(data->current_filetype != SYMBOLIC_LINK) { /* As said on page 194 of RFC3530, return NFS4ERR_INVAL in this case */ res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } /* Using cache_inode_readlink */ if(cache_inode_readlink(data->current_entry, &symlink_path, data->ht, data->pclient, data->pcontext, &cache_status) == CACHE_INODE_SUCCESS) { /* Alloc read link */ if((res_READLINK4.READLINK4res_u.resok4.link.utf8string_val = (char *)Mem_Alloc_Label(symlink_path.len, "nfs4_op_readlink")) == NULL) { res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } /* convert the fsal path to a utf8 string */ if(str2utf8((char *)symlink_path.path, &res_READLINK4.READLINK4res_u.resok4.link) == -1) { res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } res_READLINK4.status = NFS4_OK; return res_READLINK4.status; } res_READLINK4.status = nfs4_Errno(cache_status); return res_READLINK4.status; } /* nfs4_op_readlink */
/** * nfs4_op_readdir: The NFS4_OP_READDIR. * * Implements the NFS4_OP_READDIR. If fh is a pseudo FH, then call is routed to routine nfs4_op_readdir_pseudo * * @param op [IN] pointer to nfs4_op arguments * @param data [INOUT] Pointer to the compound request's data * @param resp [IN] Pointer to nfs4_op results * * @return NFS4_OK if ok, any other value show an error. * */ int nfs4_op_readdir(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_entry_t *dir_pentry = NULL; cache_entry_t *pentry = NULL; cache_inode_endofdir_t eod_met; fsal_attrib_list_t attrlookup; cache_inode_status_t cache_status; cache_inode_status_t cache_status_attr; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readdir"; unsigned long dircount; unsigned long maxcount; entry4 *entry_nfs_array; cache_inode_dir_entry_t *dirent_array; verifier4 cookie_verifier; unsigned int cookie = 0; unsigned int end_cookie = 0; unsigned int *cookie_array; fsal_handle_t *entry_FSALhandle; nfs_fh4 entryFH; char val_fh[NFS4_FHSIZE]; entry_name_array_item_t *entry_name_array; unsigned long space_used; unsigned int estimated_num_entries; unsigned int num_entries; unsigned int i = 0; bitmap4 RdAttrErrorBitmap; attrlist4 RdAttrErrorVals; resp->resop = NFS4_OP_READDIR; res_READDIR4.status = NFS4_OK; entryFH.nfs_fh4_len = 0; entryFH.nfs_fh4_val = val_fh; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_READDIR4.status = NFS4ERR_NOFILEHANDLE; return res_READDIR4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_READDIR4.status = NFS4ERR_BADHANDLE; return res_READDIR4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_READDIR4.status = NFS4ERR_FHEXPIRED; return res_READDIR4.status; } /* Pseudo Fs management */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) return nfs4_op_readdir_pseudo(op, data, resp); /* Xattrs management */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_readdir_xattr(op, data, resp); /* You can readdir only within a directory */ dir_pentry = data->current_entry; if(data->current_filetype != DIR_BEGINNING && data->current_filetype != DIR_CONTINUE) { res_READDIR4.status = NFS4ERR_NOTDIR; return res_READDIR4.status; } /* get the caracteristic value for readdir operation */ dircount = arg_READDIR4.dircount; maxcount = arg_READDIR4.maxcount; cookie = (unsigned int)arg_READDIR4.cookie; space_used = sizeof(entry4); /* dircount is considered meaningless by many nfsv4 client (like the CITI one). we use maxcount instead */ estimated_num_entries = maxcount / sizeof(entry4); /* Estimated_num_entries is probably far too big */ LogFullDebug(COMPONENT_NFS_V4, "--- nfs4_op_readdir ---> dircount=%u maxcount=%u arg_cookie=%llu cookie=%d estimated_num_entries=%u\n", dircount, maxcount, arg_READDIR4.cookie, cookie, estimated_num_entries); /* Do not use a cookie of 1 or 2 (reserved values) */ if(cookie == 1 || cookie == 2) { res_READDIR4.status = NFS4ERR_BAD_COOKIE; return res_READDIR4.status; } if(cookie != 0) cookie = cookie - 2; /* 0,1 and 2 are reserved, there is a delta of '3' because of this */ /* Get only attributes that are allowed to be read */ if(!nfs4_Fattr_Check_Access_Bitmap(&arg_READDIR4.attr_request, FATTR4_ATTR_READ)) { res_READDIR4.status = NFS4ERR_INVAL; return res_READDIR4.status; } /* If maxcount is too short, return NFS4ERR_TOOSMALL */ if(maxcount < sizeof(entry4) || estimated_num_entries == 0) { res_READDIR4.status = NFS4ERR_TOOSMALL; return res_READDIR4.status; } /* * If cookie verifier is used, then an non-trivial value is * returned to the client This value is the mtime of * the pentry. If verifier is unused (as in many NFS * Servers) then only a set of zeros is returned (trivial * value) */ memset(cookie_verifier, 0, NFS4_VERIFIER_SIZE); if(data->pexport->UseCookieVerifier == 1) memcpy(cookie_verifier, &dir_pentry->internal_md.mod_time, sizeof(time_t)); /* Cookie delivered by the server and used by the client SHOULD not ne 0, 1 or 2 (cf RFC3530, page192) * because theses value are reserved for special use. * 0 - cookie for first READDIR * 1 - reserved for . on client handside * 2 - reserved for .. on client handside * Entries '.' and '..' are not returned also * For these reason, there will be an offset of 3 between NFS4 cookie and HPSS cookie */ if((cookie != 0) && (data->pexport->UseCookieVerifier == 1)) { if(memcmp(cookie_verifier, arg_READDIR4.cookieverf, NFS4_VERIFIER_SIZE) != 0) { res_READDIR4.status = NFS4ERR_BAD_COOKIE; return res_READDIR4.status; } } /* The default behaviour is to consider that eof is not reached, the returned values by cache_inode_readdir * will let us know if eod was reached or not */ res_READDIR4.READDIR4res_u.resok4.reply.eof = FALSE; /* Get prepared for readdir */ if((dirent_array = (cache_inode_dir_entry_t *) Mem_Alloc(estimated_num_entries * sizeof(cache_inode_dir_entry_t))) == NULL) { res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } if((cookie_array = (unsigned int *)Mem_Alloc(estimated_num_entries * sizeof(unsigned int))) == NULL) { Mem_Free((char *)dirent_array); res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } /* Perform the readdir operation */ if(cache_inode_readdir(dir_pentry, cookie, estimated_num_entries, &num_entries, &end_cookie, &eod_met, dirent_array, cookie_array, data->ht, data->pclient, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_READDIR4.status = nfs4_Errno(cache_status); return res_READDIR4.status; } /* For an empty directory, we will find only . and .., so reply af if the end if reached */ if(num_entries == 0) { /* only . and .. */ res_READDIR4.READDIR4res_u.resok4.reply.entries = NULL; res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE; memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, NFS4_VERIFIER_SIZE); } else { /* Allocation of reply structures */ if((entry_name_array = (entry_name_array_item_t *) Mem_Alloc(num_entries * (FSAL_MAX_NAME_LEN + 1))) == NULL) { LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno); res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } memset((char *)entry_name_array, 0, num_entries * (FSAL_MAX_NAME_LEN + 1)); if((entry_nfs_array = (entry4 *) Mem_Alloc(num_entries * sizeof(entry4))) == NULL) { LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno); res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } for(i = 0; i < num_entries; i++) { entry_nfs_array[i].name.utf8string_val = entry_name_array[i]; if(str2utf8(dirent_array[i].name.name, &entry_nfs_array[i].name) == -1) { res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } /* Set the cookie value */ if(i != num_entries - 1) entry_nfs_array[i].cookie = cookie_array[i + 1] + 2; /* 0, 1 and 2 are reserved */ else entry_nfs_array[i].cookie = end_cookie + 2; LogFullDebug(COMPONENT_NFS_V4, " === nfs4_op_readdir ===> i=%d name=%s cookie=%llu\n", i, dirent_array[i].name.name, entry_nfs_array[i].cookie); /* Get the pentry for the object's attributes and filehandle */ if((pentry = cache_inode_lookup(dir_pentry, &dirent_array[i].name, &attrlookup, data->ht, data->pclient, data->pcontext, &cache_status)) == NULL) { Mem_Free((char *)entry_nfs_array); Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */ entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap; entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals; res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } /* If file handle is asked in the attributes, provide it */ if(arg_READDIR4.attr_request.bitmap4_val != NULL && (arg_READDIR4.attr_request.bitmap4_val[0] & FATTR4_FILEHANDLE)) { if((entry_FSALhandle = cache_inode_get_fsal_handle(pentry, &cache_status_attr)) == NULL) { /* Faulty Handle or pentry */ Mem_Free((char *)entry_nfs_array); Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } if(!nfs4_FSALToFhandle(&entryFH, entry_FSALhandle, data)) { /* Faulty type */ Mem_Free((char *)entry_nfs_array); Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); res_READDIR4.status = NFS4ERR_SERVERFAULT; return res_READDIR4.status; } } if(nfs4_FSALattr_To_Fattr(data->pexport, &attrlookup, &(entry_nfs_array[i].attrs), data, &entryFH, &(arg_READDIR4.attr_request)) != 0) { /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */ entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap; entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals; } /* Chain the entries together */ entry_nfs_array[i].nextentry = NULL; if(i != 0) entry_nfs_array[i - 1].nextentry = &(entry_nfs_array[i]); /* This test is there to avoid going further than the buffer provided by the client * the factor "9/10" is there for safety. Its value could be change as beta tests will be done */ if((caddr_t) ((caddr_t) (&entry_nfs_array[i]) - (caddr_t) (&entry_nfs_array[0])) > (caddr_t) (maxcount * 9 / 10)) break; } /* for i */ if((eod_met == END_OF_DIR) && (i == num_entries)) { /* This is the end of the directory */ res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE; memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, NFS4_VERIFIER_SIZE); } /* Put the entry's list in the READDIR reply */ res_READDIR4.READDIR4res_u.resok4.reply.entries = entry_nfs_array; } /* Do not forget to set the verifier */ memcpy((char *)res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, NFS4_VERIFIER_SIZE); Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); res_READDIR4.status = NFS4_OK; return res_READDIR4.status; } /* nfs4_op_readdir */
/** * * pnfs_lookup: looks up for a path's component. * * Looks up for a path's component. * * @param pnfsclient [IN] pointer to the pnfsclient structure (client to the ds). * @param parent_directory_handle [IN] the NFSv4 file handle for the parent directory * @param filename [IN] the path's component to be looked up * @param object_handle [OUT] the resulting NFSv4 file handle * * @return NFS4_OK if successful * @return a NFSv4 error (positive value) if failed. * */ int pnfs_lookup(pnfs_ds_client_t * pnfsdsclient, nfs_fh4 * parent_directory_handle, /* IN */ char *filename, /* IN */ nfs_fh4 * object_handle) { int rc; nfs_fh4 nfs4fh; component4 name; char nameval[MAXNAMLEN]; unsigned int index_getfh = 0; COMPOUND4args argnfs4; COMPOUND4res resnfs4; struct timeval timeout = { 25, 0 }; #define PNFS_LAYOUTFILE_NB_OP_ALLOC 4 nfs_argop4 argoparray[PNFS_LAYOUTFILE_NB_OP_ALLOC]; nfs_resop4 resoparray[PNFS_LAYOUTFILE_NB_OP_ALLOC]; uint32_t bitmap_res[2]; char padfilehandle[PNFS_LAYOUTFILE_FILEHANDLE_MAX_LEN]; /* sanity checks * note : object_attributes is optionnal * parent_directory_handle may be null for getting FS root. */ if(!object_handle || !filename || !object_handle) return NFS4ERR_INVAL; /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; argnfs4.minorversion = 1; argnfs4.argarray.argarray_len = 0; name.utf8string_val = nameval; name.utf8string_len = 0; if(!parent_directory_handle) { /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup Root" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; #define PNFS_LOOKUP_IDX_OP_SEQUENCE 0 #define PNFS_LOOKUP_IDX_OP_PUTROOTFH 1 #define PNFS_LOOKUP_IDX_OP_GETFH_ROOT 2 COMPOUNDV41_ARG_ADD_OP_SEQUENCE(argnfs4, pnfsdsclient->session, pnfsdsclient->sequence); COMPOUNDV41_ARG_ADD_OP_PUTROOTFH(argnfs4); COMPOUNDV41_ARG_ADD_OP_GETFH(argnfs4); index_getfh = PNFS_LOOKUP_IDX_OP_GETFH_ROOT; resnfs4.resarray.resarray_val[PNFS_LOOKUP_IDX_OP_GETFH_ROOT].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[PNFS_LOOKUP_IDX_OP_GETFH_ROOT].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = PNFS_LAYOUTFILE_FILEHANDLE_MAX_LEN; } else /* this is a real lookup(parent, name) */ { /* the filename should not be null */ if(filename == NULL) return NFS4ERR_INVAL; if(str2utf8(filename, &name) == -1) return NFS4ERR_SERVERFAULT; nfs4fh.nfs_fh4_len = parent_directory_handle->nfs_fh4_len; nfs4fh.nfs_fh4_val = parent_directory_handle->nfs_fh4_val; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup name" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; #define PNFS_LOOKUP_IDX_OP_SEQUENCE 0 #define PNFS_LOOKUP_IDX_OP_PUTFH 1 #define PNFS_LOOKUP_IDX_OP_LOOKUP 2 #define PNFS_LOOKUP_IDX_OP_GETFH 3 COMPOUNDV41_ARG_ADD_OP_SEQUENCE(argnfs4, pnfsdsclient->session, pnfsdsclient->sequence); COMPOUNDV41_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV41_ARG_ADD_OP_LOOKUP(argnfs4, name); COMPOUNDV41_ARG_ADD_OP_GETFH(argnfs4); index_getfh = PNFS_LOOKUP_IDX_OP_GETFH; resnfs4.resarray.resarray_val[PNFS_LOOKUP_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[PNFS_LOOKUP_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = PNFS_LAYOUTFILE_FILEHANDLE_MAX_LEN; } /* Call the NFSv4 function */ if(clnt_call(pnfsdsclient->rpc_client, NFSPROC4_COMPOUND, (xdrproc_t) xdr_COMPOUND4args, (caddr_t) & argnfs4, (xdrproc_t) xdr_COMPOUND4res, (caddr_t) & resnfs4, timeout) != RPC_SUCCESS) { return NFS4ERR_IO; /* @todo: For wanting of something more appropriate */ } /* Increment the sequence */ pnfsdsclient->sequence += 1; if(resnfs4.status != NFS4_OK) { return resnfs4.status; } object_handle->nfs_fh4_len = resnfs4.resarray.resarray_val[index_getfh].nfs_resop4_u.opgetfh.GETFH4res_u.resok4. object.nfs_fh4_len; memcpy((char *)object_handle->nfs_fh4_val, (char *)resnfs4.resarray.resarray_val[index_getfh].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val, resnfs4.resarray.resarray_val[index_getfh].nfs_resop4_u.opgetfh.GETFH4res_u. resok4.object.nfs_fh4_len); /* lookup complete ! */ return NFS4_OK; }