home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 396.lha / MSH_v1.30s / src / hanlock.c < prev    next >
C/C++ Source or Header  |  1990-07-10  |  18KB  |  752 lines

  1. /*-
  2.  * $Id: hanlock.c,v 1.30 90/06/04 23:17:18 Rhialto Rel $
  3.  * $Log:    hanlock.c,v $
  4.  * Revision 1.30  90/06/04  23:17:18  Rhialto
  5.  * Release 1 Patch 3
  6.  * 
  7.  * HANLOCK.C
  8.  *
  9.  * The code for the messydos file system handler
  10.  *
  11.  * The Lock department. Takes care of operations on locks, and consequently,
  12.  * on directories.
  13.  *
  14.  * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  15.  * not be used or copied without a licence.
  16. -*/
  17.  
  18. #include "dos.h"
  19. #include "han.h"
  20.  
  21. #ifdef HDEBUG
  22. #   define    debug(x)  dbprintf x
  23. #else
  24. #   define    debug(x)
  25. #endif
  26.  
  27. struct LockList *LockList;    /* List of all locked files we have. Note
  28.                  * this is not the same as all locks we
  29.                  * have */
  30. struct MSFileLock *RootLock;    /* Lock on root directory */
  31. struct MSFileLock *EmptyFileLock;    /* 2nd result of MSLock() */
  32.  
  33. struct DirEntry FakeRootDirEntry = {
  34.     {                /* de_Msd */
  35.     "Unnamed ",             /* msd_Name */
  36.     "   ",                  /* msd_Ext */
  37.     ATTR_VOLUMELABEL,    /* msd_Attributes */
  38.     {0},            /* msd_Pad1 */
  39.     0,            /* msd_Time */
  40.     DATE_MIN,        /* msd_Date, 1/1/80 */
  41.     0,            /* msd_Cluster */
  42.     0            /* msd_Filesize */
  43.     },
  44.     ROOT_SEC,            /* de_Sector */
  45.     0                /* de_Offset */
  46. };
  47. byte        DotDot[1 + 8 + 3] = "..          ";
  48.  
  49. /*
  50.  * This routine compares a name in a directory entry with a given name
  51.  */
  52.  
  53. int
  54. CompareNames(dir, name)
  55. register struct MsDirEntry *dir;
  56. register byte  *name;
  57. {
  58.     if (dir->msd_Name[0] & DIR_DELETED_MASK)
  59.     return CMP_FREE_SLOT;
  60.  
  61.     if (dir->msd_Name[0] == 0)
  62.     return CMP_END_OF_DIR;    /* end of directory */
  63.  
  64.     if (dir->msd_Attributes & ATTR_VOLUMELABEL)
  65.     return CMP_NOT_EQUAL;
  66.  
  67.     if (strncmp(dir->msd_Name, name, 8 + 3))
  68.     return CMP_NOT_EQUAL;
  69.  
  70.     if (dir->msd_Attributes & ATTR_DIRECTORY)
  71.     return CMP_OK_DIR;
  72.  
  73.     return CMP_OK_FILE;
  74. }
  75.  
  76. void
  77. NextDirEntry(sector, offset)
  78. register word  *sector;
  79. register word  *offset;
  80. {
  81.     if ((*offset += MS_DIRENTSIZE) >= Disk.bps) {
  82.     *offset = 0;
  83.     if (*sector >= Disk.datablock) {
  84.         /* Must be subdirectory */
  85.         *sector = NextClusteredSector(*sector);
  86.         debug(("NextClusteredSector: %d\n", *sector));
  87.     } else {
  88.         if (++*sector >= Disk.datablock) {
  89.         *sector = SEC_EOF;
  90.         }
  91.     }
  92.     }
  93.     /* else no more work needed */
  94. }
  95.  
  96. /*
  97.  * Get the directory entry following the given one. If requested, we make
  98.  * the directory longer.
  99.  */
  100.  
  101. struct DirEntry *
  102. FindNext(previous, createit)
  103. register struct DirEntry *previous;
  104. int        createit;
  105. {
  106.     byte       *sector;
  107.     word        prevsec = previous->de_Sector;
  108.  
  109.     NextDirEntry(&previous->de_Sector, &previous->de_Offset);
  110.  
  111.     if (previous->de_Sector == SEC_EOF) {
  112.     error = ERROR_OBJECT_NOT_FOUND;
  113. #ifndef READONLY
  114.     if (createit) {
  115.         if (prevsec < Disk.datablock - 1) { /* Should not be necessary */
  116.         previous->de_Sector = prevsec + 1;
  117.         } else if (prevsec >= Disk.datablock) {
  118.         previous->de_Sector = FindFreeSector(prevsec);
  119.         }
  120.         if (previous->de_Sector != SEC_EOF) {
  121.         sector = EmptySec(previous->de_Sector);
  122.         setmem(sector, (int) Disk.bps, 0);
  123.         MarkSecDirty(sector);
  124.         FreeSec(sector);
  125.         setmem(&previous->de_Msd, sizeof (previous->de_Msd), 0);
  126.  
  127.         return previous;
  128.         }
  129.     }
  130. #endif
  131.     } else if (sector = GetSec(previous->de_Sector)) {
  132.     CopyMem(sector + previous->de_Offset, &previous->de_Msd,
  133.         (long) MS_DIRENTSIZE);
  134.     OtherEndianMsd(&previous->de_Msd);
  135.     FreeSec(sector);
  136.  
  137.     return previous;
  138.     }
  139.     return NULL;
  140. }
  141.  
  142. #ifdef HDEBUG
  143.  
  144. void
  145. PrintDirEntry(de)
  146. struct DirEntry *de;
  147. {
  148.     debug(("%d,%d ", de->de_Sector, de->de_Offset));
  149.     debug(("%.8s.%.3s attr:%x time:%x date:%x start:%x size:%lx\n",
  150.        de->de_Msd.msd_Name,
  151.        de->de_Msd.msd_Ext,
  152.        de->de_Msd.msd_Attributes,
  153.        de->de_Msd.msd_Time,
  154.        de->de_Msd.msd_Date,
  155.        de->de_Msd.msd_Cluster,
  156.        de->de_Msd.msd_Filesize
  157.        ));
  158. }
  159.  
  160. #endif
  161.  
  162. /*
  163.  * MakeLock makes a struct MSFileLock from a directory entry and the
  164.  * parent directory MSFileLock pointer. It looks if it already has a Lock
  165.  * on it. In that case, it simply increments its reference count, when
  166.  * possible.
  167.  */
  168.  
  169. struct MSFileLock *
  170. MakeLock(parentdir, dir, mode)
  171. struct MSFileLock *parentdir;
  172. struct DirEntry *dir;
  173. ulong        mode;
  174. {
  175.     register struct MSFileLock *fl;
  176.     struct MSFileLock *nextfl;
  177.  
  178.     if (mode != EXCLUSIVE_LOCK || (dir->de_Msd.msd_Attributes & ATTR_DIR))
  179.     mode = SHARED_LOCK;
  180.  
  181. #ifdef HDEBUG
  182.     debug(("MakeLock: "));
  183.     PrintDirEntry(dir);
  184. #endif
  185.  
  186.     /*
  187.      * Look through our list to see if we already have it. The criteria
  188.      * for this are: 1. the directory entries are the same or 2. they have
  189.      * the same first cluster and are both directories (which can have
  190.      * multiple directory entries). Sigh.
  191.      */
  192.  
  193.     for (fl = (struct MSFileLock *) LockList->ll_List.mlh_Head;
  194.      nextfl = (struct MSFileLock *) fl->msfl_Node.mln_Succ;
  195.      fl = nextfl) {
  196. #ifdef HDEBUG
  197.     debug(("> "));
  198.     PrintDirEntry(&fl->msfl_Msd);
  199. #endif
  200.     if ((fl->msfl_DirSector == dir->de_Sector &&
  201.          fl->msfl_DirOffset == dir->de_Offset) ||
  202.         (fl->msfl_Msd.msd_Cluster == dir->de_Msd.msd_Cluster &&
  203.          (dir->de_Msd.msd_Attributes & ATTR_DIR) &&
  204.          (fl->msfl_Msd.msd_Attributes & ATTR_DIR))
  205.         ) {
  206.         /* Found existing lock on file */
  207.         if (fl->msfl_Refcount < 0 || mode == EXCLUSIVE_LOCK) {
  208.         error = ERROR_OBJECT_IN_USE;
  209.         return NULL;
  210.         }
  211.         fl->msfl_Refcount++;
  212.         return fl;
  213.     }
  214.     }
  215.  
  216.     fl = AllocMem((long) sizeof (*fl), MEMF_PUBLIC);
  217.     if (fl == NULL) {
  218.     error = ERROR_NO_FREE_STORE;
  219.     return NULL;
  220.     }
  221.     fl->msfl_Parent = parentdir ? MSDupLock(parentdir) : NULL;
  222.  
  223.     fl->msfl_Refcount = (mode == EXCLUSIVE_LOCK) ? -1 : 1;
  224.     fl->msfl_DirSector = dir->de_Sector;
  225.     fl->msfl_DirOffset = dir->de_Offset;
  226.     fl->msfl_Msd = dir->de_Msd;
  227.  
  228.     AddHead(&LockList->ll_List, fl);
  229.  
  230.     return fl;
  231. }
  232.  
  233. /*
  234.  * This routine Locks a file. It first searches it in the directory, then
  235.  * lets the rest of the work be done by MakeLock(). If it encounters an
  236.  * empty slot in the directory, it remembers where, in case we need it. If
  237.  * you clear the MODE_CREATEFILE bit in the mode parameter, we fabricate a
  238.  * new MSFileLock from the empty directory entry. It then becomes the
  239.  * caller's responsibility to MSUnLock() it eventually.
  240.  */
  241.  
  242. struct MSFileLock *
  243. MSLock(parentdir, name, mode)
  244. struct MSFileLock *parentdir;
  245. byte           *name;
  246. ulong        mode;
  247. {
  248.     byte       *sector;
  249.     struct MSFileLock *newlock;
  250.     register struct DirEntry *de;
  251.     struct DirEntry sde;
  252.     byte       *nextpart;
  253.     byte        component[8 + 3];    /* Note: not null-terminated */
  254.     int         createit;
  255.     word        freesec;
  256.     word        freeoffset;
  257.  
  258.     de = &sde;
  259.     newlock = NULL;
  260.  
  261.     /*
  262.      * See if we have an absolute path name (starting at the root).
  263.      */
  264.     {
  265.     register byte  *colon;
  266.  
  267.     if (colon = index(name, ':')) {
  268.         name = colon + 1;
  269.         parentdir = RootLock;
  270.         /*
  271.          * MSH::Command or ::Command?
  272.          */
  273.         if (name[0] == ':') {
  274.         HandleCommand(name);
  275.         error = ERROR_OBJECT_NOT_FOUND;
  276.  
  277.         return NULL;
  278.         }
  279.     }
  280.     }
  281.  
  282.  
  283.     /*
  284.      * Get a copy of the parent dir lock, so we can walk it over the
  285.      * directory tree.
  286.      */
  287.     parentdir = MSDupLock(parentdir);
  288.  
  289.     /*
  290.      * Start with the directory entry of the parent dir.
  291.      */
  292.  
  293.     sde.de_Msd = parentdir->msfl_Msd;
  294.     sde.de_Sector = parentdir->msfl_DirSector;
  295.     sde.de_Offset = parentdir->msfl_DirOffset;
  296. #ifdef HDEBUG
  297.     debug(("pdir %08lx: ", parentdir));
  298.     PrintDirEntry(&parentdir->msfl_Msd);
  299. #endif
  300.  
  301. newdir:
  302.     freesec = SEC_EOF;        /* Means none found yet */
  303.  
  304.     nextpart = ToMSName(component, name);
  305.     debug(("Component: '%11s'\n", component));
  306.     if (nextpart[0] != '/') {
  307.     nextpart = NULL;
  308. #ifndef READONLY
  309.     /*
  310.      * See if we are requested to get an empty spot in the directory
  311.      * if the given name does not exist already. The value of mode is
  312.      * not important until we actually create the filelock.
  313.      */
  314.     if (!(mode & MODE_CREATEFILE)) {
  315.         mode ^= MODE_CREATEFILE;
  316.         createit = 1;
  317.     } else
  318.         createit = 0;
  319. #endif
  320.     } else
  321.     nextpart++;
  322.  
  323.     /*
  324.      * Are we at the end of the name? Then we are finished now. This works
  325.      * because sde contains the directory entry of parentdir.
  326.      */
  327.  
  328.     if (name[0] == '\0')
  329.     goto exit;
  330.  
  331.     /*
  332.      * If there is more name, we enter the directory, and here we get the
  333.      * first entry.
  334.      */
  335.  
  336.     sde.de_Sector = DirClusterToSector(sde.de_Msd.msd_Cluster);
  337.     sde.de_Offset = 0;
  338.  
  339.     if ((sector = GetSec(sde.de_Sector)) == NULL)
  340.     goto error;
  341.  
  342.     CopyMem(sector, &sde.de_Msd, (long) sizeof (struct MsDirEntry));
  343.     OtherEndianMsd(&sde.de_Msd);
  344.     FreeSec(sector);
  345.  
  346.     while (de) {
  347.     switch (CompareNames(&sde.de_Msd, component)) {
  348.     case CMP_FREE_SLOT:
  349.         if (freesec == SEC_EOF) {
  350.         freesec = sde.de_Sector;
  351.         freeoffset = sde.de_Offset;
  352.         }
  353.         /* Fall through */
  354.     case CMP_NOT_EQUAL:
  355.         de = FindNext(&sde, createit);      /* Try next directory
  356.                          * entry */
  357.         continue;
  358.     case CMP_OK_DIR:
  359.         if (name = nextpart) {
  360.         /*
  361.          * We want to keep locks on all directories between each
  362.          * bottom directory and file lock, so we can easily find
  363.          * the parent of a lock. There just seems to be a problem
  364.          * here when we enter the 'subdirectories' . or .. , but
  365.          * that in not so: MakeLock will detect that it has
  366.          * already a lock on those, and NOT make :one/two the
  367.          * parent of :one/two/.. .
  368.          */
  369.         newlock = MakeLock(parentdir, de, SHARED_LOCK);
  370.         MSUnLock(parentdir);
  371.         parentdir = newlock;
  372.         goto newdir;
  373.         }
  374.         goto exit;
  375.     case CMP_OK_FILE:
  376.         if (nextpart) {
  377.         error = ERROR_OBJECT_WRONG_TYPE;
  378.         de = NULL;
  379.         }
  380.         goto exit;
  381.     case CMP_END_OF_DIR:    /* means we will never find it */
  382.         error = ERROR_OBJECT_NOT_FOUND;
  383.         if (freesec == SEC_EOF) {
  384.         freesec = sde.de_Sector;
  385.         freeoffset = sde.de_Offset;
  386.         }
  387.         de = NULL;
  388.         goto exit;
  389.     }
  390.     }
  391.  
  392. exit:
  393.     if (de) {
  394.     newlock = MakeLock(parentdir, &sde, mode);
  395.     } else {
  396.     newlock = NULL;
  397. #ifndef READONLY
  398.     if (createit &&         /* Do we want to make it? */
  399.         error == ERROR_OBJECT_NOT_FOUND &&    /* does it not exist yet? */
  400.         nextpart == NULL) { /* do we have the last part of the name */
  401.         if (freesec != SEC_EOF) {   /* is there any room? */
  402.         if (IDDiskState == ID_VALIDATED) {
  403.             error = 0;
  404.             setmem(&sde.de_Msd, sizeof (sde.de_Msd), 0);
  405.             sde.de_Sector = freesec;
  406.             sde.de_Offset = freeoffset;
  407.             /* ToMSName(sde.de_Msd.msd_Name, name); */
  408.             strncpy(sde.de_Msd.msd_Name, component, 8 + 3);
  409.             EmptyFileLock = MakeLock(parentdir, &sde, mode);
  410.             WriteFileLock(EmptyFileLock);
  411.         } else
  412.             error = ERROR_DISK_WRITE_PROTECTED;
  413.         } else
  414.         error = ERROR_DISK_FULL;
  415.     }
  416. #endif
  417.     }
  418.  
  419. error:
  420.     MSUnLock(parentdir);
  421.  
  422.     return newlock;
  423. }
  424.  
  425. /*
  426.  * This routine DupLocks a file. This simply means incrementing the
  427.  * reference count, if it was not an exclusive Lock.
  428.  */
  429.  
  430. struct MSFileLock *
  431. MSDupLock(fl)
  432. struct MSFileLock *fl;
  433. {
  434.     if (fl == NULL)
  435.     fl = RootLock;
  436.     if (fl->msfl_Refcount <= 0) {
  437.     error = ERROR_OBJECT_IN_USE;
  438.     return NULL;
  439.     } else {
  440.     fl->msfl_Refcount++;
  441.     }
  442.  
  443.     return fl;
  444. }
  445.  
  446. /*
  447.  * This routine DupLocks the parent of a lock, if there is one.
  448.  */
  449.  
  450. struct MSFileLock *
  451. MSParentDir(fl)
  452. register struct MSFileLock *fl;
  453. {
  454.     if (fl == NULL || fl == RootLock) {
  455.     error = ERROR_OBJECT_NOT_FOUND;
  456.     } else if (fl->msfl_Parent)
  457.     return MSDupLock(fl->msfl_Parent);
  458.  
  459.     return NULL;
  460. }
  461.  
  462. /*
  463.  * This routine UnLocks a file.
  464.  */
  465.  
  466. int
  467. MSUnLock(fl)
  468. struct MSFileLock *fl;
  469. {
  470. #ifdef HDEBUG
  471.     debug(("MSUnLock %08lx: ", fl));
  472.     PrintDirEntry(&fl->msfl_Msd);
  473. #endif
  474.  
  475.     if (fl) {
  476.     if (--fl->msfl_Refcount <= 0) {
  477.         struct LockList *list;
  478.  
  479.         list = (struct LockList *) fl->msfl_Node.mln_Pred;
  480.         Remove(fl);
  481.         debug(("Remove()d %08lx\n", fl));
  482.  
  483.         /*
  484.          * We may need to get rid of the LockList if it is empty. This
  485.          * is the current LockList iff we are called from
  486.          * MSDiskRemoved(). Please note that we are not even sure that
  487.          * 'list' really is the list header, therefore the careful
  488.          * test if fl refers to a volume label (root lock) which is
  489.          * finally UnLock()ed. Because of the recursion, we only try to
  490.          * free the LockList iff there is no parent anymore, since
  491.          * otherwise list may be invalid by the time we use it.
  492.          */
  493.         if (fl->msfl_Parent) {
  494.         MSUnLock(fl->msfl_Parent);
  495.         } else {
  496.         if ((fl->msfl_Msd.msd_Attributes & ATTR_VOLUMELABEL) &&
  497.             ((void *) list->ll_List.mlh_Head ==
  498.              (void *) &list->ll_List.mlh_Tail)
  499.             ) {
  500.             FreeLockList(list);
  501.         }
  502.         }
  503.         FreeMem(fl, (long) sizeof (*fl));
  504.     }
  505.     }
  506.     return DOSTRUE;
  507. }
  508.  
  509. /*
  510.  * This is (among other things) the inverse of ToMSName().
  511.  */
  512.  
  513. void
  514. ExamineDirEntry(msd, fib)
  515. struct MsDirEntry *msd;
  516. register struct FileInfoBlock *fib;
  517. {
  518. #ifdef HDEBUG
  519.     debug(("+ "));
  520.     PrintDirEntry(msd);
  521. #endif
  522.     /*
  523.      * Special treatment when we examine the root directory
  524.      */
  525.     if (fib->fib_DiskKey == (long)ROOT_SEC << 16) {
  526.     strncpy(&fib->fib_FileName[1], msd->msd_Name, 8 + 3);
  527.     (void) ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + 8 + 3]);
  528.     } else {
  529.     register byte  *end,
  530.                *dot;
  531.  
  532.     strncpy(&fib->fib_FileName[1], msd->msd_Name, 8);
  533.     /* Keep at least one character, even a space, before the dot */
  534.     dot = ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + 8]);
  535.     dot[0] = ' ';
  536.     strncpy(dot + 1, msd->msd_Ext, 3);
  537.     dot[4] = '\0';
  538.     end = ZapSpaces(dot, dot + 4);
  539.     if (end > dot)
  540.         dot[0] = '.';
  541.     }
  542.     fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]);
  543.  
  544.     fib->fib_EntryType =
  545.     fib->fib_DirEntryType =
  546.     (msd->msd_Attributes & ATTR_DIR) ? FILE_DIR : FILE_FILE;
  547.     fib->fib_Protection = 0;
  548.     if (!(msd->msd_Attributes & ATTR_ARCHIVED))
  549.     fib->fib_Protection |= FIBF_ARCHIVE;
  550.     if (msd->msd_Attributes & ATTR_READONLY)
  551.     fib->fib_Protection |= (FIBF_WRITE | FIBF_DELETE);
  552.     if (msd->msd_Attributes & (ATTR_HIDDEN|ATTR_SYSTEM))
  553.     fib->fib_Protection |= FIBF_HIDDEN;
  554.     fib->fib_Size = msd->msd_Filesize;
  555.     fib->fib_NumBlocks = (msd->msd_Filesize + Disk.bps - 1) / Disk.bps;
  556.     ToDateStamp(&fib->fib_Date, msd->msd_Date, msd->msd_Time);
  557.     fib->fib_Comment[0] = 0;
  558. }
  559.  
  560. /*
  561.  * We remember what we should do when we call ExNext with a lock on
  562.  * a directory (enter or step over it) by a flag in fib_EntryType.
  563.  * Unfortunately, the Commodore (1.3) List and Dir commands expect
  564.  * that fib_EntryType contains the information that the documentation
  565.  * (libraries/dos.h) specifies to be in fib_DirEntryType. Therefore
  566.  * we use the low bit in fib_DiskKey instead. Yech.
  567.  */
  568.  
  569. int
  570. MSExamine(fl, fib)
  571. struct MSFileLock *fl;
  572. register struct FileInfoBlock *fib;
  573. {
  574.     if (fl == NULL)
  575.     fl = RootLock;
  576.  
  577.     fib->fib_DiskKey = ((ulong) fl->msfl_DirSector << 16) |
  578.                fl->msfl_DirOffset +
  579.                1;    /* No ExNext called yet */
  580.     ExamineDirEntry(&fl->msfl_Msd, fib);
  581.  
  582.     return DOSTRUE;
  583. }
  584.  
  585. int
  586. MSExNext(fl, fib)
  587. struct MSFileLock *fl;
  588. register struct FileInfoBlock *fib;
  589. {
  590.     word        sector = fib->fib_DiskKey >> 16;
  591.     word        offset = (word) fib->fib_DiskKey;
  592.     byte       *buf;
  593.  
  594.     if (fl == NULL)
  595.     fl = RootLock;
  596.  
  597.     if (offset & 1) {
  598.     if (fl->msfl_Msd.msd_Attributes & ATTR_DIR) {
  599.         /* Enter subdirectory */
  600.         sector = DirClusterToSector(fl->msfl_Msd.msd_Cluster);
  601.         offset = 0;
  602.     } else {
  603.         offset--;        /* Remember, it was odd */
  604.         NextDirEntry(§or, &offset);
  605.     }
  606.     } else {
  607. skip:
  608.     NextDirEntry(§or, &offset);
  609.     }
  610.  
  611.     if (sector != SEC_EOF) {
  612.     struct MsDirEntry msd;
  613.  
  614.     if (buf = GetSec(sector)) {
  615.         msd = *(struct MsDirEntry *) (buf + offset);
  616.         FreeSec(buf);
  617.         if (msd.msd_Name[0] == '\0') {
  618.         goto end;
  619.         }
  620.         if (msd.msd_Name[0] & DIR_DELETED_MASK ||
  621.         msd.msd_Name[0] == '.' ||       /* Hide "." and ".." */
  622.         (msd.msd_Attributes & ATTR_VOLUMELABEL)) {
  623.         goto skip;
  624.         }
  625.         OtherEndianMsd(&msd);       /* Get correct endianness */
  626.         fib->fib_DiskKey = ((ulong) sector << 16) | offset;
  627.         ExamineDirEntry(&msd, fib);
  628.  
  629.         return DOSTRUE;
  630.     }
  631.     }
  632. end:
  633.     error = ERROR_NO_MORE_ENTRIES;
  634.     return DOSFALSE;
  635. }
  636.  
  637. /*
  638.  * Convert AmigaDOS protection bits to messy attribute bits.
  639.  */
  640.  
  641. long
  642. MSSetProtect(parentdir, name, mask)
  643. register struct MSFileLock *parentdir;
  644. char       *name;
  645. long       mask;
  646. {
  647.     register struct MSFileLock *lock;
  648.  
  649.     if (parentdir == NULL)
  650.     parentdir = RootLock;
  651.  
  652.     lock = MSLock(parentdir, name, EXCLUSIVE_LOCK);
  653.     if (lock) {
  654.     /* Leave SYSTEM bit as-is */
  655.     lock->msfl_Msd.msd_Attributes &= ATTR_SYSTEM;
  656.     /* write or delete protected -> READONLY */
  657.     if (mask & (FIBF_WRITE|FIBF_DELETE))
  658.         lock->msfl_Msd.msd_Attributes |= (ATTR_READONLY);
  659.     /* hidden -> hidden */
  660.     if (mask & FIBF_HIDDEN)
  661.         lock->msfl_Msd.msd_Attributes |= (ATTR_HIDDEN);
  662.     /* archived=0 (default) -> archived=1 (default) */
  663.     if (!(mask & FIBF_ARCHIVE))
  664.         lock->msfl_Msd.msd_Attributes |= (ATTR_ARCHIVED);
  665.     WriteFileLock(lock);
  666.     MSUnLock(lock);
  667.     return TRUE;
  668.     }
  669.  
  670.     return FALSE;
  671. }
  672.  
  673. int
  674. CheckLock(lock)
  675. register struct MSFileLock *lock;
  676. {
  677.     register struct MSFileLock *parent;
  678.  
  679.     if (lock) {
  680.     while (parent = lock->msfl_Parent)
  681.         lock = parent;
  682.     if (lock != RootLock)
  683.         error = ERROR_DEVICE_NOT_MOUNTED;
  684.     }
  685.     return error;
  686. }
  687.  
  688. #ifndef READONLY
  689.  
  690. void
  691. WriteFileLock(fl)
  692. register struct MSFileLock *fl;
  693. {
  694.     debug(("WriteFileLock %08lx\n", fl));
  695.  
  696.     if (fl) {
  697.     register byte  *block = GetSec(fl->msfl_DirSector);
  698.  
  699.     if (block) {
  700.         CopyMem(&fl->msfl_Msd, block + fl->msfl_DirOffset,
  701.             (long) sizeof (fl->msfl_Msd));
  702.         OtherEndianMsd(block + fl->msfl_DirOffset);
  703.         MarkSecDirty(block);
  704.         FreeSec(block);
  705.     }
  706.     }
  707. }
  708.  
  709. void
  710. UpdateFileLock(fl)
  711. register struct MSFileLock *fl;
  712. {
  713.     struct DateStamp dateStamp;
  714.  
  715.     debug(("UpdateFileLock %08lx\n", fl));
  716.  
  717.     DateStamp(&dateStamp);
  718.     ToMSDate(&fl->msfl_Msd.msd_Date, &fl->msfl_Msd.msd_Time, &dateStamp);
  719.     WriteFileLock(fl);
  720. }
  721.  
  722. #endif
  723.  
  724. struct LockList *
  725. NewLockList(cookie)
  726. void           *cookie;
  727. {
  728.     struct LockList *ll;
  729.  
  730.     if (ll = AllocMem((long) sizeof (*ll), MEMF_PUBLIC)) {
  731.     NewList(&ll->ll_List);
  732.     ll->ll_Cookie = cookie;
  733.     } else
  734.     error = ERROR_NO_FREE_STORE;
  735.  
  736.     return ll;
  737. }
  738.  
  739. void
  740. FreeLockList(ll)
  741. struct LockList *ll;
  742. {
  743.     debug(("FreeLockList %08lx\n", ll));
  744.  
  745.     if (ll) {
  746.     MayFreeVolNode(ll->ll_Cookie);  /* not too happy about this */
  747.     FreeMem(ll, (long) sizeof (*ll));
  748.     if (ll == LockList)     /* locks on current volume */
  749.         LockList = NULL;
  750.     }
  751. }
  752.