nfs-ganesha 1.4

nfs_xattr.c

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