nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=4:tabstop=4: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 3 of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 */ 00025 00036 #ifdef HAVE_CONFIG_H 00037 #include "config.h" 00038 #endif 00039 00040 #ifdef _SOLARIS 00041 #include "solaris_port.h" 00042 #endif 00043 00044 #include <stdio.h> 00045 #include <string.h> 00046 #include <pthread.h> 00047 #include <fcntl.h> 00048 #include <sys/file.h> /* for having FNDELAY */ 00049 #include "HashData.h" 00050 #include "HashTable.h" 00051 #include "log.h" 00052 #include "ganesha_rpc.h" 00053 #include "nfs4.h" 00054 #include "nfs_core.h" 00055 #include "nfs_proto_functions.h" 00056 #include "nfs_proto_tools.h" 00057 #include "nfs_tools.h" 00058 #include "nfs_exports.h" 00059 #include "nfs_file_handle.h" 00060 #include "cache_inode.h" 00061 00062 static void nfs_set_times_current(fattr3 * attrs) 00063 { 00064 time_t now = time(NULL); 00065 00066 attrs->atime.seconds = now; 00067 attrs->atime.nseconds = 0; 00068 00069 attrs->mtime.seconds = now; 00070 attrs->mtime.nseconds = 0; 00071 00072 attrs->ctime.seconds = now; 00073 attrs->ctime.nseconds = 0; 00074 } 00075 00076 static void fsal_set_times_current(fsal_attrib_list_t * attrs) 00077 { 00078 struct timeval tv; 00079 gettimeofday(&tv, NULL); 00080 00081 attrs->atime.seconds = tv.tv_sec; 00082 attrs->atime.nseconds = 1000 * tv.tv_usec; 00083 00084 attrs->mtime.seconds = tv.tv_sec; 00085 attrs->mtime.nseconds = 1000 * tv.tv_usec; 00086 00087 attrs->ctime.seconds = tv.tv_sec; 00088 attrs->ctime.nseconds = 1000 * tv.tv_usec; 00089 } 00090 00103 int nfs_XattrD_Name(char *strname, char *objectname) 00104 { 00105 if(strname == NULL) 00106 return 0; 00107 00108 if(!strncmp(strname, XATTRD_NAME, XATTRD_NAME_LEN)) 00109 { 00110 memcpy(objectname, (char *)(strname + XATTRD_NAME_LEN), 00111 strlen(strname) - XATTRD_NAME_LEN + 1); 00112 return 1; 00113 } 00114 00115 return 0; 00116 } /* nfs_Is_XattrD_Name */ 00117 00127 nfsstat3 nfs3_fh_to_xattrfh(nfs_fh3 * pfhin, nfs_fh3 * pfhout) 00128 { 00129 file_handle_v3_t *pfile_handle = NULL; 00130 00131 if(pfhin != pfhout) 00132 { 00133 memcpy(pfhout->data.data_val, pfhin->data.data_val, pfhin->data.data_len); 00134 pfhout->data.data_len = pfhin->data.data_len; 00135 } 00136 00137 pfile_handle = (file_handle_v3_t *) (pfhout->data.data_val); 00138 00139 /* the following choice is made for xattr: the field xattr_pos contains : 00140 * - 0 if the FH is related to an actual FH object 00141 * - 1 if the FH is the one for the xattr ghost directory 00142 * - a value greater than 1 if the fh is related to a ghost file in ghost xattr directory that represents a xattr. The value is then equal 00143 * to the xattr_id + 1 (see how FSAL manages xattrs for meaning of this field). This limits the number of xattrs per object to 254. 00144 */ 00145 pfile_handle->xattr_pos = 1; 00147 return NFS3_OK; 00148 } /* nfs3_fh_to_xattrfh */ 00149 00163 int nfs3_FSALattr_To_XattrDir(exportlist_t * pexport, /* In: the related export entry */ 00164 fsal_attrib_list_t * FSAL_attr, /* In: file attributes */ 00165 fattr3 * Fattr) /* Out: file attributes */ 00166 { 00167 if(FSAL_attr == NULL || Fattr == NULL) 00168 return 0; 00169 00170 Fattr->type = NF3DIR; 00172 /* r-xr-xr-x (cannot create or remove xattrs, except if HAVE_XATTR_CREATE is defined) */ 00173 #ifdef HAVE_XATTR_CREATE 00174 Fattr->mode = 0755; 00175 #else 00176 Fattr->mode = 0555; 00177 #endif 00178 00179 Fattr->nlink = 2; /* like a directory */ 00180 Fattr->uid = FSAL_attr->owner; 00181 Fattr->gid = FSAL_attr->group; 00182 Fattr->size = DEV_BSIZE; 00183 Fattr->used = DEV_BSIZE; 00184 00185 Fattr->rdev.specdata1 = 0; 00186 Fattr->rdev.specdata2 = 0; 00187 00188 /* in NFSv3, we only keeps fsid.major, casted into an nfs_uint64 */ 00189 Fattr->fsid = (nfs3_uint64) pexport->filesystem_id.major; 00190 00191 Fattr->fileid = (0xFFFFFFFF & ~(FSAL_attr->fileid)) - 1; /* xattr_pos = 1 => Parent Xattrd */ 00192 00193 /* set current time, to force the client refreshing its xattr dir */ 00194 nfs_set_times_current(Fattr); 00195 00196 return 1; 00197 } /* nfs3_FSALattr_To_XattrDir */ 00198 00212 int nfs_SetPostOpXAttrDir(fsal_op_context_t * pcontext, 00213 exportlist_t * pexport, 00214 fsal_attrib_list_t * pfsal_attr, post_op_attr * presult) 00215 { 00216 if(pfsal_attr == NULL) 00217 { 00218 presult->attributes_follow = FALSE; 00219 return 0; 00220 } 00221 00222 if(nfs3_FSALattr_To_XattrDir 00223 (pexport, pfsal_attr, &(presult->post_op_attr_u.attributes)) == 0) 00224 presult->attributes_follow = FALSE; 00225 else 00226 presult->attributes_follow = TRUE; 00227 00228 return 0; 00229 } /* nfs_SetPostOpXAttrDir */ 00230 00244 int nfs_SetPostOpXAttrFile(fsal_op_context_t * pcontext, 00245 exportlist_t * pexport, 00246 fsal_attrib_list_t * pfsal_attr, post_op_attr * presult) 00247 { 00248 if(pfsal_attr == NULL) 00249 { 00250 presult->attributes_follow = FALSE; 00251 return 0; 00252 } 00253 00254 if(nfs3_FSALattr_To_Fattr(pexport, pfsal_attr, &(presult->post_op_attr_u.attributes)) 00255 == 0) 00256 presult->attributes_follow = FALSE; 00257 else 00258 { 00259 nfs_set_times_current(&(presult->post_op_attr_u.attributes)); 00260 presult->attributes_follow = TRUE; 00261 } 00262 00263 return 0; 00264 } /* nfs_SetPostOpXAttrFile */ 00265 00282 int nfs3_Access_Xattr(nfs_arg_t * parg, 00283 exportlist_t * pexport, 00284 fsal_op_context_t * pcontext, 00285 struct svc_req *preq, nfs_res_t * pres) 00286 { 00287 fsal_attrib_list_t attr; 00288 fsal_handle_t *pfsal_handle = NULL; 00289 cache_entry_t *pentry = NULL; 00290 file_handle_v3_t *pfile_handle = NULL; 00291 unsigned int xattr_id = 0; 00292 int rc = NFS_REQ_OK; 00293 00294 /* to avoid setting it on each error case */ 00295 pres->res_access3.ACCESS3res_u.resfail.obj_attributes.attributes_follow = FALSE; 00296 00297 if((pentry = nfs_FhandleToCache(NFS_V3, 00298 NULL, 00299 &(parg->arg_access3.object), 00300 NULL, 00301 NULL, 00302 &(pres->res_access3.status), 00303 NULL, &attr, pcontext, &rc)) == NULL) 00304 { 00305 /* Stale NFS FH ? */ 00306 goto out; 00307 } 00308 00309 pfsal_handle = &pentry->handle; 00310 00311 /* Rebuild the FH */ 00312 pfile_handle = (file_handle_v3_t *) (parg->arg_access3.object.data.data_val); 00313 00314 /* for Xattr FH, we adopt the current convention: 00315 * xattr_pos = 0 ==> the FH is the one of the actual FS object 00316 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 00317 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 00318 xattr_id = pfile_handle->xattr_pos - 2; 00319 00320 /* retrieve entry attributes */ 00321 if(pfile_handle->xattr_pos == 0) 00322 { 00323 /* should not occur */ 00324 pres->res_access3.status = NFS3ERR_INVAL; 00325 rc = NFS_REQ_OK; 00326 goto out; 00327 } 00328 else if(pfile_handle->xattr_pos == 1) 00329 { 00330 00331 pres->res_access3.ACCESS3res_u.resok.access = 00332 parg->arg_access3.access & ~(ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE); 00333 00334 /* Build directory attributes */ 00335 nfs_SetPostOpXAttrDir(pcontext, pexport, 00336 &attr, 00337 &(pres->res_access3.ACCESS3res_u.resok.obj_attributes)); 00338 00339 } 00340 else /* named attribute */ 00341 { 00342 fsal_status_t fsal_status; 00343 fsal_attrib_list_t xattrs; 00344 fsal_accessflags_t access_mode; 00345 00346 access_mode = 0; 00347 if(parg->arg_access3.access & ACCESS3_READ) 00348 access_mode |= FSAL_R_OK; 00349 00350 if(parg->arg_access3.access & (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE)) 00351 access_mode |= FSAL_W_OK; 00352 00353 if(parg->arg_access3.access & ACCESS3_LOOKUP) 00354 access_mode |= FSAL_X_OK; 00355 00356 xattrs.asked_attributes = cache_inode_params.attrmask; 00357 fsal_status = FSAL_GetXAttrAttrs(pfsal_handle, pcontext, xattr_id, &xattrs); 00358 00359 if(FSAL_IS_ERROR(fsal_status)) 00360 { 00361 pres->res_access3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 00362 rc = NFS_REQ_OK; 00363 goto out; 00364 } 00365 00366 fsal_status = FSAL_test_access(pcontext, access_mode, &xattrs); 00367 00368 if(FSAL_IS_ERROR(fsal_status)) 00369 { 00370 if(fsal_status.major == ERR_FSAL_ACCESS) 00371 { 00372 pres->res_access3.ACCESS3res_u.resok.access = 0; 00373 00374 /* we have to check read/write permissions */ 00375 if(!FSAL_IS_ERROR(FSAL_test_access(pcontext, FSAL_R_OK, &xattrs))) 00376 pres->res_access3.ACCESS3res_u.resok.access |= ACCESS3_READ; 00377 if(!FSAL_IS_ERROR(FSAL_test_access(pcontext, FSAL_W_OK, &xattrs))) 00378 pres->res_access3.ACCESS3res_u.resok.access |= 00379 ACCESS3_MODIFY | ACCESS3_EXTEND; 00380 } 00381 else 00382 { 00383 /* this is an error */ 00384 nfs_SetPostOpXAttrFile(pcontext, pexport, 00385 &xattrs, 00386 &(pres->res_access3.ACCESS3res_u.resfail. 00387 obj_attributes)); 00388 00389 pres->res_access3.status = 00390 nfs3_Errno(cache_inode_error_convert(fsal_status)); 00391 rc = NFS_REQ_OK; 00392 goto out; 00393 } 00394 00395 } 00396 else /* access granted */ 00397 { 00398 pres->res_access3.ACCESS3res_u.resok.access = parg->arg_access3.access; 00399 } 00400 00401 nfs_SetPostOpXAttrFile(pcontext, pexport, 00402 &xattrs, 00403 &(pres->res_access3.ACCESS3res_u.resok.obj_attributes)); 00404 } 00405 00406 pres->res_access3.status = NFS3_OK; 00407 00408 rc = NFS_REQ_OK; 00409 00410 out: 00411 /* return references */ 00412 if (pentry) 00413 cache_inode_put(pentry); 00414 00415 return (rc); 00416 } /* nfs3_Access_Xattr */ 00417 00434 int nfs3_Lookup_Xattr(nfs_arg_t * parg, 00435 exportlist_t * pexport, 00436 fsal_op_context_t * pcontext, 00437 struct svc_req *preq, nfs_res_t * pres) 00438 { 00439 cache_inode_status_t cache_status; 00440 fsal_attrib_list_t attr, xattr_attrs; 00441 fsal_name_t name; 00442 fsal_status_t fsal_status; 00443 unsigned int xattr_id = 0; 00444 fsal_handle_t *pfsal_handle = NULL; 00445 char *strpath = parg->arg_lookup3.what.name; 00446 file_handle_v3_t *pfile_handle = NULL; 00447 cache_entry_t *pentry_dir = NULL; 00448 int rc = NFS_REQ_OK; 00449 00450 if((pentry_dir = nfs_FhandleToCache(NFS_V3, 00451 NULL, 00452 &(parg->arg_lookup3.what.dir), 00453 NULL, 00454 NULL, 00455 &(pres->res_lookup3.status), 00456 NULL, &attr, pcontext, &rc)) == NULL) 00457 { 00458 /* Stale NFS FH ? */ 00459 goto out; 00460 } 00461 00462 pfsal_handle = &pentry_dir->handle; 00463 00464 if((cache_status = cache_inode_error_convert(FSAL_str2name(strpath, 00465 MAXNAMLEN, 00466 &name))) != 00467 CACHE_INODE_SUCCESS) 00468 { 00469 pres->res_lookup3.status = nfs3_Errno(cache_status); 00470 rc = NFS_REQ_OK; 00471 goto out; 00472 } 00473 00474 /* Try to get a FSAL_XAttr of that name */ 00475 fsal_status = FSAL_GetXAttrIdByName(pfsal_handle, &name, pcontext, &xattr_id); 00476 if(FSAL_IS_ERROR(fsal_status)) 00477 { 00478 pres->res_lookup3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 00479 rc = NFS_REQ_OK; 00480 goto out; 00481 } 00482 00483 /* Build FH */ 00484 pres->res_lookup3.status = 00485 nfs3_AllocateFH((nfs_fh3 *) & (pres->res_lookup3.LOOKUP3res_u.resok.object.data)); 00486 if(pres->res_lookup3.status != NFS3_OK) 00487 { 00488 rc = NFS_REQ_OK; 00489 goto out; 00490 } 00491 00492 if(nfs3_FSALToFhandle((nfs_fh3 *) & (pres->res_lookup3.LOOKUP3res_u.resok.object.data), 00493 pfsal_handle, pexport)) 00494 { 00495 pres->res_lookup3.status = 00496 nfs3_fh_to_xattrfh((nfs_fh3 *) & 00497 (pres->res_lookup3.LOOKUP3res_u.resok.object.data), 00498 (nfs_fh3 *) & (pres->res_lookup3.LOOKUP3res_u.resok.object. 00499 data)); 00500 00501 /* Retrieve xattr attributes */ 00502 xattr_attrs.asked_attributes = cache_inode_params.attrmask; 00503 fsal_status = FSAL_GetXAttrAttrs(pfsal_handle, pcontext, xattr_id, &xattr_attrs); 00504 00505 if(FSAL_IS_ERROR(fsal_status)) 00506 { 00507 pres->res_lookup3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 00508 rc = NFS_REQ_OK; 00509 goto out; 00510 } 00511 00512 nfs_SetPostOpXAttrFile(pcontext, pexport, 00513 &xattr_attrs, 00514 &(pres->res_lookup3.LOOKUP3res_u.resok.obj_attributes)); 00515 00516 /* Build directory attributes */ 00517 nfs_SetPostOpXAttrDir(pcontext, pexport, 00518 &attr, 00519 &(pres->res_lookup3.LOOKUP3res_u.resok.dir_attributes)); 00520 00521 pres->res_lookup3.status = NFS3_OK; 00522 } 00523 00524 /* if */ 00525 /* Rebuild the FH */ 00526 pfile_handle = 00527 (file_handle_v3_t *) (pres->res_lookup3.LOOKUP3res_u.resok.object.data.data_val); 00528 00529 /* for Xattr FH, we adopt the current convention: 00530 * xattr_pos = 0 ==> the FH is the one of the actual FS object 00531 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 00532 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 00533 pfile_handle->xattr_pos = xattr_id + 2; 00534 00535 out: 00536 /* return references */ 00537 if (pentry_dir) 00538 cache_inode_put(pentry_dir); 00539 00540 return (rc); 00541 } /* nfs3_Lookup_Xattr */ 00542 00559 int nfs3_Readdir_Xattr(nfs_arg_t * parg, 00560 exportlist_t * pexport, 00561 fsal_op_context_t * pcontext, 00562 struct svc_req *preq, nfs_res_t * pres) 00563 { 00564 typedef char entry_name_array_item_t[FSAL_MAX_NAME_LEN]; 00565 typedef char fh3_buffer_item_t[NFS3_FHSIZE]; 00566 00567 unsigned int delta = 0; 00568 cache_entry_t *dir_pentry = NULL; 00569 unsigned long dircount; 00570 unsigned long maxcount = 0; 00571 fsal_attrib_list_t dir_attr; 00572 unsigned int begin_cookie; 00573 unsigned int xattr_cookie; 00574 cookieverf3 cookie_verifier; 00575 file_handle_v3_t *pfile_handle = NULL; 00576 unsigned int xattr_id = 0; 00577 unsigned int i = 0; 00578 unsigned int num_entries = 0; 00579 unsigned long space_used; 00580 unsigned long estimated_num_entries; 00581 unsigned long asked_num_entries; 00582 unsigned int eod_met; 00583 cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; 00584 fsal_handle_t *pfsal_handle = NULL; 00585 fsal_status_t fsal_status; 00586 entry_name_array_item_t *entry_name_array = NULL; 00587 fh3_buffer_item_t *fh3_array = NULL; 00588 unsigned int nb_xattrs_read = 0; 00589 fsal_xattrent_t xattrs_tab[255]; 00590 int rc = NFS_REQ_OK; 00591 00592 /* to avoid setting it on each error case */ 00593 pres->res_readdir3.READDIR3res_u.resfail.dir_attributes.attributes_follow = FALSE; 00594 00595 dircount = parg->arg_readdir3.count; 00596 begin_cookie = (unsigned int)parg->arg_readdir3.cookie; 00597 space_used = sizeof(READDIRPLUS3resok); 00598 estimated_num_entries = dircount / sizeof(entry3); 00599 00600 /* BUGAZOMEU : rajouter acces direct au DIR_CONTINUE */ 00601 if((dir_pentry = nfs_FhandleToCache(preq->rq_vers, 00602 NULL, 00603 &(parg->arg_readdir3.dir), 00604 NULL, 00605 NULL, 00606 &(pres->res_readdir3.status), 00607 NULL, 00608 &dir_attr, pcontext, &rc)) == NULL) 00609 { 00610 /* return NFS_REQ_DROP ; */ 00611 goto out; 00612 } 00613 00614 pfsal_handle = &dir_pentry->handle; 00615 00616 /* Turn the nfs FH into something readable */ 00617 pfile_handle = (file_handle_v3_t *) (parg->arg_readdir3.dir.data.data_val); 00618 00619 /* for Xattr FH, we adopt the current convention: 00620 * xattr_pos = 0 ==> the FH is the one of the actual FS object 00621 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 00622 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 00623 xattr_id = pfile_handle->xattr_pos; 00624 00625 if(xattr_id != 1) /* If this is not the xattrd */ 00626 { 00627 pres->res_readdir3.status = NFS3ERR_NOTDIR; 00628 rc = NFS_REQ_OK; 00629 goto out; 00630 } 00631 00632 /* Cookie verifier management */ 00633 memset(cookie_verifier, 0, sizeof(cookieverf3)); 00634 00635 /* 00636 * If cookie verifier is used, then an non-trivial value is 00637 * returned to the client This value is the mtime of 00638 * the directory. If verifier is unused (as in many NFS 00639 * Servers) then only a set of zeros is returned (trivial 00640 * value) 00641 */ 00642 00643 if(pexport->UseCookieVerifier) 00644 memcpy(cookie_verifier, &(dir_attr.mtime), sizeof(dir_attr.mtime)); 00645 00646 /* 00647 * nothing to do if != 0 because the area is already full of 00648 * zero 00649 */ 00650 00651 if(pexport->UseCookieVerifier && (begin_cookie != 0)) 00652 { 00653 /* 00654 * Not the first call, so we have to check the cookie 00655 * verifier 00656 */ 00657 if(memcmp(cookie_verifier, parg->arg_readdir3.cookieverf, NFS3_COOKIEVERFSIZE) != 0) 00658 { 00659 pres->res_readdir3.status = NFS3ERR_BAD_COOKIE; 00660 rc = NFS_REQ_OK; 00661 goto out; 00662 } 00663 } 00664 00665 pres->res_readdir3.READDIR3res_u.resok.reply.entries = NULL; 00666 pres->res_readdir3.READDIR3res_u.resok.reply.eof = FALSE; 00667 00668 /* How many entries will we retry from cache_inode ? */ 00669 if(begin_cookie > 1) 00670 { 00671 asked_num_entries = estimated_num_entries; 00672 xattr_cookie = begin_cookie - 2; 00673 } 00674 else 00675 { 00676 asked_num_entries = ((estimated_num_entries > 2) ? estimated_num_entries - 2 : 0); /* Keep space for '.' and '..' */ 00677 xattr_cookie = 0; 00678 } 00679 00680 /* A definition that will be very useful to avoid very long names for variables */ 00681 #define RES_READDIR_REPLY pres->res_readdir3.READDIR3res_u.resok.reply 00682 00683 /* Used FSAL extended attributes functions */ 00684 fsal_status = FSAL_ListXAttrs(pfsal_handle, 00685 xattr_cookie, 00686 pcontext, 00687 xattrs_tab, asked_num_entries, &nb_xattrs_read, &eod_met); 00688 if(!FSAL_IS_ERROR(fsal_status)) 00689 { 00690 if((nb_xattrs_read == 0) && (begin_cookie > 1)) 00691 { 00692 pres->res_readdir3.status = NFS3_OK; 00693 pres->res_readdir3.READDIR3res_u.resok.reply.entries = NULL; 00694 pres->res_readdir3.READDIR3res_u.resok.reply.eof = TRUE; 00695 00696 nfs_SetPostOpXAttrDir(pcontext, 00697 pexport, 00698 NULL, 00699 &(pres->res_readdir3.READDIR3res_u.resok.dir_attributes)); 00700 00701 memcpy(pres->res_readdir3.READDIR3res_u.resok.cookieverf, 00702 cookie_verifier, sizeof(cookieverf3)); 00703 } 00704 else 00705 { 00706 /* Allocation of the structure for reply */ 00707 entry_name_array 00708 = gsh_calloc(estimated_num_entries, 00709 (FSAL_MAX_NAME_LEN + 1)); 00710 00711 if(entry_name_array == NULL) 00712 { 00713 rc = NFS_REQ_DROP; 00714 goto out; 00715 } 00716 00717 pres->res_readdir3.READDIR3res_u.resok.reply.entries = 00718 gsh_calloc(estimated_num_entries, sizeof(entry3)); 00719 00720 if(pres->res_readdir3.READDIR3res_u.resok.reply.entries == NULL) 00721 { 00722 gsh_free(entry_name_array); 00723 rc = NFS_REQ_DROP; 00724 goto out; 00725 } 00726 00727 /* Allocation of the file handles */ 00728 00729 fh3_array = 00730 gsh_calloc(estimated_num_entries, NFS3_FHSIZE); 00731 00732 if(fh3_array == NULL) 00733 { 00734 gsh_free(entry_name_array); 00735 gsh_free(pres->res_readdir3.READDIR3res_u.resok.reply.entries); 00736 pres->res_readdir3.READDIR3res_u.resok.reply.entries = NULL; 00737 rc = NFS_REQ_DROP; 00738 goto out; 00739 } 00740 00741 delta = 0; 00742 00743 /* manage . and .. */ 00744 if(begin_cookie == 0) 00745 { 00746 /* Fill in '.' */ 00747 if(estimated_num_entries > 0) 00748 { 00749 RES_READDIR_REPLY.entries[0].fileid = (0xFFFFFFFF & ~(dir_attr.fileid)) - 1; /* xattr_pos = 1 => Parent Xattrd */ 00750 00751 RES_READDIR_REPLY.entries[0].name = entry_name_array[0]; 00752 strcpy(RES_READDIR_REPLY.entries[0].name, "."); 00753 RES_READDIR_REPLY.entries[0].cookie = 1; 00754 00755 delta += 1; 00756 } 00757 00758 } 00759 00760 /* Fill in '..' */ 00761 if(begin_cookie <= 1) 00762 { 00763 if(estimated_num_entries > delta) 00764 { 00765 RES_READDIR_REPLY.entries[delta].fileid = (0xFFFFFFFF & ~(dir_attr.fileid)) - delta; /* xattr_pos > 1 => attribute */ 00766 00767 RES_READDIR_REPLY.entries[delta].name = entry_name_array[delta]; 00768 strcpy(RES_READDIR_REPLY.entries[delta].name, ".."); 00769 RES_READDIR_REPLY.entries[delta].cookie = 2; 00770 00771 RES_READDIR_REPLY.entries[0].nextentry = 00772 &(RES_READDIR_REPLY.entries[delta]); 00773 00774 if(num_entries > delta + 1) /* not 0 ??? */ 00775 RES_READDIR_REPLY.entries[delta].nextentry = 00776 &(RES_READDIR_REPLY.entries[delta + 1]); 00777 else 00778 RES_READDIR_REPLY.entries[delta].nextentry = NULL; 00779 00780 delta += 1; 00781 } 00782 } 00783 /* if( begin_cookie == 0 ) */ 00784 for(i = delta; i < nb_xattrs_read + delta; i++) 00785 { 00786 unsigned long needed; 00787 00788 /* dircount is the size without the FH and attributes overhead, so entry3 is used intead of entryplus3 */ 00789 needed = 00790 sizeof(entry3) + 00791 ((strlen(xattrs_tab[i - delta].xattr_name.name) + 3) & ~3); 00792 00793 if((space_used += needed) > maxcount) 00794 { 00795 if(i == delta) 00796 { 00797 /* 00798 * Not enough room to make even a single reply 00799 */ 00800 gsh_free(entry_name_array); 00801 gsh_free(fh3_array); 00802 gsh_free(pres->res_readdir3.READDIR3res_u 00803 .resok.reply.entries); 00804 pres->res_readdir3.READDIR3res_u.resok.reply.entries 00805 = NULL; 00806 00807 pres->res_readdir3.status = NFS3ERR_TOOSMALL; 00808 00809 rc = NFS_REQ_OK; 00810 goto out; 00811 } 00812 break; /* Make post traitement */ 00813 } 00814 RES_READDIR_REPLY.entries[i].fileid = 00815 0xFFFFFFFF & xattrs_tab[i - delta].attributes.fileid; 00816 FSAL_name2str(&xattrs_tab[i - delta].xattr_name, entry_name_array[i], 00817 FSAL_MAX_NAME_LEN); 00818 RES_READDIR_REPLY.entries[i].name = entry_name_array[i]; 00819 00820 RES_READDIR_REPLY.entries[i].cookie = 00821 xattrs_tab[i - delta].xattr_cookie + 2; 00822 00823 RES_READDIR_REPLY.entries[i].nextentry = NULL; 00824 if(i != 0) 00825 RES_READDIR_REPLY.entries[i - 1].nextentry = 00826 &(RES_READDIR_REPLY.entries[i]); 00827 00828 } /* for */ 00829 } /* else */ 00830 00831 if(eod_met) 00832 RES_READDIR_REPLY.eof = TRUE; 00833 else 00834 RES_READDIR_REPLY.eof = FALSE; 00835 00836 nfs_SetPostOpXAttrDir(pcontext, 00837 pexport, 00838 &dir_attr, 00839 &(pres->res_readdir3.READDIR3res_u.resok.dir_attributes)); 00840 memcpy(pres->res_readdir3.READDIR3res_u.resok.cookieverf, cookie_verifier, 00841 sizeof(cookieverf3)); 00842 00843 pres->res_readdir3.status = NFS3_OK; 00844 00845 rc = NFS_REQ_OK; 00846 goto out; 00847 } 00848 00849 /* if( !FSAL_IS_ERROR( fsal_status ) ) */ 00850 /* Is this point is reached, then there is an error */ 00851 pres->res_readdir3.status = NFS3ERR_IO; 00852 00853 /* Set failed status */ 00854 nfs_SetFailedStatus(pcontext, 00855 pexport, 00856 NFS_V3, 00857 cache_status, 00858 NULL, 00859 &pres->res_readdir3.status, 00860 dir_pentry, 00861 &(pres->res_readdir3.READDIR3res_u.resfail.dir_attributes), 00862 NULL, NULL, NULL, NULL, NULL, NULL); 00863 00864 rc = NFS_REQ_OK; 00865 00866 out: 00867 /* return references */ 00868 if (dir_pentry) 00869 cache_inode_put(dir_pentry); 00870 00871 return (rc); 00872 00873 } /* nfs3_Readdir_Xattr */ 00874 00890 int nfs3_Create_Xattr(nfs_arg_t * parg, 00891 exportlist_t * pexport, 00892 fsal_op_context_t * pcontext, 00893 struct svc_req *preq, nfs_res_t * pres) 00894 { 00895 cache_entry_t *parent_pentry = NULL; 00896 fsal_attrib_list_t pre_attr; 00897 fsal_attrib_list_t post_attr; 00898 fsal_attrib_list_t attr_attrs; 00899 fsal_handle_t *pfsal_handle = NULL; 00900 fsal_name_t attr_name = FSAL_NAME_INITIALIZER; 00901 fsal_status_t fsal_status; 00902 file_handle_v3_t *p_handle_out; 00903 unsigned int attr_id; 00904 char empty_buff[16] = ""; 00905 /* alias to clear code */ 00906 CREATE3resok *resok = &pres->res_create3.CREATE3res_u.resok; 00907 int rc = NFS_REQ_OK; 00908 00909 if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, 00910 NULL, 00911 &(parg->arg_create3.where.dir), 00912 NULL, 00913 &(pres->res_dirop2.status), 00914 NULL, 00915 NULL, 00916 &pre_attr, pcontext, &rc)) == NULL) 00917 { 00918 /* Stale NFS FH ? */ 00919 goto out; 00920 } 00921 00922 /* Get the associated FSAL Handle */ 00923 pfsal_handle = &parent_pentry->handle; 00924 00925 /* convert attr name to FSAL name */ 00926 FSAL_str2name(parg->arg_create3.where.name, FSAL_MAX_NAME_LEN, &attr_name); 00927 00928 /* set empty attr */ 00929 fsal_status = FSAL_SetXAttrValue(pfsal_handle, 00930 &attr_name, 00931 pcontext, empty_buff, sizeof(empty_buff), TRUE); 00932 00933 if(FSAL_IS_ERROR(fsal_status)) 00934 { 00935 pres->res_create3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 00936 rc = NFS_REQ_OK; 00937 goto out; 00938 } 00939 00940 /* get attr id */ 00941 fsal_status = FSAL_GetXAttrIdByName(pfsal_handle, &attr_name, pcontext, &attr_id); 00942 if(FSAL_IS_ERROR(fsal_status)) 00943 { 00944 pres->res_create3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 00945 rc = NFS_REQ_OK; 00946 goto out; 00947 } 00948 00949 attr_attrs.asked_attributes = cache_inode_params.attrmask; 00950 fsal_status = FSAL_GetXAttrAttrs(pfsal_handle, pcontext, attr_id, &attr_attrs); 00951 00952 if(FSAL_IS_ERROR(fsal_status)) 00953 { 00954 pres->res_create3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 00955 rc = NFS_REQ_OK; 00956 goto out; 00957 } 00958 00959 /* Build file handle */ 00960 pres->res_create3.status = 00961 nfs3_AllocateFH(&resok->obj.post_op_fh3_u.handle); 00962 if(pres->res_create3.status != NFS3_OK) 00963 { 00964 rc = NFS_REQ_OK; 00965 goto out; 00966 } 00967 00968 /* Set Post Op Fh3 structure */ 00969 if(nfs3_FSALToFhandle(&resok->obj.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) 00970 { 00971 gsh_free(resok->obj.post_op_fh3_u.handle.data.data_val); 00972 pres->res_create3.status = NFS3ERR_BADHANDLE; 00973 rc = NFS_REQ_OK; 00974 goto out; 00975 } 00976 00977 /* Turn the nfs FH into something readable */ 00978 p_handle_out = (file_handle_v3_t *) (resok->obj.post_op_fh3_u.handle.data.data_val); 00979 00980 /* xattr_pos = 0 ==> the FH is the one of the actual FS object 00981 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 00982 */ 00983 p_handle_out->xattr_pos = attr_id + 2; 00984 00985 resok->obj.handle_follows = TRUE; 00986 00987 /* set current time (the file is new) */ 00988 fsal_set_times_current(&attr_attrs); 00989 00990 /* Set Post Op attrs */ 00991 nfs_SetPostOpXAttrFile(pcontext, pexport, &attr_attrs, &resok->obj_attributes); 00992 00993 /* We assume that creating xattr did not change related entry attrs. 00994 * Just update times for ghost directory. 00995 */ 00996 post_attr = pre_attr; 00997 00998 /* set current time, to force the client refreshing its xattr dir */ 00999 fsal_set_times_current(&post_attr); 01000 01001 pres->res_create3.status = NFS3_OK; 01002 01003 rc = NFS_REQ_OK; 01004 01005 out: 01006 /* return references */ 01007 if (parent_pentry) 01008 cache_inode_put(parent_pentry); 01009 01010 return (rc); 01011 01012 } 01013 01014 int nfs3_Write_Xattr(nfs_arg_t * parg, 01015 exportlist_t * pexport, 01016 fsal_op_context_t * pcontext, 01017 struct svc_req *preq, nfs_res_t * pres) 01018 { 01019 cache_entry_t *pentry; 01020 fsal_attrib_list_t attr; 01021 fsal_attrib_list_t attr_attrs; 01022 fsal_off_t offset = 0; 01023 fsal_status_t fsal_status; 01024 file_handle_v3_t *pfile_handle = NULL; 01025 fsal_handle_t *pfsal_handle = NULL; 01026 unsigned int xattr_id = 0; 01027 int rc = NFS_REQ_OK; 01028 01029 pres->res_write3.WRITE3res_u.resfail.file_wcc.before.attributes_follow = FALSE; 01030 pres->res_write3.WRITE3res_u.resfail.file_wcc.after.attributes_follow = FALSE; 01031 /* Convert file handle into a cache entry */ 01032 if((pentry = nfs_FhandleToCache(NFS_V3, 01033 NULL, 01034 &(parg->arg_write3.file), 01035 NULL, 01036 NULL, 01037 &(pres->res_write3.status), 01038 NULL, &attr, pcontext, &rc)) == NULL) 01039 { 01040 /* Stale NFS FH ? */ 01041 goto out; 01042 } 01043 01044 /* Turn the nfs FH into something readable */ 01045 pfile_handle = (file_handle_v3_t *) (parg->arg_write3.file.data.data_val); 01046 01047 /* Get the FSAL Handle */ 01048 pfsal_handle = &pentry->handle; 01049 01050 /* for Xattr FH, we adopt the current convention: 01051 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01052 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01053 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01054 if(pfile_handle->xattr_pos == 0) 01055 { 01056 pres->res_write3.status = NFS3ERR_INVAL; 01057 rc = NFS_REQ_OK; 01058 goto out; 01059 } 01060 01061 if(pfile_handle->xattr_pos == 1) 01062 { 01063 pres->res_write3.status = NFS3ERR_ISDIR; 01064 rc = NFS_REQ_OK; 01065 goto out; 01066 } 01067 01068 /* xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01069 xattr_id = pfile_handle->xattr_pos - 2; 01070 01071 offset = parg->arg_write3.offset; 01072 01073 if(offset > 0) 01074 { 01075 pres->res_write3.status = NFS3ERR_INVAL; 01076 rc = NFS_REQ_OK; 01077 goto out; 01078 } 01079 01080 fsal_status = FSAL_SetXAttrValueById(pfsal_handle, 01081 xattr_id, 01082 pcontext, 01083 parg->arg_write3.data.data_val, 01084 parg->arg_write3.data.data_len); 01085 01086 /* @TODO deal with error cases */ 01087 01088 attr_attrs.asked_attributes = cache_inode_params.attrmask; 01089 fsal_status = FSAL_GetXAttrAttrs(pfsal_handle, pcontext, xattr_id, &attr_attrs); 01090 01091 if(FSAL_IS_ERROR(fsal_status)) 01092 { 01093 pres->res_write3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 01094 rc = NFS_REQ_OK; 01095 goto out; 01096 } 01097 01098 /* Set the written size */ 01099 pres->res_write3.WRITE3res_u.resok.count = parg->arg_write3.data.data_len; 01100 pres->res_write3.WRITE3res_u.resok.committed = FILE_SYNC; 01101 01102 /* Set the write verifier */ 01103 memcpy(pres->res_write3.WRITE3res_u.resok.verf, NFS3_write_verifier, 01104 sizeof(writeverf3)); 01105 01106 pres->res_write3.status = NFS3_OK; 01107 01108 rc = NFS_REQ_OK; 01109 01110 out: 01111 /* return references */ 01112 if (pentry) 01113 cache_inode_put(pentry); 01114 01115 return (rc); 01116 } /* nfs3_Write_Xattr */ 01117 01133 int nfs3_Read_Xattr(nfs_arg_t * parg, 01134 exportlist_t * pexport, 01135 fsal_op_context_t * pcontext, 01136 struct svc_req *preq, nfs_res_t * pres) 01137 { 01138 cache_entry_t *pentry; 01139 fsal_attrib_list_t attr, xattr_attrs; 01140 fsal_size_t size = 0; 01141 size_t size_returned = 0; 01142 fsal_status_t fsal_status; 01143 caddr_t data = NULL; 01144 unsigned int xattr_id = 0; 01145 file_handle_v3_t *pfile_handle = NULL; 01146 fsal_handle_t *pfsal_handle = NULL; 01147 int rc = NFS_REQ_OK; 01148 01149 /* Convert file handle into a cache entry */ 01150 if((pentry = nfs_FhandleToCache(NFS_V3, 01151 NULL, 01152 &(parg->arg_read3.file), 01153 NULL, 01154 NULL, 01155 &(pres->res_read3.status), 01156 NULL, &attr, pcontext, &rc)) == NULL) 01157 { 01158 /* Stale NFS FH ? */ 01159 goto out; 01160 } 01161 01162 /* to avoid setting it on each error case */ 01163 pres->res_read3.READ3res_u.resfail.file_attributes.attributes_follow = FALSE; 01164 01165 /* Turn the nfs FH into something readable */ 01166 pfile_handle = (file_handle_v3_t *) (parg->arg_read3.file.data.data_val); 01167 01168 /* Get the FSAL Handle */ 01169 pfsal_handle = &pentry->handle; 01170 01171 /* for Xattr FH, we adopt the current convention: 01172 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01173 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01174 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01175 if(pfile_handle->xattr_pos == 0) 01176 { 01177 pres->res_read3.status = NFS3ERR_INVAL; 01178 rc = NFS_REQ_OK; 01179 goto out; 01180 } 01181 01182 if(pfile_handle->xattr_pos == 1) 01183 { 01184 pres->res_read3.status = NFS3ERR_ISDIR; 01185 rc = NFS_REQ_OK; 01186 goto out; 01187 } 01188 01189 /* xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01190 xattr_id = pfile_handle->xattr_pos - 2; 01191 01192 size = parg->arg_read3.count; 01193 01194 /* Get the xattr related to this xattr_id */ 01195 if((data = gsh_calloc(1, XATTR_BUFFERSIZE)) == NULL) 01196 { 01197 rc = NFS_REQ_DROP; 01198 goto out; 01199 } 01200 size_returned = size; 01201 fsal_status = FSAL_GetXAttrValueById(pfsal_handle, 01202 xattr_id, 01203 pcontext, data, XATTR_BUFFERSIZE, &size_returned); 01204 01205 if(FSAL_IS_ERROR(fsal_status)) 01206 { 01207 pres->res_read3.status = NFS3ERR_IO; 01208 rc = NFS_REQ_OK; 01209 goto out; 01210 } 01211 01212 /* XAttr is ALWAYS smaller than 4096 */ 01213 pres->res_read3.READ3res_u.resok.eof = TRUE; 01214 01215 /* Retrieve xattr attributes */ 01216 xattr_attrs.asked_attributes = cache_inode_params.attrmask; 01217 fsal_status = FSAL_GetXAttrAttrs(pfsal_handle, pcontext, xattr_id, &xattr_attrs); 01218 01219 if(FSAL_IS_ERROR(fsal_status)) 01220 { 01221 pres->res_read3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 01222 rc = NFS_REQ_OK; 01223 goto out; 01224 } 01225 01226 /* Build Post Op Attributes */ 01227 nfs_SetPostOpXAttrFile(pcontext, 01228 pexport, 01229 &xattr_attrs, 01230 &(pres->res_read3.READ3res_u.resok.file_attributes)); 01231 01232 pres->res_read3.READ3res_u.resok.file_attributes.attributes_follow = TRUE; 01233 01234 pres->res_read3.READ3res_u.resok.count = size_returned; 01235 pres->res_read3.READ3res_u.resok.data.data_val = data; 01236 pres->res_read3.READ3res_u.resok.data.data_len = size_returned; 01237 01238 pres->res_read3.status = NFS3_OK; 01239 01240 rc = NFS_REQ_OK; 01241 01242 out: 01243 /* return references */ 01244 if (pentry) 01245 cache_inode_put(pentry); 01246 01247 return (rc); 01248 01249 } /* nfs3_Read_Xattr */ 01250 01270 int nfs3_Readdirplus_Xattr(nfs_arg_t * parg, 01271 exportlist_t * pexport, 01272 fsal_op_context_t * pcontext, 01273 struct svc_req *preq, nfs_res_t * pres) 01274 { 01275 typedef char entry_name_array_item_t[FSAL_MAX_NAME_LEN]; 01276 typedef char fh3_buffer_item_t[NFS3_FHSIZE]; 01277 01278 unsigned int delta = 0; 01279 cache_entry_t *dir_pentry = NULL; 01280 unsigned long dircount; 01281 unsigned long maxcount = 0; 01282 fsal_attrib_list_t dir_attr; 01283 unsigned int begin_cookie; 01284 unsigned int xattr_cookie; 01285 cookieverf3 cookie_verifier; 01286 file_handle_v3_t *pfile_handle = NULL; 01287 unsigned int xattr_id = 0; 01288 unsigned int i = 0; 01289 unsigned int num_entries = 0; 01290 unsigned long space_used; 01291 unsigned long estimated_num_entries; 01292 unsigned long asked_num_entries; 01293 unsigned int eod_met; 01294 cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; 01295 fsal_handle_t *pfsal_handle = NULL; 01296 fsal_status_t fsal_status; 01297 entry_name_array_item_t *entry_name_array = NULL; 01298 fh3_buffer_item_t *fh3_array = NULL; 01299 unsigned int nb_xattrs_read = 0; 01300 fsal_xattrent_t xattrs_tab[255]; 01301 int rc = NFS_REQ_OK; 01302 01303 /* to avoid setting it on each error case */ 01304 pres->res_readdir3.READDIR3res_u.resfail.dir_attributes.attributes_follow = FALSE; 01305 01306 dircount = parg->arg_readdirplus3.dircount; 01307 maxcount = parg->arg_readdirplus3.maxcount; 01308 begin_cookie = (unsigned int)parg->arg_readdirplus3.cookie; 01309 space_used = sizeof(READDIRPLUS3resok); 01310 estimated_num_entries = dircount / sizeof(entryplus3); 01311 01312 /* BUGAZOMEU : rajouter acces direct au DIR_CONTINUE */ 01313 if((dir_pentry = nfs_FhandleToCache(preq->rq_vers, 01314 NULL, 01315 &(parg->arg_readdirplus3.dir), 01316 NULL, 01317 NULL, 01318 &(pres->res_readdirplus3.status), 01319 NULL, 01320 &dir_attr, pcontext, &rc)) == NULL) 01321 { 01322 /* return NFS_REQ_DROP ; */ 01323 goto out; 01324 } 01325 01326 pfsal_handle = &dir_pentry->handle; 01327 01328 /* Turn the nfs FH into something readable */ 01329 pfile_handle = (file_handle_v3_t *) (parg->arg_readdirplus3.dir.data.data_val); 01330 01331 /* for Xattr FH, we adopt the current convention: 01332 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01333 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01334 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01335 xattr_id = pfile_handle->xattr_pos; 01336 01337 if(xattr_id != 1) /* If this is not the xattrd */ 01338 { 01339 pres->res_readdirplus3.status = NFS3ERR_NOTDIR; 01340 rc = NFS_REQ_OK; 01341 goto out; 01342 } 01343 01344 /* Cookie verifier management */ 01345 memset(cookie_verifier, 0, sizeof(cookieverf3)); 01346 01347 /* 01348 * If cookie verifier is used, then an non-trivial value is 01349 * returned to the client This value is the mtime of 01350 * the directory. If verifier is unused (as in many NFS 01351 * Servers) then only a set of zeros is returned (trivial 01352 * value) 01353 */ 01354 01355 if(pexport->UseCookieVerifier) 01356 memcpy(cookie_verifier, &(dir_attr.mtime), sizeof(dir_attr.mtime)); 01357 01358 /* 01359 * nothing to do if != 0 because the area is already full of 01360 * zero 01361 */ 01362 01363 if(pexport->UseCookieVerifier && (begin_cookie != 0)) 01364 { 01365 /* 01366 * Not the first call, so we have to check the cookie 01367 * verifier 01368 */ 01369 if(memcmp(cookie_verifier, parg->arg_readdirplus3.cookieverf, NFS3_COOKIEVERFSIZE) 01370 != 0) 01371 { 01372 pres->res_readdirplus3.status = NFS3ERR_BAD_COOKIE; 01373 01374 rc = NFS_REQ_OK; 01375 goto out; 01376 } 01377 } 01378 01379 pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; 01380 pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; 01381 01382 /* How many entries will we retry from cache_inode ? */ 01383 if(begin_cookie > 1) 01384 { 01385 asked_num_entries = estimated_num_entries; 01386 xattr_cookie = begin_cookie - 2; 01387 } 01388 else 01389 { 01390 asked_num_entries = ((estimated_num_entries > 2) ? estimated_num_entries - 2 : 0); /* Keep space for '.' and '..' */ 01391 xattr_cookie = 0; 01392 } 01393 01394 /* A definition that will be very useful to avoid very long names for variables */ 01395 #define RES_READDIRPLUS_REPLY pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply 01396 01397 /* Used FSAL extended attributes functions */ 01398 fsal_status = FSAL_ListXAttrs(pfsal_handle, 01399 xattr_cookie, 01400 pcontext, 01401 xattrs_tab, asked_num_entries, &nb_xattrs_read, &eod_met); 01402 01403 if(!FSAL_IS_ERROR(fsal_status)) 01404 { 01405 if((nb_xattrs_read == 0) && (begin_cookie > 1)) 01406 { 01407 pres->res_readdirplus3.status = NFS3_OK; 01408 pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; 01409 pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE; 01410 01411 nfs_SetPostOpXAttrDir(pcontext, 01412 pexport, 01413 NULL, 01414 &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. 01415 dir_attributes)); 01416 01417 memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, 01418 cookie_verifier, sizeof(cookieverf3)); 01419 } 01420 else 01421 { 01422 /* Allocation of the structure for reply */ 01423 entry_name_array = 01424 gsh_calloc(estimated_num_entries, 01425 (FSAL_MAX_NAME_LEN + 1)); 01426 01427 if(entry_name_array == NULL) 01428 { 01429 rc = NFS_REQ_DROP; 01430 goto out; 01431 } 01432 01433 pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = 01434 gsh_calloc(estimated_num_entries, sizeof(entryplus3)); 01435 01436 if(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries 01437 == NULL) 01438 { 01439 gsh_free(entry_name_array); 01440 rc = NFS_REQ_DROP; 01441 goto out; 01442 } 01443 01444 /* Allocation of the file handles */ 01445 fh3_array = gsh_calloc(estimated_num_entries, NFS3_FHSIZE); 01446 01447 if(fh3_array == NULL) 01448 { 01449 gsh_free(entry_name_array); 01450 gsh_free(pres->res_readdirplus3.READDIRPLUS3res_u 01451 .resok.reply.entries); 01452 pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries 01453 = NULL; 01454 01455 rc = NFS_REQ_DROP; 01456 goto out; 01457 } 01458 01459 delta = 0; 01460 01461 /* manage . and .. */ 01462 if(begin_cookie == 0) 01463 { 01464 /* Fill in '.' */ 01465 if(estimated_num_entries > 0) 01466 { 01467 RES_READDIRPLUS_REPLY.entries[0].fileid = (0xFFFFFFFF & ~(dir_attr.fileid)) - 1; /* parent xattrd =>xattr_pos == 1 */ 01468 RES_READDIRPLUS_REPLY.entries[0].name = entry_name_array[0]; 01469 strcpy(RES_READDIRPLUS_REPLY.entries[0].name, "."); 01470 RES_READDIRPLUS_REPLY.entries[0].cookie = 1; 01471 01472 RES_READDIRPLUS_REPLY.entries[0].name_handle.post_op_fh3_u.handle.data. 01473 data_val = (char *)fh3_array[0]; 01474 01475 memcpy((char *)RES_READDIRPLUS_REPLY.entries[0].name_handle. 01476 post_op_fh3_u.handle.data.data_val, 01477 (char *)parg->arg_readdirplus3.dir.data.data_val, 01478 parg->arg_readdirplus3.dir.data.data_len); 01479 01480 RES_READDIRPLUS_REPLY.entries[0].name_handle.post_op_fh3_u.handle.data. 01481 data_len = parg->arg_readdirplus3.dir.data.data_len; 01482 pfile_handle = 01483 (file_handle_v3_t *) (RES_READDIRPLUS_REPLY.entries[0].name_handle. 01484 post_op_fh3_u.handle.data.data_val); 01485 pfile_handle->xattr_pos = 1; 01486 RES_READDIRPLUS_REPLY.entries[0].name_handle.handle_follows = TRUE; 01487 01488 /* Set PostPoFh3 structure */ 01489 nfs_SetPostOpXAttrDir(pcontext, 01490 pexport, 01491 &dir_attr, 01492 &(RES_READDIRPLUS_REPLY.entries[0]. 01493 name_attributes)); 01494 delta += 1; 01495 } 01496 01497 } 01498 01499 /* Fill in '..' */ 01500 if(begin_cookie <= 1) 01501 { 01502 if(estimated_num_entries > delta) 01503 { 01504 RES_READDIRPLUS_REPLY.entries[delta].fileid = (0xFFFFFFFF & ~(dir_attr.fileid)) - delta; /* different fileids for each xattr */ 01505 RES_READDIRPLUS_REPLY.entries[delta].name = entry_name_array[delta]; 01506 strcpy(RES_READDIRPLUS_REPLY.entries[delta].name, ".."); 01507 RES_READDIRPLUS_REPLY.entries[delta].cookie = 2; 01508 01509 RES_READDIRPLUS_REPLY.entries[delta].name_handle.post_op_fh3_u.handle. 01510 data.data_val = (char *)fh3_array[delta]; 01511 01512 memcpy((char *)RES_READDIRPLUS_REPLY.entries[delta].name_handle. 01513 post_op_fh3_u.handle.data.data_val, 01514 (char *)parg->arg_readdirplus3.dir.data.data_val, 01515 parg->arg_readdirplus3.dir.data.data_len); 01516 01517 RES_READDIRPLUS_REPLY.entries[delta].name_handle.post_op_fh3_u.handle. 01518 data.data_len = parg->arg_readdirplus3.dir.data.data_len; 01519 pfile_handle = 01520 (file_handle_v3_t *) (RES_READDIRPLUS_REPLY.entries[delta]. 01521 name_handle.post_op_fh3_u.handle.data. 01522 data_val); 01523 pfile_handle->xattr_pos = 0; 01524 RES_READDIRPLUS_REPLY.entries[delta].name_handle.handle_follows = TRUE; 01525 01526 RES_READDIRPLUS_REPLY.entries[delta].name_attributes.attributes_follow = 01527 FALSE; 01528 01529 RES_READDIRPLUS_REPLY.entries[0].nextentry = 01530 &(RES_READDIRPLUS_REPLY.entries[delta]); 01531 01532 if(num_entries > delta + 1) /* not 0 ??? */ 01533 RES_READDIRPLUS_REPLY.entries[delta].nextentry = 01534 &(RES_READDIRPLUS_REPLY.entries[delta + 1]); 01535 else 01536 RES_READDIRPLUS_REPLY.entries[delta].nextentry = NULL; 01537 01538 delta += 1; 01539 } 01540 } 01541 /* if( begin_cookie == 0 ) */ 01542 for(i = delta; i < nb_xattrs_read + delta; i++) 01543 { 01544 unsigned long needed; 01545 01546 /* dircount is the size without the FH and attributes overhead, so entry3 is used intead of entryplus3 */ 01547 needed = 01548 sizeof(entry3) + 01549 ((strlen(xattrs_tab[i - delta].xattr_name.name) + 3) & ~3); 01550 01551 if((space_used += needed) > maxcount) 01552 { 01553 if(i == delta) 01554 { 01555 /* 01556 * Not enough room to make even a single reply 01557 */ 01558 gsh_free(entry_name_array); 01559 gsh_free(fh3_array); 01560 gsh_free(pres->res_readdirplus3.READDIRPLUS3res_u 01561 .resok.reply.entries); 01562 pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply 01563 .entries = NULL; 01564 01565 pres->res_readdirplus3.status = NFS3ERR_TOOSMALL; 01566 01567 rc = NFS_REQ_OK; 01568 goto out; 01569 } 01570 break; /* Make post traitement */ 01571 } 01572 01573 /* Try to get a FSAL_XAttr of that name */ 01574 /* Build the FSAL name */ 01575 fsal_status = FSAL_GetXAttrIdByName(pfsal_handle, 01576 &xattrs_tab[i - delta].xattr_name, 01577 pcontext, &xattr_id); 01578 if(FSAL_IS_ERROR(fsal_status)) 01579 { 01580 pres->res_readdirplus3.status = 01581 nfs3_Errno(cache_inode_error_convert(fsal_status)); 01582 rc = NFS_REQ_OK; 01583 goto out; 01584 } 01585 01586 RES_READDIRPLUS_REPLY.entries[i].fileid = 01587 (0xFFFFFFFF & xattrs_tab[i - delta].attributes.fileid) - xattr_id; 01588 FSAL_name2str(&xattrs_tab[i - delta].xattr_name, entry_name_array[i], 01589 FSAL_MAX_NAME_LEN); 01590 RES_READDIRPLUS_REPLY.entries[i].name = entry_name_array[i]; 01591 01592 RES_READDIRPLUS_REPLY.entries[i].cookie = 01593 xattrs_tab[i - delta].xattr_cookie + 2; 01594 01595 RES_READDIRPLUS_REPLY.entries[i].name_attributes.attributes_follow = FALSE; 01596 RES_READDIRPLUS_REPLY.entries[i].name_handle.handle_follows = FALSE; 01597 01598 RES_READDIRPLUS_REPLY.entries[i].name_handle.post_op_fh3_u.handle.data. 01599 data_val = (char *)fh3_array[i]; 01600 01601 /* Set PostPoFh3 structure */ 01602 01603 memcpy((char *)RES_READDIRPLUS_REPLY.entries[i].name_handle.post_op_fh3_u. 01604 handle.data.data_val, 01605 (char *)parg->arg_readdirplus3.dir.data.data_val, 01606 parg->arg_readdirplus3.dir.data.data_len); 01607 RES_READDIRPLUS_REPLY.entries[i].name_handle.post_op_fh3_u.handle.data. 01608 data_len = parg->arg_readdirplus3.dir.data.data_len; 01609 pfile_handle = 01610 (file_handle_v3_t *) (RES_READDIRPLUS_REPLY.entries[i].name_handle. 01611 post_op_fh3_u.handle.data.data_val); 01612 pfile_handle->xattr_pos = xattr_id + 2; 01613 01614 RES_READDIRPLUS_REPLY.entries[i].name_handle.handle_follows = TRUE; 01615 01616 RES_READDIRPLUS_REPLY.entries[i].nextentry = NULL; 01617 if(i != 0) 01618 RES_READDIRPLUS_REPLY.entries[i - 1].nextentry = 01619 &(RES_READDIRPLUS_REPLY.entries[i]); 01620 01621 } /* for */ 01622 } /* else */ 01623 01624 if(eod_met) 01625 RES_READDIRPLUS_REPLY.eof = TRUE; 01626 else 01627 RES_READDIRPLUS_REPLY.eof = FALSE; 01628 01629 nfs_SetPostOpXAttrDir(pcontext, 01630 pexport, 01631 &dir_attr, 01632 &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. 01633 dir_attributes)); 01634 memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, 01635 sizeof(cookieverf3)); 01636 01637 pres->res_readdir3.status = NFS3_OK; 01638 01639 rc = NFS_REQ_OK; 01640 goto out; 01641 } 01642 01643 /* if( !FSAL_IS_ERROR( fsal_status ) ) */ 01644 /* Is this point is reached, then there is an error */ 01645 pres->res_readdir3.status = NFS3ERR_IO; 01646 01647 /* Set failed status */ 01648 nfs_SetFailedStatus(pcontext, 01649 pexport, 01650 NFS_V3, 01651 cache_status, 01652 NULL, 01653 &pres->res_readdirplus3.status, 01654 dir_pentry, 01655 &(pres->res_readdirplus3.READDIRPLUS3res_u.resfail.dir_attributes), 01656 NULL, NULL, NULL, NULL, NULL, NULL); 01657 01658 rc = NFS_REQ_OK; 01659 01660 out: 01661 /* return references */ 01662 if (dir_pentry) 01663 cache_inode_put(dir_pentry); 01664 01665 return (rc); 01666 01667 } /* nfs3_Readdirplus_Xattr */ 01668 01684 int nfs3_Getattr_Xattr(nfs_arg_t * parg, 01685 exportlist_t * pexport, 01686 fsal_op_context_t * pcontext, 01687 struct svc_req *preq, nfs_res_t * pres) 01688 { 01689 fsal_attrib_list_t attr; 01690 fsal_handle_t *pfsal_handle = NULL; 01691 cache_entry_t *pentry = NULL; 01692 file_handle_v3_t *pfile_handle = NULL; 01693 unsigned int xattr_id = 0; 01694 int rc = NFS_REQ_OK; 01695 01696 if((pentry = nfs_FhandleToCache(NFS_V3, 01697 NULL, 01698 &(parg->arg_getattr3.object), 01699 NULL, 01700 NULL, 01701 &(pres->res_getattr3.status), 01702 NULL, &attr, pcontext, &rc)) == NULL) 01703 { 01704 /* Stale NFS FH ? */ 01705 goto out; 01706 } 01707 01708 /* Get the FSAL Handle */ 01709 pfsal_handle = &pentry->handle; 01710 01711 /* Rebuild the FH */ 01712 pfile_handle = (file_handle_v3_t *) (parg->arg_getattr3.object.data.data_val); 01713 01714 /* for Xattr FH, we adopt the current convention: 01715 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01716 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01717 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01718 xattr_id = pfile_handle->xattr_pos - 2; 01719 01720 if(pfile_handle->xattr_pos == 0) 01721 { 01722 /* should not have been called */ 01723 pres->res_getattr3.status = NFS3ERR_INVAL; 01724 rc = NFS_REQ_OK; 01725 goto out; 01726 } 01727 else if(pfile_handle->xattr_pos == 1) 01728 nfs3_FSALattr_To_XattrDir(pexport, &attr, 01729 &pres->res_getattr3.GETATTR3res_u.resok.obj_attributes); 01730 else 01731 { 01732 fsal_status_t fsal_status; 01733 fsal_attrib_list_t xattrs; 01734 01735 xattrs.asked_attributes = cache_inode_params.attrmask; 01736 fsal_status = FSAL_GetXAttrAttrs(pfsal_handle, pcontext, xattr_id, &xattrs); 01737 01738 if(FSAL_IS_ERROR(fsal_status)) 01739 { 01740 pres->res_getattr3.status = nfs3_Errno(cache_inode_error_convert(fsal_status)); 01741 rc = NFS_REQ_OK; 01742 goto out; 01743 } 01744 01745 nfs3_FSALattr_To_Fattr(pexport, &xattrs, 01746 &pres->res_getattr3.GETATTR3res_u.resok.obj_attributes); 01747 } 01748 01749 pres->res_getattr3.status = NFS3_OK; 01750 01751 rc = NFS_REQ_OK; 01752 01753 out: 01754 /* return references */ 01755 if (pentry) 01756 cache_inode_put(pentry); 01757 01758 return (rc); 01759 01760 } /* nfs3_Getattr_Xattr */ 01761 01762 int nfs3_Remove_Xattr(nfs_arg_t * parg /* IN */ , 01763 exportlist_t * pexport /* IN */ , 01764 fsal_op_context_t * pcontext /* IN */ , 01765 struct svc_req *preq /* IN */ , 01766 nfs_res_t * pres /* OUT */ ) 01767 { 01768 cache_entry_t *pentry = NULL; 01769 fsal_handle_t *pfsal_handle = NULL; 01770 fsal_status_t fsal_status; 01771 fsal_name_t name = FSAL_NAME_INITIALIZER; 01772 fsal_attrib_list_t attr; 01773 int rc = NFS_REQ_OK; 01774 01775 if((pentry = nfs_FhandleToCache(NFS_V3, 01776 NULL, 01777 &(parg->arg_remove3.object.dir), 01778 NULL, 01779 NULL, 01780 &(pres->res_remove3.status), 01781 NULL, &attr, pcontext, &rc)) == NULL) 01782 { 01783 /* Stale NFS FH ? */ 01784 goto out; 01785 } 01786 01787 /* Get the FSAL Handle */ 01788 pfsal_handle = &pentry->handle; 01789 01790 /* convert attr name to FSAL name */ 01791 FSAL_str2name(parg->arg_remove3.object.name, MAXNAMLEN, &name); 01792 01793 fsal_status = FSAL_RemoveXAttrByName(pfsal_handle, pcontext, &name); 01794 if(FSAL_IS_ERROR(fsal_status)) 01795 { 01796 pres->res_remove3.status = NFS3ERR_SERVERFAULT; 01797 rc = NFS_REQ_OK; 01798 goto out; 01799 } 01800 01801 /* Set Post Op attrs */ 01802 pres->res_remove3.REMOVE3res_u.resok.dir_wcc.before.attributes_follow = FALSE; 01803 pres->res_remove3.REMOVE3res_u.resok.dir_wcc.after.attributes_follow = FALSE; 01804 01805 pres->res_remove3.status = NFS3_OK; 01806 rc = NFS_REQ_OK; 01807 01808 out: 01809 /* return references */ 01810 if (pentry) 01811 cache_inode_put(pentry); 01812 01813 return (rc); 01814 01815 }