home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / flistfrontend / src / dirdata.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-04  |  8.4 KB  |  343 lines

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: dirdata.c,v 1.10 1995/06/04 21:18:02 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    dirdata.c
  7.  * Author:    Thomas E. Dickey
  8.  * Created:    13 Jul 1985
  9.  * Last update:
  10.  *        28 May 1995, prototypes
  11.  *        22 Jul 1985, if rename, make sure path has same references as
  12.  *                 the data objects, use 'dirpath_add'
  13.  *        16 Jul 1985, added 'dirdata_one', 'dirdata_ren'.
  14.  *
  15.  * Function:    This module contains the principal routines which maintain the
  16.  *        'filelink' linked-list of file information for FLIST.  We
  17.  *        keep a single list of all files known to all levels of FLIST,
  18.  *        distinguishing ownership by a given level with a bit-mask
  19.  *        '.file_refs' (see NAMEHEAP).  The list is sorted in the order
  20.  *        which a SYS$SEARCH would yield the entire list of files:
  21.  *
  22.  *        * increasing by pathname,
  23.  *        * increasing by filename,
  24.  *        * increasing by filetype, and
  25.  *        * decreasing by version.
  26.  *
  27.  *        Each list entry contains a FILENT block (.fk) which records
  28.  *        everything which we know about a particular file.
  29.  *
  30.  *        The linked-list routines use an initial-pointer argument so
  31.  *        that successive calls (as within a SYS$SEARCH-loop) will tend
  32.  *        to reduce search time: we need only search from the last file
  33.  *        known.
  34.  *
  35.  * Entrypoint:    dirdata_add:    Add the given FILENT block to this level.
  36.  *        dirdata_chg:    Add FILENT block, given prior link-pointer.
  37.  *        dirdata_find:    Find a given FILENT block in the list.
  38.  *        dirdata_high:    Search list for higher-version than FILENT block.
  39.  *        dirdata_one:    Add FILENT block, searching from beginning.
  40.  *        dirdata_ren:    Rename file, relinking block.
  41.  */
  42.  
  43. #include    <stdlib.h>
  44. #include    <string.h>
  45.  
  46. #include    <rms.h>
  47.  
  48. #include    "flist.h"
  49. #include    "dirent.h"
  50. #include    "dirdata.h"
  51. #include    "dirpath.h"
  52. #include    "nameheap.h"
  53.  
  54. import(filelink);
  55.  
  56. /* <dirdata_find>:
  57.  * Returns:
  58.  *    1, iff we find the entry already in the list or
  59.  *    -1, 0, iff the entry is not in the list.
  60.  *
  61.  * If we do not find the entry in the list, we leave 'lastp' set to the entry
  62.  * which would precede the new data.  Thus, iff the list is empty, 'lastp' will
  63.  * be zero.  The "-1" return value is used to distinguish the list-beginning
  64.  * when the entry is not found in the list.
  65.  */
  66. int    dirdata_find (FILENT *z, FLINK **lastp)
  67. {
  68. FLINK    *now    = filelink,
  69.     *old    = filelink;
  70. int    found    = 0,
  71.     first,
  72.     cmp;
  73.  
  74.     if (lastp)    if (*lastp)    now    = *lastp;
  75.     first    = (now == filelink);
  76. #ifdef    DEBUG
  77.     trace ("Find: %s%s.%s;%d\n", zPATHOF(z), z->fname, z->ftype, z->fvers);
  78.     trace ("%08X ", now);
  79. #endif
  80.  
  81. #define    BINCMP(q)    (cmp = (z->q - now->fk.q))
  82. #define    STRCMP(q)    (cmp = strcmp(z->q, now->fk.q))
  83. #define    DIFFP(q)    (z->q != now->fk.q)
  84. #define    SAMEP(q)    (z->q == now->fk.q)
  85.  
  86.     while (now)
  87.     {
  88.         if (BINCMP(fpath_->path_sort) > 0)    goto after;
  89.         else if (cmp < 0)            goto before;
  90.  
  91.         if (DIFFP(fname))
  92.         {
  93.             if (STRCMP(fname) > 0)        goto after;
  94.             else if (cmp < 0)        goto before;
  95.         }
  96.  
  97.         if (DIFFP(ftype))
  98.         {
  99.             if (STRCMP(ftype) > 0)        goto after;
  100.             else if (cmp < 0)        goto before;
  101.         }
  102.  
  103.         if (BINCMP(fvers) < 0)            goto after;
  104.         else if (cmp >  0)            goto before;
  105.         else if (cmp == 0)
  106.         {
  107.             found = 1;
  108.             goto exit;
  109.         }
  110.  
  111.         /*
  112.          * The new entry should go after the 'now' entry.  Link to the
  113.          * next one, to test.
  114.          */
  115. after:        old = now;
  116.         now = now->file_next;
  117.         first = FALSE;
  118.     }
  119.  
  120.     /*
  121.      * The new entry should go before the 'now' entry.  Assume that 'old'
  122.      * points to the proper position.
  123.      */
  124. before:    if (first)
  125.     {
  126.         now    = filelink;    /* Insert at list-beginning    */
  127.         found    = -1;
  128.     }
  129.     else
  130.         now    = old;
  131.  
  132. exit:    if (lastp)            *lastp    = now;
  133. #ifdef    DEBUG
  134.     trace ("=> %08X (%d):%d\n", now, found, first);
  135. #endif
  136.     return (found);
  137. }
  138.  
  139. /* <dirdata_add>:
  140.  * Unconditionally add/replace data in the linked-list.  We use this entry, for
  141.  * example, when showing the result of reading a directory (without suppressing
  142.  * lower versions).
  143.  */
  144. void    dirdata_add (FILENT *z, FLINK **lastp)
  145. {
  146.     dirdata_chg (z, lastp, dirdata_find (z, lastp));
  147. }
  148.  
  149. /* <dirdata_chg>:
  150.  * Add/replace data in the linked-list, using the return value from 'dirdata_find'
  151.  * to guide the link-placement.  We use this entry, for example, when reading
  152.  * a directory subject to pruning lower versions (i.e., first, '_find', then
  153.  * '_high', then '_chg'.
  154.  */
  155. void    dirdata_chg (FILENT *z, FLINK **lastp, int found)
  156. {
  157.     FLINK    *p, *q, *r;
  158.  
  159. #ifdef    DEBUG
  160. trace ("CHG: %08X %d\n", *lastp, found);
  161. #endif
  162.     if (found <= 0)
  163.     {
  164.         p = calloc (1, sizeof(FLINK));
  165.         if (q = *lastp)
  166.         {
  167.             if (found < 0)    /* Insert at beginning    */
  168.             {
  169.                 p->file_next = filelink;
  170.                 filelink = p;
  171.             }
  172.             else        /* Normal insertion    */
  173.             {
  174.                 r = q->file_next;
  175.                 q->file_next = p;
  176.                 p->file_next = r;
  177.             }
  178.         }
  179.         else            /* Only entry in list    */
  180.             filelink = p;
  181.         *lastp    = p;
  182.     }
  183.     else
  184.         p = *lastp;
  185.     p->file_refs |= nameheap_ref();
  186.     p->fk    = *z;
  187. #ifdef    DEBUG
  188.     trace ("FLINK: ");
  189.     for (p = filelink; p; p = p->file_next)
  190.         trace ("%08X ", p);
  191.     trace ("\n");
  192. #endif
  193. }
  194.  
  195. /* <dirdata_high>:
  196.  * Search the list to determine if there is an entry with a higher version
  197.  * than the FILENT-block.  Use the 'lastp' argument as a reference; don't
  198.  * need to search past this point.
  199.  */
  200. int    dirdata_high (FILENT *z, FLINK **lastp)
  201. {
  202.     FLINK    *now = filelink;
  203.     int    cmp;
  204.  
  205.     while (now)
  206.     {
  207.         if (SAMEP(fpath_) && SAMEP(fname) && SAMEP(ftype))
  208.             return (BINCMP(fvers) < 0);
  209.         if (now == *lastp)    break;
  210.         now = now->file_next;
  211.     }
  212.     return (FALSE);
  213. }
  214.  
  215. /* <dirdata_one>:
  216.  * Search from list-beginning to insert/update a FILENT block.  We use this for
  217.  * code which is not driven from a SYS$SEARCH loop.
  218.  */
  219. void    dirdata_one (FILENT *z, FLINK **lastp)
  220. {
  221.     *lastp = filelink;
  222.     dirdata_add (z, lastp);
  223. }
  224.  
  225. /* <dirdata_ren>:
  226.  * Rename a file.  Because entries in 'filelist' will point to the original
  227.  * block, we do not simply allocate a new block, but re-use the old one.
  228.  * This requires that we re-link the list.
  229.  */
  230. void    dirdata_ren (FILENT *znew, FILENT *zold)
  231. {
  232.     FLINK    *pnew = 0,
  233.         *pold = 0;
  234.     int    found = dirdata_find (znew, &pnew);
  235.  
  236.     if (!memcmp(znew, zold, sizeof(FILENT)))
  237.         return;        /* don't waste my time !! */
  238.  
  239.     /*
  240.      * If the "new" name is in the list already, then this is probably
  241.      * (if no bug!) because the caller marked the file deleted.  To safely
  242.      * dispose of this, we must move it also in the list by making its
  243.      * version number non-conflicting with other entries.
  244.      */
  245.     if (found > 0)
  246.     {
  247.     FLINK    *old,
  248.         *now    = pnew->file_next;
  249.  
  250.         /*
  251.          * De-link the "new" entry from the list, saving pointer-before.
  252.          */
  253.         if (pnew == filelink)
  254.             old = filelink = pnew->file_next;
  255.         else
  256.         {
  257.         for (old = filelink; old->file_next != pnew; old = old->file_next);
  258.         old->file_next = pnew->file_next;
  259.         }
  260.  
  261.         /*
  262.          * If the block is referenced by more than the current level, find
  263.          * a new insertion point (with a negative version code to make it
  264.          * transparent to other data).
  265.          */
  266.         if (pnew->file_refs != nameheap_ref())
  267.         {
  268.         FILENT    *z    = &(pnew->fk);
  269.         int        tvers    = -1;
  270.  
  271.         now = old->file_next;    /* => after de-linked "new" data */
  272.         while (now)
  273.         {
  274.             if (!(SAMEP(fpath_) && SAMEP(fname) && SAMEP(ftype)))
  275.             break;
  276.             if (tvers >= now->fk.fvers) tvers = now->fk.fvers - 1;
  277.             old = now;
  278.             now = now->file_next;
  279.         }
  280.         pnew->fk.fvers = tvers;
  281.         if (old == filelink)
  282.         {
  283.             pnew->file_next = filelink;
  284.             filelink = pnew;
  285.         }
  286.         else
  287.         {
  288.             pnew->file_next = old->file_next;
  289.             old->file_next  = pnew;
  290.         }
  291.         }
  292.         else    /* simply de-allocate the entry    */
  293.         cfree (pnew);
  294.     }
  295.  
  296.     /*
  297.      * Now, we know that the "new" name does not appear in the list.  We
  298.      * can re-link the entry in which we have the "old" filename stored
  299.      * (if it is in the list).
  300.      *
  301.      * From the code above, we now have no instance of 'znew' in the list.
  302.      */
  303.     if ((found = dirdata_find (zold, &pold)) > 0)
  304.     {
  305.     FLINK    *now = filelink;
  306.  
  307.         if (now == pold)    /* de-link at beginning */
  308.         filelink = now->file_next;
  309.         else
  310.         {
  311.         while (now->file_next != pold)
  312.             now = now->file_next;
  313.         now->file_next = pold->file_next;
  314.         }
  315.         pold->fk = *znew;
  316.         pnew = nullS(FLINK);
  317.         if ((found = dirdata_find (znew, &pnew)) < 0)
  318.         {
  319.         pold->file_next = filelink;
  320.         filelink = pold;
  321.         }
  322.         else
  323.         {
  324.         pold->file_next = pnew->file_next;
  325.         pnew->file_next = pold;
  326.         }
  327.         pold->fk = *znew;
  328.     }
  329.     else
  330.     {
  331.         pold = 0;
  332.         dirdata_one (znew, &pold);
  333.     }
  334.  
  335.     /*
  336.      * Ensure that any strings and pathnames to which we refer have at least
  337.      * the same scope as the object which we have just renamed:
  338.      */
  339.     dirpath_add  (pold->file_refs, pold->fk.fpath_);
  340.     nameheap_add (pold->file_refs, pold->fk.fname);
  341.     nameheap_add (pold->file_refs, pold->fk.ftype);
  342. }
  343.