Path: utzoo!utgpu!watserv1!watmath!att!rutgers!usc!zaphod.mps.ohio-state.edu!uakari.primate.wisc.edu!xanth!cs.odu.edu!Amiga-Request From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) Newsgroups: comp.sources.amiga Subject: v90i214: MSH 1.30 - Messydos File System Handler, Part02/06 Message-ID: <13139@xanth.cs.odu.edu> Date: 16 Jul 90 00:00:36 GMT Sender: tadguy@cs.odu.edu Reply-To: Olaf 'Rhialto' Seibert Lines: 1514 Approved: tadguy@cs.odu.edu (Tad Guy) X-Mail-Submissions-To: Amiga@cs.odu.edu X-Post-Discussions-To: comp.sys.amiga Submitted-by: Olaf 'Rhialto' Seibert Posting-number: Volume 90, Issue 214 Archive-name: devices/msh-1.30/part02 #!/bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'doc/dev.man.uu' <<'END_OF_FILE' Xbegin 664 dev.man XM"B`@("`@;65S'141"D["@H@("`@()LQ;55304=%(`H@("`@("`@("`@FS!M365S XM5$12259%5%E012`@(%1$7T=%5$Y5351204-+4R`](%1$7T%$1$-(04Y'14E.Y XM5`H@("`@("`@("`@/2!41%]214U#2$%.1T5)3E0@*B!%5$1?5U))5$4@("`@8 XM("`@*B!%5$1?4D5!1`H@("`@("`@("`@("!%5$1?34]43U(@("`@("`@/2!%; XM5$1?4T5%2R`@("`@("`@*B!%5$1?1D]234%4"B`@("`@("`@("`J($541%]53 XM4$1!5$4@("`@("`]($541%]#3$5!4B`@("`@("`@($541%]205=214%$"B`@: XM("`@("`@("`@($541%]205=74DE410H*("`@("`@("`@(%1H92!C;VUM86YDE XM0H@("`@("`@("`@;65S61I0H@("`@("`@("`@F XM8V]N=&%I;B!T:&4@9F]L;&]W:6YG(&9L86=S.B`*"B`@("`@("`@("!)3T9?6 XM455)0TLZ(%1H:7,@9FQA9R!I6QI2 XM;F1E2`@>6]U('-E="!O6]U(')E860@=&AE(&)O;W1B;&]C:R!A;F0@97AA;6ENS XM92!I=',*"@H@("`@(%)H:6%L=&\L($MO61I61I\ XM7-T96US+@H@("`@("`@("`@0F]T:"`T,"`@T XM86YD("`X,"`@8WEL:6YD97(@(&UE9&EA("!A2`Y('-E8W1O6QI;F1E2`@8F4@% XM(')E860@(&EF('1H90H@("`@("`@("`@9')I=FEN9R`@6]U="!O9B!T:&4@=F5R>2!F:7)S="!T"!P=6QS92`@+2TM+2TM+2TM+2TM+2TM+2TM+2TMY XM+2TM+2TM+2TM+2TM+2TM+@H@("`@("`@("`@("`@("`@("`@("`@("`@("`@; XM("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("!\"B`@("`@("`@F XM("`@("`@-#`@*B`D-&4@("`@1T%0(#%!("`H)#DR-30@96YC;V1E9"D@("`@P XM("`@("`@("`@('P*("`@("`@("`@("`@("`Q,B`J("0P,"`@("`@("`@("`@W XM("@D04%!02!E;F-O9&5D*2`@("`@("`@("`@("`@?`H@("`@("`@("`@("`@Q XM("`S("H@)&,R("`@(%-93D,@("`@*"0U,C(T(&5N8V]D960I("`@("`@("`@G XM("`@("!\"B`@("`@("`@("`@("`@(#$@*B`D9F,@("`@:6YD97@@;6%R:R`@Q XM("`@("`@("`@*"0U-34R*2`@("`@("`@('P*("`@("`@("`@("`@("`@("`@, XM("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@@ XM?`H@("`@("`@("`@("`@(#0P("H@)#1E("`@($=!4"`Q0B`@*"0Y,C4T(&5N/ XM8V]D960I("`@("`@("`@("`@("!\"B`@("`@("`@("`@("`@("`@("`@("`@. XM("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@('P*("`@F XM("`@("`@("TM+2!&:7)S="!396-T;W(@+2TM+2TM+2TM+2TM+2TM+2TM+2TMP XM+2TM+2TM+2TN("`@("`@?`H@("`@("`@("`@("`@("`@("`@("`@("`@("`@< XM("`@("`@("`@("`@("`@("`@("`@("`@("`@('P@("`@("!\"B`@("`@("`@" XM("`@("`@,3(@*B`D,#`@("`@1T%0(#(@("`H)$%!04$@96YC;V1E9"D@("`@& XM("`@?"`@("`@('P*("`@("`@("`@("!\("`@,R`J("1A,2`@("!364Y#("`@. XM("@D-#0X.2!E;F-O9&5D*2`@("`@("!\("`@("`@?`H@("`@("`@("`@('P@^ XM("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@('P@\ XM("`@("!\"B`@("`@("`@("`@?"`@(#$@*B`D9F4@("`@240M061D61I71E6]U('=H:7-H('1O(&9O6]U"B`@("`@("`@("!S<&5C:69Y("`T,"`@61I2`@=7-E2!I;7!O&EM=6T@& XM2`@=')A8VL*("`@3 XM("`@("`@('=I;&P@8F4@=W)I='1E;B!B86-K+B`@1F]R='5N871E;'DL(&%L! XM;"!C=7)R96YT;'D@:VYO=VX@9FEL90H@("`@("`@("`@ XM("`@:6YT96YT:6]N("`@;V8@(%1$7U)%34]612XI("!/9B`@8V]U2!C=7)R96YT;'D@C XM;W!E;B!U;FET+B`@5VAE;B!T:&4*("`@("`@("`@('5N:70@:7,@9&5F:6YI( XM=&EV96QY(&-L;W-E9"!A;F0@;&%T97(@0H@("`@("`@("`@8F4@=7-A8FQE(&5V96X@:68@=&AE61I2`@(%=E'src/hanlock.c' <<'END_OF_FILE' X/*- X * $Id: hanlock.c,v 1.30 90/06/04 23:17:18 Rhialto Rel $ X * $Log: hanlock.c,v $ X * Revision 1.30 90/06/04 23:17:18 Rhialto X * Release 1 Patch 3 X * X * HANLOCK.C X * X * The code for the messydos file system handler X * X * The Lock department. Takes care of operations on locks, and consequently, X * on directories. X * X * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May X * not be used or copied without a licence. X-*/ X X#include "dos.h" X#include "han.h" X X#ifdef HDEBUG X# define debug(x) dbprintf x X#else X# define debug(x) X#endif X Xstruct LockList *LockList; /* List of all locked files we have. Note X * this is not the same as all locks we X * have */ Xstruct MSFileLock *RootLock; /* Lock on root directory */ Xstruct MSFileLock *EmptyFileLock; /* 2nd result of MSLock() */ X Xstruct DirEntry FakeRootDirEntry = { X { /* de_Msd */ X "Unnamed ", /* msd_Name */ X " ", /* msd_Ext */ X ATTR_VOLUMELABEL, /* msd_Attributes */ X {0}, /* msd_Pad1 */ X 0, /* msd_Time */ X DATE_MIN, /* msd_Date, 1/1/80 */ X 0, /* msd_Cluster */ X 0 /* msd_Filesize */ X }, X ROOT_SEC, /* de_Sector */ X 0 /* de_Offset */ X}; Xbyte DotDot[1 + 8 + 3] = ".. "; X X/* X * This routine compares a name in a directory entry with a given name X */ X Xint XCompareNames(dir, name) Xregister struct MsDirEntry *dir; Xregister byte *name; X{ X if (dir->msd_Name[0] & DIR_DELETED_MASK) X return CMP_FREE_SLOT; X X if (dir->msd_Name[0] == 0) X return CMP_END_OF_DIR; /* end of directory */ X X if (dir->msd_Attributes & ATTR_VOLUMELABEL) X return CMP_NOT_EQUAL; X X if (strncmp(dir->msd_Name, name, 8 + 3)) X return CMP_NOT_EQUAL; X X if (dir->msd_Attributes & ATTR_DIRECTORY) X return CMP_OK_DIR; X X return CMP_OK_FILE; X} X Xvoid XNextDirEntry(sector, offset) Xregister word *sector; Xregister word *offset; X{ X if ((*offset += MS_DIRENTSIZE) >= Disk.bps) { X *offset = 0; X if (*sector >= Disk.datablock) { X /* Must be subdirectory */ X *sector = NextClusteredSector(*sector); X debug(("NextClusteredSector: %d\n", *sector)); X } else { X if (++*sector >= Disk.datablock) { X *sector = SEC_EOF; X } X } X } X /* else no more work needed */ X} X X/* X * Get the directory entry following the given one. If requested, we make X * the directory longer. X */ X Xstruct DirEntry * XFindNext(previous, createit) Xregister struct DirEntry *previous; Xint createit; X{ X byte *sector; X word prevsec = previous->de_Sector; X X NextDirEntry(&previous->de_Sector, &previous->de_Offset); X X if (previous->de_Sector == SEC_EOF) { X error = ERROR_OBJECT_NOT_FOUND; X#ifndef READONLY X if (createit) { X if (prevsec < Disk.datablock - 1) { /* Should not be necessary */ X previous->de_Sector = prevsec + 1; X } else if (prevsec >= Disk.datablock) { X previous->de_Sector = FindFreeSector(prevsec); X } X if (previous->de_Sector != SEC_EOF) { X sector = EmptySec(previous->de_Sector); X setmem(sector, (int) Disk.bps, 0); X MarkSecDirty(sector); X FreeSec(sector); X setmem(&previous->de_Msd, sizeof (previous->de_Msd), 0); X X return previous; X } X } X#endif X } else if (sector = GetSec(previous->de_Sector)) { X CopyMem(sector + previous->de_Offset, &previous->de_Msd, X (long) MS_DIRENTSIZE); X OtherEndianMsd(&previous->de_Msd); X FreeSec(sector); X X return previous; X } X return NULL; X} X X#ifdef HDEBUG X Xvoid XPrintDirEntry(de) Xstruct DirEntry *de; X{ X debug(("%d,%d ", de->de_Sector, de->de_Offset)); X debug(("%.8s.%.3s attr:%x time:%x date:%x start:%x size:%lx\n", X de->de_Msd.msd_Name, X de->de_Msd.msd_Ext, X de->de_Msd.msd_Attributes, X de->de_Msd.msd_Time, X de->de_Msd.msd_Date, X de->de_Msd.msd_Cluster, X de->de_Msd.msd_Filesize X )); X} X X#endif X X/* X * MakeLock makes a struct MSFileLock from a directory entry and the X * parent directory MSFileLock pointer. It looks if it already has a Lock X * on it. In that case, it simply increments its reference count, when X * possible. X */ X Xstruct MSFileLock * XMakeLock(parentdir, dir, mode) Xstruct MSFileLock *parentdir; Xstruct DirEntry *dir; Xulong mode; X{ X register struct MSFileLock *fl; X struct MSFileLock *nextfl; X X if (mode != EXCLUSIVE_LOCK || (dir->de_Msd.msd_Attributes & ATTR_DIR)) X mode = SHARED_LOCK; X X#ifdef HDEBUG X debug(("MakeLock: ")); X PrintDirEntry(dir); X#endif X X /* X * Look through our list to see if we already have it. The criteria X * for this are: 1. the directory entries are the same or 2. they have X * the same first cluster and are both directories (which can have X * multiple directory entries). Sigh. X */ X X for (fl = (struct MSFileLock *) LockList->ll_List.mlh_Head; X nextfl = (struct MSFileLock *) fl->msfl_Node.mln_Succ; X fl = nextfl) { X#ifdef HDEBUG X debug(("> ")); X PrintDirEntry(&fl->msfl_Msd); X#endif X if ((fl->msfl_DirSector == dir->de_Sector && X fl->msfl_DirOffset == dir->de_Offset) || X (fl->msfl_Msd.msd_Cluster == dir->de_Msd.msd_Cluster && X (dir->de_Msd.msd_Attributes & ATTR_DIR) && X (fl->msfl_Msd.msd_Attributes & ATTR_DIR)) X ) { X /* Found existing lock on file */ X if (fl->msfl_Refcount < 0 || mode == EXCLUSIVE_LOCK) { X error = ERROR_OBJECT_IN_USE; X return NULL; X } X fl->msfl_Refcount++; X return fl; X } X } X X fl = AllocMem((long) sizeof (*fl), MEMF_PUBLIC); X if (fl == NULL) { X error = ERROR_NO_FREE_STORE; X return NULL; X } X fl->msfl_Parent = parentdir ? MSDupLock(parentdir) : NULL; X X fl->msfl_Refcount = (mode == EXCLUSIVE_LOCK) ? -1 : 1; X fl->msfl_DirSector = dir->de_Sector; X fl->msfl_DirOffset = dir->de_Offset; X fl->msfl_Msd = dir->de_Msd; X X AddHead(&LockList->ll_List, fl); X X return fl; X} X X/* X * This routine Locks a file. It first searches it in the directory, then X * lets the rest of the work be done by MakeLock(). If it encounters an X * empty slot in the directory, it remembers where, in case we need it. If X * you clear the MODE_CREATEFILE bit in the mode parameter, we fabricate a X * new MSFileLock from the empty directory entry. It then becomes the X * caller's responsibility to MSUnLock() it eventually. X */ X Xstruct MSFileLock * XMSLock(parentdir, name, mode) Xstruct MSFileLock *parentdir; Xbyte *name; Xulong mode; X{ X byte *sector; X struct MSFileLock *newlock; X register struct DirEntry *de; X struct DirEntry sde; X byte *nextpart; X byte component[8 + 3]; /* Note: not null-terminated */ X int createit; X word freesec; X word freeoffset; X X de = &sde; X newlock = NULL; X X /* X * See if we have an absolute path name (starting at the root). X */ X { X register byte *colon; X X if (colon = index(name, ':')) { X name = colon + 1; X parentdir = RootLock; X /* X * MSH::Command or ::Command? X */ X if (name[0] == ':') { X HandleCommand(name); X error = ERROR_OBJECT_NOT_FOUND; X X return NULL; X } X } X } X X X /* X * Get a copy of the parent dir lock, so we can walk it over the X * directory tree. X */ X parentdir = MSDupLock(parentdir); X X /* X * Start with the directory entry of the parent dir. X */ X X sde.de_Msd = parentdir->msfl_Msd; X sde.de_Sector = parentdir->msfl_DirSector; X sde.de_Offset = parentdir->msfl_DirOffset; X#ifdef HDEBUG X debug(("pdir %08lx: ", parentdir)); X PrintDirEntry(&parentdir->msfl_Msd); X#endif X Xnewdir: X freesec = SEC_EOF; /* Means none found yet */ X X nextpart = ToMSName(component, name); X debug(("Component: '%11s'\n", component)); X if (nextpart[0] != '/') { X nextpart = NULL; X#ifndef READONLY X /* X * See if we are requested to get an empty spot in the directory X * if the given name does not exist already. The value of mode is X * not important until we actually create the filelock. X */ X if (!(mode & MODE_CREATEFILE)) { X mode ^= MODE_CREATEFILE; X createit = 1; X } else X createit = 0; X#endif X } else X nextpart++; X X /* X * Are we at the end of the name? Then we are finished now. This works X * because sde contains the directory entry of parentdir. X */ X X if (name[0] == '\0') X goto exit; X X /* X * If there is more name, we enter the directory, and here we get the X * first entry. X */ X X sde.de_Sector = DirClusterToSector(sde.de_Msd.msd_Cluster); X sde.de_Offset = 0; X X if ((sector = GetSec(sde.de_Sector)) == NULL) X goto error; X X CopyMem(sector, &sde.de_Msd, (long) sizeof (struct MsDirEntry)); X OtherEndianMsd(&sde.de_Msd); X FreeSec(sector); X X while (de) { X switch (CompareNames(&sde.de_Msd, component)) { X case CMP_FREE_SLOT: X if (freesec == SEC_EOF) { X freesec = sde.de_Sector; X freeoffset = sde.de_Offset; X } X /* Fall through */ X case CMP_NOT_EQUAL: X de = FindNext(&sde, createit); /* Try next directory X * entry */ X continue; X case CMP_OK_DIR: X if (name = nextpart) { X /* X * We want to keep locks on all directories between each X * bottom directory and file lock, so we can easily find X * the parent of a lock. There just seems to be a problem X * here when we enter the 'subdirectories' . or .. , but X * that in not so: MakeLock will detect that it has X * already a lock on those, and NOT make :one/two the X * parent of :one/two/.. . X */ X newlock = MakeLock(parentdir, de, SHARED_LOCK); X MSUnLock(parentdir); X parentdir = newlock; X goto newdir; X } X goto exit; X case CMP_OK_FILE: X if (nextpart) { X error = ERROR_OBJECT_WRONG_TYPE; X de = NULL; X } X goto exit; X case CMP_END_OF_DIR: /* means we will never find it */ X error = ERROR_OBJECT_NOT_FOUND; X if (freesec == SEC_EOF) { X freesec = sde.de_Sector; X freeoffset = sde.de_Offset; X } X de = NULL; X goto exit; X } X } X Xexit: X if (de) { X newlock = MakeLock(parentdir, &sde, mode); X } else { X newlock = NULL; X#ifndef READONLY X if (createit && /* Do we want to make it? */ X error == ERROR_OBJECT_NOT_FOUND && /* does it not exist yet? */ X nextpart == NULL) { /* do we have the last part of the name */ X if (freesec != SEC_EOF) { /* is there any room? */ X if (IDDiskState == ID_VALIDATED) { X error = 0; X setmem(&sde.de_Msd, sizeof (sde.de_Msd), 0); X sde.de_Sector = freesec; X sde.de_Offset = freeoffset; X /* ToMSName(sde.de_Msd.msd_Name, name); */ X strncpy(sde.de_Msd.msd_Name, component, 8 + 3); X EmptyFileLock = MakeLock(parentdir, &sde, mode); X WriteFileLock(EmptyFileLock); X } else X error = ERROR_DISK_WRITE_PROTECTED; X } else X error = ERROR_DISK_FULL; X } X#endif X } X Xerror: X MSUnLock(parentdir); X X return newlock; X} X X/* X * This routine DupLocks a file. This simply means incrementing the X * reference count, if it was not an exclusive Lock. X */ X Xstruct MSFileLock * XMSDupLock(fl) Xstruct MSFileLock *fl; X{ X if (fl == NULL) X fl = RootLock; X if (fl->msfl_Refcount <= 0) { X error = ERROR_OBJECT_IN_USE; X return NULL; X } else { X fl->msfl_Refcount++; X } X X return fl; X} X X/* X * This routine DupLocks the parent of a lock, if there is one. X */ X Xstruct MSFileLock * XMSParentDir(fl) Xregister struct MSFileLock *fl; X{ X if (fl == NULL || fl == RootLock) { X error = ERROR_OBJECT_NOT_FOUND; X } else if (fl->msfl_Parent) X return MSDupLock(fl->msfl_Parent); X X return NULL; X} X X/* X * This routine UnLocks a file. X */ X Xint XMSUnLock(fl) Xstruct MSFileLock *fl; X{ X#ifdef HDEBUG X debug(("MSUnLock %08lx: ", fl)); X PrintDirEntry(&fl->msfl_Msd); X#endif X X if (fl) { X if (--fl->msfl_Refcount <= 0) { X struct LockList *list; X X list = (struct LockList *) fl->msfl_Node.mln_Pred; X Remove(fl); X debug(("Remove()d %08lx\n", fl)); X X /* X * We may need to get rid of the LockList if it is empty. This X * is the current LockList iff we are called from X * MSDiskRemoved(). Please note that we are not even sure that X * 'list' really is the list header, therefore the careful X * test if fl refers to a volume label (root lock) which is X * finally UnLock()ed. Because of the recursion, we only try to X * free the LockList iff there is no parent anymore, since X * otherwise list may be invalid by the time we use it. X */ X if (fl->msfl_Parent) { X MSUnLock(fl->msfl_Parent); X } else { X if ((fl->msfl_Msd.msd_Attributes & ATTR_VOLUMELABEL) && X ((void *) list->ll_List.mlh_Head == X (void *) &list->ll_List.mlh_Tail) X ) { X FreeLockList(list); X } X } X FreeMem(fl, (long) sizeof (*fl)); X } X } X return DOSTRUE; X} X X/* X * This is (among other things) the inverse of ToMSName(). X */ X Xvoid XExamineDirEntry(msd, fib) Xstruct MsDirEntry *msd; Xregister struct FileInfoBlock *fib; X{ X#ifdef HDEBUG X debug(("+ ")); X PrintDirEntry(msd); X#endif X /* X * Special treatment when we examine the root directory X */ X if (fib->fib_DiskKey == (long)ROOT_SEC << 16) { X strncpy(&fib->fib_FileName[1], msd->msd_Name, 8 + 3); X (void) ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + 8 + 3]); X } else { X register byte *end, X *dot; X X strncpy(&fib->fib_FileName[1], msd->msd_Name, 8); X /* Keep at least one character, even a space, before the dot */ X dot = ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + 8]); X dot[0] = ' '; X strncpy(dot + 1, msd->msd_Ext, 3); X dot[4] = '\0'; X end = ZapSpaces(dot, dot + 4); X if (end > dot) X dot[0] = '.'; X } X fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]); X X fib->fib_EntryType = X fib->fib_DirEntryType = X (msd->msd_Attributes & ATTR_DIR) ? FILE_DIR : FILE_FILE; X fib->fib_Protection = 0; X if (!(msd->msd_Attributes & ATTR_ARCHIVED)) X fib->fib_Protection |= FIBF_ARCHIVE; X if (msd->msd_Attributes & ATTR_READONLY) X fib->fib_Protection |= (FIBF_WRITE | FIBF_DELETE); X if (msd->msd_Attributes & (ATTR_HIDDEN|ATTR_SYSTEM)) X fib->fib_Protection |= FIBF_HIDDEN; X fib->fib_Size = msd->msd_Filesize; X fib->fib_NumBlocks = (msd->msd_Filesize + Disk.bps - 1) / Disk.bps; X ToDateStamp(&fib->fib_Date, msd->msd_Date, msd->msd_Time); X fib->fib_Comment[0] = 0; X} X X/* X * We remember what we should do when we call ExNext with a lock on X * a directory (enter or step over it) by a flag in fib_EntryType. X * Unfortunately, the Commodore (1.3) List and Dir commands expect X * that fib_EntryType contains the information that the documentation X * (libraries/dos.h) specifies to be in fib_DirEntryType. Therefore X * we use the low bit in fib_DiskKey instead. Yech. X */ X Xint XMSExamine(fl, fib) Xstruct MSFileLock *fl; Xregister struct FileInfoBlock *fib; X{ X if (fl == NULL) X fl = RootLock; X X fib->fib_DiskKey = ((ulong) fl->msfl_DirSector << 16) | X fl->msfl_DirOffset + X 1; /* No ExNext called yet */ X ExamineDirEntry(&fl->msfl_Msd, fib); X X return DOSTRUE; X} X Xint XMSExNext(fl, fib) Xstruct MSFileLock *fl; Xregister struct FileInfoBlock *fib; X{ X word sector = fib->fib_DiskKey >> 16; X word offset = (word) fib->fib_DiskKey; X byte *buf; X X if (fl == NULL) X fl = RootLock; X X if (offset & 1) { X if (fl->msfl_Msd.msd_Attributes & ATTR_DIR) { X /* Enter subdirectory */ X sector = DirClusterToSector(fl->msfl_Msd.msd_Cluster); X offset = 0; X } else { X offset--; /* Remember, it was odd */ X NextDirEntry(§or, &offset); X } X } else { Xskip: X NextDirEntry(§or, &offset); X } X X if (sector != SEC_EOF) { X struct MsDirEntry msd; X X if (buf = GetSec(sector)) { X msd = *(struct MsDirEntry *) (buf + offset); X FreeSec(buf); X if (msd.msd_Name[0] == '\0') { X goto end; X } X if (msd.msd_Name[0] & DIR_DELETED_MASK || X msd.msd_Name[0] == '.' || /* Hide "." and ".." */ X (msd.msd_Attributes & ATTR_VOLUMELABEL)) { X goto skip; X } X OtherEndianMsd(&msd); /* Get correct endianness */ X fib->fib_DiskKey = ((ulong) sector << 16) | offset; X ExamineDirEntry(&msd, fib); X X return DOSTRUE; X } X } Xend: X error = ERROR_NO_MORE_ENTRIES; X return DOSFALSE; X} X X/* X * Convert AmigaDOS protection bits to messy attribute bits. X */ X Xlong XMSSetProtect(parentdir, name, mask) Xregister struct MSFileLock *parentdir; Xchar *name; Xlong mask; X{ X register struct MSFileLock *lock; X X if (parentdir == NULL) X parentdir = RootLock; X X lock = MSLock(parentdir, name, EXCLUSIVE_LOCK); X if (lock) { X /* Leave SYSTEM bit as-is */ X lock->msfl_Msd.msd_Attributes &= ATTR_SYSTEM; X /* write or delete protected -> READONLY */ X if (mask & (FIBF_WRITE|FIBF_DELETE)) X lock->msfl_Msd.msd_Attributes |= (ATTR_READONLY); X /* hidden -> hidden */ X if (mask & FIBF_HIDDEN) X lock->msfl_Msd.msd_Attributes |= (ATTR_HIDDEN); X /* archived=0 (default) -> archived=1 (default) */ X if (!(mask & FIBF_ARCHIVE)) X lock->msfl_Msd.msd_Attributes |= (ATTR_ARCHIVED); X WriteFileLock(lock); X MSUnLock(lock); X return TRUE; X } X X return FALSE; X} X Xint XCheckLock(lock) Xregister struct MSFileLock *lock; X{ X register struct MSFileLock *parent; X X if (lock) { X while (parent = lock->msfl_Parent) X lock = parent; X if (lock != RootLock) X error = ERROR_DEVICE_NOT_MOUNTED; X } X return error; X} X X#ifndef READONLY X Xvoid XWriteFileLock(fl) Xregister struct MSFileLock *fl; X{ X debug(("WriteFileLock %08lx\n", fl)); X X if (fl) { X register byte *block = GetSec(fl->msfl_DirSector); X X if (block) { X CopyMem(&fl->msfl_Msd, block + fl->msfl_DirOffset, X (long) sizeof (fl->msfl_Msd)); X OtherEndianMsd(block + fl->msfl_DirOffset); X MarkSecDirty(block); X FreeSec(block); X } X } X} X Xvoid XUpdateFileLock(fl) Xregister struct MSFileLock *fl; X{ X struct DateStamp dateStamp; X X debug(("UpdateFileLock %08lx\n", fl)); X X DateStamp(&dateStamp); X ToMSDate(&fl->msfl_Msd.msd_Date, &fl->msfl_Msd.msd_Time, &dateStamp); X WriteFileLock(fl); X} X X#endif X Xstruct LockList * XNewLockList(cookie) Xvoid *cookie; X{ X struct LockList *ll; X X if (ll = AllocMem((long) sizeof (*ll), MEMF_PUBLIC)) { X NewList(&ll->ll_List); X ll->ll_Cookie = cookie; X } else X error = ERROR_NO_FREE_STORE; X X return ll; X} X Xvoid XFreeLockList(ll) Xstruct LockList *ll; X{ X debug(("FreeLockList %08lx\n", ll)); X X if (ll) { X MayFreeVolNode(ll->ll_Cookie); /* not too happy about this */ X FreeMem(ll, (long) sizeof (*ll)); X if (ll == LockList) /* locks on current volume */ X LockList = NULL; X } X} END_OF_FILE if test 18293 -ne `wc -c <'src/hanlock.c'`; then echo shar: \"'src/hanlock.c'\" unpacked with wrong size! fi # end of 'src/hanlock.c' fi if test -f 'src/hanmain.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/hanmain.c'\" else echo shar: Extracting \"'src/hanmain.c'\" \(10018 characters\) sed "s/^X//" >'src/hanmain.c' <<'END_OF_FILE' X/*- X * $Id: hanmain.c,v 1.30 90/06/04 23:16:50 Rhialto Rel $ X * $Log: hanmain.c,v $ X * Revision 1.30 90/06/04 23:16:50 Rhialto X * Release 1 Patch 3 X * X * HANMAIN.C X * X * The code for the messydos file system handler. X * X * Some start/stop stuff that is not really part of the X * file system itself but that must be done anyway. X * X * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May X * not be used or copied without a licence. X-*/ X X#include "dos.h" X#include "han.h" X X#ifdef HDEBUG X# define debug(x) dbprintf x X#else X# define debug(x) X#endif X Xextern int CheckBootBlock; Xextern char DotDot[1 + 8 + 3]; Xstruct Library *IntuitionBase; Xstatic char RCSId[] = "Messydos filing system $Revision: 1.30 $ $Date: 90/06/04 23:16:50 $, by Olaf Seibert"; X Xbyte XToUpper(ch) Xregister byte ch; X{ X if (ch >= 'a' && ch <= 'z') X return ch + ('A' - 'a'); X if (ch == '.') X return '!'; X return ch & ~DIR_DELETED_MASK; X} X Xlong Xlmin(a, b) Xlong a, X b; X{ X return (a < b) ? a : b; X} X Xbyte * XZapSpaces(begin, end) Xregister byte *begin, X *end; X{ X while (end > begin && end[-1] == ' ') X *--end = '\0'; X X return end; X} X X/* X * Map an arbitrary file name to MS-DOS conventions. The output format is X * 8+3 without dot, padded with spaces, suitable for direct comparison X * with directory entries. Return a pointer to the delimiter found ('\0' X * or '/'). [[Make sure that Examine/ExNext return a proper inverse of X * this...]] X */ X Xbyte * XToMSName(dest, source) Xbyte *dest; Xregister byte *source; X{ X byte *dotp; X byte *slashp; X register int i, X len; X X if (*source == '/') { /* parentdir */ X strncpy(dest, DotDot, 8 + 3); /* ".." */ X return source; X } X /* X * Remove any strictly leading dots. .info -> info, .indent.pro -> X * indent.pro, .profile -> profile, etc. X */ X while (*source == '.') X source++; X X /* X * Find dot and slash which are delimiters of name and extension. X */ X { X register byte *cp; X X cp = source; X while (*cp) { X if (*cp == '.' || *cp == '/') X break; X cp++; X } X dotp = cp; X while (*cp) { X if (*cp == '/') X break; X cp++; X } X slashp = cp; X } X X len = dotp - source; X if (len > 8) X len = 8; X X for (i = 0; i < len; i++) { X *dest++ = ToUpper(*source++); X } X for (; i < 8; i++) { X *dest++ = ' '; X } X X source = dotp + 1; X len = slashp - source; /* so will be -1 if no suffix */ X if (len > 3) X len = 3; X X for (i = 0; i < len; i++) { X *dest++ = ToUpper(*source++); X } X for (; i < 3; i++) { X *dest++ = ' '; X } X X return slashp; X} X X/* X * Do the Info call. X */ X Xlong XMSDiskInfo(infodata) Xstruct InfoData *infodata; X{ X extern DEVLIST *VolNode; X X setmem(infodata, sizeof (*infodata), 0); X X infodata->id_DiskState = IDDiskState; X infodata->id_DiskType = IDDiskType; X infodata->id_UnitNumber = UnitNr; X X infodata->id_VolumeNode = (BPTR) CTOB(VolNode); X infodata->id_InUse = LockList ? 1 : 0; X X if (IDDiskType == ID_DOS_DISK) { X infodata->id_NumBlocks = Disk.nsects; X infodata->id_NumBlocksUsed = Disk.nsects - Disk.nsectsfree; X infodata->id_BytesPerBlock = Disk.bps; X } X return DOSTRUE; X} X X/* X * We (re-)establish our List of MSFileLocks after a disk has been X * (re-)inserted. If there are no known locks, we make the root lock from X * the volume label, if there is one. X * X * We get a special cookie to hand to a cleanup routine that we must call X * when finally all locks on the current disk are UnLock()ed. (this is X * actually the volume node, but we don't want to know that.) X * X * This must be called some time after IdentifyDisk(). X */ X Xvoid XMSDiskInserted(locks, cookie) Xregister struct LockList **locks; Xvoid *cookie; X{ X debug(("MSDiskInserted %08lx\n", cookie)); X X LockList = *locks; X X if (LockList == NULL) { X LockList = NewLockList(cookie); X RootLock = MakeLock(NULL, &Disk.vollabel, SHARED_LOCK); X } else { X RootLock = MSDupLock(GetTail(&LockList->ll_List)); X } X X InitCacheList(); X} X X/* X * Remove the current disk. A place is offered to save the current X * LockList to restore later. We must unlock the root lock since it isn't X * a real reference to the disk, just a placeholder for dummies that hand X * us NULL locks. X */ X Xint XMSDiskRemoved(locks) Xregister struct LockList **locks; X{ X#ifndef READONLY X if (FatDirty || (DelayState & DELAY_DIRTY)) X MSUpdate(1); /* Force a requester */ X#endif X X FreeFat(); X FreeCacheList(); X X IDDiskType = ID_NO_DISK_PRESENT; X *locks = NULL; X X if (RootLock == NULL) { X debug(("MSDiskRemoved with no RootLock\n")); X return 1; X } X#ifdef HDEBUG X if (RootLock != GetTail(&LockList->ll_List)) { X debug(("RootLock not at end of LockList!\n")); X /* Get the lock on the root dir at the tail of the List */ X Remove(RootLock); X AddTail(&LockList->ll_List, RootLock); X } X#endif X X /* X * If there are no real locks on the disk, we need not keep any X * information about it. X */ X X MSUnLock(RootLock); /* may call FreeLockList and free VolNode X * (!) */ X RootLock = NULL; X X if (LockList) { X *locks = LockList; /* VolNode can't be gone now... */ X LockList = NULL; X return 0; /* not all references gone */ X } else { X return 1; /* all gone, even the VolNode */ X } X} X Xvoid XHanCloseDown() X{ X#ifdef HDEBUG X register struct MSFileLock *fl; X X while (LockList && (fl = (struct MSFileLock *) GetHead(&LockList->ll_List))) { X debug(("UNLOCKING %08lx: ", fl)); X PrintDirEntry(&fl->msfl_Msd); X MSUnLock(fl); /* Remove()s it from this List */ X } X#endif X if (DiskIOReq) { X if (DiskIOReq->iotd_Req.io_Unit) { X MSUpdate(1); X CloseDevice(DiskIOReq); X } X DeleteExtIO(DiskIOReq); X DiskIOReq = NULL; X } X if (TimeIOReq) { X if (TimeIOReq->tr_node.io_Unit) { X WaitIO(TimeIOReq); X CloseDevice(TimeIOReq); X } X DeleteExtIO(TimeIOReq); X TimeIOReq = NULL; X } X if (DiskReplyPort) { X DeletePort(DiskReplyPort); X DiskReplyPort = NULL; X } X if (IntuitionBase) { X CloseLibrary(IntuitionBase); X IntuitionBase = NULL; X } X} X Xint XHanOpenUp() X{ X LockList = NULL; X RootLock = NULL; X Fat = NULL; X IDDiskState = ID_WRITE_PROTECTED; X IDDiskType = ID_NO_DISK_PRESENT; X DelayState = DELAY_OFF; X Disk.bps = MS_BPS; X CheckBootBlock = 1; X InitCacheList(); X X TimeIOReq = NULL; X X#ifdef HDEBUG X if (!(DiskReplyPort = CreatePort("MSH:disk.replyport", -1L))) X goto abort; X#else X if (!(DiskReplyPort = CreatePort(NULL, -1L))) X goto abort; X#endif X X debug(("DiskReplyPort = 0x%08lx\n", DiskReplyPort)); X X if (!(DiskIOReq = CreateExtIO(DiskReplyPort, (long) sizeof (*DiskIOReq)))) { X debug(("Failed to CreateExtIO\n")); X goto abort; X } X if (OpenDevice(DevName, UnitNr, DiskIOReq, DevFlags | TDF_ALLOW_NON_3_5)) { X debug(("Failed to OpenDevice\n")); X goto abort; X } X TimeIOReq = (struct timerequest *) CreateExtIO(DiskReplyPort, X (long) sizeof (*TimeIOReq)); X X if (TimeIOReq == NULL || OpenDevice(TIMERNAME, UNIT_VBLANK, TimeIOReq, 0L)) X goto abort; X TimeIOReq->tr_node.io_Flags = IOF_QUICK; /* For the first WaitIO() */ X X IntuitionBase = OpenLibrary("intuition.library", 0L); X return DOSTRUE; X Xabort: X HanCloseDown(); X return 0; X} X X/* X * Relabel the disk. We create new labels if necessary. X */ X Xlong XMSRelabel(newname) Xbyte *newname; X{ X#ifdef READONLY X return DOSFALSE; X#else X /* X * A null or empty string means: remove the label, if any. X */ X if (!newname || !*newname) { X if ((int) RootLock->msfl_DirSector >= (int) Disk.rootdir) { X RootLock->msfl_Msd.msd_Name[0] = DIR_DELETED; X RootLock->msfl_Msd.msd_Attributes = 0; X WriteFileLock(RootLock); X RootLock->msfl_Msd = FakeRootDirEntry.de_Msd; X RootLock->msfl_DirSector = -1; X Disk.vollabel = FakeRootDirEntry; X } X return DOSTRUE; X } X /* X * No label yet? Then we must create one, even if we need to move X * something else for it. X */ X X if ((int) RootLock->msfl_DirSector < 0) { X struct MSFileLock *new; X X new = MSLock(RootLock, "><>.\\", EXCLUSIVE_LOCK ^ MODE_CREATEFILE); X if ((new == NULL) && (new = EmptyFileLock)) { X error = 0; X if (new->msfl_DirSector == Disk.rootdir) { X RootLock->msfl_DirSector = Disk.rootdir; X RootLock->msfl_DirOffset = new->msfl_DirOffset; X } else { X /* X * Move something out of the first directory block. Try X * not to move system files or directories (. ..), but X * we'll do it if we need to. Set the root dir date to X * now. X */ X byte *fromsec; X byte *tosec; X register struct MsDirEntry *dir; X X fromsec = GetSec(Disk.rootdir); X tosec = GetSec(new->msfl_DirSector); X X dir = (struct MsDirEntry *) fromsec; X while (dir->msd_Attributes & (ATTR_SYSTEM | ATTR_DIRECTORY)) { X if ((byte *) ++dir >= fromsec + Disk.bps) { X --dir; /* Back to last entry in the block */ X break; /* and move it no matter what */ X } X } X CopyMem(dir, tosec + new->msfl_DirOffset, X (long) sizeof (struct MsDirEntry)); X MarkSecDirty(tosec); X RootLock->msfl_DirSector = Disk.rootdir; X RootLock->msfl_DirOffset = (byte *) dir - fromsec; X X FreeSec(tosec); X FreeSec(fromsec); X X } X } X EmptyFileLock = NULL; X MSUnLock(new); X } X if ((int) RootLock->msfl_DirSector >= Disk.rootdir) { X struct DateStamp dateStamp; X X /* X * The easy part: Copy the name to Disk.vollabel and RootLock. X */ X { X register int i; X register byte *s, X *d; X X s = newname; X d = Disk.vollabel.de_Msd.msd_Name; X for (i = 0; i < 8 + 3; i++) { X if (s[0]) X *d++ = ToUpper(*s++); X else X *d++ = ' '; X } X } X DateStamp(&dateStamp); X ToMSDate(&Disk.vollabel.de_Msd.msd_Date, X &Disk.vollabel.de_Msd.msd_Time, &dateStamp); X RootLock->msfl_Msd = Disk.vollabel.de_Msd; /* Just for the name and X * date */ X WriteFileLock(RootLock); X X return DOSTRUE; X } X return DOSFALSE; X#endif X} X X#ifdef HDEBUG X X_abort() X{ X HanCloseDown(); X RemTask(NULL); X} X X#endif /* HDEBUG */ END_OF_FILE if test 10018 -ne `wc -c <'src/hanmain.c'`; then echo shar: \"'src/hanmain.c'\" unpacked with wrong size! fi # end of 'src/hanmain.c' fi echo shar: End of archive 2 \(of 6\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 5 6 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 6 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mail submissions (sources or binaries) to . Mail comments to the moderator at . Post requests for sources, and general discussion to comp.sys.amiga.