nfs-ganesha 1.4

nfs4_pseudo.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 #define NB_TOK_ARG 10
00062 #define NB_OPT_TOK 10
00063 #define NB_TOK_PATH 20
00064 
00065 static pseudofs_t gPseudoFs;
00066 
00081 uint64_t nfs4_PseudoToId(nfs_fh4 * fh4p)
00082 {
00083   file_handle_v4_t *pfhandle4;
00084   uint64_t out = 0LL;
00085 
00086   pfhandle4 = (file_handle_v4_t *) (fh4p->nfs_fh4_val);
00087 
00088   out = (uint64_t) (pfhandle4->pseudofs_id);
00089   return out;
00090 }                               /* nfs4_PseudoToId */
00091 
00101 pseudofs_t *nfs4_GetPseudoFs(void)
00102 {
00103   return &gPseudoFs;
00104 }                               /*  nfs4_GetExportList */
00105 
00115 int nfs4_ExportToPseudoFS(exportlist_t * pexportlist)
00116 {
00117   exportlist_t *entry;
00118   exportlist_t *next;           /* exportlist entry   */
00119   int i = 0;
00120   int j = 0;
00121   int found = 0;
00122   char tmp_pseudopath[MAXPATHLEN];
00123   char *PathTok[NB_TOK_PATH];
00124   int NbTokPath;
00125   pseudofs_t *PseudoFs = NULL;
00126   pseudofs_entry_t *PseudoFsRoot = NULL;
00127   pseudofs_entry_t *PseudoFsCurrent = NULL;
00128   pseudofs_entry_t *newPseudoFsEntry = NULL;
00129   pseudofs_entry_t *iterPseudoFs = NULL;
00130 
00131   entry = pexportlist;
00132 
00133   PseudoFs = &gPseudoFs;
00134 
00135   /* Init Root of the Pseudo FS tree */
00136   strncpy(PseudoFs->root.name, "/", MAXNAMLEN);
00137   strncpy(PseudoFs->root.fullname, "(nfsv4root)", MAXPATHLEN);
00138   PseudoFs->root.pseudo_id = 0;
00139   PseudoFs->root.junction_export = NULL;
00140   PseudoFs->root.next = NULL;
00141   PseudoFs->root.last = PseudoFsRoot;
00142   PseudoFs->root.sons = NULL;
00143   PseudoFs->root.parent = &(PseudoFs->root);    /* root is its own parent */
00144 
00145   /* Allocation of the parsing table */
00146   for(i = 0; i < NB_TOK_PATH; i++)
00147     if((PathTok[i] = gsh_malloc(MAXNAMLEN)) == NULL)
00148       return ENOMEM;
00149 
00150   while(entry)
00151     {
00152       /* To not forget to init "/" entry */
00153       PseudoFsCurrent = &(PseudoFs->root);
00154       PseudoFs->reverse_tab[0] = &(PseudoFs->root);
00155 
00156       /* skip exports that aren't for NFS v4 */
00157       if((entry->options & EXPORT_OPTION_NFSV4) == 0)
00158         {
00159           next = entry->next;
00160           entry = next;
00161           continue;
00162         }
00163 
00164       if(entry->options & EXPORT_OPTION_PSEUDO)
00165         {
00166           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00167                        "BUILDING PSEUDOFS: Id          = %d",
00168                        entry->id);
00169           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00170                        "BUILDING PSEUDOFS: ANON        = %d",
00171                        entry->anonymous_uid);
00172           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00173                        "BUILDING PSEUDOFS: Path        = %s",
00174                        entry->fullpath);
00175           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00176                        "BUILDING PSEUDOFS: Options     = 0x%x",
00177                        entry->options);
00178           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00179                        "BUILDING PSEUDOFS: Num Clients = %d",
00180                        entry->clients.num_clients);
00181 
00182           /* A pseudo path is to ne managed */
00183           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00184                        "BUILDING PSEUDOFS: Now managing %s seen as %s",
00185                        entry->fullpath, entry->pseudopath);
00186 
00187           /* Parsing the path */
00188           strncpy(tmp_pseudopath, entry->pseudopath, MAXPATHLEN);
00189           if((NbTokPath =
00190               nfs_ParseConfLine(PathTok, NB_TOK_PATH, tmp_pseudopath, find_slash,
00191                                 find_endLine)) < 0)
00192             {
00193               /* Path is badly formed */
00194               LogCrit(COMPONENT_NFS_V4_PSEUDO,
00195                       "BUILDING PSEUDOFS: Invalid 'pseudo' option: %s",
00196                       entry->pseudopath);
00197               next = entry->next;
00198               entry = next;
00199               continue;
00200             }
00201 
00202           /* there must be a leading '/' in the pseudo path */
00203           if(entry->pseudopath[0] != '/')
00204             {
00205               /* Path is badly formed */
00206               LogCrit(COMPONENT_NFS_V4_PSEUDO,
00207                       "Pseudo Path '%s' is badly formed",
00208                       entry->pseudopath);
00209               next = entry->next;
00210               entry = next;
00211               continue;
00212             }
00213 
00214           /* Loop on each token. Because first character in pseudo path is '/'
00215            * we can avoid looking at PathTok[0] which is necessary '\0'. That's 
00216            * the reason why we start looping at pos = 1 */
00217           for(j = 1; j < NbTokPath; j++)
00218             LogFullDebug(COMPONENT_NFS_V4, "     tokens are #%s#", PathTok[j]);
00219 
00220           for(j = 1; j < NbTokPath; j++)
00221             {
00222               found = 0;
00223               for(iterPseudoFs = PseudoFsCurrent->sons; iterPseudoFs != NULL;
00224                   iterPseudoFs = iterPseudoFs->next)
00225                 {
00226                   /* Looking for a matching entry */
00227                   if(!strcmp(iterPseudoFs->name, PathTok[j]))
00228                     {
00229                       found = 1;
00230                       break;
00231                     }
00232                 }               /* for iterPseudoFs */
00233 
00234               if(found)
00235                 {
00236                   /* a matching entry was found in the tree */
00237                   PseudoFsCurrent = iterPseudoFs;
00238                 }
00239               else
00240                 {
00241                   /* a new entry is to be created */
00242                   if((newPseudoFsEntry =
00243                       gsh_malloc(sizeof(pseudofs_entry_t))) == NULL)
00244                     return ENOMEM;
00245 
00246                   /* Creating the new entry, allocate an id for it and add it to reverse tab */
00247                   strncpy(newPseudoFsEntry->name, PathTok[j], MAXNAMLEN);
00248                   newPseudoFsEntry->pseudo_id = PseudoFs->last_pseudo_id + 1;
00249                   PseudoFs->last_pseudo_id = newPseudoFsEntry->pseudo_id;
00250                   PseudoFs->reverse_tab[PseudoFs->last_pseudo_id] = newPseudoFsEntry;
00251                   newPseudoFsEntry->junction_export = NULL;
00252                   newPseudoFsEntry->last = newPseudoFsEntry;
00253                   newPseudoFsEntry->next = NULL;
00254                   newPseudoFsEntry->sons = NULL;
00255                   snprintf(newPseudoFsEntry->fullname, MAXPATHLEN, "%s/%s",
00256                            PseudoFsCurrent->fullname, PathTok[j]);
00257 
00258                   /* Step into the new entry and attach it to the tree */
00259                   if(PseudoFsCurrent->sons == NULL)
00260                     PseudoFsCurrent->sons = newPseudoFsEntry;
00261                   else
00262                     {
00263                       PseudoFsCurrent->sons->last->next = newPseudoFsEntry;
00264                       PseudoFsCurrent->sons->last = newPseudoFsEntry;
00265                     }
00266                   newPseudoFsEntry->parent = PseudoFsCurrent;
00267                   PseudoFsCurrent = newPseudoFsEntry;
00268                 }
00269 
00270             }                   /* for j */
00271 
00272           /* Now that all entries are added to pseudofs tree, add the junction to the pseudofs */
00273           PseudoFsCurrent->junction_export = entry;
00274 
00275         }
00276       /* if( entry->options & EXPORT_OPTION_PSEUDO ) */
00277       next = entry->next;
00278 
00279       entry = next;
00280     }                           /* while( entry ) */
00281 
00282   /* desalocation of the parsing table */
00283   for(i = 0; i < NB_TOK_PATH; i++)
00284     gsh_free(PathTok[i]);
00285 
00286   return (0);
00287 }
00288 
00304 int nfs4_PseudoToFattr(pseudofs_entry_t * psfsp,
00305                        fattr4 * Fattr,
00306                        compound_data_t * data, nfs_fh4 * objFH, bitmap4 * Bitmap)
00307 {
00308   fattr4_type file_type;
00309   fattr4_link_support link_support;
00310   fattr4_symlink_support symlink_support;
00311   fattr4_fh_expire_type expire_type;
00312   fattr4_named_attr named_attr;
00313   fattr4_unique_handles unique_handles;
00314   fattr4_archive archive;
00315   fattr4_cansettime cansettime;
00316   fattr4_case_insensitive case_insensitive;
00317   fattr4_case_preserving case_preserving;
00318   fattr4_chown_restricted chown_restricted;
00319   fattr4_hidden hidden;
00320   fattr4_mode file_mode;
00321   fattr4_no_trunc no_trunc;
00322   fattr4_numlinks file_numlinks;
00323   fattr4_rawdev rawdev;
00324   fattr4_system system;
00325   fattr4_size file_size;
00326   fattr4_space_used file_space_used;
00327   fattr4_fsid fsid;
00328   fattr4_time_access time_access;
00329   fattr4_time_modify time_modify;
00330   fattr4_time_metadata time_metadata;
00331   fattr4_time_delta time_delta;
00332   fattr4_time_backup time_backup;
00333   fattr4_time_create time_create;
00334   fattr4_change file_change;
00335   fattr4_fileid file_id;
00336   fattr4_owner file_owner;
00337   fattr4_owner_group file_owner_group;
00338   fattr4_space_avail space_avail;
00339   fattr4_space_free space_free;
00340   fattr4_space_total space_total;
00341   fattr4_files_avail files_avail;
00342   fattr4_files_free files_free;
00343   fattr4_files_total files_total;
00344   fattr4_lease_time lease_time;
00345   fattr4_maxfilesize max_filesize;
00346   fattr4_maxread maxread;
00347   fattr4_maxwrite maxwrite;
00348   fattr4_maxname maxname;
00349   fattr4_maxlink maxlink;
00350   fattr4_homogeneous homogeneous;
00351   fattr4_acl acl;
00352   fattr4_mimetype mimetype;
00353   fattr4_aclsupport aclsupport;
00354   fattr4_quota_avail_hard quota_avail_hard;
00355   fattr4_quota_avail_soft quota_avail_soft;
00356   fattr4_quota_used quota_used;
00357   fattr4_mounted_on_fileid mounted_on_fileid;
00358 #ifdef _USE_NFS4_1
00359   fattr4_fs_layout_types layout_types;
00360   layouttype4 layouts[1];
00361 #endif
00362 
00363   u_int fhandle_len = 0;
00364   unsigned int LastOffset;
00365   unsigned int len = 0, off = 0;        /* Use for XDR alignment */
00366   int op_attr_success = 0;
00367   unsigned int i = 0;
00368   unsigned int j = 0;
00369   unsigned int attrmasklen = 0;
00370   unsigned int attribute_to_set = 0;
00371 
00372 #ifdef _USE_NFS4_1
00373   unsigned int attrmasklist[FATTR4_FS_CHARSET_CAP];     /* List cannot be longer than FATTR4_FS_CHARSET_CAP */
00374   unsigned int attrvalslist[FATTR4_FS_CHARSET_CAP];     /* List cannot be longer than FATTR4_FS_CHARSET_CAP */
00375 #else
00376   unsigned int attrmasklist[FATTR4_MOUNTED_ON_FILEID];  /* List cannot be longer than FATTR4_MOUNTED_ON_FILEID */
00377   unsigned int attrvalslist[FATTR4_MOUNTED_ON_FILEID];  /* List cannot be longer than FATTR4_MOUNTED_ON_FILEID */
00378 #endif
00379   char attrvalsBuffer[ATTRVALS_BUFFLEN];
00380 
00381   char __attribute__ ((__unused__)) funcname[] = "nfs4_PseudoToFattr";
00382 
00383   /* memset to make sure the arrays are initiated to 0 */
00384   memset(attrvalsBuffer, 0, NFS4_ATTRVALS_BUFFLEN);
00385 #ifdef _USE_NFS4_1
00386   memset((uint32_t *) attrmasklist, 0, FATTR4_FS_CHARSET_CAP * sizeof(uint32_t));
00387   memset((uint32_t *) attrvalslist, 0, FATTR4_FS_CHARSET_CAP * sizeof(uint32_t));
00388 #else
00389   memset((uint32_t *) attrmasklist, 0, FATTR4_MOUNTED_ON_FILEID * sizeof(uint32_t));
00390   memset((uint32_t *) attrvalslist, 0, FATTR4_MOUNTED_ON_FILEID * sizeof(uint32_t));
00391 #endif
00392 
00393   /* Convert the attribute bitmap to an attribute list */
00394   nfs4_bitmap4_to_list(Bitmap, &attrmasklen, attrmasklist);
00395 
00396   /* Once the bitmap has been converted to a list of attribute, manage each attribute */
00397   Fattr->attr_vals.attrlist4_len = 0;
00398   LastOffset = 0;
00399   j = 0;
00400 
00401   LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00402                "Asked Attributes (Pseudo): Bitmap = (len=%d, val[0]=%d, val[1]=%d), %d item in list",
00403                Bitmap->bitmap4_len, Bitmap->bitmap4_val[0],
00404                Bitmap->bitmap4_val[1], attrmasklen);
00405 
00406   if(attrmasklen == 0)
00407     {
00408       Bitmap->bitmap4_len = 0;
00409       Bitmap->bitmap4_val = 0;
00410       return 0;                 /* Nothing to be done */
00411     }
00412 
00413   for(i = 0; i < attrmasklen; i++)
00414     {
00415       attribute_to_set = attrmasklist[i];
00416 
00417       LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00418                    "Flag for Operation (Pseudo) = %d|%d is ON,  name  = %s  reply_size = %d supported = %d",
00419                    attrmasklist[i], fattr4tab[attribute_to_set].val,
00420                    fattr4tab[attribute_to_set].name,
00421                    fattr4tab[attribute_to_set].size_fattr4,
00422                    fattr4tab[attribute_to_set].supported);
00423 
00424       op_attr_success = 0;
00425 
00426       /* compute the new size for the fattr4 reply */
00427       /* This space is to be filled below in the big switch/case statement */
00428 
00429       switch (attribute_to_set)
00430         {
00431         case FATTR4_SUPPORTED_ATTRS:
00432           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00433                        "-----> Wanting FATTR4_SUPPORTED_ATTRS");
00434 
00435           LastOffset += nfs4_supported_attrs_to_fattr(attrvalsBuffer+LastOffset);
00436 
00437           /* This kind of operation is always a success */
00438           op_attr_success = 1;
00439           break;
00440 
00441         case FATTR4_TYPE:
00442           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00443                        "-----> Wanting FATTR4_TYPE");
00444 
00445           op_attr_success = 1;
00446           file_type = htonl(NF4DIR);    /* There are only directories in the pseudo fs */
00447 
00448           memcpy((char *)(attrvalsBuffer + LastOffset), &file_type, sizeof(fattr4_type));
00449           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00450           break;
00451 
00452         case FATTR4_FH_EXPIRE_TYPE:
00453           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00454                        "-----> Wanting FATTR4_FH_EXPIRE_TYPE");
00455 
00456           /* For the moment, we handle only the persistent filehandle 
00457           expire_type = htonl(FH4_VOLATILE_ANY); */
00458           expire_type = htonl( FH4_PERSISTENT ) ; 
00459           memcpy((char *)(attrvalsBuffer + LastOffset), &expire_type,
00460                  sizeof(expire_type));
00461           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00462           op_attr_success = 1;
00463           break;
00464 
00465         case FATTR4_CHANGE:
00466           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00467                        "-----> Wanting FATTR4_CHANGE");
00468 
00469           /* Use boot time as time value for every pseudo fs object */
00470           memset(&file_change, 0, sizeof(changeid4));
00471           file_change = nfs_htonl64((changeid4) ServerBootTime);
00472 
00473           memcpy((char *)(attrvalsBuffer + LastOffset), &file_change,
00474                  sizeof(fattr4_change));
00475           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00476           op_attr_success = 1;
00477           break;
00478 
00479         case FATTR4_SIZE:
00480           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00481                        "-----> Wanting FATTR4_SIZE");
00482 
00483           file_size = nfs_htonl64((fattr4_size) DEV_BSIZE);
00484           memcpy((char *)(attrvalsBuffer + LastOffset), &file_size, sizeof(fattr4_size));
00485           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00486           op_attr_success = 1;
00487           break;
00488 
00489         case FATTR4_LINK_SUPPORT:
00490           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00491                        "-----> Wanting FATTR4_LINK_SUPPORT");
00492 
00493           /* HPSS NameSpace support hard link */
00494           link_support = htonl(TRUE);
00495           memcpy((char *)(attrvalsBuffer + LastOffset), &link_support,
00496                  sizeof(fattr4_link_support));
00497           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00498           op_attr_success = 1;
00499           break;
00500 
00501         case FATTR4_SYMLINK_SUPPORT:
00502           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00503                        "-----> Wanting FATTR4_SYMLINK_SUPPORT");
00504 
00505           /* HPSS NameSpace support symbolic link */
00506           symlink_support = htonl(TRUE);
00507           memcpy((char *)(attrvalsBuffer + LastOffset), &symlink_support,
00508                  sizeof(fattr4_symlink_support));
00509           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00510           op_attr_success = 1;
00511           break;
00512 
00513         case FATTR4_NAMED_ATTR:
00514           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00515                        "-----> Wanting FATTR4_NAMED_ATTR");
00516 
00517           /* For this version of the binary, named attributes is not supported */
00518           named_attr = htonl(FALSE);
00519           memcpy((char *)(attrvalsBuffer + LastOffset), &named_attr,
00520                  sizeof(fattr4_named_attr));
00521           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00522           op_attr_success = 1;
00523           break;
00524 
00525         case FATTR4_FSID:
00526           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00527                        "-----> Wanting FATTR4_FSID");
00528 
00529           /* The file system id (should be unique per fileset according to the HPSS logic) */
00530           if(psfsp->junction_export == NULL)
00531             {
00532               fsid.major = nfs_htonl64(152LL);
00533               fsid.minor = nfs_htonl64(152LL);
00534             }
00535           else
00536             {
00537               fsid.major = nfs_htonl64(153LL);  /* @todo BUGAZOMEU : tres cradem mais utile */
00538               fsid.minor = nfs_htonl64(153LL);
00539             }
00540           memcpy((char *)(attrvalsBuffer + LastOffset), &fsid, sizeof(fattr4_fsid));
00541           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00542           op_attr_success = 1;
00543           break;
00544 
00545         case FATTR4_UNIQUE_HANDLES:
00546           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00547                        "-----> Wanting FATTR4_UNIQUE_HANDLES");
00548 
00549           /* Filehandles are unique */
00550           unique_handles = htonl(TRUE);
00551           memcpy((char *)(attrvalsBuffer + LastOffset), &unique_handles,
00552                  sizeof(fattr4_unique_handles));
00553           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00554           op_attr_success = 1;
00555           break;
00556 
00557         case FATTR4_LEASE_TIME:
00558           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00559                        "-----> Wanting FATTR4_LEASE_TIME");
00560 
00561           lease_time = htonl(nfs_param.nfsv4_param.lease_lifetime);
00562           memcpy((char *)(attrvalsBuffer + LastOffset), &lease_time,
00563                  sizeof(fattr4_lease_time));
00564           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00565           op_attr_success = 1;
00566           break;
00567 
00568         case FATTR4_RDATTR_ERROR:
00569           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00570                        "-----> Wanting FATTR4_RDATTR_ERROR");
00571 
00572           op_attr_success = htonl(0);   /* not used in a getattr call */
00573           break;
00574 
00575         case FATTR4_ACL:
00576           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00577                        "-----> Wanting FATTR4_ACL");
00578 
00579           acl.fattr4_acl_len = htonl(0);
00580           memcpy((char *)(attrvalsBuffer + LastOffset), &acl, sizeof(fattr4_acl));
00581           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00582           op_attr_success = 1;
00583           break;
00584 
00585         case FATTR4_ACLSUPPORT:
00586           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00587                        "-----> Wanting FATTR4_ACL_SUPPORT");
00588 
00589 #ifdef _USE_NFS4_ACL
00590           aclsupport = htonl(ACL4_SUPPORT_ALLOW_ACL | ACL4_SUPPORT_DENY_ACL);
00591 #else
00592           aclsupport = htonl(0);
00593 #endif
00594           memcpy((char *)(attrvalsBuffer + LastOffset), &aclsupport,
00595                  sizeof(fattr4_aclsupport));
00596           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00597           op_attr_success = 1;
00598           break;
00599 
00600         case FATTR4_ARCHIVE:
00601           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00602                        "-----> Wanting FATTR4_ARCHIVE");
00603 
00604           /* Archive flag is not supported */
00605           archive = htonl(FALSE);
00606           memcpy((char *)(attrvalsBuffer + LastOffset), &archive, sizeof(fattr4_archive));
00607           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00608           op_attr_success = 1;
00609           break;
00610 
00611         case FATTR4_CANSETTIME:
00612           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00613                        "-----> Wanting FATTR4_CANSETTIME");
00614 
00615           /* The time can be set on files */
00616           cansettime = htonl(TRUE);
00617           memcpy((char *)(attrvalsBuffer + LastOffset), &cansettime,
00618                  sizeof(fattr4_cansettime));
00619           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00620           op_attr_success = 1;
00621           break;
00622 
00623         case FATTR4_CASE_INSENSITIVE:
00624           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00625                        "-----> Wanting FATTR4_CASE_INSENSITIVE");
00626 
00627           /* pseudofs is not case INSENSITIVE... it is Read-Only */
00628           case_insensitive = htonl(FALSE);
00629           memcpy((char *)(attrvalsBuffer + LastOffset), &case_insensitive,
00630                  sizeof(fattr4_case_insensitive));
00631           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00632           op_attr_success = 1;
00633           break;
00634 
00635         case FATTR4_CASE_PRESERVING:
00636           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00637                        "-----> Wanting FATTR4_PRESERVING");
00638 
00639           /* pseudofs is case preserving... it is Read-Only */
00640           case_preserving = htonl(TRUE);
00641           memcpy((char *)(attrvalsBuffer + LastOffset), &case_preserving,
00642                  sizeof(fattr4_case_preserving));
00643           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00644           op_attr_success = 1;
00645           break;
00646 
00647         case FATTR4_CHOWN_RESTRICTED:
00648           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00649                        "-----> Wanting FATTR4_CHOWN_RESTRICTED");
00650 
00651           /* chown is restricted to root, but in fact no chown will be done on pseudofs */
00652           chown_restricted = htonl(TRUE);
00653           memcpy((char *)(attrvalsBuffer + LastOffset), &chown_restricted,
00654                  sizeof(fattr4_chown_restricted));
00655           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00656           op_attr_success = 1;
00657           break;
00658 
00659         case FATTR4_FILEHANDLE:
00660           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00661                        "-----> Wanting FATTR4_FILEHANDLE");
00662 
00663           /* Return the file handle */
00664           fhandle_len = htonl(objFH->nfs_fh4_len);
00665 
00666           memcpy((char *)(attrvalsBuffer + LastOffset), &fhandle_len, sizeof(u_int));
00667           LastOffset += sizeof(u_int);
00668 
00669           memcpy((char *)(attrvalsBuffer + LastOffset),
00670                  objFH->nfs_fh4_val, objFH->nfs_fh4_len);
00671           LastOffset += objFH->nfs_fh4_len;
00672 
00673           /* XDR's special stuff for 32-bit alignment */
00674           len = objFH->nfs_fh4_len;
00675           off = 0;
00676           while((len + off) % 4 != 0)
00677             {
00678               char c = '\0';
00679 
00680               off += 1;
00681               memset((char *)(attrvalsBuffer + LastOffset), c, 1);
00682               LastOffset += 1;
00683             }
00684 
00685           op_attr_success = 1;
00686           break;
00687 
00688         case FATTR4_FILEID:
00689           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00690                        "-----> Wanting FATTR4_FILEID");
00691 
00692           /* The analog to the inode number. RFC3530 says "a number uniquely identifying the file within the filesystem" 
00693            * In the case of a pseudofs entry, the entry's unique id is used */
00694           file_id = nfs_htonl64((fattr4_fileid) psfsp->pseudo_id);
00695 
00696           memcpy((char *)(attrvalsBuffer + LastOffset), &file_id, sizeof(fattr4_fileid));
00697           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00698           op_attr_success = 1;
00699           break;
00700 
00701         case FATTR4_FILES_AVAIL:
00702           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00703                        "-----> Wanting FATTR4_FILES_AVAIL");
00704 
00705           files_avail = nfs_htonl64((fattr4_files_avail) 512);  /* Fake value */
00706           memcpy((char *)(attrvalsBuffer + LastOffset), &files_avail,
00707                  sizeof(fattr4_files_avail));
00708           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00709           op_attr_success = 1;
00710           break;
00711 
00712         case FATTR4_FILES_FREE:
00713           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00714                        "-----> Wanting FATTR4_FILES_FREE");
00715 
00716           files_free = nfs_htonl64((fattr4_files_avail) 512);   /* Fake value */
00717           memcpy((char *)(attrvalsBuffer + LastOffset), &files_free,
00718                  sizeof(fattr4_files_free));
00719           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00720           op_attr_success = 1;
00721           break;
00722 
00723         case FATTR4_FILES_TOTAL:
00724           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00725                        "-----> Wanting FATTR4_FILES_TOTAL");
00726 
00727           files_total = nfs_htonl64((fattr4_files_avail) 512);  /* Fake value */
00728           memcpy((char *)(attrvalsBuffer + LastOffset), &files_total,
00729                  sizeof(fattr4_files_total));
00730           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00731           op_attr_success = 1;
00732           break;
00733 
00734         case FATTR4_FS_LOCATIONS:
00735           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00736                        "-----> Wanting FATTR4_FS_LOCATIONS");
00737 /* RFC 3530: "When the fs_locations attribute is interrogated and there are no
00738    alternate file system locations, the server SHOULD return a zero-
00739    length array of fs_location4 structures, together with a valid
00740    fs_root. The code below does not return a fs_root which causes client
00741    problems when they interrogate this attribute. For now moving attribute to
00742    unsupported.
00743           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00744           op_attr_success = 1;
00745 */
00746           op_attr_success = 0;
00747           break;
00748 
00749         case FATTR4_HIDDEN:
00750           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00751                        "-----> Wanting FATTR4_HIDDEN");
00752 
00753           /* There are no hidden file in pseudofs */
00754           hidden = htonl(FALSE);
00755           memcpy((char *)(attrvalsBuffer + LastOffset), &hidden, sizeof(fattr4_hidden));
00756           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00757           op_attr_success = 1;
00758           break;
00759 
00760         case FATTR4_HOMOGENEOUS:
00761           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00762                        "-----> Wanting FATTR4_HOMOGENEOUS");
00763 
00764           /* Unix semantic is homogeneous (all objects have the same kind of attributes) */
00765           homogeneous = htonl(TRUE);
00766           memcpy((char *)(attrvalsBuffer + LastOffset), &homogeneous,
00767                  sizeof(fattr4_homogeneous));
00768           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00769           op_attr_success = 1;
00770           break;
00771 
00772         case FATTR4_MAXFILESIZE:
00773           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00774                        "-----> Wanting FATTR4_MAXFILESIZE");
00775 
00776           max_filesize = nfs_htonl64((fattr4_maxfilesize) FSINFO_MAX_FILESIZE);
00777           memcpy((char *)(attrvalsBuffer + LastOffset), &max_filesize,
00778                  sizeof(fattr4_maxfilesize));
00779           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00780           op_attr_success = 1;
00781           break;
00782 
00783         case FATTR4_MAXLINK:
00784           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00785                        "-----> Wanting FATTR4_MAXLINK");
00786 
00787           maxlink = htonl(MAX_HARD_LINK_VALUE);
00788           memcpy((char *)(attrvalsBuffer + LastOffset), &maxlink, sizeof(fattr4_maxlink));
00789           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00790           op_attr_success = 1;
00791           break;
00792 
00793         case FATTR4_MAXNAME:
00794           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00795                        "-----> Wanting FATTR4_MAXNAME");
00796 
00797           maxname = htonl((fattr4_maxname) MAXNAMLEN);
00798           memcpy((char *)(attrvalsBuffer + LastOffset), &maxname, sizeof(fattr4_maxname));
00799           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00800           op_attr_success = 1;
00801           break;
00802 
00803         case FATTR4_MAXREAD:
00804           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00805                        "-----> Wanting FATTR4_MAXREAD");
00806 
00807           maxread = nfs_htonl64((fattr4_maxread) NFS4_PSEUDOFS_MAX_READ_SIZE);
00808           memcpy((char *)(attrvalsBuffer + LastOffset), &maxread, sizeof(fattr4_maxread));
00809           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00810           op_attr_success = 1;
00811           break;
00812 
00813         case FATTR4_MAXWRITE:
00814           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00815                        "-----> Wanting FATTR4_MAXWRITE");
00816 
00817           maxwrite = nfs_htonl64((fattr4_maxwrite) NFS4_PSEUDOFS_MAX_WRITE_SIZE);
00818           memcpy((char *)(attrvalsBuffer + LastOffset), &maxwrite,
00819                  sizeof(fattr4_maxwrite));
00820           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00821           op_attr_success = 1;
00822           break;
00823 
00824         case FATTR4_MIMETYPE:
00825           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00826                        "-----> Wanting FATTR4_MIMETYPE");
00827 
00828           mimetype.utf8string_len = htonl(0);
00829           memcpy((char *)(attrvalsBuffer + LastOffset), &mimetype,
00830                  sizeof(fattr4_mimetype));
00831           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00832           op_attr_success = 1;  /* No supported for the moment */
00833           break;
00834 
00835         case FATTR4_MODE:
00836           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00837                        "-----> Wanting FATTR4_MODE");
00838 
00839           file_mode = htonl(0555);      /* Every pseudo fs object is dr-xr-xr-x */
00840           memcpy((char *)(attrvalsBuffer + LastOffset), &file_mode, sizeof(fattr4_mode));
00841           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00842           op_attr_success = 1;
00843           break;
00844 
00845         case FATTR4_NO_TRUNC:
00846           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00847                        "-----> Wanting FATTR4_NO_TRUNC");
00848 
00849           /* File's names are not truncated, an error is returned is name is too long */
00850           no_trunc = htonl(TRUE);
00851           memcpy((char *)(attrvalsBuffer + LastOffset), &no_trunc,
00852                  sizeof(fattr4_no_trunc));
00853           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00854           op_attr_success = 1;
00855           break;
00856 
00857         case FATTR4_NUMLINKS:
00858           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00859                        "-----> Wanting FATTR4_NUMLINKS");
00860 
00861           /* Reply the number of links found in vattr structure */
00862           file_numlinks = htonl((fattr4_numlinks) 1);
00863           memcpy((char *)(attrvalsBuffer + LastOffset), &file_numlinks,
00864                  sizeof(fattr4_numlinks));
00865           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00866           op_attr_success = 1;
00867           break;
00868 
00869         case FATTR4_OWNER:
00870           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00871                        "-----> Wanting FATTR4_OWNER");
00872 
00873           /* Return the uid as a human readable utf8 string */
00874           if(uid2utf8(NFS4_ROOT_UID, &file_owner) == 0)
00875             {
00876               u_int utf8len = 0;
00877               u_int deltalen = 0;
00878 
00879               /* Take care of 32 bits alignment */
00880               if(file_owner.utf8string_len % 4 == 0)
00881                 deltalen = 0;
00882               else
00883                 deltalen = 4 - file_owner.utf8string_len % 4;
00884 /* Following code used to add deltalen to utf8len which is wrong. It caused
00885  * clients verifying utf8 strings to reject the attribute.
00886  */
00887               utf8len = htonl(file_owner.utf8string_len);
00888               memcpy((char *)(attrvalsBuffer + LastOffset), &utf8len, sizeof(u_int));
00889               LastOffset += sizeof(u_int);
00890 
00891               memcpy((char *)(attrvalsBuffer + LastOffset),
00892                      file_owner.utf8string_val, file_owner.utf8string_len);
00893               LastOffset += file_owner.utf8string_len;
00894 
00895               /* Free what was allocated by uid2utf8 */
00896               gsh_free(file_owner.utf8string_val);
00897 
00898               /* Pad with zero to keep xdr alignement */
00899               if(deltalen != 0)
00900                 memset((char *)(attrvalsBuffer + LastOffset), 0, deltalen);
00901               LastOffset += deltalen;
00902 
00903               op_attr_success = 1;
00904             }
00905           else
00906             op_attr_success = 0;
00907           break;
00908 
00909         case FATTR4_OWNER_GROUP:
00910           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00911                        "-----> Wanting FATTR4_OWNER_GROUP");
00912 
00913           /* Return the uid as a human readable utf8 string */
00914           if(gid2utf8(2, &file_owner_group) == 0)
00915             {
00916               u_int utf8len = 0;
00917               u_int deltalen = 0;
00918 
00919               /* Take care of 32 bits alignment */
00920               if(file_owner_group.utf8string_len % 4 == 0)
00921                 deltalen = 0;
00922               else
00923                 deltalen = 4 - file_owner_group.utf8string_len % 4;
00924 
00925 /* Following code used to add deltalen to utf8len which is wrong. It caused
00926  * clients verifying utf8 strings to reject the attribute.
00927  */
00928               utf8len = htonl(file_owner_group.utf8string_len);
00929               memcpy((char *)(attrvalsBuffer + LastOffset), &utf8len, sizeof(u_int));
00930               LastOffset += sizeof(u_int);
00931 
00932               memcpy((char *)(attrvalsBuffer + LastOffset),
00933                      file_owner_group.utf8string_val, file_owner_group.utf8string_len);
00934               LastOffset += file_owner_group.utf8string_len;
00935 
00936               /* Free what was used for utf8 conversion */
00937               gsh_free(file_owner_group.utf8string_val);
00938 
00939               /* Pad with zero to keep xdr alignement */
00940               if(deltalen != 0)
00941                 memset((char *)(attrvalsBuffer + LastOffset), 0, deltalen);
00942               LastOffset += deltalen;
00943 
00944               op_attr_success = 1;
00945             }
00946           else
00947             op_attr_success = 0;
00948           break;
00949 
00950         case FATTR4_QUOTA_AVAIL_HARD:
00951           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00952                        "-----> Wanting FATTR4_QUOTA_AVAIL_HARD");
00953 
00954           quota_avail_hard = nfs_htonl64((fattr4_quota_avail_hard) NFS_V4_MAX_QUOTA_HARD);    
00955           memcpy((char *)(attrvalsBuffer + LastOffset), &quota_avail_hard,
00956                  sizeof(fattr4_quota_avail_hard));
00957           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00958           op_attr_success = 1;
00959           break;
00960 
00961         case FATTR4_QUOTA_AVAIL_SOFT:
00962           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00963                        "-----> Wanting FATTR4_QUOTA_AVAIL_SOFT");
00964 
00965           quota_avail_soft = nfs_htonl64((fattr4_quota_avail_soft) NFS_V4_MAX_QUOTA_SOFT);    
00966           memcpy((char *)(attrvalsBuffer + LastOffset), &quota_avail_soft,
00967                  sizeof(fattr4_quota_avail_soft));
00968           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00969           op_attr_success = 1;
00970           break;
00971 
00972         case FATTR4_QUOTA_USED:
00973           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00974                        "-----> Wanting FATTR4_QUOTA_AVAIL_USED");
00975 
00976           quota_used = nfs_htonl64((fattr4_quota_used) NFS_V4_MAX_QUOTA);
00977           memcpy((char *)(attrvalsBuffer + LastOffset), &quota_used,
00978                  sizeof(fattr4_quota_used));
00979           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00980           op_attr_success = 1;
00981           break;
00982 
00983         case FATTR4_RAWDEV:
00984           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00985                        "-----> Wanting FATTR4_RAWDEV");
00986 
00987           /* Not usefull, there are no special block or character file in HPSS */
00988           /* since FATTR4_TYPE will never be NFS4BLK or NFS4CHR, this value should not be used by the client */
00989           rawdev.specdata1 = htonl(0);
00990           rawdev.specdata2 = htonl(0);
00991           memcpy((char *)(attrvalsBuffer + LastOffset), &rawdev, sizeof(fattr4_rawdev));
00992           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
00993           op_attr_success = 1;
00994           break;
00995 
00996         case FATTR4_SPACE_AVAIL:
00997           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
00998                        "-----> Wanting FATTR4_SPACE_AVAIL");
00999 
01000           space_avail = nfs_htonl64(512000LL);  /* Fake value */
01001           memcpy((char *)(attrvalsBuffer + LastOffset), &space_avail,
01002                  sizeof(fattr4_space_avail));
01003           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01004           op_attr_success = 1;
01005           break;
01006 
01007         case FATTR4_SPACE_FREE:
01008           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01009                        "-----> Wanting FATTR4_SPACE_FREE");
01010 
01011           space_free = nfs_htonl64(512000LL);   /* Fake value */
01012           memcpy((char *)(attrvalsBuffer + LastOffset), &space_free,
01013                  sizeof(fattr4_space_free));
01014           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01015           op_attr_success = 1;
01016           break;
01017 
01018         case FATTR4_SPACE_TOTAL:
01019           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01020                        "-----> Wanting FATTR4_SPACE_TOTAL");
01021 
01022           space_total = nfs_htonl64(1024000LL); /* Fake value */
01023           memcpy((char *)(attrvalsBuffer + LastOffset), &space_total,
01024                  sizeof(fattr4_space_total));
01025           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01026           op_attr_success = 1;
01027           break;
01028 
01029         case FATTR4_SPACE_USED:
01030           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01031                        "-----> Wanting FATTR4_SPACE_USED");
01032 
01033           /* the number of bytes on the filesystem used by the object, which is slightly different 
01034            * from the file's size (there can be hole in the file) */
01035           file_space_used = nfs_htonl64((fattr4_space_used) DEV_BSIZE);
01036           memcpy((char *)(attrvalsBuffer + LastOffset), &file_space_used,
01037                  sizeof(fattr4_space_used));
01038           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01039           op_attr_success = 1;
01040           break;
01041 
01042         case FATTR4_SYSTEM:
01043           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01044                        "-----> Wanting FATTR4_SYSTEM");
01045 
01046           /* This is not a windows system File-System with respect to the regarding API */
01047           system = htonl(FALSE);
01048           memcpy((char *)(attrvalsBuffer + LastOffset), &system, sizeof(fattr4_system));
01049           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01050           op_attr_success = 1;
01051           break;
01052 
01053         case FATTR4_TIME_ACCESS:
01054           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01055                        "-----> Wanting FATTR4_TIME_ACCESS");
01056 
01057           /* This will contain the object's time os last access, the 'atime' in the Unix semantic */
01058           memset(&(time_access.seconds), 0, sizeof(int64_t));
01059           time_access.seconds = nfs_htonl64((int64_t) ServerBootTime);
01060           time_access.nseconds = htonl(0);
01061           memcpy((char *)(attrvalsBuffer + LastOffset), &time_access,
01062                  fattr4tab[attribute_to_set].size_fattr4);
01063           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01064           op_attr_success = 1;
01065           break;
01066 
01067         case FATTR4_TIME_ACCESS_SET:
01068           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01069                        "-----> Wanting FATTR4_TIME_ACCESS_SET");
01070 
01071           /* To be used with NFS4_OP_SETATTR only */
01072           op_attr_success = 0;
01073           break;
01074 
01075         case FATTR4_TIME_BACKUP:
01076           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01077                        "-----> Wanting FATTR4_TIME_BACKUP");
01078 
01079           /* No time backup, return unix's beginning of time */
01080           time_backup.seconds = nfs_htonl64(0LL);
01081           time_backup.nseconds = htonl(0);
01082           memcpy((char *)(attrvalsBuffer + LastOffset), &time_backup,
01083                  fattr4tab[attribute_to_set].size_fattr4);
01084           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01085           op_attr_success = 1;
01086           break;
01087 
01088         case FATTR4_TIME_CREATE:
01089           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01090                        "-----> Wanting FATTR4_TIME_CREATE");
01091 
01092           /* No time create, return unix's beginning of time */
01093           time_create.seconds = nfs_htonl64(0LL);
01094           time_create.nseconds = htonl(0);
01095           memcpy((char *)(attrvalsBuffer + LastOffset), &time_create,
01096                  fattr4tab[attribute_to_set].size_fattr4);
01097           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01098           op_attr_success = 1;
01099           break;
01100 
01101         case FATTR4_TIME_DELTA:
01102           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01103                        "-----> Wanting FATTR4_TIME_DELTA");
01104 
01105 
01106           /* According to RFC3530, this is "the smallest usefull server time granularity", I set this to 1s */
01107           time_delta.seconds = nfs_htonl64(1LL);
01108           time_delta.nseconds = 0;
01109           memcpy((char *)(attrvalsBuffer + LastOffset), &time_delta,
01110                  fattr4tab[attribute_to_set].size_fattr4);
01111           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01112           op_attr_success = 1;
01113           break;
01114 
01115         case FATTR4_TIME_METADATA:
01116           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01117                        "-----> Wanting FATTR4_TIME_METADATA");
01118 
01119           /* The time for the last metadata operation, the ctime in the unix's semantic */
01120           memset(&(time_metadata.seconds), 0, sizeof(int64_t));
01121           time_metadata.seconds = nfs_htonl64((int64_t) ServerBootTime);
01122           time_metadata.nseconds = htonl(0);
01123           memcpy((char *)(attrvalsBuffer + LastOffset), &time_metadata,
01124                  fattr4tab[attribute_to_set].size_fattr4);
01125           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01126           op_attr_success = 1;
01127           break;
01128 
01129         case FATTR4_TIME_MODIFY:
01130           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01131                        "-----> Wanting FATTR4_TIME_MODIFY");
01132 
01133           /* The time for the last modify operation, the mtime in the unix's semantic */
01134           memset(&(time_modify.seconds), 0, sizeof(int64_t));
01135           time_modify.seconds = nfs_htonl64((int64_t) ServerBootTime);
01136           time_modify.nseconds = htonl(0);
01137           memcpy((char *)(attrvalsBuffer + LastOffset), &time_modify,
01138                  fattr4tab[attribute_to_set].size_fattr4);
01139           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01140           op_attr_success = 1;
01141           break;
01142 
01143         case FATTR4_TIME_MODIFY_SET:
01144           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01145                        "-----> Wanting FATTR4_TIME_MODIFY_SET");
01146 
01147           op_attr_success = 0;  /* should never be used here, only for setattr */
01148           break;
01149 
01150         case FATTR4_MOUNTED_ON_FILEID:
01151           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01152                        "-----> Wanting FATTR4_MOUNTED_ON_FILEID");
01153 
01154           mounted_on_fileid = nfs_htonl64((fattr4_fileid) psfsp->pseudo_id);
01155           memcpy((char *)(attrvalsBuffer + LastOffset), &mounted_on_fileid,
01156                  sizeof(fattr4_mounted_on_fileid));
01157           LastOffset += fattr4tab[attribute_to_set].size_fattr4;
01158           op_attr_success = 1;
01159           break;
01160 
01161 #ifdef _USE_NFS4_1
01162         case FATTR4_FS_LAYOUT_TYPES:
01163           layout_types.fattr4_fs_layout_types_len = htonl(1);
01164           memcpy((char *)(attrvalsBuffer + LastOffset),
01165                  &layout_types.fattr4_fs_layout_types_len, sizeof(u_int));
01166           LastOffset += sizeof(u_int);
01167 
01168           layout_types.fattr4_fs_layout_types_val = layouts;
01169           layouts[0] = htonl(LAYOUT4_NFSV4_1_FILES);
01170           memcpy((char *)(attrvalsBuffer + LastOffset),
01171                  layout_types.fattr4_fs_layout_types_val, sizeof(layouttype4));
01172           LastOffset += sizeof(layouttype4);
01173 
01174           op_attr_success = 1;
01175           break;
01176 #endif
01177 
01178         default:
01179           LogWarn(COMPONENT_NFS_V4_PSEUDO, "Bad file attributes %d queried",
01180                   attribute_to_set);
01181           /* BUGAZOMEU : un traitement special ici */
01182           break;
01183         }                       /* switch( attr_to_set ) */
01184 
01185       /* Increase the Offset for the next operation if this was a success */
01186       if(op_attr_success)
01187         {
01188           /* Set the returned bitmask */
01189           attrvalslist[j] = attribute_to_set;
01190           j += 1;
01191 
01192           /* Be carefull not to get out of attrvalsBuffer */
01193           if(LastOffset > NFS4_ATTRVALS_BUFFLEN)
01194             return -1;
01195         }
01196 
01197     }                           /* for i */
01198 
01199   LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01200                "----------------------------------------");
01201 
01202   /* LastOffset contains the length of the attrvalsBuffer usefull data */
01203   LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01204                "Fattr (pseudo) At the end LastOffset = %u, i=%d, j=%d",
01205                LastOffset, i, j);
01206 
01207   return nfs4_Fattr_Fill(Fattr, j, attrvalslist, LastOffset, attrvalsBuffer);
01208 }                               /* nfs4_PseudoToFattr */
01209 
01221 int nfs4_FhandleToPseudo(nfs_fh4 * fh4p, pseudofs_t * psfstree,
01222                          pseudofs_entry_t * psfsentry)
01223 {
01224   file_handle_v4_t *pfhandle4;
01225 
01226   /* Map the filehandle to the correct structure */
01227   pfhandle4 = (file_handle_v4_t *) (fh4p->nfs_fh4_val);
01228 
01229   /* The function must be called with a fh pointed to a pseudofs entry */
01230   if(pfhandle4->pseudofs_flag == FALSE)
01231     return FALSE;
01232 
01233   /* Get the object pointer by using the reverse tab in the pseudofs structure */
01234   memcpy(psfsentry, psfstree->reverse_tab[pfhandle4->pseudofs_id],
01235          sizeof(pseudofs_entry_t));
01236 
01237   return TRUE;
01238 }                               /* nfs4_FhandleToPseudo */
01239 
01252 int nfs4_PseudoToFhandle(nfs_fh4 * fh4p, pseudofs_entry_t * psfsentry)
01253 {
01254   file_handle_v4_t *fhandle4;
01255 
01256   memset(fh4p->nfs_fh4_val, 0, sizeof(struct alloc_file_handle_v4)); /* clean whole thing */
01257   fhandle4 = (file_handle_v4_t *)fh4p->nfs_fh4_val;
01258   fhandle4->fhversion = GANESHA_FH_VERSION;
01259   fhandle4->pseudofs_flag = TRUE;
01260   fhandle4->pseudofs_id = psfsentry->pseudo_id;
01261 
01262   LogFullDebug(COMPONENT_NFS_V4_PSEUDO, "PSEUDO_TO_FH: Pseudo id = %d -> %d",
01263                psfsentry->pseudo_id, fhandle4->pseudofs_id);
01264 
01265   fh4p->nfs_fh4_len = sizeof(file_handle_v4_t); /* no handle in opaque */
01266 
01267   return TRUE;
01268 }                               /* nfs4_PseudoToFhandle */
01269 
01282 int nfs4_CreateROOTFH4(nfs_fh4 * fh4p, compound_data_t * data)
01283 {
01284   pseudofs_entry_t psfsentry;
01285   int status = 0;
01286 
01287   psfsentry = *(data->pseudofs->reverse_tab[0]);
01288 
01289   LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01290                "CREATE ROOTFH (pseudo): root to pseudofs = #%s#",
01291                psfsentry.name);
01292 
01293   if((status = nfs4_AllocateFH(&(data->rootFH))) != NFS4_OK)
01294     return status;
01295 
01296   if(!nfs4_PseudoToFhandle(&(data->rootFH), &psfsentry))
01297     {
01298       LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01299                    "CREATE ROOTFH (pseudo): Creation of root fh is impossible");
01300       return NFS4ERR_BADHANDLE;
01301     }
01302 
01303   /* Test */
01304   if(isFullDebug(COMPONENT_NFS_V4))
01305     {
01306       char str[LEN_FH_STR];
01307       sprint_fhandle4(str, &data->rootFH);
01308       LogFullDebug(COMPONENT_NFS_V4, "CREATE ROOT FH: %s", str);
01309     }
01310 
01311   return NFS4_OK;
01312 }                               /* nfs4_CreateROOTFH4 */
01313 
01327 #define arg_GETATTR4 op->nfs_argop4_u.opgetattr
01328 #define res_GETATTR4 resp->nfs_resop4_u.opgetattr
01329 
01330 int nfs4_op_getattr_pseudo(struct nfs_argop4 *op,
01331                            compound_data_t * data, struct nfs_resop4 *resp)
01332 {
01333   pseudofs_entry_t psfsentry;
01334   char __attribute__ ((__unused__)) funcname[] = "nfs4_op_getattr";
01335 
01336   resp->resop = NFS4_OP_GETATTR;
01337 
01338   /* Get the pseudo entry related to this fhandle */
01339   if(!nfs4_FhandleToPseudo(&(data->currentFH), data->pseudofs, &psfsentry))
01340     {
01341       res_GETATTR4.status = NFS4ERR_BADHANDLE;
01342       return res_GETATTR4.status;
01343     }
01344 
01345   /* All directories in pseudo fs have the same Fattr */
01346   if(nfs4_PseudoToFattr(&psfsentry,
01347                         &(res_GETATTR4.GETATTR4res_u.resok4.obj_attributes),
01348                         data, &(data->currentFH), &(arg_GETATTR4.attr_request)) != 0)
01349     res_GETATTR4.status = NFS4ERR_SERVERFAULT;
01350   else
01351     res_GETATTR4.status = NFS4_OK;
01352 
01353   LogFullDebug(COMPONENT_NFS_V4,
01354                "Apres nfs4_PseudoToFattr: attrmask(bitmap4_len)=%d attrlist4_len=%d",
01355                res_GETATTR4.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len,
01356                res_GETATTR4.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len);
01357 
01358   return res_GETATTR4.status;
01359 }                               /* nfs4_op_getattr */
01360 
01375 /* Shorter notation to avoid typos */
01376 #define res_ACCESS4 resp->nfs_resop4_u.opaccess
01377 #define arg_ACCESS4 op->nfs_argop4_u.opaccess
01378 
01379 int nfs4_op_access_pseudo(struct nfs_argop4 *op,
01380                           compound_data_t * data, struct nfs_resop4 *resp)
01381 {
01382   char __attribute__ ((__unused__)) funcname[] = "nfs4_op_access_pseudo";
01383 
01384   resp->resop = NFS4_OP_ACCESS;
01385 
01386   /* All access types are supported */
01387   res_ACCESS4.ACCESS4res_u.resok4.supported = ACCESS4_READ | ACCESS4_LOOKUP;
01388 
01389   /* DELETE/MODIFY/EXTEND are not supported in the pseudo fs */
01390   res_ACCESS4.ACCESS4res_u.resok4.access =
01391       arg_ACCESS4.access & ~(ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_DELETE);
01392 
01393   return NFS4_OK;
01394 }                               /* nfs4_op_access_pseudo */
01395 
01409 /* Shorter notation to avoid typos */
01410 #define arg_LOOKUP4 op->nfs_argop4_u.oplookup
01411 #define res_LOOKUP4 resp->nfs_resop4_u.oplookup
01412 
01413 int nfs4_op_lookup_pseudo(struct nfs_argop4 *op,
01414                           compound_data_t * data, struct nfs_resop4 *resp)
01415 {
01416   char name[MAXNAMLEN];
01417   char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lookup_pseudo";
01418   pseudofs_entry_t psfsentry;
01419   pseudofs_entry_t *iter = NULL;
01420   int found = FALSE;
01421   int pseudo_is_slash = FALSE ;
01422   int error = 0;
01423   cache_inode_status_t cache_status = 0;
01424   fsal_status_t fsal_status;
01425   cache_inode_fsal_data_t fsdata;
01426   fsal_path_t exportpath_fsal;
01427   char pathfsal[MAXPATHLEN] ;
01428   fsal_attrib_list_t attr;
01429   fsal_handle_t fsal_handle;
01430   cache_entry_t *pentry = NULL;
01431   fsal_mdsize_t strsize = MNTPATHLEN + 1;
01432 
01433   resp->resop = NFS4_OP_LOOKUP;
01434 
01435   /* UTF8 strings may not end with \0, but they carry their length */
01436   utf82str(name, sizeof(name), &arg_LOOKUP4.objname);
01437 
01438   /* Get the pseudo fs entry related to the file handle */
01439   if(!nfs4_FhandleToPseudo(&(data->currentFH), data->pseudofs, &psfsentry))
01440     {
01441       res_LOOKUP4.status = NFS4ERR_BADHANDLE;
01442       return res_LOOKUP4.status;
01443     }
01444 
01445  
01446   /* If "/" is set as pseudopath, then gPseudoFS.root.junction_export is not NULL but 
01447    * gPseudoFS.root has no son */
01448   if( ( gPseudoFs.root.junction_export != NULL ) && ( gPseudoFs.root.sons == NULL )  )
01449    {
01450         iter = &gPseudoFs.root ;
01451         pseudo_is_slash = TRUE ;
01452         found = TRUE ;
01453    }
01454   else
01455    {
01456      found = FALSE;
01457      for(iter = psfsentry.sons; iter != NULL; iter = iter->next)
01458        {
01459          if(!strcmp(iter->name, name))
01460            {
01461              found = TRUE;
01462              break;
01463            } 
01464        } /* for */
01465     } /* else */
01466 
01467   if(!found)
01468     {
01469       res_LOOKUP4.status = NFS4ERR_NOENT;
01470       return res_LOOKUP4.status;
01471     }
01472 
01473   /* A matching entry was found */
01474   if(iter->junction_export == NULL)
01475     {
01476       /* The entry is not a junction, we stay within the pseudo fs */
01477       if(!nfs4_PseudoToFhandle(&(data->currentFH), iter))
01478         {
01479           res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01480           return res_LOOKUP4.status;
01481         }
01482     }
01483   else
01484     {
01485       /* The entry is a junction */
01486       LogFullDebug(COMPONENT_NFS_V4_PSEUDO,      
01487                    "A junction in pseudo fs is traversed: name = %s, id = %d",
01488                    iter->name, iter->junction_export->id);
01489       data->pexport = iter->junction_export;
01490       strncpy(data->MntPath, iter->fullname, NFS_MAXPATHLEN);
01491 
01492       /* Build credentials */
01493       if(nfs4_MakeCred(data) != 0)
01494         {
01495           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01496                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to get FSAL credentials for %s, id=%d",
01497                    data->pexport->fullpath, data->pexport->id);
01498           res_LOOKUP4.status = NFS4ERR_WRONGSEC;
01499           return res_LOOKUP4.status;
01500         }
01501 
01502       /* Build fsal data for creation of the first entry */
01503       strncpy( pathfsal, data->pexport->fullpath, MAXPATHLEN ) ;
01504 
01505       if( pseudo_is_slash == TRUE )
01506        {
01507          strncat( pathfsal, "/", MAXPATHLEN ) ;
01508          strncat( pathfsal, name, MAXPATHLEN - strlen(pathfsal) - 1) ;  // - 1 for the '/0'
01509        }
01510 
01511       if(FSAL_IS_ERROR
01512          ((fsal_status =
01513            FSAL_str2path( pathfsal, strsize, &exportpath_fsal))))
01514         {
01515           res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01516           return res_LOOKUP4.status;
01517         }
01518 
01519       /* Lookup the FSAL to build the fsal handle */
01520       if(FSAL_IS_ERROR(fsal_status = FSAL_lookupPath(&exportpath_fsal,
01521                                                      data->pcontext, &fsal_handle, NULL)))
01522         {
01523           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01524                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to lookup for %s, id=%d",
01525                    data->pexport->fullpath, data->pexport->id);
01526           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01527                    "PSEUDO FS JUNCTION TRAVERSAL: fsal_status = ( %d, %d )",
01528                    fsal_status.major, fsal_status.minor);
01529           res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01530           return res_LOOKUP4.status;
01531         }
01532 
01533       if(data->mounted_on_FH.nfs_fh4_len == 0)
01534         {
01535           if((error = nfs4_AllocateFH(&(data->mounted_on_FH))) != NFS4_OK)
01536             {
01537               LogMajor(COMPONENT_NFS_V4_PSEUDO,
01538                        "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to allocate the 'mounted on' file handle");
01539               res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01540               return res_LOOKUP4.status;
01541             }
01542         }
01543 
01544       if(data->currentFH.nfs_fh4_len == 0)
01545         {
01546           if((error = nfs4_AllocateFH(&(data->currentFH))) != NFS4_OK)
01547             {
01548               LogMajor(COMPONENT_NFS_V4_PSEUDO,
01549                        "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to allocate the first file handle");
01550               res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01551               return res_LOOKUP4.status;
01552             }
01553         }
01554 
01555       /* Build the nfs4 handle */
01556       if(!nfs4_FSALToFhandle(&data->currentFH, &fsal_handle, data))
01557         {
01558           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01559                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to build the first file handle");
01560           res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01561           return res_LOOKUP4.status;
01562         }
01563 
01564       /* The new fh is to be the "mounted on Filehandle" */
01565       memcpy(data->mounted_on_FH.nfs_fh4_val, data->currentFH.nfs_fh4_val,
01566              sizeof(file_handle_v4_t));
01567       data->mounted_on_FH.nfs_fh4_len = data->currentFH.nfs_fh4_len;
01568 
01569       /* Add the entry to the cache as a root (BUGAZOMEU: make it a junction entry when junction is available) */
01570       fsdata.fh_desc.start = (caddr_t)&fsal_handle;
01571       fsdata.fh_desc.len = 0;
01572       FSAL_ExpandHandle(data->pcontext->export_context,
01573                         FSAL_DIGEST_SIZEOF,
01574                         &fsdata.fh_desc);
01575 
01576       if((pentry = cache_inode_make_root(&fsdata,
01577                                          data->pcontext,
01578                                          &cache_status)) == NULL)
01579         {
01580           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01581                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Allocate root entry in cache inode failed, for %s, id=%d",
01582                    data->pexport->fullpath, data->pexport->id);
01583           res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01584           return res_LOOKUP4.status;
01585         }
01586 
01587       /* Get the attributes (costless: the attributes was cached when the root pentry was created */
01588       if(cache_inode_getattr(pentry,
01589                              &attr,
01590                              data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
01591         {
01592           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01593                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to get attributes for root pentry");
01594           res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
01595           cache_inode_put(pentry);
01596           return res_LOOKUP4.status;
01597         }
01598 
01599       /* Keep the pentry within the compound data */
01600       if (data->current_entry) {
01601           cache_inode_put(data->current_entry);
01602       }
01603       data->current_entry = pentry;
01604       data->current_filetype = cache_inode_fsal_type_convert(attr.type);
01605 
01606     }                           /* else */
01607 
01608 
01609   res_LOOKUP4.status = NFS4_OK;
01610   return NFS4_OK;
01611 }                               /* nfs4_op_lookup_pseudo */
01612 
01626 /* Shorter notation to avoid typos */
01627 #define arg_LOOKUPP4 op->nfs_argop4_u.oplookupp
01628 #define res_LOOKUPP4 resp->nfs_resop4_u.oplookupp
01629 
01630 int nfs4_op_lookupp_pseudo(struct nfs_argop4 *op,
01631                            compound_data_t * data, struct nfs_resop4 *resp)
01632 {
01633   char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lookup_pseudo";
01634   pseudofs_entry_t psfsentry;
01635 
01636   resp->resop = NFS4_OP_LOOKUPP;
01637 
01638   /* Get the pseudo fs entry related to the file handle */
01639   if(!nfs4_FhandleToPseudo(&(data->currentFH), data->pseudofs, &psfsentry))
01640     {
01641       res_LOOKUPP4.status = NFS4ERR_BADHANDLE;
01642       return res_LOOKUPP4.status;
01643     }
01644 
01645   /* lookupp on the root on the pseudofs should return NFS4ERR_NOENT (RFC3530, page 166) */
01646   if(!memcmp(&psfsentry, data->pseudofs->reverse_tab[0], sizeof(psfsentry)))
01647     {
01648       res_LOOKUPP4.status = NFS4ERR_NOENT;
01649       return res_LOOKUPP4.status;
01650     }
01651 
01652   /* A matching entry was found */
01653   if(!nfs4_PseudoToFhandle(&(data->currentFH), psfsentry.parent))
01654     {
01655       res_LOOKUPP4.status = NFS4ERR_SERVERFAULT;
01656       return res_LOOKUPP4.status;
01657     }
01658 
01659   /* Copy this to the mounted on FH (if no junction is traversed */
01660   memcpy((char *)(data->mounted_on_FH.nfs_fh4_val),
01661          (char *)(data->currentFH.nfs_fh4_val), data->currentFH.nfs_fh4_len);
01662   data->mounted_on_FH.nfs_fh4_len = data->currentFH.nfs_fh4_len;
01663 
01664   /* Keep the vnode pointer within the data compound */
01665   if (data->current_entry) {
01666       cache_inode_put(data->current_entry);
01667   }
01668   data->current_entry = NULL;
01669 /* pseudo file system is always a directory and we need to keep
01670  * nfs4_sanity_check_FH  happy.
01671  */
01672   data->current_filetype = DIRECTORY;
01673   res_LOOKUPP4.status = NFS4_OK;
01674   return NFS4_OK;
01675 }                               /* nfs4_op_lookupp_pseudo */
01676 
01690 /* shorter notation to avoid typo */
01691 #define arg_READDIR4 op->nfs_argop4_u.opreaddir
01692 #define res_READDIR4 resp->nfs_resop4_u.opreaddir
01693 
01694 int nfs4_op_readdir_pseudo(struct nfs_argop4 *op,
01695                            compound_data_t * data, struct nfs_resop4 *resp)
01696 {
01697   unsigned long dircount = 0;
01698   unsigned long maxcount = 0;
01699   unsigned long estimated_num_entries = 0;
01700   unsigned long i = 0;
01701   nfs_cookie4 cookie;
01702   verifier4 cookie_verifier;
01703   unsigned long space_used = 0;
01704   pseudofs_entry_t psfsentry;
01705   pseudofs_entry_t *iter = NULL;
01706   entry4 *entry_nfs_array = NULL;
01707   exportlist_t *save_pexport;
01708   nfs_fh4 entryFH;
01709   cache_inode_fsal_data_t fsdata;
01710   fsal_path_t exportpath_fsal;
01711   fsal_attrib_list_t attr;
01712   fsal_handle_t fsal_handle;
01713   fsal_mdsize_t strsize = MNTPATHLEN + 1;
01714   fsal_status_t fsal_status;
01715   int error = 0;
01716   size_t namelen = 0;
01717   cache_inode_status_t cache_status = CACHE_INODE_SUCCESS;
01718   cache_entry_t *pentry = NULL;
01719 
01720   char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readdir_pseudo";
01721 
01722   bitmap4 RdAttrErrorBitmap = { 1, (uint32_t *) "\0\0\0\b" };   /* 0xB = 11 = FATTR4_RDATTR_ERROR */
01723   attrlist4 RdAttrErrorVals = { 0, NULL };      /* Nothing to be seen here */
01724 
01725   resp->resop = NFS4_OP_READDIR;
01726   res_READDIR4.status = NFS4_OK;
01727 
01728   entryFH.nfs_fh4_len = 0;
01729 
01730   LogFullDebug(COMPONENT_NFS_V4_PSEUDO, "Entering NFS4_OP_READDIR_PSEUDO");
01731 
01732   /* get the caracteristic value for readdir operation */
01733   dircount = arg_READDIR4.dircount;
01734   maxcount = arg_READDIR4.maxcount;
01735   cookie = arg_READDIR4.cookie;
01736   space_used = sizeof(entry4);
01737 
01738   /* dircount is considered meaningless by many nfsv4 client (like the CITI one). we use maxcount instead */
01739   estimated_num_entries = maxcount / sizeof(entry4);
01740 
01741   LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01742                "PSEUDOFS READDIR: dircount=%lu, maxcount=%lu, cookie=%"PRIu64", sizeof(entry4)=%lu num_entries=%lu",
01743                dircount, maxcount, (uint64_t)cookie, space_used, estimated_num_entries);
01744 
01745   /* If maxcount is too short, return NFS4ERR_TOOSMALL */
01746   if(maxcount < sizeof(entry4) || estimated_num_entries == 0)
01747     {
01748       res_READDIR4.status = NFS4ERR_TOOSMALL;
01749       return res_READDIR4.status;
01750     }
01751 
01752   /* Now resolve the file handle to pseudo fs */
01753   if(!nfs4_FhandleToPseudo(&(data->currentFH), data->pseudofs, &psfsentry))
01754     {
01755       res_READDIR4.status = NFS4ERR_BADHANDLE;
01756       return res_READDIR4.status;
01757     }
01758   LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01759                "PSEUDOFS READDIR in #%s#", psfsentry.name);
01760 
01761   /* If this a junction filehandle ? */
01762   if(psfsentry.junction_export != NULL)
01763     {
01764       /* This is a junction */
01765       LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01766                    "PSEUDOFS READDIR : DIR #%s# id=%u is a junction",
01767                    psfsentry.name, psfsentry.junction_export->id);
01768 
01769       /* Step up the compound data */
01770       data->pexport = psfsentry.junction_export;
01771       strncpy(data->MntPath, psfsentry.fullname, NFS_MAXPATHLEN);
01772 
01773       /* Build the credentials */
01774       if(nfs4_MakeCred(data) != 0)
01775         {
01776           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01777                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to get FSAL credentials for %s, id=%d",
01778                    data->pexport->fullpath, data->pexport->id);
01779           res_READDIR4.status = NFS4ERR_WRONGSEC;
01780           return res_READDIR4.status;
01781         }
01782       /* Build fsal data for creation of the first entry */
01783       if(FSAL_IS_ERROR
01784          ((fsal_status =
01785            FSAL_str2path(data->pexport->fullpath, strsize, &exportpath_fsal))))
01786         {
01787           res_READDIR4.status = NFS4ERR_SERVERFAULT;
01788           return res_READDIR4.status;
01789         }
01790 
01791       /* Lookup the FSAL to build the fsal handle */
01792       if(FSAL_IS_ERROR(fsal_status = FSAL_lookupPath(&exportpath_fsal,
01793                                                      data->pcontext, &fsal_handle, NULL)))
01794         {
01795           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01796                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to lookup for %s, id=%d",
01797                    data->pexport->fullpath, data->pexport->id);
01798           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01799                    "PSEUDO FS JUNCTION TRAVERSAL: fsal_status = ( %d, %d )",
01800                    fsal_status.major, fsal_status.minor);
01801           res_READDIR4.status = NFS4ERR_SERVERFAULT;
01802           return res_READDIR4.status;
01803         }
01804 
01805       if(data->mounted_on_FH.nfs_fh4_len == 0)
01806         {
01807           if((error = nfs4_AllocateFH(&(data->mounted_on_FH))) != NFS4_OK)
01808             {
01809               LogMajor(COMPONENT_NFS_V4_PSEUDO,
01810                        "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to allocate the 'mounted on' file handle");
01811               res_READDIR4.status = NFS4ERR_SERVERFAULT;
01812               return res_READDIR4.status;
01813             }
01814         }
01815 
01816       if(data->currentFH.nfs_fh4_len == 0)
01817         {
01818           if((error = nfs4_AllocateFH(&(data->currentFH))) != NFS4_OK)
01819             {
01820               LogMajor(COMPONENT_NFS_V4_PSEUDO,
01821                        "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to allocate the first file handle");
01822               res_READDIR4.status = NFS4ERR_SERVERFAULT;
01823               return res_READDIR4.status;
01824             }
01825         }
01826 
01827       /* Build the nfs4 handle */
01828       if(!nfs4_FSALToFhandle(&data->currentFH, &fsal_handle, data))
01829         {
01830           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01831                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to build the first file handle");
01832           res_READDIR4.status = NFS4ERR_SERVERFAULT;
01833           return res_READDIR4.status;
01834         }
01835 
01836       /* The new fh is to be the "mounted on Filehandle" */
01837       memcpy(data->mounted_on_FH.nfs_fh4_val, data->currentFH.nfs_fh4_val,
01838              sizeof(file_handle_v4_t));
01839       data->mounted_on_FH.nfs_fh4_len = data->currentFH.nfs_fh4_len;
01840 
01841       /* Add the entry to the cache as a root (BUGAZOMEU: make it a junction entry when junction is available) */
01842       fsdata.fh_desc.start = (caddr_t) &fsal_handle;
01843       fsdata.fh_desc.len = 0;
01844       FSAL_ExpandHandle(data->pcontext->export_context,
01845                         FSAL_DIGEST_SIZEOF,
01846                         &fsdata.fh_desc);
01847 
01848       if((pentry = cache_inode_make_root(&fsdata,
01849                                          data->pcontext,
01850                                          &cache_status)) == NULL)
01851         {
01852           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01853                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Allocate root entry in cache inode failed, for %s, id=%d",
01854                    data->pexport->fullpath, data->pexport->id);
01855           res_READDIR4.status = NFS4ERR_SERVERFAULT;
01856           return res_READDIR4.status;
01857         }
01858 
01859       /* Get the attributes (costless: the attributes was cached when the root pentry was created */
01860       if(cache_inode_getattr(pentry,
01861                              &attr,
01862                              data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
01863         {
01864           LogMajor(COMPONENT_NFS_V4_PSEUDO,
01865                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to get attributes for root pentry");
01866           res_READDIR4.status = NFS4ERR_SERVERFAULT;
01867           cache_inode_put(pentry);
01868           return res_READDIR4.status;
01869         }
01870 
01871       /* Keep the pentry within the compound data */
01872       if (data->current_entry) {
01873           cache_inode_put(data->current_entry);
01874       }
01875       data->current_entry = pentry;
01876       data->current_filetype = cache_inode_fsal_type_convert(attr.type);
01877 
01878       /* redo the call on the other side of the junction */
01879       return nfs4_op_readdir(op, data, resp);
01880     }
01881 
01882   /* Allocation of the entries array */
01883   if((entry_nfs_array =
01884       gsh_calloc(estimated_num_entries, sizeof(entry4))) == NULL)
01885     {
01886       LogError(COMPONENT_NFS_V4_PSEUDO, ERR_SYS, ERR_MALLOC, errno);
01887       res_READDIR4.status = NFS4ERR_SERVERFAULT;
01888       return res_READDIR4.status;
01889     }
01890 
01891   /* Cookie verifier has the value of the Server Boot Time for pseudo fs */
01892   memset(cookie_verifier, 0, NFS4_VERIFIER_SIZE);
01893 #ifdef _WITH_COOKIE_VERIFIER
01894   /* BUGAZOMEU: management of the cookie verifier */
01895   if(NFS_SpecificConfig.UseCookieVerf == 1)
01896     {
01897       memcpy(cookie_verifier, &ServerBootTime, sizeof(ServerBootTime));
01898       if(cookie != 0)
01899         {
01900           if(memcmp(cookie_verifier, arg_READDIR4.cookieverf, NFS4_VERIFIER_SIZE) != 0)
01901             {
01902               res_READDIR4.status = NFS4ERR_BAD_COOKIE;
01903               gsh_free(entry_nfs_array);
01904               return res_READDIR4.status;
01905             }
01906         }
01907     }
01908 #endif
01909   /* Cookie delivered by the server and used by the client SHOULD not ne 0, 1 or 2 (cf RFC3530, page192)
01910    * because theses value are reserved for special use.
01911    *      0 - cookie for first READDIR
01912    *      1 - reserved for . on client handside
01913    *      2 - reserved for .. on client handside
01914    * Entries '.' and '..' are not returned also
01915    * For these reason, there will be an offset of 3 between NFS4 cookie and HPSS cookie */
01916 
01917   /* make sure to start at the right position given by the cookie */
01918   iter = psfsentry.sons;
01919   if(cookie != 0)
01920     {
01921       for(; iter != NULL; iter = iter->next)
01922         if((iter->pseudo_id + 3) == cookie)
01923           break;
01924     }
01925 
01926   /* Here, where are sure that iter is set to the position indicated eventually by the cookie */
01927   i = 0;
01928   for(; iter != NULL; iter = iter->next)
01929     {
01930       LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01931                    "PSEUDO FS: Found entry %s", iter->name);
01932 
01933       namelen = strlen(iter->name);
01934       entry_nfs_array[i].name.utf8string_len = namelen;
01935       if ((entry_nfs_array[i].name.utf8string_val = gsh_malloc(namelen + 1)) == NULL) 
01936         {
01937             LogError(COMPONENT_NFS_V4_PSEUDO, ERR_SYS, ERR_MALLOC, errno);
01938             res_READDIR4.status = NFS4ERR_SERVERFAULT;
01939             return res_READDIR4.status;
01940         }
01941       strncpy(entry_nfs_array[i].name.utf8string_val, iter->name, namelen);
01942       entry_nfs_array[i].name.utf8string_val[namelen] = '\0';
01943 
01944       entry_nfs_array[i].cookie = iter->pseudo_id + 3;
01945 
01946       /* This used to be in an if with a bogus check for FATTR4_FILEHANDLE. Such
01947        * a common case, elected to set up FH for call to xxxx_ToFattr
01948        * unconditionally.
01949        */ 
01950       if(entryFH.nfs_fh4_len == 0)
01951         {
01952           if(nfs4_AllocateFH(&entryFH) != NFS4_OK)
01953             {
01954               return res_READDIR4.status;
01955             }
01956         }
01957       /* Do the case where we stay within the pseudo file system. */
01958       if(iter->junction_export == NULL) {
01959 
01960           if(!nfs4_PseudoToFhandle(&entryFH, iter))
01961             {
01962               res_READDIR4.status = NFS4ERR_SERVERFAULT;
01963               gsh_free(entry_nfs_array);
01964               return res_READDIR4.status;
01965             }
01966 
01967           if(nfs4_PseudoToFattr(iter,
01968                             &(entry_nfs_array[i].attrs),
01969                             data, &entryFH, &(arg_READDIR4.attr_request)) != 0)
01970             {
01971               /* Should never occured, but the is no reason for leaving the section without any information */
01972               entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap;
01973               entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals;
01974             }
01975       } else {
01976       /* This is a junction. Code used to not recognize this which resulted
01977        * in readdir giving different attributes ( including FH, FSid, etc... )
01978        * to clients from a lookup. AIX refused to list the directory because of
01979        * this. Now we go to the junction to get the attributes.
01980        */
01981           LogFullDebug(COMPONENT_NFS_V4_PSEUDO,
01982                  "PSEUDOFS READDIR : Offspring DIR #%s# id=%u is a junction full path %s ", 
01983                   iter->name, iter->junction_export->id, iter->junction_export->fullpath); 
01984           /* Save the compound data context */
01985           save_pexport = data->pexport;
01986           data->pexport = iter->junction_export;
01987           /* Build the credentials */
01988           /* XXX Is this really necessary for doing a lookup and 
01989            * getting attributes?
01990            * The logic is borrowed from the process invoked above in this code
01991            * when the target directory is a junction.
01992            */ 
01993           if(nfs4_MakeCred(data) != 0)
01994             {
01995               LogMajor(COMPONENT_NFS_V4_PSEUDO,
01996                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to get FSAL credentials for %s, id=%d",
01997                    data->pexport->fullpath, data->pexport->id);
01998               res_READDIR4.status = NFS4ERR_WRONGSEC;
01999               return res_READDIR4.status;
02000             }
02001           /* Do the look up. */
02002           if(FSAL_IS_ERROR
02003              ((fsal_status =
02004                FSAL_str2path(iter->junction_export->fullpath, (strlen(iter->junction_export->fullpath) +1 ), &exportpath_fsal))))
02005             {
02006               res_READDIR4.status = NFS4ERR_SERVERFAULT;
02007               return res_READDIR4.status;
02008             }
02009           if(FSAL_IS_ERROR(fsal_status = FSAL_lookupPath(&exportpath_fsal,
02010                                                  data->pcontext, 
02011                                                  &fsal_handle, NULL)))
02012             {
02013               LogMajor(COMPONENT_NFS_V4_PSEUDO,
02014                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to lookup for %s , id=%d",
02015                    data->pexport->fullpath, data->pexport->id);
02016               LogMajor(COMPONENT_NFS_V4_PSEUDO,
02017                    "PSEUDO FS JUNCTION TRAVERSAL: fsal_status = ( %d, %d )",
02018                    fsal_status.major, fsal_status.minor);
02019               res_READDIR4.status = NFS4ERR_SERVERFAULT;
02020               return res_READDIR4.status;
02021             }
02022           /* Build the nfs4 handle. Again, we do this unconditionally. */
02023           if(!nfs4_FSALToFhandle(&entryFH, &fsal_handle, data))
02024             {
02025               LogMajor(COMPONENT_NFS_V4_PSEUDO,
02026                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to build the first file handle");
02027               res_READDIR4.status = NFS4ERR_SERVERFAULT;
02028               return res_READDIR4.status;
02029             }
02030           /* Add the entry to the cache as a root. There has to be a better way. */
02031           fsdata.fh_desc.start = (caddr_t) &fsal_handle;
02032           fsdata.fh_desc.len = 0;
02033           FSAL_ExpandHandle(data->pcontext->export_context,
02034                             FSAL_DIGEST_SIZEOF,
02035                             &fsdata.fh_desc);
02036           if((pentry = cache_inode_make_root(&fsdata,
02037                                              data->pcontext,
02038                                              &cache_status)) == NULL)
02039             {
02040               LogMajor(COMPONENT_NFS_V4_PSEUDO,
02041                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Allocate root entry in cache inode failed, for %s, id=%d",
02042                    data->pexport->fullpath, data->pexport->id);
02043               res_READDIR4.status = NFS4ERR_SERVERFAULT;
02044               return res_READDIR4.status;
02045             }
02046           /* Finally, get the attributes */
02047           if(cache_inode_getattr(pentry,
02048                              &attr,
02049                              data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
02050             {
02051               LogMajor(COMPONENT_NFS_V4_PSEUDO,
02052                    "PSEUDO FS JUNCTION TRAVERSAL: /!\\ | Failed to get attributes for root pentry");
02053               res_READDIR4.status = NFS4ERR_SERVERFAULT;
02054               return res_READDIR4.status;
02055             }
02056           if(nfs4_FSALattr_To_Fattr(data->pexport,
02057                                 &attr,
02058                                 &(entry_nfs_array[i].attrs),
02059                                 data, &entryFH, &(arg_READDIR4.attr_request)) != 0)
02060             {
02061               /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */
02062               entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap;
02063               entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals;
02064             }
02065            data->pexport = save_pexport;
02066       }        
02067       /* Chain the entry together */
02068       entry_nfs_array[i].nextentry = NULL;
02069       if(i != 0)
02070         entry_nfs_array[i - 1].nextentry = &(entry_nfs_array[i]);
02071 
02072       /* Increment the counter */
02073       i += 1;
02074 
02075       /* Did we reach the maximum number of entries */
02076       if(i == estimated_num_entries)
02077         break;
02078     }
02079 
02080   /* Resize entry_nfs_array */
02081   /* @todo : Is this reallocation actually needed ? */
02082 #ifdef BUGAZOMEU
02083   if(i < estimated_num_entries)
02084     if((entry_nfs_array = gsh_realloc(entry_nfs_array, i *
02085                                       sizeof(entry4))) == NULL)
02086       {
02087         LogError(COMPONENT_NFS_V4_PSEUDO, ERR_SYS, ERR_MALLOC, errno);
02088         res_READDIR4.status = NFS4ERR_SERVERFAULT;
02089         gsh_free(entry_nfs_array);
02090         return res_READDIR4.status;
02091       }
02092 #endif
02093   /* Build the reply */
02094   memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier,
02095          NFS4_VERIFIER_SIZE);
02096   if(i == 0)
02097     res_READDIR4.READDIR4res_u.resok4.reply.entries = NULL;
02098   else
02099     res_READDIR4.READDIR4res_u.resok4.reply.entries = entry_nfs_array;
02100 
02101   /* did we reach the end ? */
02102   if(iter == NULL)
02103     {
02104       /* Yes, we did */
02105       res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE;
02106     }
02107   else
02108     {
02109       /* No, there are some more entries */
02110       res_READDIR4.READDIR4res_u.resok4.reply.eof = FALSE;
02111     }
02112 
02113   /* Exit properly */
02114   res_READDIR4.status = NFS4_OK;
02115 
02116   return NFS4_OK;
02117 }                               /* nfs4_op_readdir_pseudo */