home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / nfsd / src / handle_list.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-30  |  11.8 KB  |  468 lines

  1. /*  Routines to manage a list of local files and their NFS representation
  2.  
  3.     ©1998, 1999 Joseph Walton
  4.  
  5.     This software is distributed under the terms of the GNU General Public
  6.     License; either version 2 of the License, or (at your option) any
  7.     later version.
  8. */
  9.  
  10. /*
  11.      29-Sep-1999 - Hashtables now used - should go faster.
  12.       4-Oct-1999 - Now prunes unused entries from memory.
  13.      30-Nov-1999 - Changes to integrate with new RPC code.
  14. */
  15.  
  16. #include "nfsd.h"
  17. #include "handle_list.h"
  18. #include "auth.h"
  19. #include "memory.h"
  20. #include "nfs_utils.h"
  21. #include "dirlist.h"
  22. #include "hashtable.h"
  23.  
  24. #include <stdio.h>
  25.  
  26. #include <exec/memory.h>
  27. #include <clib/alib_protos.h>
  28.  
  29. #include <stdlib.h> /* rand() prototype */
  30.  
  31. #include <ctype.h> /* tolower() */
  32.  
  33. #include <proto/exec.h>
  34. #include <proto/dos.h>
  35. #include <proto/timer.h>
  36.  
  37. /* The file to store persistent inode data in */
  38. #define INODE_FILE "nfsd.inode"
  39.  
  40. extern struct InfoData infodata;
  41. extern struct FileInfoBlock fib;
  42.  
  43. /*
  44.     lf_list is a list of all LocalFiles in the system.
  45.     handle_ht is a hash from handles to nodes in the list.
  46.     name_ht is a case-insensitive hash from names to nodes.
  47.     Iterate over lf_list - use the others just for lookup
  48. */
  49. static struct List lf_list;
  50. static struct HashTable *handle_ht;
  51. static struct HashTable *name_ht;
  52.  
  53. /* This needs to be unique when used */
  54. static u_int next_id = 0;
  55.  
  56. /* Internal prototypes */
  57. static BOOL fh_match(nfs_fh *fha, nfs_fh *fhb);
  58. static void fh_fillin(nfs_fh *fh);
  59. static u_int new_inode(void);
  60. static struct LocalFile *create_localfile(STRPTR name);
  61. static void free_localfile(struct LocalFile *lf);
  62. static void remove_localfile(struct LocalFile *lf);
  63.  
  64. /* Prototypes for hashtable callbacks */
  65. static ULONG handleHash(APTR handle);
  66. static ULONG handleEquals(APTR a, APTR b);
  67. static ULONG stringHash(APTR string);
  68. static BOOL stringEquals(APTR a, APTR b);
  69.  
  70. /* Initialise the internal data for handle_list */
  71. BOOL init_handle_list()
  72. {
  73.     handle_ht = htMakeNew(&handleHash, &handleEquals);
  74.     name_ht = htMakeNew(&stringHash, &stringEquals);
  75.     if (handle_ht && name_ht) {
  76.         NewList(&lf_list);
  77.         return TRUE;
  78.     }
  79.     return FALSE;
  80. }
  81.  
  82. /* next_id needs to be unique amongst subsequent runs - we
  83.     need to keep a persistent copy somewhere */
  84.  
  85. /* Okay, I'm writing it in binary rather than text. This is probably
  86.     the Wrong Thing, but I'm in no mood right now. */
  87.  
  88. #define SNI sizeof(next_id)
  89.  
  90. /* Fetch the base inode from persistent store */
  91. void persistent_inode_fetch()
  92. {
  93.     BPTR file;
  94.     if (file = Open(INODE_FILE, MODE_OLDFILE)) {
  95.         if (Read(file, &next_id, SNI) != SNI) {
  96.             next_id = 0;
  97.             PrintFault(IoErr(), "failed to read from " INODE_FILE);
  98.         }
  99.  
  100.         Close(file);
  101.     } else
  102.         PrintFault(IoErr(), "unable to open " INODE_FILE);
  103.  
  104.     /* Was it set? */
  105.     if (!next_id) {
  106.         next_id = 1;
  107.         puts("Unable to get persistent inode data. This will cause problems unless this is a first run.");
  108.     }
  109.     printf("First inode is %d.\n", next_id);
  110. }
  111.  
  112. /* Place the current inode in persistent store */
  113. BOOL persistent_inode_store()
  114. {
  115.     BPTR file;
  116.     BOOL result = TRUE;
  117.     if (file = Open(INODE_FILE, MODE_NEWFILE)) {
  118.         if (SNI != Write(file, &next_id, SNI)) {
  119.             result = FALSE;
  120.             PrintFault(IoErr(), "failed to write inode data");
  121.         }
  122.         Close(file);
  123.     } else {
  124.         result = FALSE;
  125.         PrintFault(IoErr(), "failed to open " INODE_FILE " for writing");
  126.     }
  127.  
  128.     return result;
  129. }
  130.  
  131. #undef SNI
  132.  
  133. /* Create a new node for a given filename */
  134. static struct LocalFile *create_localfile(STRPTR name)
  135. {
  136.     struct LocalFile *nlf;
  137.     if (name == NULL)
  138.         return NULL;
  139.  
  140.     nlf = AllocVecPooled(sizeof(struct LocalFile));
  141.     if (nlf) {
  142.         nlf->lf_Name = DupString(name);
  143.  
  144.         if (nlf->lf_Name) {
  145.             fh_fillin(&nlf->lf_NFSHandle); /* Give it a new handle */
  146.             nlf->lf_FileID = 0; /* This will be filled in when it's used */
  147.             nlf->lf_IsMount = FALSE;
  148.             nlf->lf_Type = NFNON; /* This as well */
  149.             nlf->lf_Lock = NULL;
  150.             nlf->lf_DEList = NULL;
  151.  
  152.             /* These values, if set, will override the real ones */
  153.             nlf->lf_ForcedUID = -1;
  154.             nlf->lf_ForcedGID = -1;
  155.             nlf->lf_ForcedProtection = -1;
  156.  
  157.             impose_configuration(nlf);
  158.  
  159.             GetSysTime(&(nlf->lf_LastUsed));
  160.  
  161.             /* And add it to the list */
  162.             AddTail(&lf_list, (struct Node *)nlf);
  163.  
  164.             /* Put it in the hashtables */
  165.             htAdd(handle_ht, &nlf->lf_NFSHandle, nlf);
  166.             htAdd(name_ht, nlf->lf_Name, nlf);
  167.  
  168.             DEBUG(printf("Created handle for '%s'\n", nlf->lf_Name));
  169.  
  170.             /* fh_print(&(nlf->lf_NFSHandle)); */
  171.         } else {
  172.             FreeVecPooled(nlf);
  173.             nlf = NULL;
  174.         }
  175.     }
  176.     return nlf;
  177. }
  178.  
  179.  
  180. /* Free a LocalFile and any resources directly attached to it.
  181.     Make sure you're not using it for list navigation at this point!
  182. */
  183. static void free_localfile(struct LocalFile *lf)
  184. {
  185.     if (lf) {
  186.         FreeVecPooled(lf->lf_Name);
  187.         if (lf->lf_DEList) {
  188.             free_delist_nodes(lf->lf_DEList);
  189.             FreeVecPooled(lf->lf_DEList);
  190.         }
  191.         FreeVecPooled(lf);
  192.     }
  193. }
  194.  
  195. /* Remove a LocalFile from internal structures it may belong to.
  196.     Afterwards it is safe to free it.
  197. */
  198. static void remove_localfile(struct LocalFile *lf)
  199. {
  200.     if (lf) {
  201.         Remove((struct Node *)lf); /* Assumes all LocalFiles are in a list */
  202.  
  203.         /* Remove it from the hashtables as well */
  204.         if (!htRemove(handle_ht, &lf->lf_NFSHandle)
  205.             || !htRemove(name_ht, lf->lf_Name))
  206.         {
  207.             printf("Internal error - %lx was not found in the hashtables", lf);
  208.         }
  209.     }
  210. }
  211.  
  212.  
  213. /* Search the list for a given filename (case insensitive) */
  214. struct LocalFile *find_namedlocalfile(STRPTR name)
  215. {
  216.     if (!name)
  217.         return NULL;
  218.  
  219.     return (struct LocalFile *)htGet(name_ht, name);
  220. }
  221.  
  222. /* Get a structure for the given filename, creating one
  223.     if need be */
  224. struct LocalFile *get_namedlocalfile(STRPTR name)
  225. {
  226.     struct LocalFile *lf = find_namedlocalfile(name);
  227.  
  228.     if (lf)
  229.         return lf;
  230.  
  231.     /* Nothing found? Create a new one, then. */
  232.     return create_localfile(name);
  233. }
  234.  
  235. /* Search the list for a given NFS file handle */
  236. struct LocalFile *find_handle(nfs_fh *fh)
  237. {
  238.     struct LocalFile *lf;
  239.  
  240.     if (!fh)
  241.         return NULL;
  242.  
  243.     lf = (struct LocalFile *)htGet(handle_ht, fh);
  244.  
  245.     if (!lf) {
  246.         /* We couldn't find this handle, so print it.
  247.             If it ever prunes old handles, take this out, because it'll
  248.             happen fairly often. */
  249.         DEBUG(puts("Stale handle received "));
  250.         DEBUG(fh_print(fh));
  251.     }
  252.  
  253.     return lf;
  254. }
  255.  
  256. /* "Lose" a LocalFile, removing it from the list and freeing the
  257.     memory */
  258. void lose_localfile(STRPTR full_name)
  259. {
  260.     struct LocalFile *lf;
  261.  
  262.     if (lf = find_namedlocalfile(full_name)) {
  263.         release_lf(lf);
  264.         remove_localfile(lf);
  265.         free_localfile(lf);
  266.     }
  267. }
  268.  
  269. /* Gets access to a file we've given out a handle to */
  270. struct LocalFile *get_by_handle(nfs_fh *fh, nfsstat *stat, ULONG mode)
  271. {
  272.     BPTR lock;
  273.     struct LocalFile *lf = find_handle(fh);
  274.     if (lf == NULL) { /* We don't know this handle */
  275.         *stat = NFSERR_STALE;
  276.         return NULL;
  277.     }
  278.  
  279.     lock = Lock(lf->lf_Name, mode);
  280.  
  281.     /* Why did we fail to lock it? */
  282.     if (lock == NULL) {
  283.         LONG err = IoErr();
  284.         PrintFault(IoErr(), "Unable to lock");
  285.         if ((err == ERROR_OBJECT_NOT_FOUND) || (err == ERROR_DIR_NOT_FOUND)) {
  286.             lf->lf_Type = NFNON; /* It's gone away... */
  287.         } else {
  288.             *stat = NFS_err(IoErr());
  289.         }
  290.         return NULL;
  291.     }
  292.  
  293.     /* Try and get details of the drive and file */
  294.     if (Info(lock, &infodata) && Examine(lock, &fib)) {
  295.         correct_struct(lf);
  296.         lf->lf_Lock = lock;
  297.         return lf;
  298.     } else {
  299.         *stat = NFS_err(IoErr());
  300.         UnLock(lock);
  301.         return NULL;
  302.     }
  303. }
  304.  
  305. /* Give up any interest in this LocalFile */
  306. void release_lf(struct LocalFile *rlf)
  307. {
  308.     if (rlf) {
  309.         if (rlf->lf_Lock) {
  310.             UnLock(rlf->lf_Lock);
  311.             rlf->lf_Lock = NULL;
  312.         }
  313.         /* One day we'll use this to determine what can go */
  314.         GetSysTime(&(rlf->lf_LastUsed));
  315.     }
  316. }
  317.  
  318. /* Flushes any handles that haven't been used for a while from
  319.     the system. Returns 'TRUE' if there would be any purpose in calling
  320.     it again in FLUSH_HANDLES_EVERY seconds time.
  321. */
  322. BOOL flush_handles()
  323. {
  324.     struct timeval time_now;
  325.     BOOL handles_pending = FALSE;
  326.  
  327.     /* Now - do we need to flush? */
  328.     GetSysTime(&time_now);
  329.  
  330.     /* We can't use SubTime because we need time_now repeatedly.
  331.         This means we run the risk of being a couple of seconds out -
  332.          that's not really a problem.
  333.     */
  334.  
  335.     struct LocalFile *lf;
  336.  
  337.     lf = lf_list.lh_Head;
  338.     /* This is a fairly expensive operation */
  339.     while (lf->lf_Node.mln_Succ) {
  340.         struct LocalFile *next = (struct LocalFile *)lf->lf_Node.mln_Succ;
  341.         /* We never flush mountpoints. It isn't, is it? */
  342.         if (!lf->lf_IsMount) {
  343.             if ((time_now.tv_secs - lf->lf_LastUsed.tv_secs) > FLUSH_HANDLES_AFTER) {
  344.                 /* It's not a mountpoint, and it hasn't been used for
  345.                     FLUSH_HANDLES_AFTER seconds */
  346.                 DEBUG(printf("Flushing handle for '%s'\n", lf->lf_Name));
  347.                 remove_localfile(lf);
  348.                 free_localfile(lf);
  349.             } else {
  350.                 /* It should be flushed, but not yet */
  351.                 DEBUG(printf("'%s' is a pending flushee\n", lf->lf_Name));
  352.                 handles_pending = TRUE;
  353.             }
  354.         }
  355.         lf = next;
  356.     }
  357.  
  358.     return handles_pending;
  359. }
  360.  
  361. /* Compare two NFS file handles */
  362. static BOOL fh_match(nfs_fh *fha, nfs_fh *fhb)
  363. {
  364.     return (memcmp(fha, fhb, NFS_FHSIZE) == 0);
  365. }
  366.  
  367. /* Copy an NFS handle for a response */
  368. int32 *fh_copy(struct LocalFile *lf, int32 *dest)
  369. {
  370.     if (!lf || !dest) {
  371.         puts("null arguments to fh_copy");
  372.         return NULL;
  373.     }
  374.  
  375.     CopyMem(&lf->lf_NFSHandle, dest, NFS_FHSIZE);
  376.  
  377.     return dest + INT32S(NFS_FHSIZE);
  378. }
  379.  
  380. /* Print a handle, purely for debugging */
  381. void fh_print(nfs_fh *fh)
  382. {
  383.     int i;
  384.     printf("{");
  385.     for (i = 0 ; i < NFS_FHSIZE ; i++) {
  386.         if (i > 0)
  387.             putchar(',');
  388.         printf("%2x", fh[i]);
  389.     }
  390.     printf("}\n");
  391. }
  392.  
  393. /* Fill in a unique NFS handle */
  394. static void fh_fillin(nfs_fh *fh)
  395. {
  396.     /* As well as all the random data, ensure it actually is unique
  397.         by placing a counter in there */
  398.     static ULONG handle_counter = 1;
  399.  
  400.     int32 *ptr = fh;
  401.  
  402.     GetSysTime((struct timeval *)ptr); /* First 8 bytes */
  403.     ptr += 2;
  404.  
  405.     *ptr++ = handle_counter++;
  406.  
  407.     /* We have 5 more int32s; pad with noise to make spoofing harder */
  408.     *ptr++ = rand();
  409.     *ptr++ = rand();
  410.     *ptr++ = rand();
  411.     *ptr++ = rand();
  412.     *ptr = rand();
  413. }
  414.  
  415. /* Give a unique inode */
  416. static u_int new_inode()
  417. {
  418.     return next_id++;
  419. }
  420.  
  421. /* Correct the type of a LocalFile structure,
  422.     and possibly give it a new inode */
  423. void correct_struct(struct LocalFile *lf)
  424. {
  425.     u_int type = NFS_type(fib.fib_DirEntryType);
  426.  
  427.     if (type != lf->lf_Type) { /* It's changed... */
  428.         lf->lf_Type = type;
  429.         lf->lf_FileID = new_inode();
  430.     }
  431. }
  432.  
  433. /* Callbacks for hash tables */
  434. static ULONG handleHash(APTR handle)
  435. {
  436.     ULONG val = 0;
  437.     BYTE *ba = (BYTE *)handle;
  438.     int i;
  439.  
  440.     for (i = 0 ; i < NFS_FHSIZE ; i++) {
  441.         val = (val << 5) ^ (val >> 27) ^ *ba++;
  442.     }
  443.     return val;
  444. }
  445.  
  446. static ULONG handleEquals(APTR a, APTR b)
  447. {
  448.     return fh_match((nfs_fh *)a, (nfs_fh *)b);
  449. }
  450.  
  451. /* This is a case insensitive hash */
  452. static ULONG stringHash(APTR string)
  453. {
  454.     ULONG val = 0;
  455.     STRPTR ba = (STRPTR)string;
  456.  
  457.     while (*ba) {
  458.         val = (val << 5) ^ (val >> 27) ^ tolower(*ba++);
  459.     }
  460.     return val;
  461. }
  462.  
  463. static BOOL stringEquals(APTR a, APTR b)
  464. {
  465.     return (0 == stricmp((STRPTR)a, (STRPTR)b));
  466. }
  467.  
  468.