nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 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_tools.h" 00057 #include "nfs_exports.h" 00058 #include "nfs_file_handle.h" 00059 #include "cache_inode.h" 00060 00061 int nfs4_XattrToFattr(fattr4 * Fattr, 00062 compound_data_t * data, nfs_fh4 * objFH, bitmap4 * Bitmap) 00063 { 00064 fattr4_type file_type; 00065 fattr4_link_support link_support; 00066 fattr4_symlink_support symlink_support; 00067 fattr4_fh_expire_type expire_type; 00068 fattr4_named_attr named_attr; 00069 fattr4_unique_handles unique_handles; 00070 fattr4_archive archive; 00071 fattr4_cansettime cansettime; 00072 fattr4_case_insensitive case_insensitive; 00073 fattr4_case_preserving case_preserving; 00074 fattr4_chown_restricted chown_restricted; 00075 fattr4_hidden hidden; 00076 fattr4_mode file_mode; 00077 fattr4_no_trunc no_trunc; 00078 fattr4_numlinks file_numlinks; 00079 fattr4_rawdev rawdev; 00080 fattr4_system system; 00081 fattr4_size file_size; 00082 fattr4_space_used file_space_used; 00083 fattr4_fsid fsid; 00084 fattr4_time_access time_access; 00085 fattr4_time_modify time_modify; 00086 fattr4_time_metadata time_metadata; 00087 fattr4_time_delta time_delta; 00088 fattr4_time_backup time_backup; 00089 fattr4_time_create time_create; 00090 fattr4_change file_change; 00091 fattr4_fileid file_id; 00092 fattr4_owner file_owner; 00093 fattr4_owner_group file_owner_group; 00094 fattr4_space_avail space_avail; 00095 fattr4_space_free space_free; 00096 fattr4_space_total space_total; 00097 fattr4_files_avail files_avail; 00098 fattr4_files_free files_free; 00099 fattr4_files_total files_total; 00100 fattr4_lease_time lease_time; 00101 fattr4_maxfilesize max_filesize; 00102 fattr4_maxread maxread; 00103 fattr4_maxwrite maxwrite; 00104 fattr4_maxname maxname; 00105 fattr4_maxlink maxlink; 00106 fattr4_homogeneous homogeneous; 00107 fattr4_acl acl; 00108 fattr4_mimetype mimetype; 00109 fattr4_aclsupport aclsupport; 00110 fattr4_quota_avail_hard quota_avail_hard; 00111 fattr4_quota_avail_soft quota_avail_soft; 00112 fattr4_quota_used quota_used; 00113 fattr4_rdattr_error rdattr_error; 00114 file_handle_v4_t *pfile_handle = NULL; 00115 fsal_attrib_list_t fsalattr; 00116 00117 u_int fhandle_len = 0; 00118 unsigned int LastOffset; 00119 unsigned int len = 0, off = 0; /* Use for XDR alignment */ 00120 int op_attr_success = 0; 00121 unsigned int i = 0; 00122 unsigned int j = 0; 00123 unsigned int attrmasklen = 0; 00124 unsigned int attribute_to_set = 0; 00125 00126 unsigned int attrmasklist[FATTR4_MOUNTED_ON_FILEID]; /* List cannot be longer than FATTR4_MOUNTED_ON_FILEID */ 00127 unsigned int attrvalslist[FATTR4_MOUNTED_ON_FILEID]; /* List cannot be longer than FATTR4_MOUNTED_ON_FILEID */ 00128 char attrvalsBuffer[ATTRVALS_BUFFLEN]; 00129 00130 char __attribute__ ((__unused__)) funcname[] = "nfs4_XattrToFattr"; 00131 00132 pfile_handle = (file_handle_v4_t *) (objFH->nfs_fh4_val); 00133 00134 /* memset to make sure the arrays are initiated to 0 */ 00135 memset(attrvalsBuffer, 0, NFS4_ATTRVALS_BUFFLEN); 00136 memset(&attrmasklist, 0, FATTR4_MOUNTED_ON_FILEID * sizeof(unsigned int)); 00137 memset(&attrvalslist, 0, FATTR4_MOUNTED_ON_FILEID * sizeof(unsigned int)); 00138 00139 /* Convert the attribute bitmap to an attribute list */ 00140 nfs4_bitmap4_to_list(Bitmap, &attrmasklen, attrmasklist); 00141 00142 /* Once the bitmap has been converted to a list of attribute, manage each attribute */ 00143 Fattr->attr_vals.attrlist4_len = 0; 00144 LastOffset = 0; 00145 j = 0; 00146 00147 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00148 "Asked Attributes (Pseudo): Bitmap = (len=%d, val[0]=%d, val[1]=%d), %d item in list", 00149 Bitmap->bitmap4_len, Bitmap->bitmap4_val[0], Bitmap->bitmap4_val[1], 00150 attrmasklen); 00151 00152 for(i = 0; i < attrmasklen; i++) 00153 { 00154 attribute_to_set = attrmasklist[i]; 00155 00156 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00157 "Flag for Operation (Pseudo) = %d|%d is ON, name = %s reply_size = %d", 00158 attrmasklist[i], fattr4tab[attribute_to_set].val, 00159 fattr4tab[attribute_to_set].name, 00160 fattr4tab[attribute_to_set].size_fattr4); 00161 00162 op_attr_success = 0; 00163 00164 /* compute the new size for the fattr4 reply */ 00165 /* This space is to be filled below in the big switch/case statement */ 00166 00167 switch (attribute_to_set) 00168 { 00169 case FATTR4_SUPPORTED_ATTRS: 00170 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00171 "-----> Wanting FATTR4_SUPPORTED_ATTRS"); 00172 LastOffset += nfs4_supported_attrs_to_fattr(attrvalsBuffer+LastOffset); 00173 00174 /* This kind of operation is always a success */ 00175 op_attr_success = 1; 00176 break; 00177 00178 case FATTR4_TYPE: 00179 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00180 "-----> Wanting FATTR4_TYPE"); 00181 00182 op_attr_success = 1; 00183 00184 if(pfile_handle->xattr_pos == 1) 00185 file_type = htonl(NF4DIR); /* There are only directories in the pseudo fs */ 00186 else 00187 file_type = htonl(NF4REG); 00188 00189 memcpy((char *)(attrvalsBuffer + LastOffset), &file_type, sizeof(fattr4_type)); 00190 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00191 break; 00192 00193 case FATTR4_FH_EXPIRE_TYPE: 00194 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00195 "-----> Wanting FATTR4_FH_EXPIRE_TYPE"); 00196 00197 /* For the moment, we handle only the persistent filehandle */ 00198 /* expire_type = htonl( FH4_VOLATILE_ANY ) ; */ 00199 expire_type = htonl(FH4_PERSISTENT); 00200 memcpy((char *)(attrvalsBuffer + LastOffset), &expire_type, 00201 sizeof(expire_type)); 00202 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00203 op_attr_success = 1; 00204 break; 00205 00206 case FATTR4_CHANGE: 00207 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00208 "-----> Wanting FATTR4_CHANGE"); 00209 00210 /* Use boot time as time value for every pseudo fs object */ 00211 memset(&file_change, 0, sizeof(changeid4)); 00212 file_change = nfs_htonl64((changeid4) time(NULL)); 00213 00214 memcpy((char *)(attrvalsBuffer + LastOffset), &file_change, 00215 sizeof(fattr4_change)); 00216 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00217 op_attr_success = 1; 00218 break; 00219 00220 case FATTR4_SIZE: 00221 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00222 "-----> Wanting FATTR4_SIZE"); 00223 00224 file_size = nfs_htonl64((fattr4_size) DEV_BSIZE); 00225 memcpy((char *)(attrvalsBuffer + LastOffset), &file_size, sizeof(fattr4_size)); 00226 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00227 op_attr_success = 1; 00228 break; 00229 00230 case FATTR4_LINK_SUPPORT: 00231 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00232 "-----> Wanting FATTR4_LINK_SUPPORT"); 00233 00234 /* HPSS NameSpace support hard link */ 00235 link_support = htonl(TRUE); 00236 memcpy((char *)(attrvalsBuffer + LastOffset), &link_support, 00237 sizeof(fattr4_link_support)); 00238 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00239 op_attr_success = 1; 00240 break; 00241 00242 case FATTR4_SYMLINK_SUPPORT: 00243 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00244 "-----> Wanting FATTR4_SYMLINK_SUPPORT"); 00245 00246 /* HPSS NameSpace support symbolic link */ 00247 symlink_support = htonl(TRUE); 00248 memcpy((char *)(attrvalsBuffer + LastOffset), &symlink_support, 00249 sizeof(fattr4_symlink_support)); 00250 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00251 op_attr_success = 1; 00252 break; 00253 00254 case FATTR4_NAMED_ATTR: 00255 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00256 "-----> Wanting FATTR4_NAMED_ATTR"); 00257 00258 /* For this version of the binary, named attributes is not supported */ 00259 named_attr = htonl(FALSE); 00260 memcpy((char *)(attrvalsBuffer + LastOffset), &named_attr, 00261 sizeof(fattr4_named_attr)); 00262 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00263 op_attr_success = 1; 00264 break; 00265 00266 case FATTR4_FSID: 00267 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00268 "-----> Wanting FATTR4_FSID"); 00269 00270 fsid.major = nfs_htonl64((uint64_t) data->pexport->filesystem_id.major); 00271 fsid.minor = nfs_htonl64((uint64_t) data->pexport->filesystem_id.minor); 00272 00273 memcpy((char *)(attrvalsBuffer + LastOffset), &fsid, sizeof(fattr4_fsid)); 00274 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00275 op_attr_success = 1; 00276 break; 00277 00278 case FATTR4_UNIQUE_HANDLES: 00279 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00280 "-----> Wanting FATTR4_UNIQUE_HANDLES"); 00281 00282 /* Filehandles are unique */ 00283 unique_handles = htonl(TRUE); 00284 memcpy((char *)(attrvalsBuffer + LastOffset), &unique_handles, 00285 sizeof(fattr4_unique_handles)); 00286 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00287 op_attr_success = 1; 00288 break; 00289 00290 case FATTR4_LEASE_TIME: 00291 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00292 "-----> Wanting FATTR4_LEASE_TIME"); 00293 00294 lease_time = htonl(nfs_param.nfsv4_param.lease_lifetime); 00295 memcpy((char *)(attrvalsBuffer + LastOffset), &lease_time, 00296 sizeof(fattr4_lease_time)); 00297 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00298 op_attr_success = 1; 00299 break; 00300 00301 case FATTR4_RDATTR_ERROR: 00302 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00303 "-----> Wanting FATTR4_RDATTR_ERROR"); 00304 00305 rdattr_error = htonl(NFS4_OK); /* By default, READDIR call may use a different value */ 00306 memcpy((char *)(attrvalsBuffer + LastOffset), &rdattr_error, 00307 sizeof(fattr4_rdattr_error)); 00308 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00309 op_attr_success = 1; 00310 break; 00311 00312 case FATTR4_ACL: 00313 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00314 "-----> Wanting FATTR4_ACL"); 00315 00316 acl.fattr4_acl_len = htonl(0); 00317 memcpy((char *)(attrvalsBuffer + LastOffset), &acl, sizeof(fattr4_acl)); 00318 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00319 op_attr_success = 1; 00320 break; 00321 00322 case FATTR4_ACLSUPPORT: 00323 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00324 "-----> Wanting FATTR4_ACL_SUPPORT"); 00325 00326 aclsupport = htonl(ACL4_SUPPORT_DENY_ACL); /* temporary, wanting for houston to give me information to implemente ACL's support */ 00327 memcpy((char *)(attrvalsBuffer + LastOffset), &aclsupport, 00328 sizeof(fattr4_aclsupport)); 00329 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00330 op_attr_success = 1; 00331 break; 00332 00333 case FATTR4_ARCHIVE: 00334 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00335 "-----> Wanting FATTR4_ARCHIVE"); 00336 00337 /* Archive flag is not supported */ 00338 archive = htonl(FALSE); 00339 memcpy((char *)(attrvalsBuffer + LastOffset), &archive, sizeof(fattr4_archive)); 00340 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00341 op_attr_success = 1; 00342 break; 00343 00344 case FATTR4_CANSETTIME: 00345 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00346 "-----> Wanting FATTR4_CANSETTIME"); 00347 00348 /* The time can be set on files */ 00349 cansettime = htonl(TRUE); 00350 memcpy((char *)(attrvalsBuffer + LastOffset), &cansettime, 00351 sizeof(fattr4_cansettime)); 00352 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00353 op_attr_success = 1; 00354 break; 00355 00356 case FATTR4_CASE_INSENSITIVE: 00357 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00358 "-----> Wanting FATTR4_CASE_INSENSITIVE"); 00359 00360 /* pseudofs is not case INSENSITIVE... it is Read-Only */ 00361 case_insensitive = htonl(FALSE); 00362 memcpy((char *)(attrvalsBuffer + LastOffset), &case_insensitive, 00363 sizeof(fattr4_case_insensitive)); 00364 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00365 op_attr_success = 1; 00366 break; 00367 00368 case FATTR4_CASE_PRESERVING: 00369 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00370 "-----> Wanting FATTR4_PRESERVING"); 00371 00372 /* pseudofs is case preserving... it is Read-Only */ 00373 case_preserving = htonl(TRUE); 00374 memcpy((char *)(attrvalsBuffer + LastOffset), &case_preserving, 00375 sizeof(fattr4_case_preserving)); 00376 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00377 op_attr_success = 1; 00378 break; 00379 00380 case FATTR4_CHOWN_RESTRICTED: 00381 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00382 "-----> Wanting FATTR4_CHOWN_RESTRICTED"); 00383 00384 /* chown is restricted to root, but in fact no chown will be done on pseudofs */ 00385 chown_restricted = htonl(TRUE); 00386 memcpy((char *)(attrvalsBuffer + LastOffset), &chown_restricted, 00387 sizeof(fattr4_chown_restricted)); 00388 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00389 op_attr_success = 1; 00390 break; 00391 00392 case FATTR4_FILEHANDLE: 00393 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00394 "-----> Wanting FATTR4_FILEHANDLE"); 00395 00396 /* Return the file handle */ 00397 fhandle_len = htonl(objFH->nfs_fh4_len); 00398 00399 memcpy((char *)(attrvalsBuffer + LastOffset), &fhandle_len, sizeof(u_int)); 00400 LastOffset += sizeof(u_int); 00401 00402 memcpy((char *)(attrvalsBuffer + LastOffset), 00403 objFH->nfs_fh4_val, objFH->nfs_fh4_len); 00404 LastOffset += objFH->nfs_fh4_len; 00405 00406 /* XDR's special stuff for 32-bit alignment */ 00407 len = objFH->nfs_fh4_len; 00408 off = 0; 00409 while((len + off) % 4 != 0) 00410 { 00411 char c = '\0'; 00412 00413 off += 1; 00414 memset((char *)(attrvalsBuffer + LastOffset), c, 1); 00415 LastOffset += 1; 00416 } 00417 00418 op_attr_success = 1; 00419 break; 00420 00421 case FATTR4_FILEID: 00422 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00423 "-----> Wanting FATTR4_FILEID xattr_pos=%u", 00424 pfile_handle->xattr_pos + 1); 00425 00426 /* The analog to the inode number. RFC3530 says "a number uniquely identifying the file within the filesystem" 00427 * In the case of a pseudofs entry, the entry's unique id is used */ 00428 fsalattr = data->current_entry->attributes; 00429 00430 #ifndef _XATTR_D_USE_SAME_INUM /* I wrapped off this part of the code... Not sure it would be useful */ 00431 file_id = nfs_htonl64(~(fsalattr.fileid)); 00432 00433 file_id = nfs_htonl64(~(fsalattr.fileid)) - pfile_handle->xattr_pos; 00434 #else 00435 file_id = nfs_htonl64(fsalattr.fileid); 00436 #endif 00437 00438 memcpy((char *)(attrvalsBuffer + LastOffset), &file_id, sizeof(fattr4_fileid)); 00439 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00440 op_attr_success = 1; 00441 break; 00442 00443 case FATTR4_FILES_AVAIL: 00444 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00445 "-----> Wanting FATTR4_FILES_AVAIL"); 00446 00447 files_avail = nfs_htonl64((fattr4_files_avail) 512); /* Fake value */ 00448 memcpy((char *)(attrvalsBuffer + LastOffset), &files_avail, 00449 sizeof(fattr4_files_avail)); 00450 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00451 op_attr_success = 1; 00452 break; 00453 00454 case FATTR4_FILES_FREE: 00455 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00456 "-----> Wanting FATTR4_FILES_FREE"); 00457 00458 files_free = nfs_htonl64((fattr4_files_avail) 512); /* Fake value */ 00459 memcpy((char *)(attrvalsBuffer + LastOffset), &files_free, 00460 sizeof(fattr4_files_free)); 00461 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00462 op_attr_success = 1; 00463 break; 00464 00465 case FATTR4_FILES_TOTAL: 00466 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00467 "-----> Wanting FATTR4_FILES_TOTAL"); 00468 00469 files_total = nfs_htonl64((fattr4_files_avail) 512); /* Fake value */ 00470 memcpy((char *)(attrvalsBuffer + LastOffset), &files_total, 00471 sizeof(fattr4_files_total)); 00472 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00473 op_attr_success = 1; 00474 break; 00475 00476 case FATTR4_FS_LOCATIONS: 00477 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00478 "-----> Wanting FATTR4_FS_LOCATIONS"); 00479 /* RFC 3530: "When the fs_locations attribute is interrogated and there are no 00480 alternate file system locations, the server SHOULD return a zero- 00481 length array of fs_location4 structures, together with a valid 00482 fs_root. The code below does not return a fs_root which causes client 00483 problems when they interrogate this attribute. For now moving attribute to 00484 unsupported. 00485 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00486 op_attr_success = 1; 00487 */ 00488 op_attr_success = 0; 00489 break; 00490 00491 case FATTR4_HIDDEN: 00492 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00493 "-----> Wanting FATTR4_HIDDEN"); 00494 00495 /* There are no hidden file in pseudofs */ 00496 hidden = htonl(FALSE); 00497 memcpy((char *)(attrvalsBuffer + LastOffset), &hidden, sizeof(fattr4_hidden)); 00498 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00499 op_attr_success = 1; 00500 break; 00501 00502 case FATTR4_HOMOGENEOUS: 00503 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00504 "-----> Wanting FATTR4_HOMOGENEOUS"); 00505 00506 /* Unix semantic is homogeneous (all objects have the same kind of attributes) */ 00507 homogeneous = htonl(TRUE); 00508 memcpy((char *)(attrvalsBuffer + LastOffset), &homogeneous, 00509 sizeof(fattr4_homogeneous)); 00510 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00511 op_attr_success = 1; 00512 break; 00513 00514 case FATTR4_MAXFILESIZE: 00515 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00516 "-----> Wanting FATTR4_MAXFILESIZE"); 00517 00518 max_filesize = nfs_htonl64((fattr4_maxfilesize) FSINFO_MAX_FILESIZE); 00519 memcpy((char *)(attrvalsBuffer + LastOffset), &max_filesize, 00520 sizeof(fattr4_maxfilesize)); 00521 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00522 op_attr_success = 1; 00523 break; 00524 00525 case FATTR4_MAXLINK: 00526 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00527 "-----> Wanting FATTR4_MAXLINK"); 00528 00529 maxlink = htonl(MAX_HARD_LINK_VALUE); 00530 memcpy((char *)(attrvalsBuffer + LastOffset), &maxlink, sizeof(fattr4_maxlink)); 00531 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00532 op_attr_success = 1; 00533 break; 00534 00535 case FATTR4_MAXNAME: 00536 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00537 "-----> Wanting FATTR4_MAXNAME"); 00538 00539 maxname = htonl((fattr4_maxname) MAXNAMLEN); 00540 memcpy((char *)(attrvalsBuffer + LastOffset), &maxname, sizeof(fattr4_maxname)); 00541 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00542 op_attr_success = 1; 00543 break; 00544 00545 case FATTR4_MAXREAD: 00546 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00547 "-----> Wanting FATTR4_MAXREAD"); 00548 00549 maxread = nfs_htonl64((fattr4_maxread) NFS4_PSEUDOFS_MAX_READ_SIZE); 00550 memcpy((char *)(attrvalsBuffer + LastOffset), &maxread, sizeof(fattr4_maxread)); 00551 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00552 op_attr_success = 1; 00553 break; 00554 00555 case FATTR4_MAXWRITE: 00556 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00557 "-----> Wanting FATTR4_MAXWRITE"); 00558 00559 maxwrite = nfs_htonl64((fattr4_maxwrite) NFS4_PSEUDOFS_MAX_WRITE_SIZE); 00560 memcpy((char *)(attrvalsBuffer + LastOffset), &maxwrite, 00561 sizeof(fattr4_maxwrite)); 00562 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00563 op_attr_success = 1; 00564 break; 00565 00566 case FATTR4_MIMETYPE: 00567 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00568 "-----> Wanting FATTR4_MIMETYPE"); 00569 00570 mimetype.utf8string_len = htonl(0); 00571 memcpy((char *)(attrvalsBuffer + LastOffset), &mimetype, 00572 sizeof(fattr4_mimetype)); 00573 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00574 op_attr_success = 1; /* No supported for the moment */ 00575 break; 00576 00577 case FATTR4_MODE: 00578 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00579 "-----> Wanting FATTR4_MODE"); 00580 00581 if(pfile_handle->xattr_pos == 1) 00582 file_mode = htonl(0555); /* Every pseudo fs object is dr-xr-xr-x */ 00583 else 00584 file_mode = htonl(0644); /* -rw-r--r-- */ 00585 00586 memcpy((char *)(attrvalsBuffer + LastOffset), &file_mode, sizeof(fattr4_mode)); 00587 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00588 op_attr_success = 1; 00589 break; 00590 00591 case FATTR4_NO_TRUNC: 00592 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00593 "-----> Wanting FATTR4_NO_TRUNC"); 00594 00595 /* File's names are not truncated, an error is returned is name is too long */ 00596 no_trunc = htonl(TRUE); 00597 memcpy((char *)(attrvalsBuffer + LastOffset), &no_trunc, 00598 sizeof(fattr4_no_trunc)); 00599 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00600 op_attr_success = 1; 00601 break; 00602 00603 case FATTR4_NUMLINKS: 00604 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00605 "-----> Wanting FATTR4_NUMLINKS"); 00606 00607 /* Reply the number of links found in vattr structure */ 00608 file_numlinks = htonl((fattr4_numlinks) 1); 00609 memcpy((char *)(attrvalsBuffer + LastOffset), &file_numlinks, 00610 sizeof(fattr4_numlinks)); 00611 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00612 op_attr_success = 1; 00613 break; 00614 00615 case FATTR4_OWNER: 00616 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00617 "-----> Wanting FATTR4_OWNER"); 00618 00619 /* Return the uid as a human readable utf8 string */ 00620 if(uid2utf8(NFS4_ROOT_UID, &file_owner) == 0) 00621 { 00622 u_int utf8len = 0; 00623 u_int deltalen = 0; 00624 00625 /* Take care of 32 bits alignment */ 00626 if(file_owner.utf8string_len % 4 == 0) 00627 deltalen = 0; 00628 else 00629 deltalen = 4 - file_owner.utf8string_len % 4; 00630 /* Following code used to add deltalen to utf8len which is wrong. It caused 00631 * clients verifying utf8 strings to reject the attribute. 00632 */ 00633 utf8len = htonl(file_owner.utf8string_len); 00634 memcpy((char *)(attrvalsBuffer + LastOffset), &utf8len, sizeof(u_int)); 00635 LastOffset += sizeof(u_int); 00636 00637 memcpy((char *)(attrvalsBuffer + LastOffset), 00638 file_owner.utf8string_val, file_owner.utf8string_len); 00639 LastOffset += file_owner.utf8string_len; 00640 00641 /* Free what was allocated by uid2utf8 */ 00642 gsh_free(file_owner.utf8string_val); 00643 00644 /* Pad with zero to keep xdr alignement */ 00645 if(deltalen != 0) 00646 memset((char *)(attrvalsBuffer + LastOffset), 0, deltalen); 00647 LastOffset += deltalen; 00648 00649 op_attr_success = 1; 00650 } 00651 else 00652 op_attr_success = 0; 00653 break; 00654 00655 case FATTR4_OWNER_GROUP: 00656 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00657 "-----> Wanting FATTR4_OWNER_GROUP"); 00658 00659 /* Return the uid as a human readable utf8 string */ 00660 if(gid2utf8(2, &file_owner_group) == 0) 00661 { 00662 u_int utf8len = 0; 00663 u_int deltalen = 0; 00664 00665 /* Take care of 32 bits alignment */ 00666 if(file_owner_group.utf8string_len % 4 == 0) 00667 deltalen = 0; 00668 else 00669 deltalen = 4 - file_owner_group.utf8string_len % 4; 00670 00671 /* Following code used to add deltalen to utf8len which is wrong. It caused 00672 * clients verifying utf8 strings to reject the attribute. 00673 */ 00674 utf8len = htonl(file_owner_group.utf8string_len); 00675 memcpy((char *)(attrvalsBuffer + LastOffset), &utf8len, sizeof(u_int)); 00676 LastOffset += sizeof(u_int); 00677 00678 memcpy((char *)(attrvalsBuffer + LastOffset), 00679 file_owner_group.utf8string_val, file_owner_group.utf8string_len); 00680 LastOffset += file_owner_group.utf8string_len; 00681 00682 /* Free what was used for utf8 conversion */ 00683 gsh_free(file_owner_group.utf8string_val); 00684 00685 /* Pad with zero to keep xdr alignement */ 00686 if(deltalen != 0) 00687 memset((attrvalsBuffer + LastOffset), 0, deltalen); 00688 LastOffset += deltalen; 00689 00690 op_attr_success = 1; 00691 } 00692 else 00693 op_attr_success = 0; 00694 break; 00695 00696 case FATTR4_QUOTA_AVAIL_HARD: 00697 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00698 "-----> Wanting FATTR4_QUOTA_AVAIL_HARD"); 00699 00700 quota_avail_hard = nfs_htonl64((fattr4_quota_avail_hard) NFS_V4_MAX_QUOTA_HARD); 00701 memcpy((char *)(attrvalsBuffer + LastOffset), "a_avail_hard, 00702 sizeof(fattr4_quota_avail_hard)); 00703 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00704 op_attr_success = 1; 00705 break; 00706 00707 case FATTR4_QUOTA_AVAIL_SOFT: 00708 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00709 "-----> Wanting FATTR4_QUOTA_AVAIL_SOFT"); 00710 00711 quota_avail_soft = nfs_htonl64((fattr4_quota_avail_soft) NFS_V4_MAX_QUOTA_SOFT); 00712 memcpy((char *)(attrvalsBuffer + LastOffset), "a_avail_soft, 00713 sizeof(fattr4_quota_avail_soft)); 00714 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00715 op_attr_success = 1; 00716 break; 00717 00718 case FATTR4_QUOTA_USED: 00719 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00720 "-----> Wanting FATTR4_QUOTA_AVAIL_USED"); 00721 00722 quota_used = nfs_htonl64((fattr4_quota_used) NFS_V4_MAX_QUOTA); 00723 memcpy((char *)(attrvalsBuffer + LastOffset), "a_used, 00724 sizeof(fattr4_quota_used)); 00725 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00726 op_attr_success = 1; 00727 break; 00728 00729 case FATTR4_RAWDEV: 00730 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00731 "-----> Wanting FATTR4_RAWDEV"); 00732 00733 /* Not usefull, there are no special block or character file in HPSS */ 00734 /* since FATTR4_TYPE will never be NFS4BLK or NFS4CHR, this value should not be used by the client */ 00735 rawdev.specdata1 = htonl(0); 00736 rawdev.specdata2 = htonl(0); 00737 memcpy((char *)(attrvalsBuffer + LastOffset), &rawdev, sizeof(fattr4_rawdev)); 00738 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00739 op_attr_success = 1; 00740 break; 00741 00742 case FATTR4_SPACE_AVAIL: 00743 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00744 "-----> Wanting FATTR4_SPACE_AVAIL"); 00745 00746 space_avail = nfs_htonl64(512000LL); /* Fake value */ 00747 memcpy((char *)(attrvalsBuffer + LastOffset), &space_avail, 00748 sizeof(fattr4_space_avail)); 00749 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00750 op_attr_success = 1; 00751 break; 00752 00753 case FATTR4_SPACE_FREE: 00754 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00755 "-----> Wanting FATTR4_SPACE_FREE"); 00756 00757 space_free = nfs_htonl64(512000LL); /* Fake value */ 00758 memcpy((char *)(attrvalsBuffer + LastOffset), &space_free, 00759 sizeof(fattr4_space_free)); 00760 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00761 op_attr_success = 1; 00762 break; 00763 00764 case FATTR4_SPACE_TOTAL: 00765 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00766 "-----> Wanting FATTR4_SPACE_TOTAL"); 00767 00768 space_total = nfs_htonl64(1024000LL); /* Fake value */ 00769 memcpy((char *)(attrvalsBuffer + LastOffset), &space_total, 00770 sizeof(fattr4_space_total)); 00771 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00772 op_attr_success = 1; 00773 break; 00774 00775 case FATTR4_SPACE_USED: 00776 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00777 "-----> Wanting FATTR4_SPACE_USED"); 00778 00779 /* the number of bytes on the filesystem used by the object, which is slightly different 00780 * from the file's size (there can be hole in the file) */ 00781 file_space_used = nfs_htonl64((fattr4_space_used) DEV_BSIZE); 00782 memcpy((char *)(attrvalsBuffer + LastOffset), &file_space_used, 00783 sizeof(fattr4_space_used)); 00784 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00785 op_attr_success = 1; 00786 break; 00787 00788 case FATTR4_SYSTEM: 00789 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00790 "-----> Wanting FATTR4_SYSTEM"); 00791 00792 /* This is not a windows system File-System with respect to the regarding API */ 00793 system = htonl(FALSE); 00794 memcpy((char *)(attrvalsBuffer + LastOffset), &system, sizeof(fattr4_system)); 00795 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00796 op_attr_success = 1; 00797 break; 00798 00799 case FATTR4_TIME_ACCESS: 00800 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00801 "-----> Wanting FATTR4_TIME_ACCESS"); 00802 00803 /* This will contain the object's time os last access, the 'atime' in the Unix semantic */ 00804 memset(&(time_access.seconds), 0, sizeof(int64_t)); 00805 time_access.seconds = nfs_htonl64((int64_t) time(NULL)); 00806 time_access.nseconds = htonl(0); 00807 memcpy((char *)(attrvalsBuffer + LastOffset), &time_access, 00808 fattr4tab[attribute_to_set].size_fattr4); 00809 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00810 op_attr_success = 1; 00811 break; 00812 00813 case FATTR4_TIME_ACCESS_SET: 00814 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00815 "-----> Wanting FATTR4_TIME_ACCESS_SET"); 00816 00817 /* To be used with NFS4_OP_SETATTR only */ 00818 op_attr_success = 0; 00819 break; 00820 00821 case FATTR4_TIME_BACKUP: 00822 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00823 "-----> Wanting FATTR4_TIME_BACKUP"); 00824 00825 /* No time backup, return unix's beginning of time */ 00826 time_backup.seconds = nfs_htonl64(0LL); 00827 time_backup.nseconds = htonl(0); 00828 memcpy((char *)(attrvalsBuffer + LastOffset), &time_backup, 00829 fattr4tab[attribute_to_set].size_fattr4); 00830 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00831 op_attr_success = 1; 00832 break; 00833 00834 case FATTR4_TIME_CREATE: 00835 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00836 "-----> Wanting FATTR4_TIME_CREATE"); 00837 00838 /* No time create, return unix's beginning of time */ 00839 time_create.seconds = nfs_htonl64(0LL); 00840 time_create.nseconds = htonl(0); 00841 memcpy((char *)(attrvalsBuffer + LastOffset), &time_create, 00842 fattr4tab[attribute_to_set].size_fattr4); 00843 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00844 op_attr_success = 1; 00845 break; 00846 00847 case FATTR4_TIME_DELTA: 00848 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00849 "-----> Wanting FATTR4_TIME_DELTA"); 00850 00851 00852 /* According to RFC3530, this is "the smallest usefull server time granularity", I set this to 1s */ 00853 time_delta.seconds = nfs_htonl64(1LL); 00854 time_delta.nseconds = 0; 00855 memcpy((char *)(attrvalsBuffer + LastOffset), &time_delta, 00856 fattr4tab[attribute_to_set].size_fattr4); 00857 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00858 op_attr_success = 1; 00859 break; 00860 00861 case FATTR4_TIME_METADATA: 00862 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00863 "-----> Wanting FATTR4_TIME_METADATA"); 00864 00865 00866 /* The time for the last metadata operation, the ctime in the unix's semantic */ 00867 memset(&(time_metadata.seconds), 0, sizeof(int64_t)); 00868 time_metadata.seconds = nfs_htonl64((int64_t) time(NULL)); 00869 time_metadata.nseconds = htonl(0); 00870 memcpy((char *)(attrvalsBuffer + LastOffset), &time_metadata, 00871 fattr4tab[attribute_to_set].size_fattr4); 00872 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00873 op_attr_success = 1; 00874 break; 00875 00876 case FATTR4_TIME_MODIFY: 00877 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00878 "-----> Wanting FATTR4_TIME_MODIFY"); 00879 00880 00881 /* The time for the last modify operation, the mtime in the unix's semantic */ 00882 memset(&(time_modify.seconds), 0, sizeof(int64_t)); 00883 time_modify.seconds = nfs_htonl64((int64_t) time(NULL)); 00884 time_modify.nseconds = htonl(0); 00885 memcpy((char *)(attrvalsBuffer + LastOffset), &time_modify, 00886 fattr4tab[attribute_to_set].size_fattr4); 00887 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00888 op_attr_success = 1; 00889 break; 00890 00891 case FATTR4_TIME_MODIFY_SET: 00892 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00893 "-----> Wanting FATTR4_TIME_MODIFY_SET"); 00894 00895 00896 op_attr_success = 0; /* should never be used here, only for setattr */ 00897 break; 00898 00899 case FATTR4_MOUNTED_ON_FILEID: 00900 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00901 "-----> Wanting FATTR4_MOUNTED_ON_FILEID"); 00902 00903 fsalattr = data->current_entry->attributes; 00904 00905 #ifndef _XATTR_D_USE_SAME_INUM /* I wrapped off this part of the code... Not sure it would be useful */ 00906 file_id = nfs_htonl64(~(fsalattr.fileid)); 00907 00908 file_id = nfs_htonl64(~(fsalattr.fileid)) - pfile_handle->xattr_pos; 00909 #else 00910 file_id = nfs_htonl64(fsalattr.fileid); 00911 #endif 00912 00913 memcpy((char *)(attrvalsBuffer + LastOffset), &file_id, sizeof(fattr4_fileid)); 00914 LastOffset += fattr4tab[attribute_to_set].size_fattr4; 00915 op_attr_success = 1; 00916 00917 break; 00918 00919 default: 00920 LogWarn(COMPONENT_NFS_V4_XATTR, "Bad file attributes %d queried", 00921 attribute_to_set); 00922 /* BUGAZOMEU : un traitement special ici */ 00923 break; 00924 } /* switch( attr_to_set ) */ 00925 00926 /* Increase the Offset for the next operation if this was a success */ 00927 if(op_attr_success) 00928 { 00929 /* Set the returned bitmask */ 00930 attrvalslist[j] = attribute_to_set; 00931 j += 1; 00932 00933 /* Be carefull not to get out of attrvalsBuffer */ 00934 if(LastOffset > NFS4_ATTRVALS_BUFFLEN) 00935 return -1; 00936 } 00937 00938 } /* for i */ 00939 00940 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00941 "----------------------------------------"); 00942 00943 /* LastOffset contains the length of the attrvalsBuffer usefull data */ 00944 LogFullDebug(COMPONENT_NFS_V4_XATTR, 00945 "Fattr (pseudo) At the end LastOffset = %u, i=%d, j=%d", 00946 LastOffset, i, j); 00947 00948 return nfs4_Fattr_Fill(Fattr, j, attrvalslist, LastOffset, attrvalsBuffer); 00949 } /* nfs4_XattrToFattr */ 00950 00960 nfsstat4 nfs4_fh_to_xattrfh(nfs_fh4 * pfhin, nfs_fh4 * pfhout) 00961 { 00962 file_handle_v4_t *pfile_handle = NULL; 00963 00964 memcpy(pfhout->nfs_fh4_val, pfhin->nfs_fh4_val, pfhin->nfs_fh4_len); 00965 00966 pfile_handle = (file_handle_v4_t *) (pfhout->nfs_fh4_val); 00967 00968 /* the following choice is made for xattr: the field xattr_pos contains : 00969 * - 0 if the FH is related to an actual FH object 00970 * - 1 if the FH is the one for the xattr ghost directory 00971 * - 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 00972 * 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. 00973 */ 00974 pfile_handle->xattr_pos = 1; 00976 return NFS4_OK; 00977 } /* nfs4_fh_to_xattrfh */ 00978 00988 nfsstat4 nfs4_xattrfh_to_fh(nfs_fh4 * pfhin, nfs_fh4 * pfhout) 00989 { 00990 file_handle_v4_t *pfile_handle = NULL; 00991 00992 memcpy(pfhout->nfs_fh4_val, pfhin->nfs_fh4_val, pfhin->nfs_fh4_len); 00993 00994 pfile_handle = (file_handle_v4_t *) (pfhout->nfs_fh4_val); 00995 00996 pfile_handle->xattr_pos = 0; 00998 return NFS4_OK; 00999 } /* nfs4_fh_to_xattrfh */ 01000 01001 01015 #define arg_GETATTR4 op->nfs_argop4_u.opgetattr 01016 #define res_GETATTR4 resp->nfs_resop4_u.opgetattr 01017 01018 int nfs4_op_getattr_xattr(struct nfs_argop4 *op, 01019 compound_data_t * data, struct nfs_resop4 *resp) 01020 { 01021 char __attribute__ ((__unused__)) funcname[] = "nfs4_op_getattr"; 01022 01023 resp->resop = NFS4_OP_GETATTR; 01024 01025 res_GETATTR4.status = NFS4_OK; 01026 01027 if(nfs4_XattrToFattr(&(res_GETATTR4.GETATTR4res_u.resok4.obj_attributes), 01028 data, &(data->currentFH), &(arg_GETATTR4.attr_request)) != 0) 01029 res_GETATTR4.status = NFS4ERR_SERVERFAULT; 01030 else 01031 res_GETATTR4.status = NFS4_OK; 01032 01033 return res_GETATTR4.status; 01034 } /* nfs4_op_getattr_xattr */ 01035 01049 /* Shorter notation to avoid typos */ 01050 #define res_ACCESS4 resp->nfs_resop4_u.opaccess 01051 #define arg_ACCESS4 op->nfs_argop4_u.opaccess 01052 01053 int nfs4_op_access_xattr(struct nfs_argop4 *op, 01054 compound_data_t * data, struct nfs_resop4 *resp) 01055 { 01056 char __attribute__ ((__unused__)) funcname[] = "nfs4_op_access_xattr"; 01057 01058 resp->resop = NFS4_OP_ACCESS; 01059 01060 /* All access types are supported */ 01062 res_ACCESS4.ACCESS4res_u.resok4.supported = ACCESS4_READ | ACCESS4_LOOKUP; 01063 01064 /* DELETE/MODIFY/EXTEND are not supported in the pseudo fs */ 01065 res_ACCESS4.ACCESS4res_u.resok4.access = 01066 arg_ACCESS4.access & ~(ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_DELETE); 01067 01068 return NFS4_OK; 01069 } /* nfs4_op_access_xattr */ 01070 01084 /* Shorter notation to avoid typos */ 01085 #define arg_LOOKUP4 op->nfs_argop4_u.oplookup 01086 #define res_LOOKUP4 resp->nfs_resop4_u.oplookup 01087 01088 int nfs4_op_lookup_xattr(struct nfs_argop4 *op, 01089 compound_data_t * data, struct nfs_resop4 *resp) 01090 { 01091 fsal_name_t name; 01092 char strname[MAXNAMLEN]; 01093 fsal_status_t fsal_status; 01094 cache_inode_status_t cache_status; 01095 fsal_handle_t *pfsal_handle = NULL; 01096 unsigned int xattr_id = 0; 01097 file_handle_v4_t *pfile_handle = NULL; 01098 01099 char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lookup_xattr"; 01100 01101 /* The xattr directory contains no subdirectory, lookup always returns ENOENT */ 01102 res_LOOKUP4.status = NFS4_OK; 01103 01104 /* Get the FSAL Handle fo the current object */ 01105 pfsal_handle = &data->current_entry->handle; 01106 01107 /* UTF8 strings may not end with \0, but they carry their length */ 01108 utf82str(strname, sizeof(strname), &arg_LOOKUP4.objname); 01109 01110 /* Build the FSAL name */ 01111 if((cache_status = cache_inode_error_convert(FSAL_str2name(strname, 01112 MAXNAMLEN, 01113 &name))) != 01114 CACHE_INODE_SUCCESS) 01115 { 01116 res_LOOKUP4.status = nfs4_Errno(cache_status); 01117 return res_LOOKUP4.status; 01118 } 01119 01120 /* Try to get a FSAL_XAttr of that name */ 01121 fsal_status = FSAL_GetXAttrIdByName(pfsal_handle, &name, data->pcontext, &xattr_id); 01122 if(FSAL_IS_ERROR(fsal_status)) 01123 { 01124 return NFS4ERR_NOENT; 01125 } 01126 01127 /* Attribute was found */ 01128 pfile_handle = (file_handle_v4_t *) (data->currentFH.nfs_fh4_val); 01129 01130 /* for Xattr FH, we adopt the current convention: 01131 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01132 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01133 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01134 pfile_handle->xattr_pos = xattr_id + 2; 01135 01136 return NFS4_OK; 01137 } /* nfs4_op_lookup_xattr */ 01138 01152 /* Shorter notation to avoid typos */ 01153 #define arg_LOOKUPP4 op->nfs_argop4_u.oplookupp 01154 #define res_LOOKUPP4 resp->nfs_resop4_u.oplookupp 01155 01156 int nfs4_op_lookupp_xattr(struct nfs_argop4 *op, 01157 compound_data_t * data, struct nfs_resop4 *resp) 01158 { 01159 char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lookup_xattr"; 01160 01161 resp->resop = NFS4_OP_LOOKUPP; 01162 01163 res_LOOKUPP4.status = nfs4_xattrfh_to_fh(&(data->currentFH), &(data->currentFH)); 01164 01165 res_LOOKUPP4.status = NFS4_OK; 01166 return NFS4_OK; 01167 } /* nfs4_op_lookupp_xattr */ 01168 01182 /* shorter notation to avoid typo */ 01183 #define arg_READDIR4 op->nfs_argop4_u.opreaddir 01184 #define res_READDIR4 resp->nfs_resop4_u.opreaddir 01185 01186 int nfs4_op_readdir_xattr(struct nfs_argop4 *op, 01187 compound_data_t * data, struct nfs_resop4 *resp) 01188 { 01189 unsigned long dircount = 0; 01190 unsigned long maxcount = 0; 01191 unsigned long estimated_num_entries = 0; 01192 unsigned long i = 0; 01193 int eod_met = FALSE; 01194 unsigned int nb_xattrs_read = 0; 01195 fsal_xattrent_t xattrs_tab[255]; 01196 nfs_cookie4 cookie; 01197 verifier4 cookie_verifier; 01198 unsigned long space_used = 0; 01199 entry4 *entry_nfs_array = NULL; 01200 entry_name_array_item_t *entry_name_array = NULL; 01201 fsal_handle_t *pfsal_handle = NULL; 01202 fsal_status_t fsal_status; 01203 file_handle_v4_t *file_handle; 01204 nfs_fh4 nfsfh; 01205 struct alloc_file_handle_v4 temp_handle; 01206 01207 char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readdir_xattr"; 01208 01209 bitmap4 RdAttrErrorBitmap = { 1, (uint32_t *) "\0\0\0\b" }; /* 0xB = 11 = FATTR4_RDATTR_ERROR */ 01210 attrlist4 RdAttrErrorVals = { 0, NULL }; /* Nothing to be seen here */ 01211 01212 resp->resop = NFS4_OP_READDIR; 01213 res_READDIR4.status = NFS4_OK; 01214 01215 nfsfh.nfs_fh4_val = (caddr_t) &temp_handle; 01216 nfsfh.nfs_fh4_len = sizeof(struct alloc_file_handle_v4); 01217 memset(nfsfh.nfs_fh4_val, 0, nfsfh.nfs_fh4_len); 01218 01219 memcpy(nfsfh.nfs_fh4_val, data->currentFH.nfs_fh4_val, data->currentFH.nfs_fh4_len); 01220 nfsfh.nfs_fh4_len = data->currentFH.nfs_fh4_len; 01221 01222 file_handle = &temp_handle.handle; 01223 01224 LogFullDebug(COMPONENT_NFS_V4_XATTR, "Entering NFS4_OP_READDIR_PSEUDO"); 01225 01226 /* get the caracteristic value for readdir operation */ 01227 dircount = arg_READDIR4.dircount; 01228 maxcount = arg_READDIR4.maxcount; 01229 cookie = arg_READDIR4.cookie; 01230 space_used = sizeof(entry4); 01231 01232 /* dircount is considered meaningless by many nfsv4 client (like the CITI one). we use maxcount instead */ 01233 estimated_num_entries = maxcount / sizeof(entry4); 01234 01235 LogFullDebug(COMPONENT_NFS_V4_XATTR, 01236 "PSEUDOFS READDIR: dircount=%lu, maxcount=%lu, cookie=%"PRIu64", sizeof(entry4)=%lu num_entries=%lu", 01237 dircount, maxcount, (uint64_t)cookie, space_used, estimated_num_entries); 01238 01239 /* If maxcount is too short, return NFS4ERR_TOOSMALL */ 01240 if(maxcount < sizeof(entry4) || estimated_num_entries == 0) 01241 { 01242 res_READDIR4.status = NFS4ERR_TOOSMALL; 01243 return res_READDIR4.status; 01244 } 01245 01246 /* Cookie delivered by the server and used by the client SHOULD not ne 0, 1 or 2 (cf RFC3530, page192) 01247 * because theses value are reserved for special use. 01248 * 0 - cookie for first READDIR 01249 * 1 - reserved for . on client handside 01250 * 2 - reserved for .. on client handside 01251 * Entries '.' and '..' are not returned also 01252 * For these reason, there will be an offset of 3 between NFS4 cookie and HPSS cookie */ 01253 01254 /* Do not use a cookie of 1 or 2 (reserved values) */ 01255 if(cookie == 1 || cookie == 2) 01256 { 01257 res_READDIR4.status = NFS4ERR_BAD_COOKIE; 01258 return res_READDIR4.status; 01259 } 01260 01261 if(cookie != 0) 01262 cookie = cookie - 3; /* 0,1 and 2 are reserved, there is a delta of '3' because of this */ 01263 01264 /* Get only attributes that are allowed to be read */ 01265 if(!nfs4_Fattr_Check_Access_Bitmap(&arg_READDIR4.attr_request, FATTR4_ATTR_READ)) 01266 { 01267 res_READDIR4.status = NFS4ERR_INVAL; 01268 return res_READDIR4.status; 01269 } 01270 01271 /* If maxcount is too short, return NFS4ERR_TOOSMALL */ 01272 if(maxcount < sizeof(entry4) || estimated_num_entries == 0) 01273 { 01274 res_READDIR4.status = NFS4ERR_TOOSMALL; 01275 return res_READDIR4.status; 01276 } 01277 01278 /* Cookie verifier has the value of the Server Boot Time for pseudo fs */ 01279 memset(cookie_verifier, 0, NFS4_VERIFIER_SIZE); 01280 #ifdef _WITH_COOKIE_VERIFIER 01281 /* BUGAZOMEU: management of the cookie verifier */ 01282 if(NFS_SpecificConfig.UseCookieVerf == 1) 01283 { 01284 memcpy(cookie_verifier, &ServerBootTime, sizeof(ServerBootTime)); 01285 if(cookie != 0) 01286 { 01287 if(memcmp(cookie_verifier, arg_READDIR4.cookieverf, NFS4_VERIFIER_SIZE) != 0) 01288 { 01289 res_READDIR4.status = NFS4ERR_BAD_COOKIE; 01290 gsh_free(entry_nfs_array); 01291 return res_READDIR4.status; 01292 } 01293 } 01294 } 01295 #endif 01296 01297 /* The default behaviour is to consider that eof is not reached, the returned values by cache_inode_readdir 01298 * will let us know if eod was reached or not */ 01299 res_READDIR4.READDIR4res_u.resok4.reply.eof = FALSE; 01300 01301 /* Get the fsal_handle */ 01302 pfsal_handle = &data->current_entry->handle; 01303 01304 /* Used FSAL extended attributes functions */ 01305 fsal_status = FSAL_ListXAttrs(pfsal_handle, 01306 cookie, 01307 data->pcontext, 01308 xattrs_tab, 01309 estimated_num_entries, &nb_xattrs_read, &eod_met); 01310 if(FSAL_IS_ERROR(fsal_status)) 01311 { 01312 res_READDIR4.status = NFS4ERR_SERVERFAULT; 01313 return res_READDIR4.status; 01314 } 01315 01316 if(eod_met == TRUE) 01317 { 01318 /* This is the end of the directory */ 01319 res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE; 01320 memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, 01321 NFS4_VERIFIER_SIZE); 01322 } 01323 01324 if(nb_xattrs_read == 0) 01325 { 01326 /* only . and .. */ 01327 res_READDIR4.READDIR4res_u.resok4.reply.entries = NULL; 01328 res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE; 01329 memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, 01330 NFS4_VERIFIER_SIZE); 01331 } 01332 else 01333 { 01334 /* Allocation of reply structures */ 01335 if((entry_name_array = 01336 gsh_calloc(estimated_num_entries, (FSAL_MAX_NAME_LEN + 1))) == NULL) 01337 { 01338 LogError(COMPONENT_NFS_V4_XATTR, ERR_SYS, ERR_MALLOC, errno); 01339 res_READDIR4.status = NFS4ERR_SERVERFAULT; 01340 return res_READDIR4.status; 01341 } 01342 01343 if((entry_nfs_array = 01344 gsh_calloc(estimated_num_entries, sizeof(entry4))) == NULL) 01345 { 01346 LogError(COMPONENT_NFS_V4_XATTR, ERR_SYS, ERR_MALLOC, errno); 01347 res_READDIR4.status = NFS4ERR_SERVERFAULT; 01348 return res_READDIR4.status; 01349 } 01350 01351 for(i = 0; i < nb_xattrs_read; i++) 01352 { 01353 entry_nfs_array[i].name.utf8string_val = entry_name_array[i]; 01354 01355 if(str2utf8(xattrs_tab[i].xattr_name.name, &entry_nfs_array[i].name) == -1) 01356 { 01357 res_READDIR4.status = NFS4ERR_SERVERFAULT; 01358 return res_READDIR4.status; 01359 } 01360 01361 /* Set the cookie value */ 01362 entry_nfs_array[i].cookie = cookie + i + 3; /* 0, 1 and 2 are reserved */ 01363 01364 file_handle->xattr_pos = xattrs_tab[i].xattr_id + 2; 01365 if(nfs4_XattrToFattr(&(entry_nfs_array[i].attrs), 01366 data, &nfsfh, &(arg_READDIR4.attr_request)) != 0) 01367 { 01368 /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */ 01369 entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap; 01370 entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals; 01371 } 01372 01373 /* Chain the entries together */ 01374 entry_nfs_array[i].nextentry = NULL; 01375 if(i != 0) 01376 entry_nfs_array[i - 1].nextentry = &(entry_nfs_array[i]); 01377 01378 /* This test is there to avoid going further than the buffer provided by the client 01379 * the factor "9/10" is there for safety. Its value could be change as beta tests will be done */ 01380 if((caddr_t) 01381 ((caddr_t) (&entry_nfs_array[i]) - (caddr_t) (&entry_nfs_array[0])) > 01382 (caddr_t) (maxcount * 9 / 10)) 01383 break; 01384 01385 } /* for */ 01386 01387 } /* else */ 01388 01389 /* Build the reply */ 01390 memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier, 01391 NFS4_VERIFIER_SIZE); 01392 if(i == 0) 01393 res_READDIR4.READDIR4res_u.resok4.reply.entries = NULL; 01394 else 01395 res_READDIR4.READDIR4res_u.resok4.reply.entries = entry_nfs_array; 01396 01397 res_READDIR4.status = NFS4_OK; 01398 01399 return NFS4_OK; 01400 01401 } /* nfs4_op_readdir_xattr */ 01402 01413 #define arg_READ4 op->nfs_argop4_u.opread 01414 #define res_READ4 resp->nfs_resop4_u.opread 01415 01416 #define arg_OPEN4 op->nfs_argop4_u.opopen 01417 #define res_OPEN4 resp->nfs_resop4_u.opopen 01418 int nfs4_op_open_xattr(struct nfs_argop4 *op, 01419 compound_data_t * data, struct nfs_resop4 *resp) 01420 { 01421 fsal_name_t name; 01422 char strname[MAXNAMLEN]; 01423 fsal_status_t fsal_status; 01424 cache_inode_status_t cache_status; 01425 fsal_handle_t *pfsal_handle = NULL; 01426 unsigned int xattr_id = 0; 01427 file_handle_v4_t *pfile_handle = NULL; 01428 char empty_buff[16] = ""; 01429 01430 res_OPEN4.status = NFS4_OK; 01431 01432 /* Get the FSAL Handle fo the current object */ 01433 pfsal_handle = &data->current_entry->handle; 01434 01435 /* UTF8 strings may not end with \0, but they carry their length */ 01436 utf82str(strname, sizeof(strname), &arg_OPEN4.claim.open_claim4_u.file); 01437 01438 /* Build the FSAL name */ 01439 if((cache_status = cache_inode_error_convert(FSAL_str2name(strname, 01440 MAXNAMLEN, 01441 &name))) != 01442 CACHE_INODE_SUCCESS) 01443 { 01444 res_OPEN4.status = nfs4_Errno(cache_status); 01445 return res_OPEN4.status; 01446 } 01447 01448 /* we do not use the stateful logic for accessing xattrs */ 01449 switch (arg_OPEN4.openhow.opentype) 01450 { 01451 case OPEN4_CREATE: 01452 /* To be done later */ 01453 /* set empty attr */ 01454 fsal_status = FSAL_SetXAttrValue(pfsal_handle, 01455 &name, 01456 data->pcontext, empty_buff, sizeof(empty_buff), 01457 TRUE); 01458 01459 if(FSAL_IS_ERROR(fsal_status)) 01460 { 01461 res_OPEN4.status = nfs4_Errno(cache_inode_error_convert(fsal_status)); 01462 return res_OPEN4.status; 01463 } 01464 01465 /* Now, getr the id */ 01466 fsal_status = FSAL_GetXAttrIdByName(pfsal_handle, &name, data->pcontext, &xattr_id); 01467 if(FSAL_IS_ERROR(fsal_status)) 01468 { 01469 res_OPEN4.status = NFS4ERR_NOENT; 01470 return res_OPEN4.status; 01471 } 01472 01473 /* Attribute was found */ 01474 pfile_handle = (file_handle_v4_t *) (data->currentFH.nfs_fh4_val); 01475 01476 /* for Xattr FH, we adopt the current convention: 01477 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01478 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01479 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01480 pfile_handle->xattr_pos = xattr_id + 2; 01481 01482 res_OPEN4.status = NFS4_OK; 01483 return NFS4_OK; 01484 01485 break; 01486 01487 case OPEN4_NOCREATE: 01488 01489 /* Try to get a FSAL_XAttr of that name */ 01490 fsal_status = FSAL_GetXAttrIdByName(pfsal_handle, &name, data->pcontext, &xattr_id); 01491 if(FSAL_IS_ERROR(fsal_status)) 01492 { 01493 res_OPEN4.status = NFS4ERR_NOENT; 01494 return res_OPEN4.status; 01495 } 01496 01497 /* Attribute was found */ 01498 pfile_handle = (file_handle_v4_t *) (data->currentFH.nfs_fh4_val); 01499 01500 /* for Xattr FH, we adopt the current convention: 01501 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01502 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01503 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01504 pfile_handle->xattr_pos = xattr_id + 2; 01505 01506 res_OPEN4.status = NFS4_OK; 01507 return NFS4_OK; 01508 01509 break; 01510 01511 } /* switch (arg_OPEN4.openhow.opentype) */ 01512 01513 res_OPEN4.status = NFS4_OK; 01514 return NFS4_OK; 01515 } /* nfs4_op_open_xattr */ 01516 01527 #define arg_READ4 op->nfs_argop4_u.opread 01528 #define res_READ4 resp->nfs_resop4_u.opread 01529 01530 int nfs4_op_read_xattr(struct nfs_argop4 *op, 01531 compound_data_t * data, struct nfs_resop4 *resp) 01532 { 01533 fsal_handle_t *pfsal_handle = NULL; 01534 file_handle_v4_t *pfile_handle = NULL; 01535 unsigned int xattr_id = 0; 01536 fsal_status_t fsal_status; 01537 char *buffer = NULL; 01538 size_t size_returned; 01539 01540 /* Get the FSAL Handle fo the current object */ 01541 pfsal_handle = &data->current_entry->handle; 01542 01543 /* Get the xattr_id */ 01544 pfile_handle = (file_handle_v4_t *) (data->currentFH.nfs_fh4_val); 01545 01546 /* for Xattr FH, we adopt the current convention: 01547 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01548 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01549 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01550 xattr_id = pfile_handle->xattr_pos - 2; 01551 01552 /* Get the xattr related to this xattr_id */ 01553 if((buffer = gsh_calloc(1, XATTR_BUFFERSIZE)) == NULL) 01554 { 01555 res_READ4.status = NFS4ERR_SERVERFAULT; 01556 return res_READ4.status; 01557 } 01558 01559 fsal_status = FSAL_GetXAttrValueById(pfsal_handle, 01560 xattr_id, 01561 data->pcontext, 01562 buffer, XATTR_BUFFERSIZE, &size_returned); 01563 01564 if(FSAL_IS_ERROR(fsal_status)) 01565 { 01566 res_READ4.status = NFS4ERR_SERVERFAULT; 01567 return res_READ4.status; 01568 } 01569 01570 res_READ4.READ4res_u.resok4.data.data_len = size_returned; 01571 res_READ4.READ4res_u.resok4.data.data_val = buffer; 01572 01573 res_READ4.READ4res_u.resok4.eof = TRUE; 01574 01575 res_READ4.status = NFS4_OK; 01576 01577 return res_READ4.status; 01578 } /* nfs4_op_read_xattr */ 01579 01590 #define arg_WRITE4 op->nfs_argop4_u.opwrite 01591 #define res_WRITE4 resp->nfs_resop4_u.opwrite 01592 01593 int nfs4_op_write_xattr(struct nfs_argop4 *op, 01594 compound_data_t * data, struct nfs_resop4 *resp) 01595 { 01596 fsal_handle_t *pfsal_handle = NULL; 01597 file_handle_v4_t *pfile_handle = NULL; 01598 unsigned int xattr_id = 0; 01599 fsal_status_t fsal_status; 01600 01601 /* Get the FSAL Handle fo the current object */ 01602 pfsal_handle = &data->current_entry->handle; 01603 01604 /* Get the xattr_id */ 01605 pfile_handle = (file_handle_v4_t *) (data->currentFH.nfs_fh4_val); 01606 01607 /* for Xattr FH, we adopt the current convention: 01608 * xattr_pos = 0 ==> the FH is the one of the actual FS object 01609 * xattr_pos = 1 ==> the FH is the one of the xattr ghost directory 01610 * xattr_pos > 1 ==> The FH is the one for the xattr ghost file whose xattr_id = xattr_pos -2 */ 01611 xattr_id = pfile_handle->xattr_pos - 2; 01612 01613 fsal_status = FSAL_SetXAttrValueById(pfsal_handle, 01614 xattr_id, 01615 data->pcontext, 01616 arg_WRITE4.data.data_val, 01617 arg_WRITE4.data.data_len); 01618 01619 if(FSAL_IS_ERROR(fsal_status)) 01620 { 01621 res_WRITE4.status = NFS4ERR_SERVERFAULT; 01622 return res_WRITE4.status; 01623 } 01624 01625 res_WRITE4.WRITE4res_u.resok4.committed = FILE_SYNC4; 01626 01627 res_WRITE4.WRITE4res_u.resok4.count = arg_WRITE4.data.data_len; 01628 memcpy(res_WRITE4.WRITE4res_u.resok4.writeverf, NFS4_write_verifier, sizeof(verifier4)); 01629 01630 res_WRITE4.status = NFS4_OK; 01631 01632 return NFS4_OK; 01633 } /* nfs4_op_write_xattr */ 01634 01635 #define arg_REMOVE4 op->nfs_argop4_u.opremove 01636 #define res_REMOVE4 resp->nfs_resop4_u.opremove 01637 int nfs4_op_remove_xattr(struct nfs_argop4 *op, compound_data_t * data, 01638 struct nfs_resop4 *resp) 01639 { 01640 fsal_status_t fsal_status; 01641 cache_inode_status_t cache_status; 01642 fsal_handle_t *pfsal_handle = NULL; 01643 fsal_name_t name; 01644 01645 /* Check for name length */ 01646 if(arg_REMOVE4.target.utf8string_len > FSAL_MAX_NAME_LEN) 01647 { 01648 res_REMOVE4.status = NFS4ERR_NAMETOOLONG; 01649 return res_REMOVE4.status; 01650 } 01651 01652 /* get the filename from the argument, it should not be empty */ 01653 if(arg_REMOVE4.target.utf8string_len == 0) 01654 { 01655 res_REMOVE4.status = NFS4ERR_INVAL; 01656 return res_REMOVE4.status; 01657 } 01658 01659 /* NFS4_OP_REMOVE can delete files as well as directory, it replaces NFS3_RMDIR and NFS3_REMOVE 01660 * because of this, we have to know if object is a directory or not */ 01661 if((cache_status = 01662 cache_inode_error_convert(FSAL_buffdesc2name 01663 ((fsal_buffdesc_t *) & arg_REMOVE4.target, 01664 &name))) != CACHE_INODE_SUCCESS) 01665 { 01666 res_REMOVE4.status = nfs4_Errno(cache_status); 01667 return res_REMOVE4.status; 01668 } 01669 01670 /* Get the FSAL Handle fo the current object */ 01671 pfsal_handle = &data->current_entry->handle; 01672 01673 /* Test RM7: remiving '.' should return NFS4ERR_BADNAME */ 01674 if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) 01675 || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) 01676 { 01677 res_REMOVE4.status = NFS4ERR_BADNAME; 01678 return res_REMOVE4.status; 01679 } 01680 01681 fsal_status = FSAL_RemoveXAttrByName(pfsal_handle, data->pcontext, &name); 01682 if(FSAL_IS_ERROR(fsal_status)) 01683 { 01684 res_REMOVE4.status = NFS4ERR_SERVERFAULT; 01685 return res_REMOVE4.status; 01686 } 01687 01688 res_REMOVE4.status = NFS4_OK; 01689 return res_REMOVE4.status; 01690 }