📄 fsys.c
字号:
/* This is the MMURTL, MS-DOS Compatible (FAT) File system. */
/*
MMURTL Operating System Source Code
Copyright 1991,1992,1993, Richard A. Burgess
ALL RIGHTS RESERVED
Version x0.8
*/
/*
About MS-DOS disk formats and how MMURTL handles them.
Physical Disk Layouts
From the disk controller's standpoint:
Cylinder numbers run from 0 to nMaxCyls-1.
Head numbers run from 0 to nMaxheads-1.
Sector numbers run from 1 to nMaxSectorsPerTrack.
Physical (Absolute) Sector Numbers
Physical sector numbers (absolute) begin at Cyl 0, Head 0, Sector 1.
As the physical sector number rolls over (nMaxSectorsPerTrack+1),
the Head number is incremented which moves us to the next track
(same cylinder, next head). When the head number rolls over
(nMaxHeads is reached) the cylinder number is incremented.
Note: Track and cylinder are NOT interchangable terms in the
above text. If you have 6 heads on your drive, you have
6 tracks per cylinder. This can be confusing because many
books and documents use the terms interchangably.
And you can, so long as you know that's what you're doing.
Hidden Sectors
MS-DOS reserves a section of the physical hard disk. This area
is called the Hidden Sectors. This is usually the very first
track on the disk (begins at Cyl 0, head 0, Sector 1). The
partition tables are kept at the very end of the first sector in
this hidden area (offset 01BEh in the first sector to be exact).
The partition tables are 16 byte entries that describe
"logical" sections of the disk that can be treated as separate drives.
There are usually no "hidden sectors" on floppy disks, nor are there
any partition tables.
MMURTL Logical Block Address (LBA)
MMURTL device drivers treat the entire disk as a single physical
drive. The MMURTL file system reads the partition tables,
then sets up the device driver to span the entire physical disk
as 0 to nMaxBlockNumbers-1. This is refered to as the Logical Block
Address (LBA) and is the value passed in to the DeviceOp call for
the MMURTL hard/floppy disk device drivers (LBAs are used with
all MMURTL devices).
Note: DO NOT confuse MMURTL's LBA for the sector number in an MS-DOS
logical drive. MMURTL calls these logical blocks because we still
have to convert them into physical cylinder, head and sector to
retrieve the data.
MS-DOS Boot Sector
The first sector of an MS-DOS logical drive will be its boot
sector. Each of the MS-DOS logical partitions will have a boot
sector although only the first will be marked as bootable (if any are).
It's position on the disk is calculated from the partition table
information.
MMURTL File System Initialization
The MMURTL-FAT file system reads the partition table and saves
the starting LBA and length of each of DOS logical disk that is
found. Armed with this information, MMURTL can access each of
the DOS logical disks as a separate disk drive. To maintain some
sanity, the MMURTL file system gives all of its logical drives
a letter just like MS-DOS. MMURTL supports two floppy drives
(A & B) and up to eight logical hard disk (C-J). All information
on the Logical Drives are kept in an array of records (Ldrvs).
This includes the logical letter to physical drive conversions.
Once we have the layout of each of the partitons, we read the boot
sector from the first DOS logical drive. The boot sector contains
several pieces of important information about the drive geometry
(numbers of heads, sectors per track, etc.), which are also placed
in the Logical Drive stuctures.
Once we have the drive geometry information we setup the MMURTL
device driver. This tells the device driver how many cylinders,
heads and sectors per track are on the physical disk.
Until this is done, the device driver assumes a minimum drive size
and you should only read the partition table (or boot sector if no
partition table is on the disk). This provides enough
information to do a DeviceInit call to set up proper drive
geometry.
If you were building a loadable file system to replace the one that
is included in MMURTL, you would call your routine to initialize
the file system very early in the main program block. You must
not service file system requests until this is done.
*/
#define U32 unsigned long
#define U16 unsigned int
#define U8 unsigned char
#define S32 long
#define S16 int
#define S8 char
#define TRUE 1
#define FALSE 0
/*********** MMURTL Public Prototypes ***************/
/* From MKernel */
extern far AllocExch(long *pExchRet);
extern far U32 GetTSSExch(U32 *pExchRet);
extern far SpawnTask(char *pEntry,
long dPriority,
long fDebug,
char *pStack,
long fOSCode);
extern far long WaitMsg(long Exch, char *pMsgRet);
extern far long CheckMsg(long Exch, char *pMsgRet);
extern far long Request(unsigned char *pSvcName,
unsigned int wSvcCode,
unsigned long dRespExch,
unsigned long *pRqHndlRet,
unsigned long dnpSend,
unsigned char *pData1,
unsigned long dcbData1,
unsigned char *pData2,
unsigned long dcbData2,
unsigned long dData0,
unsigned long dData1,
unsigned long dData2);
extern far long Respond(long dRqHndl, long dStatRet);
/* From MData */
extern far void CopyData(U8 *pSource, U8 *pDestination, U32 dBytes);
extern far void FillData(U8 *pDest, U32 cBytes, U8 bFill);
extern far long CompareNCS(U8 *pS1, U8 *pS2, U32 dSize);
/* From MTimer.h */
extern far long GetCMOSTime(long *pTimeRet);
extern far long GetCMOSDate(long *pTimeRet);
extern far long GetTimerTick(long *pTickRet);
/* From MVid.h */
extern far long TTYOut (char *pTextOut, long ddTextOut, long ddAttrib);
extern far long GetNormVid(long *pNormVidRet);
#include "MKbd.h"
/* From MDevDrv */
extern far U32 DeviceOp(U32 dDevice,
U32 dOpNum,
U32 dLBA,
U32 dnBlocks,
U8 *pData);
extern far U32 DeviceStat(U32 dDevice,
S8 * pStatRet,
U32 dStatusMax,
U32 *pdSatusRet);
extern far U32 DeviceInit(U32 dDevNum,
S8 *pInitData,
U32 sdInitData);
/* From MMemory.h */
extern far U32 AllocOSPage(U32 nPages, U8 *ppMemRet);
extern far U32 DeAllocPage(U8 *pOrigMem, U32 nPages);
/* From MJob.h */
extern far U32 GetPath(long JobNum, char *pPathRet, long *pdcbPathRet);
extern far U32 RegisterSvc(S8 *pName, U32 Exch);
/* NEAR support for debugging */
extern long xprintf(char *fmt, ...);
extern U32 Dump(unsigned char *pb, long cb);
/* File System error codes */
#define ErcOK 0 /* Alls Well */
#define ErcEOF 1 /* DUH... The END */
#define ErcBadSvcCode 32 /* Service doesn't handle that code */
#define ErcBadFileSpec 200 /* invalid file spec (not correct format)*/
#define ErcNoSuchDrive 201 /* Try another letter bozo */
#define ErcNotAFile 202 /* Open a directory?? NOT */
#define ErcNoSuchFile 203 /* No can do! It ain't there...*/
#define ErcNoSuchDir 204 /* Ain't no such dir... */
#define ErcReadOnly 205 /* You can't modify it bubba */
#define ErcNoFreeFCB 206 /* We're really hurtin... */
#define ErcBadOpenMode 207 /* Say what? Mode??? */
#define ErcFileInUse 208 /* File is open in incompatible mode */
#define ErcNoFreeFUB 209 /* Sorry, out of File User Blocks */
#define ErcBadFileHandle 210 /* WHOAAA, bad handle buddy! */
#define ErcBrokenFile 211 /* Cluster chain broken on file */
#define ErcBadFCB 213 /* We got REAL problems... */
#define ErcStreamFile 214 /* Operation not allowed on Stream File */
#define ErcBlockFile 215 /* Operation not allowed on Block File */
#define ErcBeyondEOF 217 /* SetLFA or WriteBlock beyond EOF */
#define ErcNoParTable 218 /* No partiton table found on disk!!! */
#define ErcBadFATClstr 220 /* File system screwed up (or your disk is) */
#define ErcRenameDrv 222 /* They have tried to rename across Dir/Vol*/
#define ErcRenameDir 223 /* They have tried to rename across Dir/Vol*/
#define ErcNoMatch 224 /* No matching directory entry */
#define ErcWriteOnly 225 /* Attempt to read write-only device */
#define ErcDupName 226 /* Name exists as a file or dir already */
#define ErcNotSupported 227 /* Not supported on this file */
#define ErcRootFull 228 /* The Root Directory is Full */
#define ErcDiskFull 230 /* No more free CLUSTERS!!! */
#define ErcDirFull 231 /* No free Dir entries TEMP ERROR */
#define ErcNewMedia 605 /* for floppy mounting from FDD */
/**************** FAT Buffer control structure **********************/
/*
The Fat structures are for keeping track of the FAT buffers.
We never want to have more than one copy of a FAT sector in
memory at one time, and we also never want to read one when
its already here (a waste of time)! We also keep track
of the last time it was used and deallocate the oldest (LRU -
Least Recently Used). Initially filling out the Fat control
structure is part of the file system initialization. If the
FAT sector we are in has been modified (data written to clusters
in it & FAT updated) we write it ASAP!
*/
#define nFATBufs 16 /* 16 * 512 = 8192, 2 pages */
struct { /* */
U8 *pBuf; /* points to beginning of fat buffer */
U32 LastUsed; /* Tick when last used (0 = Never) */
U32 LBASect; /* LBA this FAT sector came from */
U16 iClstrStart; /* Starting cluster for each buf */
U8 Drive; /* LDrive this FAT sector is from */
U8 fModLock; /* Bit 0 = Modified, bit 1 = Locked */
} Fat[nFATBufs]; /* 12 bytes total */
#define FATMOD 0x01
#define FATLOCK 0x02
/**************** File Contol Block Structures (FCBs) **********/
/* One FCB is allocated and filled out for each file that is open.
The actual directory entry structure from the disk is embedded
in the FCB so it can be copied directly to/from the directory
sector on the disk.
*/
#define nFCBs 128
#define sFCB 64
struct FCB {
S8 Name[8]; /* From here to Filesize is copy of DirEnt */
S8 Ext[3];
S8 Attr; /* from MS-DOS */
U8 Resvd1[10]; /* ???????? */
U16 Time; /* Only changed when created or updated */
U16 Date;
U16 StartClstr; /* At least one per file!! */
U32 FileSize; /* last entry in FAT Dir Ent (32 bytes) */
U32 LBADirSect; /* LBA of directory sector this is from */
U16 oSectDirEnt; /* Offset in sector for the dir entry */
U8 Ldrv; /* Logical drive this is on (A-J, 0-9) */
U8 Mode; /* 0 or 1 (Read or Modify). */
U8 nUsers; /* Active FUBs for this file (255 MAX). 0= Free FCB */
U8 fMod; /* This file was modified! */
U8 Resvd[22]; /* Out to 64 bytes */
};
struct FCB *paFCB; /* a pointer to array of allocated FCBs. */
struct FCB *pFCB; /* pointer to one FCB */
/********************** File User Blocks **************************/
/* Each user of an open file is assigned a FUB. The FUB number is the
filehandle (beginning with 3). ) 0, 1 & 2 are reserved for NUL,
KBD and VID devices.
*/
#define nFUBs 128
#define sFUB 32
/* The FUB contains information on a file related to a user's view
of the file. It is used to hold information on files opened
in stream and block mode. Three important fields in the FUB are:
LFABuf - LFA of first byte in buffer for a stream file.
Clstr - Clstr of last block read or stream fill.
LFAClstr - LFA of first byte in Clstr.
LFAClstr and Clstr give us a relative starting point when
reading a file from disk. If we didn't save this information
on the last access, we would have to "run" the cluster chain
everytime we wanted to read or access a file beyond the last
point we read. */
struct FUB {
U16 Job; /* User's Job Number. 0 if FUB is free. */
U16 iFCB; /* FCB number for this file (0 to nFCBs-1) */
U32 CrntLFA; /* Current Logical File Address (File Ptr) */
U8 *pBuf; /* Ptr to buffer if stream mode */
U32 sBuf; /* Size of buffer for Stream file in bytes */
U32 LFABuf; /* S-First LFA in Clstr Buffer */
U32 LFAClstr; /* LFA of Clstr (below). */
U16 Clstr; /* Last Cluster read */
U8 fModified; /* Data in buffer was modified */
U8 fStream; /* NonZero for STREAM mode */
U8 Rsvd[4]; /* Pad to 32 bytes */
};
struct FUB *paFUB; /* a pointer to allocated FUBs. Set up at init. */
struct FUB *pFUB; /* a pointer to allocated FUBs. Set up at init. */
/* Boot sector info (62 byte structure) */
struct {
U8 Jmp[3];
U8 OEMname[8];
U16 bps;
U8 SecPerClstr;
U16 ResSectors;
U8 FATs;
U16 RootDirEnts;
U16 Sectors;
U8 Media;
U16 SecPerFAT;
U16 SecPerTrack;
U16 Heads;
U32 HiddenSecs;
U32 HugeSecs;
U8 DriveNum;
U8 Rsvd1;
U8 BootSig;
U32 VolID;
U8 VolLabel[11];
U8 FileSysType[8]; /* 62 bytes */
} fsb;
/* Partition Table Entry info. 16 bytes */
struct partent {
U8 fBootable;
U8 HeadStart;
U8 SecStart;
U8 CylStart;
U8 FATType;
U8 HeadEnd;
U8 SecEnd;
U8 CylEnd;
U32 nFirstSector;
U32 nSectorsTotal;
};
struct partent partab[4]; /* 4 partition table entries 64 bytes */
U16 partsig;
/* Bit definitions in attribute field for a directory entry */
#define ATTRNORM 0x00
#define READONLY 0x01
#define HIDDEN 0x02
#define SYSTEM 0x04
#define VOLNAME 0x08
#define DIRECTORY 0x10
#define ARCHIVE 0x20
/* Directory Entry Record, 32 bytes */
struct dirstruct {
U8 Name[8];
U8 Ext[3];
U8 Attr;
U8 Rsvd[10];
U16 Time;
U16 Date;
U16 StartClstr;
U32 FileSize;
} dirent;
struct dirstruct *pDirEnt; /* a pointer to a dir entry */
/* When a file is opened, the filename is parsed into an array
to facilitate searching the directory tree. IN MS-DOS all
dir and file names are SPACE padded (20h). The FileSpec array
contains the fully parsed path of the file. For instance,
If you were to open "A:\Dog\Food\IsGood.txt" the FileSpec
array would look like this:
FileSpec[0] = "DOG "
FileSpec[1] = "FOOD "
FileSpec[2] = "ISGOOD TXT"
FileSpec[3][0] = NULL;
Note that the DOT is not inlcuded (it's not in the DOS directory
either), and the next unused FileSpec entry contain NULL in the
first byte. SpecDepth tells us how many directories deep the
name goes.
*/
U8 FDrive /* Drive parsed from file operation */
U8 FileSpec[7][11]; /* Hierarchy from file spec parsing */
U8 SpecDepth; /* Depth of parse (0=Root File) */
/* Used for Rename */
U8 FDrive1 /* Drive parsed from file operation */
U8 FileSpec1[7][11]; /* Hierarchy from file spec parsing */
U8 SpecDepth1; /* Depth of parse (0=Root File) */
/* raw sector buffer for all kinds of stuff */
U8 abRawSector[516];
U8 abTmpSector[516];
U8 abDirSectBuf[516];
/* These arrays keep track of physical drive data (0-4). */
#define nPDrvs 4
struct phydrv {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -