Advertisement
Guest User

UNFS3 readdir.c

a guest
Jan 27th, 2015
298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.43 KB | None | 0 0
  1.  
  2. /*
  3.  * UNFS3 readdir routine
  4.  * (C) 2004, Pascal Schmidt
  5.  * see file LICENSE for license details
  6.  */
  7.  
  8. #include "config.h"
  9.  
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <rpc/rpc.h>
  13. #include <dirent.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <time.h>
  18. #include <unistd.h>
  19.  
  20. #include "nfs.h"
  21. #include "mount.h"
  22. #include "fh.h"
  23. #include "readdir.h"
  24. #include "backend.h"
  25. #include "Config/exports.h"
  26. #include "daemon.h"
  27. #include "error.h"
  28.  
  29. /*
  30.  * maximum number of entries in readdir results
  31.  *
  32.  * this is 4096 / 28 (the minimum size of an entry3)
  33.  */
  34. #define MAX_ENTRIES 143
  35.  
  36. /*
  37.  * static READDIR3resok size with XDR overhead
  38.  *
  39.  * 88 bytes attributes, 8 bytes verifier, 4 bytes value_follows for
  40.  * first entry, 4 bytes eof flag
  41.  */
  42. #define RESOK_SIZE 104
  43.  
  44. /*
  45.  * static entry3 size with XDR overhead
  46.  *
  47.  * 8 bytes fileid, 4 bytes name length, 8 bytes cookie, 4 byte value_follows
  48.  */
  49. #define ENTRY_SIZE 24
  50.  
  51. /*
  52.  * size of a name with XDR overhead
  53.  *
  54.  * XDR pads to multiple of 4 bytes
  55.  */
  56. #define NAME_SIZE(x) (((strlen((x))+3)/4)*4)
  57.  
  58. uint32 directory_hash(const char *path)
  59. {
  60.     backend_dirstream *search;
  61.     struct dirent *this;
  62.     uint32 hval = 0;
  63.  
  64.     search = backend_opendir(path);
  65.     if (!search) {
  66.     return 0;
  67.     }
  68.  
  69.     while ((this = backend_readdir(search)) != NULL) {
  70.     hval = fnv1a_32(this->d_name, hval);
  71.     }
  72.  
  73.     backend_closedir(search);
  74.     return hval;
  75. }
  76.  
  77. /*
  78.  * perform a READDIR operation
  79.  *
  80.  * fh_decomp must be called directly before to fill the stat cache
  81.  */
  82. READDIR3res read_dir(const char *path, cookie3 cookie, cookieverf3 verf,
  83.              count3 count)
  84. {
  85.     READDIR3res result;
  86.     READDIR3resok resok;
  87.     cookie3 upper;
  88.     static entry3 entry[MAX_ENTRIES];
  89.     backend_statstruct buf;
  90.     int res;
  91.     backend_dirstream *search;
  92.     struct dirent *this;
  93.     count3 i, real_count;
  94.     static char obj[NFS_MAXPATHLEN * MAX_ENTRIES];
  95.     char scratch[NFS_MAXPATHLEN];
  96.  
  97.     /* check upper part of cookie */
  98.     upper = cookie & 0xFFFFFFFF00000000ULL;
  99.     if (cookie != 0 && upper != rcookie) {
  100.       /* ignore cookie if unexpected so we restart from the beginning */
  101.       cookie = 0;
  102.     }
  103.     cookie &= 0xFFFFFFFFULL;
  104.  
  105.     /* we refuse to return more than 4k from READDIR */
  106.     if (count > 4096)
  107.     count = 4096;
  108.  
  109.     /* account for size of information heading resok structure */
  110.     real_count = RESOK_SIZE;
  111.  
  112.     /* We are always returning zero as a cookie verifier. One reason for this
  113.        is that stat() on Windows seems to return cached st_mtime values,
  114.        which gives spurious NFS3ERR_BAD_COOKIEs. Btw, here's what Peter
  115.        Staubach has to say about cookie verifiers:
  116.  
  117.        "From my viewpoint, the cookieverifier was a failed experiment in NFS
  118.        Version 3.  The semantics were never well understood nor supported by
  119.        many local file systems.  The Solaris NFS server always returns zeros
  120.        in the cookieverifier field." */
  121.     memset(verf, 0, NFS3_COOKIEVERFSIZE);
  122.  
  123.     search = backend_opendir(path);
  124.     if (!search) {
  125.     if ((exports_opts & OPT_REMOVABLE) && (export_point(path))) {
  126.         /* Removable media export point; probably no media inserted.
  127.            Return empty directory. */
  128.         memset(resok.cookieverf, 0, NFS3_COOKIEVERFSIZE);
  129.         resok.reply.entries = NULL;
  130.         resok.reply.eof = TRUE;
  131.         result.status = NFS3_OK;
  132.         result.READDIR3res_u.resok = resok;
  133.         return result;
  134.     } else {
  135.         result.status = readdir_err();
  136.         return result;
  137.     }
  138.     }
  139.  
  140.     this = backend_readdir(search);
  141.     /* We cannot use telldir()/seekdir(), since the value from telldir() is
  142.        not valid after closedir(). */
  143.     for (i = 0; i < cookie; i++)
  144.     if (this)
  145.         this = backend_readdir(search);
  146.  
  147.     i = 0;
  148.     entry[0].name = NULL;
  149.     while (this && real_count < count && i < MAX_ENTRIES) {
  150.     if (i > 0)
  151.         entry[i - 1].nextentry = &entry[i];
  152.  
  153.     if (strlen(path) + strlen(this->d_name) + 1 < NFS_MAXPATHLEN) {
  154.  
  155.         if (strcmp(path, "/") == 0)
  156.         sprintf(scratch, "/%s", this->d_name);
  157.         else
  158.         sprintf(scratch, "%s/%s", path, this->d_name);
  159.  
  160.         res = backend_lstat(scratch, &buf);
  161.         if (res == -1) {
  162.         result.status = readdir_err();
  163.         backend_closedir(search);
  164.         return result;
  165.         }
  166.  
  167.         strcpy(&obj[i * NFS_MAXPATHLEN], this->d_name);
  168.  
  169. #if defined(WIN32) || defined(AFS_SUPPORT)
  170.         /* See comment in attr.c:get_post_buf */
  171.         entry[i].fileid = (buf.st_ino >> 32) ^ (buf.st_ino & 0xffffffff);
  172. #else
  173.         entry[i].fileid = buf.st_ino;
  174. #endif
  175.         entry[i].name = &obj[i * NFS_MAXPATHLEN];
  176.         entry[i].cookie = (cookie + 1 + i) | rcookie;
  177.         entry[i].nextentry = NULL;
  178.  
  179.         /* account for entry size */
  180.         real_count += ENTRY_SIZE + NAME_SIZE(this->d_name);
  181.  
  182.         /* whoops, overflowed the maximum size */
  183.         if (real_count > count && i > 0)
  184.         entry[i - 1].nextentry = NULL;
  185.         else {
  186.         /* advance to next entry */
  187.         this = backend_readdir(search);
  188.         }
  189.  
  190.         i++;
  191.     } else {
  192.         result.status = NFS3ERR_IO;
  193.         backend_closedir(search);
  194.         return result;
  195.     }
  196.     }
  197.     backend_closedir(search);
  198.  
  199.     if (entry[0].name)
  200.     resok.reply.entries = &entry[0];
  201.     else
  202.     resok.reply.entries = NULL;
  203.  
  204.     if (this)
  205.     resok.reply.eof = FALSE;
  206.     else
  207.     resok.reply.eof = TRUE;
  208.  
  209.     memcpy(resok.cookieverf, verf, NFS3_COOKIEVERFSIZE);
  210.  
  211.     result.status = NFS3_OK;
  212.     result.READDIR3res_u.resok = resok;
  213.  
  214.     return result;
  215. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement