/*- * $Id: hanmain.c,v 1.4 90/01/27 20:13:00 Rhialto Exp $ * $Log: hanmain.c,v $ * Revision 1.4 90/01/27 20:13:00 Rhialto * *** empty log message *** * * Revision 1.3 89/12/17 21:29:51 Rhialto * *** empty log message *** * * Revision 1.1 89/12/17 20:02:31 Rhialto * Initial revision * * * HANMAIN.C * * The code for the messydos file system handler. * * Some start/stop stuff that is not really part of the * file system itself but that must be done anyway. * * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May * not be used or copied without a licence. -*/ #include "han.h" #include "dos.h" #ifdef DEBUG # define debug(x) dbprintf x #else # define debug(x) #endif extern char DotDot[1 + 8 + 3]; struct Library *IntuitionBase; static char RCSId[] = "Messydos filing system $Revision: 1.4 $ $Date: 90/01/27 20:13:00 $, by Olaf Seibert"; byte ToUpper(ch) register byte ch; { if (ch >= 'a' && ch <= 'z') return ch + ('A' - 'a'); if (ch == '.') return '!'; return ch & ~DIR_DELETED_MASK; } long lmin(a, b) long a, b; { return (a < b) ? a : b; } byte * ZapSpaces(begin, end) register byte *begin, *end; { while (end > begin && end[-1] == ' ') *--end = '\0'; return end; } /* * Map an arbitrary file name to MS-DOS conventions. The output format is * 8+3 without dot, padded with spaces, suitable for direct comparison * with directory entries. Return a pointer to the delimiter found ('\0' * or '/'). [[Make sure that Examine/ExNext return a proper inverse of * this...]] */ byte * ToMSName(dest, source) byte *dest; register byte *source; { byte *dotp; byte *slashp; register int i, len; if (*source == '/') { /* parentdir */ strncpy(dest, DotDot, 8 + 3); /* ".." */ return source; } /* * Remove any strictly leading dots. .info -> info, .indent.pro -> * indent.pro, .profile -> profile, etc. */ while (*source == '.') source++; /* * Find dot and slash which are delimiters of name and extension. */ { register byte *cp; cp = source; while (*cp) { if (*cp == '.' || *cp == '/') break; cp++; } dotp = cp; while (*cp) { if (*cp == '/') break; cp++; } slashp = cp; } len = dotp - source; if (len > 8) len = 8; for (i = 0; i < len; i++) { *dest++ = ToUpper(*source++); } for (; i < 8; i++) { *dest++ = ' '; } source = dotp + 1; len = slashp - source; /* so will be -1 if no suffix */ if (len > 3) len = 3; for (i = 0; i < len; i++) { *dest++ = ToUpper(*source++); } for (; i < 3; i++) { *dest++ = ' '; } return slashp; } /* * Do the Info call. */ long MSDiskInfo(infodata) struct InfoData *infodata; { extern DEVLIST *VolNode; setmem(infodata, sizeof (*infodata), 0); infodata->id_DiskState = IDDiskState; infodata->id_DiskType = IDDiskType; infodata->id_UnitNumber = UnitNr; infodata->id_VolumeNode = (BPTR) CTOB(VolNode); infodata->id_InUse = LockList ? 1 : 0; if (IDDiskType == ID_DOS_DISK) { infodata->id_NumBlocks = Disk.nsects; infodata->id_NumBlocksUsed = Disk.nsects - Disk.nsectsfree; infodata->id_BytesPerBlock = Disk.bps; } return DOSTRUE; } /* * We (re-)establish our List of MSFileLocks after a disk has been * (re-)inserted. If there are no known locks, we make the root lock from * the volume label, if there is one. * * We get a special cookie to hand to a cleanup routine that we must call * when finally all locks on the current disk are UnLock()ed. (this is * actually the volume node, but we don't want to know that.) * * This must be called some time after IdentifyDisk(). */ void MSDiskInserted(locks, cookie) register struct LockList **locks; void *cookie; { debug(("MSDiskInserted %08lx\n", cookie)); LockList = *locks; if (LockList == NULL) { LockList = NewLockList(cookie); RootLock = MakeLock(NULL, &Disk.vollabel, SHARED_LOCK); } else { RootLock = MSDupLock(GetTail(&LockList->ll_List)); } InitCacheList(); } /* * Remove the current disk. A place is offered to save the current * LockList to restore later. We must unlock the root lock since it isn't * a real reference to the disk, just a placeholder for dummies that hand * us NULL locks. */ int MSDiskRemoved(locks) register struct LockList **locks; { #ifndef READONLY if (FatDirty || (DelayState & DELAY_DIRTY)) MSUpdate(1); /* Force a requester */ #endif FreeFat(); FreeCacheList(); IDDiskType = ID_NO_DISK_PRESENT; *locks = NULL; if (RootLock == NULL) { debug(("MSDiskRemoved with no RootLock\n")); return 1; } #ifdef DEBUG if (RootLock != GetTail(&LockList->ll_List)) { debug(("RootLock not at end of LockList!\n")); /* Get the lock on the root dir at the tail of the List */ Remove(RootLock); AddTail(&LockList->ll_List, RootLock); } #endif /* * If there are no real locks on the disk, we need not keep any * information about it. */ MSUnLock(RootLock); /* may call FreeLockList and free VolNode * (!) */ RootLock = NULL; if (LockList) { *locks = LockList; /* VolNode can't be gone now... */ LockList = NULL; return 0; /* not all references gone */ } else { return 1; /* all gone, even the VolNode */ } } void HanCloseDown() { #ifdef DEBUG register struct MSFileLock *fl; while (LockList && (fl = (struct MSFileLock *) GetHead(&LockList->ll_List))) { debug(("UNLOCKING %08lx: ", fl)); PrintDirEntry(&fl->msfl_Msd); MSUnLock(fl); /* Remove()s it from this List */ } #endif if (DiskIOReq) { if (DiskIOReq->iotd_Req.io_Unit) { MSUpdate(1); CloseDevice(DiskIOReq); } DeleteExtIO(DiskIOReq); DiskIOReq = NULL; } if (TimeIOReq) { if (TimeIOReq->tr_node.io_Unit) { WaitIO(TimeIOReq); CloseDevice(TimeIOReq); } DeleteExtIO(TimeIOReq); TimeIOReq = NULL; } if (DiskReplyPort) { DeletePort(DiskReplyPort); DiskReplyPort = NULL; } if (IntuitionBase) { CloseLibrary(IntuitionBase); IntuitionBase = NULL; } } int HanOpenUp() { LockList = NULL; RootLock = NULL; Fat = NULL; IDDiskState = ID_WRITE_PROTECTED; IDDiskType = ID_NO_DISK_PRESENT; DelayState = DELAY_OFF; Disk.bps = MS_BPS; InitCacheList(); TimeIOReq = NULL; #ifdef DEBUG if (!(DiskReplyPort = CreatePort("MSH:disk.replyport", -1L))) goto abort; #else if (!(DiskReplyPort = CreatePort(NULL, -1L))) goto abort; #endif debug(("DiskReplyPort = 0x%08lx\n", DiskReplyPort)); if (!(DiskIOReq = CreateExtIO(DiskReplyPort, (long) sizeof (*DiskIOReq)))) { debug(("Failed to CreateExtIO\n")); goto abort; } if (OpenDevice(DevName, UnitNr, DiskIOReq, DevFlags | TDF_ALLOW_NON_3_5)) { debug(("Failed to OpenDevice\n")); goto abort; } TimeIOReq = (struct timerequest *) CreateExtIO(DiskReplyPort, (long) sizeof (*TimeIOReq)); if (TimeIOReq == NULL || OpenDevice(TIMERNAME, UNIT_VBLANK, TimeIOReq, 0L)) goto abort; TimeIOReq->tr_node.io_Flags = IOF_QUICK; /* For the first WaitIO() */ IntuitionBase = OpenLibrary("intuition.library", 0L); return DOSTRUE; abort: HanCloseDown(); return 0; } /* * Relabel the disk. We create new labels if necessary. */ long MSRelabel(newname) byte *newname; { #ifdef READONLY return DOSFALSE; #else /* * A null or empty string means: remove the label, if any. */ if (!newname || !*newname) { if ((int) RootLock->msfl_DirSector >= (int) Disk.rootdir) { RootLock->msfl_Msd.msd_Name[0] = DIR_DELETED; RootLock->msfl_Msd.msd_Attributes = 0; WriteFileLock(RootLock); RootLock->msfl_Msd = FakeRootDirEntry.de_Msd; RootLock->msfl_DirSector = -1; Disk.vollabel = FakeRootDirEntry; } return DOSTRUE; } /* * No label yet? Then we must create one, even if we need to move * something else for it. */ if ((int) RootLock->msfl_DirSector < 0) { struct MSFileLock *new; new = MSLock(RootLock, "><>.\\", EXCLUSIVE_LOCK ^ MODE_CREATEFILE); if ((new == NULL) && (new = EmptyFileLock)) { error = 0; if (new->msfl_DirSector == Disk.rootdir) { RootLock->msfl_DirSector = Disk.rootdir; RootLock->msfl_DirOffset = new->msfl_DirOffset; } else { /* * Move something out of the first directory block. Try * not to move system files or directories (. ..), but * we'll do it if we need to. Set the root dir date to * now. */ byte *fromsec; byte *tosec; register struct MsDirEntry *dir; fromsec = GetSec(Disk.rootdir); tosec = GetSec(new->msfl_DirSector); dir = (struct MsDirEntry *) fromsec; while (dir->msd_Attributes & (ATTR_SYSTEM | ATTR_DIRECTORY)) { if ((byte *) ++dir >= fromsec + Disk.bps) { --dir; /* Back to last entry in the block */ break; /* and move it no matter what */ } } CopyMem(dir, tosec + new->msfl_DirOffset, (long) sizeof (struct MsDirEntry)); MarkSecDirty(tosec); RootLock->msfl_DirSector = Disk.rootdir; RootLock->msfl_DirOffset = (byte *) dir - fromsec; FreeSec(tosec); FreeSec(fromsec); } } EmptyFileLock = NULL; MSUnLock(new); } if ((int) RootLock->msfl_DirSector >= Disk.rootdir) { struct DateStamp dateStamp; /* * The easy part: Copy the name to Disk.vollabel and RootLock. */ { register int i; register byte *s, *d; s = newname; d = Disk.vollabel.de_Msd.msd_Name; for (i = 0; i < 8 + 3; i++) { if (s[0]) *d++ = ToUpper(*s++); else *d++ = ' '; } } DateStamp(&dateStamp); ToMSDate(&Disk.vollabel.de_Msd.msd_Date, &Disk.vollabel.de_Msd.msd_Time, &dateStamp); RootLock->msfl_Msd = Disk.vollabel.de_Msd; /* Just for the name and * date */ WriteFileLock(RootLock); return DOSTRUE; } return DOSFALSE; #endif } #ifdef DEBUG _abort() { HanCloseDown(); RemTask(NULL); } #endif /* DEBUG */