nfs-ganesha 1.4

fsal_lookup.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  */
00004 
00013 #ifdef HAVE_CONFIG_H
00014 #include "config.h"
00015 #endif
00016 
00017 #include "fsal.h"
00018 #include "fsal_internal.h"
00019 #include "fsal_convert.h"
00020 #include "fsal_common.h"
00021 
00022 #include <string.h>
00023 
00024 extern size_t i_snapshots;
00025 extern snapshot_t *p_snapshots;
00026 
00062 fsal_status_t ZFSFSAL_lookup(fsal_handle_t * parent_hdl,      /* IN */
00063                           fsal_name_t * p_filename,     /* IN */
00064                           fsal_op_context_t * context,        /* IN */
00065                           fsal_handle_t * obj_handle,        /* OUT */
00066                           fsal_attrib_list_t * object_attributes        /* [ IN/OUT ] */
00067     )
00068 {
00069   int rc;
00070   zfsfsal_handle_t * parent_directory_handle = (zfsfsal_handle_t *)parent_hdl;
00071   zfsfsal_op_context_t * p_context = (zfsfsal_op_context_t *)context;
00072   zfsfsal_handle_t * object_handle = (zfsfsal_handle_t *)obj_handle;
00073 
00074   /* sanity checks
00075    * note : object_attributes is optionnal
00076    *        parent_directory_handle may be null for getting FS root.
00077    */
00078   if(!object_handle || !p_context)
00079     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup);
00080 
00081   /* retrieves root handle */
00082 
00083   if(!parent_directory_handle)
00084     {
00085       /* check that p_filename is NULL,
00086        * else, parent_directory_handle should not
00087        * be NULL.
00088        */
00089       if(p_filename != NULL)
00090         Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup);
00091 
00092       /* >> retrieve root handle filehandle here << */
00093       if((rc = libzfswrap_getroot(p_context->export_context->p_vfs, &(object_handle->data.zfs_handle))))
00094         Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup);
00095 
00096       object_handle->data.type = FSAL_TYPE_DIR;
00097       object_handle->data.i_snap = 0;
00098 
00099       /* >> retrieves root attributes, if asked << */
00100 
00101       if(object_attributes)
00102         {
00103           fsal_status_t status = ZFSFSAL_getattrs(obj_handle, context, object_attributes);
00104           /* On error, we set a flag in the returned attributes */
00105           if(FSAL_IS_ERROR(status))
00106             {
00107               FSAL_CLEAR_MASK(object_attributes->asked_attributes);
00108               FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00109             }
00110         }
00111 
00112     }
00113   else                          /* this is a real lookup(parent, name)  */
00114     {
00115       /* the filename should not be null */
00116       if(p_filename == NULL)
00117         Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup);
00118 
00119       /* >> Be careful about junction crossing, symlinks, hardlinks,...
00120        * You may check the parent type if it's sored into the handle <<
00121        */
00122       switch (parent_directory_handle->data.type)
00123         {
00124         case FSAL_TYPE_DIR:
00125           /* OK */
00126           break;
00127 
00128         case FSAL_TYPE_JUNCTION:
00129           /* This is a junction */
00130           Return(ERR_FSAL_XDEV, 0, INDEX_FSAL_lookup);
00131 
00132         case FSAL_TYPE_FILE:
00133         case FSAL_TYPE_LNK:
00134         case FSAL_TYPE_XATTR:
00135           /* not a directory */
00136           Return(ERR_FSAL_NOTDIR, 0, INDEX_FSAL_lookup);
00137 
00138         default:
00139           Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_lookup);
00140         }
00141 
00142       TakeTokenFSCall();
00143 
00144       /* >> Call your filesystem lookup function here << */
00145       /* >> Be carefull you don't traverse junction nor follow symlinks << */
00146       inogen_t object;
00147       int type;
00148       char i_snap = parent_directory_handle->data.i_snap;
00149 
00150       /* Hook to add the hability to go inside a .zfs directory inside the root dir */
00151       if(parent_directory_handle->data.zfs_handle.inode == 3 &&
00152           !strcmp(p_filename->name, ZFS_SNAP_DIR))
00153       {
00154         LogDebug(COMPONENT_FSAL, "Lookup for the .zfs/ pseudo-directory");
00155 
00156         object.inode = ZFS_SNAP_DIR_INODE;
00157         object.generation = 0;
00158         type = S_IFDIR;
00159         rc = 0;
00160       }
00161 
00162       /* Hook for the files inside the .zfs directory */
00163       else if(parent_directory_handle->data.zfs_handle.inode == ZFS_SNAP_DIR_INODE)
00164       {
00165         LogDebug(COMPONENT_FSAL, "Lookup inside the .zfs/ pseudo-directory");
00166 
00167         ZFSFSAL_VFS_RDLock();
00168         int i;
00169         for(i = 1; i < i_snapshots + 1; i++)
00170           if(!strcmp(p_snapshots[i].psz_name, p_filename->name))
00171             break;
00172 
00173         if(i == i_snapshots + 1)
00174         {
00175           ReleaseTokenFSCall();
00176           Return(ERR_FSAL_NOENT, 0, INDEX_FSAL_lookup);
00177         }
00178 
00179         libzfswrap_getroot(p_snapshots[i].p_vfs, &object);
00180         ZFSFSAL_VFS_Unlock();
00181 
00182         type = S_IFDIR;
00183         i_snap = i + 1;
00184         rc = 0;
00185       }
00186       else
00187       {
00188         /* Get the right VFS */
00189         ZFSFSAL_VFS_RDLock();
00190         libzfswrap_vfs_t *p_vfs = ZFSFSAL_GetVFS(parent_directory_handle);
00191         if(!p_vfs) {
00192           rc = ENOENT;
00193         } else {
00194           creden_t cred;
00195 
00196           cred.uid = p_context->credential.user;
00197           cred.gid = p_context->credential.group;
00198           rc = libzfswrap_lookup(p_vfs, &cred,
00199                                  parent_directory_handle->data.zfs_handle, p_filename->name,
00200                                  &object, &type);
00201         }
00202         ZFSFSAL_VFS_Unlock();
00203 
00204         //FIXME!!! Hook to remove the i_snap bit when going up from the .zfs directory
00205         if(object.inode == 3)
00206           i_snap = 0;
00207       }
00208 
00209       ReleaseTokenFSCall();
00210 
00211       /* >> convert the error code and return on error << */
00212       if(rc)
00213         Return(posix2fsal_error(rc), rc, INDEX_FSAL_lookup);
00214 
00215       /* >> set output handle << */
00216       object_handle->data.zfs_handle = object;
00217       object_handle->data.type = posix2fsal_type(type);
00218       object_handle->data.i_snap = i_snap;
00219       if(object_attributes)
00220         {
00221           fsal_status_t status = ZFSFSAL_getattrs(obj_handle, context, object_attributes);
00222           /* On error, we set a flag in the returned attributes */
00223           if(FSAL_IS_ERROR(status))
00224             {
00225               FSAL_CLEAR_MASK(object_attributes->asked_attributes);
00226               FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00227             }
00228         }
00229     }
00230 
00231   /* lookup complete ! */
00232   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup);
00233 
00234 }
00235 
00263 fsal_status_t ZFSFSAL_lookupJunction(fsal_handle_t * p_junction_handle,    /* IN */
00264                                      fsal_op_context_t * p_context,        /* IN */
00265                                      fsal_handle_t * p_fsoot_handle,       /* OUT */
00266                                      fsal_attrib_list_t * p_fsroot_attributes      /* [ IN/OUT ] */
00267     )
00268 {
00269   /* sanity checks
00270    * note : p_fsroot_attributes is optionnal
00271    */
00272   if(!p_junction_handle || !p_fsoot_handle || !p_context)
00273     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookupJunction);
00274 
00275   /* >> you can also check object type if it is in stored in the handle << */
00276 
00277   if(((zfsfsal_handle_t *)p_junction_handle)->data.type != FSAL_TYPE_JUNCTION)
00278     Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_lookupJunction);
00279 
00280   TakeTokenFSCall();
00281 
00282   /* >> traverse the junction here << */
00283 
00284   ReleaseTokenFSCall();
00285 
00286   /* >> convert the error code and return on error << */
00287 
00288   /* >> set output handle << */
00289 
00290   if(p_fsroot_attributes)
00291     {
00292 
00293       /* >> fill output attributes if asked << */
00294 
00295     }
00296 
00297   /* lookup complete ! */
00298   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookupJunction);
00299 }
00300 
00335 fsal_status_t ZFSFSAL_lookupPath(fsal_path_t * p_path,     /* IN */
00336                               fsal_op_context_t * p_context,    /* IN */
00337                               fsal_handle_t * object_handle,    /* OUT */
00338                               fsal_attrib_list_t * object_attributes    /* [ IN/OUT ] */
00339     )
00340 {
00341   fsal_name_t obj_name = FSAL_NAME_INITIALIZER; /* empty string */
00342   char *ptr_str;
00343   zfsfsal_handle_t out_hdl;
00344   fsal_status_t status;
00345   int b_is_last = FALSE;        /* is it the last lookup ? */
00346 
00347 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00348  *  this function may be adapted to most FSALs
00349  *<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
00350 
00351   /* sanity checks
00352    * note : object_attributes is optionnal.
00353    */
00354 
00355   if(!object_handle || !p_context || !p_path)
00356     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookupPath);
00357 
00358   /* test whether the path begins with a slash */
00359 
00360   if(p_path->path[0] != '/')
00361     Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_lookupPath);
00362 
00363   /* the pointer now points on the next name in the path,
00364    * skipping slashes.
00365    */
00366 
00367   ptr_str = p_path->path + 1;
00368   while(ptr_str[0] == '/')
00369     ptr_str++;
00370 
00371   /* is the next name empty ? */
00372 
00373   if(ptr_str[0] == '\0')
00374     b_is_last = TRUE;
00375 
00376   /* retrieves root directory */
00377 
00378   status = ZFSFSAL_lookup(NULL,    /* looking up for root */
00379                           NULL,    /* empty string to get root handle */
00380                           p_context,       /* user's credentials */
00381                           (fsal_handle_t *) &out_hdl,        /* output root handle */
00382                           /* retrieves attributes if this is the last lookup : */
00383                           (b_is_last ? object_attributes : NULL));
00384 
00385   if(FSAL_IS_ERROR(status))
00386     Return(status.major, status.minor, INDEX_FSAL_lookupPath);
00387 
00388   /* exits if this was the last lookup */
00389 
00390   if(b_is_last)
00391     {
00392       (*(zfsfsal_handle_t *)object_handle) = out_hdl;
00393       Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookupPath);
00394     }
00395 
00396   /* proceed a step by step lookup */
00397 
00398   while(ptr_str[0])
00399     {
00400 
00401       zfsfsal_handle_t in_hdl;
00402       char *dest_ptr;
00403 
00404       /* preparing lookup */
00405 
00406       in_hdl = out_hdl;
00407 
00408       /* compute next name */
00409       obj_name.len = 0;
00410       dest_ptr = obj_name.name;
00411       while(ptr_str[0] != '\0' && ptr_str[0] != '/')
00412         {
00413           dest_ptr[0] = ptr_str[0];
00414           dest_ptr++;
00415           ptr_str++;
00416           obj_name.len++;
00417         }
00418       /* final null char */
00419       dest_ptr[0] = '\0';
00420 
00421       /* skip multiple slashes */
00422       while(ptr_str[0] == '/')
00423         ptr_str++;
00424 
00425       /* is the next name empty ? */
00426       if(ptr_str[0] == '\0')
00427         b_is_last = TRUE;
00428 
00429       /*call to FSAL_lookup */
00430       status = ZFSFSAL_lookup((fsal_handle_t *) &in_hdl,     /* parent directory handle */
00431                               &obj_name,   /* object name */
00432                               p_context,   /* user's credentials */
00433                               (fsal_handle_t *) &out_hdl,    /* output root handle */
00434                               /* retrieves attributes if this is the last lookup : */
00435                               (b_is_last ? object_attributes : NULL));
00436 
00437       if(FSAL_IS_ERROR(status))
00438         Return(status.major, status.minor, INDEX_FSAL_lookupPath);
00439 
00440       /* if the target object is a junction, an we allow cross junction lookups,
00441        * we cross it.
00442        */
00443       if(global_fs_info.auth_exportpath_xdev
00444          && (out_hdl.data.type == FSAL_TYPE_JUNCTION))
00445         {
00446           zfsfsal_handle_t tmp_hdl;
00447 
00448           tmp_hdl = out_hdl;
00449 
00450           /*call to FSAL_lookup */
00451           status = ZFSFSAL_lookupJunction((fsal_handle_t *) &tmp_hdl,        /* object handle */
00452                                           p_context,       /* user's credentials */
00453                                           (fsal_handle_t *) &out_hdl, /* output root handle */
00454                                           /* retrieves attributes if this is the last lookup : */
00455                                           (b_is_last ? object_attributes : NULL));
00456 
00457         }
00458 
00459       /* ptr_str is ok, we are ready for next loop */
00460     }
00461 
00462   (*(zfsfsal_handle_t *)object_handle) = out_hdl;
00463   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookupPath);
00464 
00465 }