nfs-ganesha 1.4

nfs4_xattr.c

Go to the documentation of this file.
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), &quota_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), &quota_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), &quota_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 }