Path: utzoo!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!wuarchive!psuvax1!ukma!xanth!cs.odu.edu!Amiga-Request From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) Newsgroups: comp.sources.amiga Subject: v90i082: MSH 1.5 - Messydos File System Handler , Part04/06 Message-ID: <11501@xanth.cs.odu.edu> Date: 21 Feb 90 02:00:50 GMT Sender: tadguy@cs.odu.edu Reply-To: Olaf 'Rhialto' Seibert Lines: 1338 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 082 Archive-name: devices/msh-1.5/part04 #!/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/msh.man.uu' <<'END_OF_FILE' Xbegin 664 msh.man XM"B`@("`@35-(.BA&:6QE4WES=&5M7-T96US*0H*"@H@("`@()LQ;5-9) XM3D]04UE3(`H@("`@("`@("`@FS!M36]U;G0@35-(.B`*"B`@("`@("`@("!-D XM4T@Z/&%N>2!V86QI9"!F:6QE('-P96-I9FEC871I;VX^+"!O2`@=F%L:60@9FEL92!S<&5C:69I8V%T:6]N/B!I9B!Y[ XM;W5R(&-U6QE($9I;&4@4WES=&5M(&AA;F1L97(@=&AA> XM="`@:&%N9&QE61O2!T:&4@6]U("!U2!D:7-K2P@22!H879E(&YO="!B965N(&%B! XM;&4@('1O("!T97-T("!-4T@Z("!O;B`@:&%R9`H@("`@("`@("`@9&ES:W,[U XM('!R;V-E960@=VET:"!E>'1R96UE(&-A=71I;VXI+B`@"@H@("`@()LQ;4U/K XM54Y43$E35"`*("`@("`@("`@()LP;4$@('-A;7!L92!-;W5N=&QI2!F:6QE('-Y2!B;&]C:W,Z"B`@("`@("`@("`@*B\*Q XM("`@("`@("`@($U32#H@("`@1FEL95-Y61I6P@/2`P(#L@2&EG:$-Y;"`](#2`@=6YI="`@,2P*("`@("`@("`@(&DN92X@($1&,3H@(&%N' XM9"`@=&AE("!M97-S>61I0H@("`@("`@("`@;F%M92!I;G-T96%D(&]F($U32#H@=&AA="!Y;W4@;&EK1 XM92X@("!&;W(@('1H:7,@(&-A6EN9R!T:&4@<')O<&5R"B`@("`@("`@("!D979I8V4@;F%M92!A;F0@=6YI* XM="!N=6UB97(N("!)9B!Y;W4@=VES:"`@=&\@('5S92`@9FQO<'!I97,*"@H@B XM("`@($MO6]U(&UA>0H@("`@("`@("`@ XM:6QL"B`@("`@("`@("!N;W1I8V4@('1H870@('=H96X@('EO=2`@:6YS97)TB XM("!A(&1I2!T:&4@9&ES:RX@(%1H92!R97-U;'0@=VEL;"!B92!T:&%T"B`@("`@("`@- XM("!O;F4@;V8@=&AE('1W;R!W:6QL(&)E('5N86)L92!T;R!R96%D(&ET+"!A1 XM;F0@=&AE;B!L96%V92`@:70*("`@("`@("`@(&%L;VYE('-O('1H870@=&AEX XM(&]T:&5R(&UA>2!U2!T;R!R96%D('1H0 XM92!B;V]T(&)L;V-K("!O9B`@=&AE("!D:7-K+@H@("`@("`@("`@5&AE(')EU XM9W5L87(@06UI9V$@9FEL92!S>7-T96T@9V5TF4@8V]N=')O;"!O=F5R('1H92!D:7-K('5N:70L"B`@L XM("`@("`@("!R96%D('1H92!D:7-K+"!A;F0@6]U(&1O;B=T(&%T=&5M! XM<'0@=&\@(')E9F5R("!T;R`@35-(.@H@("`@("`@("`@=VAI;&4@;W1H97(@% XM9FEL97-Y6EN9R!T;R!R96%D('1H92!D:7-K+B`@"@H@: XM("`@("`@("`@26X@('-O;64@('-I='5A=&EO;G,@('=H97)E('1H97)E(&%RD XM92!M=6QT:7!L92!E&ES=&5N="!F:6QEO XM(&9R;VT*("`@("`@("`@(&$@=W)I=&4M<')O=&5C=&5D(&1I2!H86YD;&5R('EO=0H@O XM("`@("`@("`@=VES:"X@($EF('1H97)E(&ES(&%N>2!P'!E8W1S($U32#H@('1O"B`@("`@("`@("!R96UA:6X@('!R/ XM97-E;G0@979E;B!W:&EL92!T:&5R92!A2!B92!D86YG97)O=7,@[ XM=&\@7-T96US*2`@("`@X XM06UI9V$@4')O9W)A;6UE6]U(&%D9"!B=69F97)S+"!T:&4@2`@87,@=&AE6EN9R!AI XM"B`@("`@("`@("!N96=A=&EV92!N=6UB97(@>6]U(')E9'5C92!T:&4@;G5ML XM8F5R(&]F(&)U9F9E6]U(&-A;B!A;'-O('-P96-I9GD@-C4U,S4L("TRV XM(&ES(#8U-3,T+B!9;W4*("`@("`@("`@('=O=6QD;B=T('=A;G0@('1O("!A* XM9&0@(&UO7-T96US+"!N;W0@= XM86QL(&]P97)A=&EO;G,@=&AA="`@87)E("!A=F%I;&%B;&4@(&9O64M8V%T8VAI;F<@(&1I9F9E6)E(&9O;&QO=V5D(&)Y("!A("!T:')E92UCG XM:&%R86-T97(*("`@("`@("`@(")E>'1E;G-I;VXB+"`@=VAI8V@@(&ES("!S# XM97!A XM<&5R:6]D("@G+B6]U("!WL XM:7-H+"!B=70@=&AE(&-H87)A=&5R(&-H;VEC92!I&-E<'0@('-P86-E("H@/R`@+B`\(#X@+R`]('P@P XM+"`Z"B`@("`@("`@("!A;F0@7"X@(`H*("`@("`@("`@($U32#H@=VEL;"!T/ XM6]U("!O6UO2P@2`@87)E("!N;W0*J XM("`@("`@("`@(")S=6(B(&1I XM=70@('1R;W5B;&4N("`@("A4:&5I7-T96T@9G)O;2!H879E(&$@=')E92!S=')UK XM8W1U0H@("`@("`@("`@=')A=F5R2`@FS!MS XM:&ED9&5N("!F0H@("`@("`@("`@86YY(&YA;64N("`*"@H*("`@("!+;W-M;U-OI XM9G0@("`@("`@("`@("`@("`@("`@("`@("`M,RT@("`@("`@("`@("`@("`@G XM("`@("`@5F5R7-T96US*2`@X XM("`@06UI9V$@4')O9W)A;6UE0H@("`@("`@("`@;65S2!N86UE("(B*2!A;F0@=&AE('!A XM('!R;V=R86US('=H:6-H(&1O;B=T("!K;F]W("!H;W<@('1O("!H86YD;&4@V XM('1H96T*("`@("`@("`@('-H;W5L9"`@(&5I=&AE&ES="`@& XM86YY;6]R92`@;W(@(&EG;F]R92`@=&AE("!L:6YK61O2!A(&)A8VMU<"!P6QI;F1E6EN9R`@9&5V:6-E"B`@("`@("`@("!D61I XM+B!/;FQY('1H92!L;V=I8V%L(&QA>6]U=`H@("`@("`@("`@:6YF;W)M871I= XM;VX@:7,@=7-E9#H@4VEZ92!O9B!A("!B;&]C:RP@(&YU;6)E7-T96US*2`@("`@06UI9V$@4')O9W)A;6UE2!F;W(@;64N*2!)9B!Y;W4@=VES:"!T;R!F;W)M870@= XM6]U2`@;F]T("!C:&5C:V5D("!F;W(@(&EN=&5G2`@" XM86YD"B`@("`@("`@("!C;VYS:7-T96YC>2X@(%1H92!&050@:7,@87-S=6UEC XM9"!T;R!H879E(#$R+6)I="`@96YT61OQ XM'1E;G-I;VXI($ET("!I2!T;R!U2 XM2!S96-T;W(I(&)E9F]R3 XM92P@($U32#H@('=I;&P*("`@("`@("`@('1R>2`@=&\@(&UO=F4@(&$@(&9I> XM;&4@(&9R;VT@('1H92`@9FER2!B;&]C:R!T;PH@("`@[ XM("`@("`@7-T96US(`H*P XM("`@("`@("`@()LP;51H92!-97-S>49I;&53>7-T96T@(&ES("!U;F9O2!F:6QEK XM('-Y6)E($%M:6=A1$]30 XM(&ES(&YO="!S;R!S;6%R="!T;R!S964*("`@("`@("`@('1H870@='=O(&9IZ XM;&4@6)E('EO=2!D;VXG; XM="!N965D('1O(&AA=F4@;75L=&EP;&4@8V]P:65S"B`@("`@("`@("!O9B!-R XM97-S>49I;&53>7-T96T@;VX@>6]U7-T96US*2`@("`@06UI9V$@4')O9W)A;6UE XM251)15,@"B`@("`@("`@("";,&U!('!R;V=R86T@8V%L;&5D()LS;6UE6]U("!T;R`@9F]R;6%T("!D:7-K XM97-S>69M="`\=6YI=&YR/B`\9&5V:6-E/B`*"B`@("`@("`@("!4:&4@("`@D XM/&1E=FEC93X@("!N86UE("`@:7,@("!O<'1I;VYA;"`@(&%N9"`@(&1E9F%UE XM;'1S("`@=&\*("`@("`@("`@(")M97-S>61I"`@/2`@Q XM:&5X861E8VEM86PL("`P("`]("!O8W1A;"P@(&%N9"`@979E&5S\ XM("!A2`@8W)E871E("`X+"`@.2`@W XM;W(@(#$P('-E8W1O0H@("`@("`@("`@86YS=V5R:6YG('1H_ XM92!Q=65S=&EO;B`B4V5C=&]R2`@0 XM=&AE("!F:7)S="!P87)T('=I=&@@=&AE(&)O;W1B;&]C:RP@1D%4(&%N9"!D: XM:7)E8W1O6]U(&%RC XM92!S=&EL;"!A=V%K92P@>6]U(&UU7-T96US(&UO=6YT960N("!.;W1E2 XM+"!H;W=E=F5R+"!T:&%T"B`@("`@("`@("!$:7-K0V]P>2!L;V]K61O2`@9FEL92!S>7-T96T@:&%N9&QE'src/hanfile.c' <<'END_OF_FILE' X/*- X * $Id: hanfile.c,v 1.6 90/02/10 21:38:26 Rhialto Exp $ X * $Log: hanfile.c,v $ X * Revision 1.6 90/02/10 21:38:26 Rhialto X * Optimized 12-bit fat unpacking. X * X * Revision 1.5 90/01/27 20:26:51 Rhialto X * Fixed ATTR_ARCHIVED bit in MSWrite() X * X * Revision 1.4 90/01/23 02:32:23 Rhialto X * Add 16-bit FAT support. X * X * Revision 1.3 90/01/23 00:39:04 Rhialto X * Always return -1 on MSWrite error. X * X * Revision 1.2 89/12/17 23:04:39 Rhialto X * Add ATTR_READONLY support X * X * Revision 1.1 89/12/17 20:03:11 Rhialto X * Initial revision X * X * HANFILE.C X * X * The code for the messydos file system handler. X * X * This parts handles files and the File Allocation Table. X * X * This code is (C) Copyright 1989,1990 by Olaf Seibert. All rights reserved. X * May not be used or copied without a licence. X-*/ X X#include "han.h" X#include "dos.h" X X#ifdef DEBUG X# define debug(x) dbprintf x X#else X# define debug(x) X#endif X Xextern char DotDot[1 + 8 + 3]; X X/* X * Read the FAT from the disk, and count the free clusters. X */ X Xint XGetFat() X{ X int i; X byte *secptr; X X if (!Fat && !(Fat = AllocMem((long) Disk.bps * Disk.spf, BufMemType))) { X debug(("No memory for FAT\n")); X return 0; X } X FatDirty = FALSE; X for (i = 0; i < Disk.spf; i++) { X if (secptr = GetSec(Disk.res + i)) { X CopyMem(secptr, Fat + i * Disk.bps, (long) Disk.bps); X FreeSec(secptr); X } else { X /* q&d way to set the entire FAT to FAT_EOF */ X setmem(Fat + i * Disk.bps, (int) Disk.bps, FAT_EOF); /* 0xFF */ X } X } X X debug(("counting free clusters\n")); X X Disk.nsectsfree = 0; X for (i = MS_FIRSTCLUST; i <= Disk.maxclst; i++) { X if (GetFatEntry((word) i) == FAT_UNUSED) X Disk.nsectsfree += Disk.spc; X } X X return 1; X} X Xvoid XFreeFat() X{ X if (Fat) { X FreeMem(Fat, (long) Disk.bps * Disk.spf); X Fat = NULL; X FatDirty = FALSE; X } X} X X/*- X * The FAT consists of 12-bits entries for each cluster, X * indicating the next cluster in the chain, or FFF for EOF. X * X * Every two entries are packed in three bytes, like this: X * X * Two entries abc 123 (for one cluster and the next) X * are packed as bc 3a 12 X-*/ X Xword XGetFatEntry(cluster) Xword cluster; X{ X if (!Fat && !GetFat()) X return FAT_EOF; X X if (Disk.fat16bits) { X return OtherEndianWord(((word *)Fat)[cluster]); X } else { X register int offset = 3 * (cluster / 2); X register word twoentries; X X if (cluster & 1) { X twoentries = Fat[offset + 1] >> 4; X twoentries |= Fat[offset + 2] << 4; X } else { X twoentries = Fat[offset]; X twoentries |= (Fat[offset + 1] & 0x0F) << 8; X } X X /* X * Convert the special values 0xFF0 .. 0xFFF to 16 bits so they X * can be checked consistently. X */ X if (twoentries >= 0xFF0) X twoentries |= 0xF000; X X return twoentries; X } X} X X#ifndef READONLY X Xvoid XSetFatEntry(cluster, value) Xword cluster; Xword value; X{ X if (!Fat && !GetFat()) X return; X X if (Disk.fat16bits) { X ((word *)Fat)[cluster] = OtherEndianWord(value); X } else { X register int offset = 3 * (cluster / 2); X X if (cluster & 1) { /* 123 kind of entry */ X Fat[offset + 2] = value >> 4; X Fat[offset + 1] &= 0x0F; X Fat[offset + 1] |= (value & 0x0F) << 4; X } else { /* abc kind of entry */ X Fat[offset + 0] = value; X Fat[offset + 1] &= 0xF0; X Fat[offset + 1] |= (value >> 8) & 0x0F; X } X } X X FatDirty = TRUE; X} X X/* X * Find a free cluster to install as the one following this one. Start X * looking for it right after the given one, so we allocate the cluster X * chain as contiguous as possible. If we run off the end of the disk, we X * start again at the beginning. The termination test should not be X * necessary (and won't work if we are given MSFIRSTCLUST - 1) but won't X * harm either. X */ X Xword XFindFreeCluster(prev) Xword prev; X{ X register word i; X X if (prev == 0 || prev == FAT_EOF) X prev = MS_FIRSTCLUST - 1; X X if (Disk.nsectsfree >= Disk.spc) { X for (i = prev + 1; i != prev; i++) { X if (i > Disk.maxclst) /* Wrap around */ X i = MS_FIRSTCLUST; X if (GetFatEntry(i) == FAT_UNUSED) { X SetFatEntry(i, FAT_EOF); X if (prev >= MS_FIRSTCLUST) X SetFatEntry(prev, i); X Disk.nsectsfree -= Disk.spc; X return i; X } X } X } X return FAT_EOF; X} X X/* X * Add a cluster to a cluster chain. For input, we get some cluster we X * know that is on the chain, even if it is the first one. X */ X Xword XExtendClusterChain(cluster) Xregister word cluster; X{ X register word nextcluster; X X /* X * Find the end of the cluster chain to tack the new cluster on to. X * Then FindFreeCluster will (or won't) extend the chain for us. X */ X if (cluster != 0) X while ((nextcluster = NextCluster(cluster)) != FAT_EOF) { X cluster = nextcluster; X } X X return FindFreeCluster(cluster); X} X X/* X * Free a chain of clusters by setting their FAT entries to FAT_UNUSED. X */ X Xvoid XFreeClusterChain(cluster) Xregister word cluster; X{ X register word nextcluster; X X while (cluster != FAT_EOF) { X nextcluster = NextCluster(cluster); X SetFatEntry(cluster, FAT_UNUSED); X Disk.nsectsfree += Disk.spc; X cluster = nextcluster; X } X} X X#endif /* READONLY */ X X/* X * This routine opens a file. X */ X Xstruct MSFileHandle * XMSOpen(parentdir, name, mode) Xstruct MSFileLock *parentdir; Xchar *name; Xlong mode; X{ X struct MSFileLock *fl; X struct MSFileHandle *fh = NULL; X long lockmode; X X switch (mode) { X case MODE_NEWFILE: X case MODE_READWRITE: X lockmode = EXCLUSIVE_LOCK ^ MODE_CREATEFILE; X break; X default: X mode = MODE_OLDFILE; X case MODE_OLDFILE: X lockmode = SHARED_LOCK; X } X X if (fl = MSLock(parentdir, name, lockmode)) { Xmakefh: X if (fl->msfl_Msd.msd_Attributes & ATTR_DIR) { X error = ERROR_OBJECT_WRONG_TYPE; X MSUnLock(fl); X } else if (fh = AllocMem((long) sizeof (*fh), MEMF_PUBLIC)) { X#ifndef READONLY X /* Do we need to truncate the file? */ X if (mode == MODE_NEWFILE && fl->msfl_Msd.msd_Cluster) { X FreeClusterChain(fl->msfl_Msd.msd_Cluster); X fl->msfl_Msd.msd_Cluster = 0; X fl->msfl_Msd.msd_Filesize = 0; X UpdateFileLock(fl); X } X#endif X fh->msfh_Cluster = fl->msfl_Msd.msd_Cluster; X fh->msfh_SeekPos = 0; X fh->msfh_FileLock = fl; X } else { X error = ERROR_NO_FREE_STORE; X MSUnLock(fl); X } X return fh; X } X#ifndef READONLY X /* X * If the file was not found, see if we can make a new one. Therefore X * we need to have an empty spot in the desired directory, and create X * an MSFileLock for it. X */ X X if (!(lockmode & MODE_CREATEFILE) && (fl = EmptyFileLock)) { X debug(("Creating new file\n")); X EmptyFileLock = NULL; X fl->msfl_Msd.msd_Attributes = ATTR_ARCHIVED; X UpdateFileLock(fl); X X goto makefh; X } X if (EmptyFileLock) { X MSUnLock(EmptyFileLock); X EmptyFileLock = NULL; X } X#endif X X return NULL; X} X Xvoid XMSClose(fh) Xregister struct MSFileHandle *fh; X{ X if (fh) { X MSUnLock(fh->msfh_FileLock); X FreeMem(fh, (long) sizeof (*fh)); X } X} X Xlong XMSSeek(fh, position, mode) Xstruct MSFileHandle *fh; Xlong position; Xlong mode; X{ X long oldpos = fh->msfh_SeekPos; X long newpos = oldpos; X long filesize = fh->msfh_FileLock->msfl_Msd.msd_Filesize; X word cluster = fh->msfh_Cluster; X word oldcluster; X word newcluster; X X switch (mode) { X case OFFSET_BEGINNING: X newpos = position; X break; X case OFFSET_CURRENT: X newpos += position; X break; X case OFFSET_END: X newpos = filesize - position; X break; X } X X if (newpos < 0 || newpos > filesize) { X error = ERROR_SEEK_ERROR; X return -1; X } X newcluster = newpos / Disk.bpc; X oldcluster = oldpos / Disk.bpc; X X if (oldcluster > newcluster) { /* Seek backwards */ X cluster = fh->msfh_FileLock->msfl_Msd.msd_Cluster; X oldcluster = 0; X } X if (oldcluster < newcluster) { X if (CheckLock(fh->msfh_FileLock)) X return -1L; X while (oldcluster < newcluster) { X cluster = NextCluster(cluster); X oldcluster++; X } X } X fh->msfh_Cluster = cluster; X fh->msfh_SeekPos = newpos; X X return oldpos; X} X Xlong XMSRead(fh, userbuffer, size) Xregister struct MSFileHandle *fh; Xregister byte *userbuffer; Xregister long size; X{ X long oldsize; X X if (CheckLock(fh->msfh_FileLock)) X return -1L; X X if (fh->msfh_SeekPos + size > fh->msfh_FileLock->msfl_Msd.msd_Filesize) X size = fh->msfh_FileLock->msfl_Msd.msd_Filesize - fh->msfh_SeekPos; X X oldsize = size; X X while (size > 0) { X word offset; X word sector; X byte *diskbuffer; X long insector; X long tocopy; X X offset = fh->msfh_SeekPos % Disk.bpc; X sector = ClusterOffsetToSector(fh->msfh_Cluster, (word) offset); X if (diskbuffer = GetSec(sector)) { X offset %= Disk.bps; X insector = Disk.bps - offset; X tocopy = lmin(size, insector); X X CopyMem(diskbuffer + offset, userbuffer, tocopy); X userbuffer += tocopy; X size -= tocopy; X FreeSec(diskbuffer); X /* MSSeek(fh, tocopy, (long) OFFSET_CURRENT); */ X if ((fh->msfh_SeekPos += tocopy) % Disk.bpc == 0) X fh->msfh_Cluster = NextCluster(fh->msfh_Cluster); X } else { /* Read error. Return amount successfully X * read, if any. Else return -1 for error. */ X if (size == oldsize) { X return -1L; X } X return oldsize - size; X } X } X X return oldsize; X} X Xlong XMSWrite(fh, userbuffer, size) Xregister struct MSFileHandle *fh; Xregister byte *userbuffer; Xregister long size; X{ X#ifdef READONLY X return -1; X#else X long oldsize; X struct MSFileLock *fl = fh->msfh_FileLock; X word prevclust = fl->msfl_Msd.msd_Cluster; X word update = 0; X X if (CheckLock(fl)) X return -1; X X if (fl->msfl_Msd.msd_Attributes & ATTR_READONLY) { X error = ERROR_WRITE_PROTECTED; X return -1; X } X X oldsize = size; X X while (size > 0) { X /* X * Do we need to extend the file? X */ X X if (fh->msfh_Cluster == 0 || fh->msfh_Cluster == FAT_EOF) { X word newclust; X X newclust = ExtendClusterChain(prevclust); X debug(("Extend with %d\n", newclust)); X if (newclust != FAT_EOF) { X if (prevclust == 0) { /* Record first cluster in dir */ X fl->msfl_Msd.msd_Cluster = newclust; X } X fh->msfh_Cluster = newclust; X prevclust = newclust; X } else { X error = ERROR_DISK_FULL; X goto error; X } X } X { X word offset; X word sector; X byte *diskbuffer; X long insector; X long tocopy; X X offset = fh->msfh_SeekPos % Disk.bpc; X sector = ClusterOffsetToSector(fh->msfh_Cluster, (word) offset); X offset %= Disk.bps; X insector = Disk.bps - offset; X tocopy = lmin(size, insector); X X if (tocopy == Disk.bps) X diskbuffer = EmptySec(sector); X else X diskbuffer = GetSec(sector); X X if (diskbuffer != NULL) { X CopyMem(userbuffer, diskbuffer + offset, tocopy); X userbuffer += tocopy; X size -= tocopy; X MarkSecDirty(diskbuffer); X FreeSec(diskbuffer); X /* MSSeek(fh, tocopy, (long) OFFSET_CURRENT); */ X if ((fh->msfh_SeekPos += tocopy) % Disk.bpc == 0) X fh->msfh_Cluster = NextCluster(fh->msfh_Cluster); X if (fh->msfh_SeekPos > fl->msfl_Msd.msd_Filesize) X fl->msfl_Msd.msd_Filesize = fh->msfh_SeekPos; X fl->msfl_Msd.msd_Attributes |= ATTR_ARCHIVED; X update = 1; X } else { /* Write error. */ X error: X if (update) X UpdateFileLock(fl); X#if 1 X return -1; /* We loose the information about how much X * data we wrote, but the standard file system X * seems to do it this way. */ X#else X if (size == oldsize) { X return -1; X } X return oldsize - size; /* Amount successfully written */ X#endif X } X } X } X X if (update) X UpdateFileLock(fl); X X return oldsize; X#endif X} X Xlong XMSDeleteFile(parentdir, name) Xstruct MSFileLock *parentdir; Xbyte *name; X{ X#ifdef READONLY X return DOSFALSE; X#else X register struct MSFileLock *fl; X X fl = MSLock(parentdir, name, EXCLUSIVE_LOCK); X if (fl) { X if (fl->msfl_Msd.msd_Attributes & ATTR_READONLY) { X error = ERROR_DELETE_PROTECTED; X goto error; X } X if (fl->msfl_Msd.msd_Attributes & ATTR_DIRECTORY) { X struct FileInfoBlock fib; X X /* X * We normally can't get REAL exclusive locks on directories, X * so we check here just to be sure. We don't want to delete X * anyone's current directory, do we? X */ X X if (fl->msfl_Refcount != 1 || fl == RootLock) { X error = ERROR_OBJECT_IN_USE; X goto error; X } X if (MSExamine(fl, &fib) && /* directory itself */ X MSExNext(fl, &fib)) { /* should fail */ X if (error == 0) { X not_empty: X error = ERROR_DIRECTORY_NOT_EMPTY; X error: X MSUnLock(fl); X return DOSFALSE; X } X } X if (error != ERROR_NO_MORE_ENTRIES) X goto error; X X error = 0; X } X if (fl->msfl_Msd.msd_Cluster) X FreeClusterChain(fl->msfl_Msd.msd_Cluster); X fl->msfl_Msd.msd_Name[0] = DIR_DELETED; X WriteFileLock(fl); X MSUnLock(fl); X X return DOSTRUE; X } X return DOSFALSE; X#endif X} X Xlong XMSSetDate(parentdir, name, datestamp) Xstruct MSFileLock *parentdir; Xbyte *name; Xstruct DateStamp *datestamp; X{ X#ifdef READONLY X return DOSFALSE; X#else X register struct MSFileLock *fl; X X fl = MSLock(parentdir, name, EXCLUSIVE_LOCK); X if (fl) { X ToMSDate(&fl->msfl_Msd.msd_Date, &fl->msfl_Msd.msd_Time, datestamp); X WriteFileLock(fl); X MSUnLock(fl); X X return DOSTRUE; X } X return DOSFALSE; X#endif X} X X/* X * Create a new directory, with its own initial "." and ".." entries. X */ X Xstruct MSFileLock * XMSCreateDir(parentdir, name) Xstruct MSFileLock *parentdir; Xbyte *name; X{ X#ifdef READONLY X return DOSFALSE; X#else X register struct MSFileLock *fl; X X /* X * Go create a new file. If we fail later, we have an empty file that X * we delete again. X */ X X fl = MSLock(parentdir, name, EXCLUSIVE_LOCK ^ MODE_CREATEFILE); X if (fl || error == ERROR_OBJECT_IN_USE) { X error = ERROR_OBJECT_EXISTS; X goto error; X } X if (error != 0) { X goto error; X } X if (fl = EmptyFileLock) { X debug(("Creating new dir\n")); X EmptyFileLock = NULL; X if ((fl->msfl_Msd.msd_Cluster = FindFreeCluster(FAT_EOF)) != FAT_EOF) { X struct MsDirEntry direntry; X byte *sec; X word sector; X X sector = ClusterToSector(fl->msfl_Msd.msd_Cluster); X sec = EmptySec(sector); X if (sec == NULL) X goto error_no_free_store; X setmem(sec, (int) Disk.bps, 0); X X /* X * Turn the file into a directory. X */ X fl->msfl_Msd.msd_Attributes = ATTR_DIRECTORY; X UpdateFileLock(fl); X X /* X * Create the "." entry. X */ X direntry = fl->msfl_Msd; X strncpy(direntry.msd_Name, DotDot + 1, 8 + 3); X OtherEndianMsd(&direntry); X ((struct MsDirEntry *) sec)[0] = direntry; X X /* X * Get the real parent directory because we will duplicate the X * directory entry in the subdirectory. X */ X X parentdir = MSParentDir(fl); X if (parentdir == NULL) /* Cannot happen */ X parentdir = MSDupLock(RootLock); X X /* X * Create the ".." entry. X */ X direntry = parentdir->msfl_Msd; X strncpy(direntry.msd_Name, DotDot, 8 + 3); X direntry.msd_Attributes = ATTR_DIRECTORY; X OtherEndianMsd(&direntry); X ((struct MsDirEntry *) sec)[1] = direntry; X X MSUnLock(parentdir); X X MarkSecDirty(sec); X FreeSec(sec); X X /* X * Clear out the rest of the newly created directory. X */ X X while ((sector = NextClusteredSector(sector)) != SEC_EOF) { X sec = EmptySec(sector); X if (sec == NULL) X goto error_no_free_store; X setmem(sec, (int) Disk.bps, 0); X MarkSecDirty(sec); X FreeSec(sec); X } X } else { X MSUnLock(fl); X fl = NULL; X MSDeleteFile(parentdir, name); X error = ERROR_DISK_FULL; X } X } X if (EmptyFileLock) { X MSUnLock(EmptyFileLock); X EmptyFileLock = NULL; X } X return fl; X Xerror_no_free_store: X error = ERROR_NO_FREE_STORE; Xerror: X if (fl) X MSUnLock(fl); X return DOSFALSE; X#endif X} X X/* X * Rename a file or directory, possibly moving it to a different X * directory. X * X * "Tuned" to also work in full directories by first deleting the source X * name, then look for a slot to put the destination name. If that fails, X * we undo the deletion. By playing with the cache, we even avoid a write X * of the sector with the undeleted entry. X */ X Xlong XMSRename(slock, sname, dlock, dname) Xstruct MSFileLock *slock; Xbyte *sname; Xstruct MSFileLock *dlock; Xbyte *dname; X{ X#ifdef READONLY X return DOSFALSE; X#else X struct MSFileLock *sfl; X struct MSFileLock *dfl; X long success; X struct CacheSec *scache; X ulong oldstatus; X X success = DOSFALSE; X scache = NULL; X dfl = NULL; X X sfl = MSLock(slock, sname, SHARED_LOCK); X if (sfl == NULL || sfl == RootLock) X goto error; X X /* X * Now we are going to pull a dirty trick with the cache. We are going X * to temporarily delete the source file, in the chache only, and X * undelete it again if we cannot create the new name. And above all X * we want to avoid unnecessary writes if we decide not to do the X * deletion after all. X */ X { X byte *sec; X byte old; X X if ((sec = GetSec(sfl->msfl_DirSector)) == NULL) X goto error; X scache = FindSecByBuffer(sec); X oldstatus = scache->sec_Refcount; X X old = sfl->msfl_Msd.msd_Name[0]; X sfl->msfl_Msd.msd_Name[0] = DIR_DELETED; X WriteFileLock(sfl); X sfl->msfl_Msd.msd_Name[0] = old; X X /* X * Don't FreeSec it yet; we don't want it written out to disk. X */ X } X X /* X * Now we have freed the directory entry of the source name, we might X * be able to use it for the destination name. But only if we also X * temporarily hide the MSFileLock on that spot. Gross hack ahead! X */ X X sfl->msfl_DirOffset = ~sfl->msfl_DirOffset; X dfl = MSLock(dlock, dname, EXCLUSIVE_LOCK ^ MODE_CREATEFILE); X sfl->msfl_DirOffset = ~sfl->msfl_DirOffset; X X if (dfl != NULL || error == ERROR_OBJECT_IN_USE) { X error = ERROR_OBJECT_EXISTS; X goto undelete; X } X dfl = EmptyFileLock; X EmptyFileLock = NULL; X if (dfl == NULL) { X /* X * Sigh, we could not create the new name. But because of that, we X * are sure that we need to write nothing to the disk at all. So X * we can safely reset the sector-dirty flag to what it was X * before, if we also restore the cached sector. X */ Xundelete: X WriteFileLock(sfl); X scache->sec_Refcount = oldstatus; X goto error; X } X /* X * Now, if the moved entry was a directory, and it was moved to a X * different directory, we need to adapt its "..", which is the second X * entry. X */ X X if (sfl->msfl_Msd.msd_Attributes & ATTR_DIRECTORY && X sfl->msfl_Parent != dfl->msfl_Parent) { X struct MSFileLock *parentdir; X struct MsDirEntry *dir; X X if (dir = (struct MsDirEntry *) X GetSec(DirClusterToSector(sfl->msfl_Msd.msd_Cluster))) { X parentdir = MSParentDir(dfl); X /* X * Copy everything except the name which must remain "..". But X * first a quick consistency check... X */ X debug(("Creating new \"..\" ")); X if (dir[1].msd_Name[1] == '.') { X CopyMem(&parentdir->msfl_Msd.msd_Attributes, X &dir[1].msd_Attributes, X (long) sizeof (struct MsDirEntry) - X OFFSETOF(MsDirEntry, msd_Attributes)); X dir[1].msd_Attributes = ATTR_DIRECTORY; X OtherEndianMsd(&dir[1]); X MarkSecDirty(dir); X } X#ifdef DEBUG X else X debug(("!!! No \"..\" found ??\n")); X#endif X MSUnLock(parentdir); X FreeSec(dir); X } X } X /* X * Move the name from the new entry to the old filelock. We do this X * for the case that somebody else has a lock on the (possibly moved) X * file/directory. Also move the other administration. X */ X X strncpy(sfl->msfl_Msd.msd_Name, dfl->msfl_Msd.msd_Name, 8 + 3); X sfl->msfl_DirSector = dfl->msfl_DirSector; X sfl->msfl_DirOffset = dfl->msfl_DirOffset; X /* X * Free the old, and get the new parent directory. They might be the X * same, of course... X */ X MSUnLock(sfl->msfl_Parent); X sfl->msfl_Parent = dfl->msfl_Parent; X dfl->msfl_Parent = NULL; X sfl->msfl_Msd.msd_Attributes &= ~ATTR_ARCHIVED; X WriteFileLock(sfl); /* Write the new name; the old name X * already has been deleted. */ X success = DOSTRUE; X Xerror: X if (sfl) X MSUnLock(sfl); X if (dfl) X MSUnLock(dfl); X if (scache) X FreeSec(scache->sec_Data); X X return success; X#endif X} END_OF_FILE if test 20226 -ne `wc -c <'src/hanfile.c'`; then echo shar: \"'src/hanfile.c'\" unpacked with wrong size! fi # end of 'src/hanfile.c' fi echo shar: End of archive 4 \(of 6\). cp /dev/null ark4isdone 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.