nfs-ganesha 1.4

fsal_dirs.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #include "fsal.h"
00019 #include "fsal_internal.h"
00020 #include "FSAL/access_check.h"
00021 #include "fsal_convert.h"
00022 #include <string.h>
00023 
00044 fsal_status_t VFSFSAL_opendir(fsal_handle_t * p_dir_handle,  /* IN */
00045                               fsal_op_context_t * p_context, /* IN */
00046                               fsal_dir_t * dir_desc, /* OUT */
00047                               fsal_attrib_list_t * p_dir_attributes     /* [ IN/OUT ] */
00048     )
00049 {
00050   vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t *) dir_desc;
00051   int rc, errsv;
00052   fsal_status_t status;
00053 
00054   struct stat buffstat;
00055 
00056   /* sanity checks
00057    * note : dir_attributes is optionnal.
00058    */
00059   if(!p_dir_handle || !p_context || !p_dir_descriptor)
00060     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir);
00061 
00062   /* get the path of the directory */
00063   TakeTokenFSCall();
00064   status =
00065       fsal_internal_handle2fd(p_context, p_dir_handle, &p_dir_descriptor->fd,
00066                               O_RDONLY | O_DIRECTORY);
00067   ReleaseTokenFSCall();
00068 
00069   if(FSAL_IS_ERROR(status))
00070     ReturnStatus(status, INDEX_FSAL_opendir);
00071 
00072   /* get directory metadata */
00073   TakeTokenFSCall();
00074   rc = fstat(p_dir_descriptor->fd, &buffstat);
00075   errsv = errno;
00076   ReleaseTokenFSCall();
00077 
00078   if(rc != 0)
00079     {
00080       close(p_dir_descriptor->fd);
00081       if(errsv == ENOENT)
00082         Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_opendir);
00083       else
00084         Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_opendir);
00085     }
00086 
00087   /* Test access rights for this directory */
00088   status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL);
00089   if(FSAL_IS_ERROR(status))
00090     ReturnStatus(status, INDEX_FSAL_opendir);
00091 
00092   /* if everything is OK, fills the dir_desc structure : */
00093 
00094   memcpy(&(p_dir_descriptor->context), p_context, sizeof(vfsfsal_op_context_t));
00095   memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(vfsfsal_handle_t));
00096 
00097   if(p_dir_attributes)
00098     {
00099       status = posix2fsal_attributes(&buffstat, p_dir_attributes);
00100       if(FSAL_IS_ERROR(status))
00101         {
00102           FSAL_CLEAR_MASK(p_dir_attributes->asked_attributes);
00103           FSAL_SET_MASK(p_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00104         }
00105     }
00106 
00107   p_dir_descriptor->dir_offset = 0;
00108 
00109   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir);
00110 
00111 }
00112 
00147 struct linux_dirent
00148 {
00149   long d_ino;
00150   long d_off;                   /* Be careful, SYS_getdents is a 32 bits call */
00151   unsigned short d_reclen;
00152   char d_name[];
00153 };
00154 
00155 #define BUF_SIZE 1024
00156 
00157 fsal_status_t VFSFSAL_readdir(fsal_dir_t * dir_descriptor,      /* IN */
00158                               fsal_cookie_t startposition,      /* IN */
00159                               fsal_attrib_mask_t get_attr_mask, /* IN */
00160                               fsal_mdsize_t buffersize,         /* IN */
00161                               fsal_dirent_t * p_pdirent,        /* OUT */
00162                               fsal_cookie_t * end_position,     /* OUT */
00163                               fsal_count_t * p_nb_entries,      /* OUT */
00164                               fsal_boolean_t * p_end_of_dir     /* OUT */
00165     )
00166 {
00167   vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t * ) dir_descriptor;
00168   vfsfsal_cookie_t start_position;
00169   vfsfsal_cookie_t * p_end_position = (vfsfsal_cookie_t *) end_position;
00170   fsal_status_t st;
00171   fsal_count_t max_dir_entries;
00172   fsal_name_t entry_name;
00173   char buff[BUF_SIZE];
00174   struct linux_dirent *dp = NULL;
00175   int bpos = 0;
00176 
00177   struct stat buffstat;
00178 
00179   int rc = 0;
00180 
00181   memset(buff, 0, BUF_SIZE);
00182   memset(&entry_name, 0, sizeof(fsal_name_t));
00183 
00184   /*****************/
00185   /* sanity checks */
00186   /*****************/
00187 
00188   if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir)
00189     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);
00190 
00191   max_dir_entries = (buffersize / sizeof(fsal_dirent_t));
00192 
00193   /***************************/
00194   /* seek into the directory */
00195   /***************************/
00196   start_position.data.cookie = *((off_t*) &startposition.data);
00197   rc = errno = 0;
00198   lseek(p_dir_descriptor->fd, start_position.data.cookie, SEEK_SET);
00199   rc = errno;
00200 
00201   if(rc)
00202     Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);
00203 
00204   /************************/
00205   /* browse the directory */
00206   /************************/
00207 
00208   *p_nb_entries = 0;
00209   while(*p_nb_entries < max_dir_entries)
00210     {
00211     /***********************/
00212       /* read the next entry */
00213     /***********************/
00214       TakeTokenFSCall();
00215       rc = syscall(SYS_getdents, p_dir_descriptor->fd, buff, BUF_SIZE);
00216       ReleaseTokenFSCall();
00217       if(rc < 0)
00218         {
00219           rc = errno;
00220           Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);
00221         }
00222       /* End of directory */
00223       if(rc == 0)
00224         {
00225           *p_end_of_dir = 1;
00226           break;
00227         }
00228 
00229     /***********************************/
00230       /* Get information about the entry */
00231     /***********************************/
00232 
00233       for(bpos = 0; bpos < rc;)
00234         {
00235           dp = (struct linux_dirent *)(buff + bpos);
00236 
00237           bpos += dp->d_reclen;
00238 
00239           if(!(*p_nb_entries < max_dir_entries))
00240             break;
00241 
00242           /* skip . and .. */
00243           if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
00244             continue;
00245 
00246           /* build the full path of the file into "fsalpath */
00247           if(FSAL_IS_ERROR
00248              (st =
00249               FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN,
00250                             &(p_pdirent[*p_nb_entries].name))))
00251             ReturnStatus(st, INDEX_FSAL_readdir);
00252 
00253 
00254           // TODO: there is a race here, because between handle fetch
00255           // and open at things might change.  we need to figure out if there
00256           // is another way to open without the pcontext
00257 
00258           strncpy(entry_name.name, dp->d_name, sizeof(entry_name.name));
00259           entry_name.len = strlen(entry_name.name);
00260 
00261           /* get object handle */
00262           TakeTokenFSCall();
00263 
00264           
00265           if(fstatat(p_dir_descriptor->fd, dp->d_name, &buffstat, AT_SYMLINK_NOFOLLOW) < 0 )
00266             {
00267               ReleaseTokenFSCall();
00268               Return(posix2fsal_error(errno), errno, INDEX_FSAL_readdir);
00269             }
00270 
00271           st = fsal_internal_get_handle_at( p_dir_descriptor->fd, dp->d_name,
00272                                                                     &p_pdirent[*p_nb_entries].handle) ;
00273           if(FSAL_IS_ERROR(st))
00274             {
00275               ReleaseTokenFSCall();
00276               ReturnStatus(st, INDEX_FSAL_readdir);
00277             }
00278           p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask;
00279 
00280           st = posix2fsal_attributes(&buffstat, &p_pdirent[*p_nb_entries].attributes);
00281           if(FSAL_IS_ERROR(st))
00282             {
00283               ReleaseTokenFSCall();
00284               FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes);
00285               FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes,
00286                             FSAL_ATTR_RDATTR_ERR);
00287               ReturnStatus(st, INDEX_FSAL_getattrs);
00288             }
00289 
00290           ReleaseTokenFSCall();
00291 
00292           //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off;
00293           ((vfsfsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = dp->d_off;
00294           p_pdirent[*p_nb_entries].nextentry = NULL;
00295           if(*p_nb_entries)
00296             p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]);
00297 
00298           //(*p_end_position) = p_pdirent[*p_nb_entries].cookie;
00299           memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie,
00300                  sizeof(vfsfsal_cookie_t));
00301 
00302           (*p_nb_entries)++;
00303 
00304         }                       /* for */
00305     }                           /* While */
00306 
00307   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);
00308 
00309 }
00310 
00322 fsal_status_t VFSFSAL_closedir(fsal_dir_t * p_dir_desc /* IN */
00323     )
00324 {
00325   vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t *)p_dir_desc;
00326   int rc;
00327 
00328   /* sanity checks */
00329   if(!p_dir_descriptor)
00330     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_closedir);
00331 
00332   rc = close(p_dir_descriptor->fd);
00333   if(rc != 0)
00334     Return(posix2fsal_error(errno), errno, INDEX_FSAL_closedir);
00335 
00336   /* fill dir_descriptor with zeros */
00337   memset(p_dir_descriptor, 0, sizeof(vfsfsal_dir_t));
00338 
00339   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_closedir);
00340 
00341 }