diff options
Diffstat (limited to 'main/common/dosfs.h')
-rw-r--r-- | main/common/dosfs.h | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/main/common/dosfs.h b/main/common/dosfs.h new file mode 100644 index 0000000..1deb16b --- /dev/null +++ b/main/common/dosfs.h @@ -0,0 +1,393 @@ +/* + DOSFS Embedded FAT-Compatible Filesystem + (C) 2005 Lewin A.R.W. Edwards (sysadm@zws.com) +*/ + +#ifndef _DOSFS_H +#define _DOSFS_H + +#include <stddefs.h> + +//#define USE_GMHFIX // Defined to pull in dosfs fixes from Graham Henderson + + +//=================================================================== +// User-supplied functions +uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count); +uint32_t DFS_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count); + + +//=================================================================== +// Configurable items +#define MAX_PATH 64 // Maximum path length (increasing this will + // GREATLY increase stack requirements!) +#define DIR_SEPARATOR '/' // character separating directory components + +// End of configurable items +//=================================================================== + +//=================================================================== +// 32-bit error codes +#define DFS_OK 0 // no error +#define DFS_EOF 1 // end of file (not an error) +#define DFS_WRITEPROT 2 // volume is write protected +#define DFS_NOTFOUND 3 // path or file not found +#define DFS_PATHLEN 4 // path too long +#define DFS_ALLOCNEW 5 // must allocate new directory cluster +#define DFS_ERRMISC 0xffffffff // generic error + +//=================================================================== +// File access modes +#define DFS_READ 1 // read-only +#define DFS_WRITE 2 // write-only + +//=================================================================== +// Miscellaneous constants +#define SECTOR_SIZE 512 // sector size in bytes + +//=================================================================== +// Internal subformat identifiers +#define FAT12 0 +#define FAT16 1 +#define FAT32 2 + +//=================================================================== +// DOS attribute bits +#define ATTR_READ_ONLY 0x01 +#define ATTR_HIDDEN 0x02 +#define ATTR_SYSTEM 0x04 +#define ATTR_VOLUME_ID 0x08 +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 +#define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID) + + +/* + Directory entry structure + note: if name[0] == 0xe5, this is a free dir entry + if name[0] == 0x00, this is a free entry and all subsequent entries are free + if name[0] == 0x05, the first character of the name is 0xe5 [a kanji nicety] + + Date format: bit 0-4 = day of month (1-31) + bit 5-8 = month, 1=Jan..12=Dec + bit 9-15 = count of years since 1980 (0-127) + Time format: bit 0-4 = 2-second count, (0-29) + bit 5-10 = minutes (0-59) + bit 11-15= hours (0-23) +*/ + +// some macros to aid in formatting file date, times. and file sizes +#define CREATE_DAY( _x_) ((_x_.crtdate_l) & 0x1f) +#define CREATE_MON( _x_) (((_x_.crtdate_l >> 5) & 0x07) | ((_x_.crtdate_h & 1) << 3)) +#define CREATE_YEAR( _x_) ((_x_.crtdate_h >> 1) + 1980) + +#define CREATE_SEC( _x_) (((_x_.crttime_l) & 0x1f) * 2) +#define CREATE_MIN( _x_) (((_x_.crttime_l >> 5) & 0x07) | ((_x_.crttime_h & 0x07) << 3)) +#define CREATE_HR( _x_) ((_x_.crttime_h >> 3)) + +#define FILESIZE(_x_) (int)( ( _x_.filesize_3 << 24)| ( _x_.filesize_2 << 16) | ( _x_.filesize_1 << 8) | _x_.filesize_0) + + +typedef struct __attribute__ ((__packed__)) _tagDIRENT { + uint8_t name[11]; // filename + uint8_t attr; // attributes (see ATTR_* constant definitions) + uint8_t reserved; // reserved, must be 0 + uint8_t crttimetenth; // create time, 10ths of a second (0-199 are valid) + uint8_t crttime_l; // creation time low byte + uint8_t crttime_h; // creation time high byte + uint8_t crtdate_l; // creation date low byte + uint8_t crtdate_h; // creation date high byte + uint8_t lstaccdate_l; // last access date low byte + uint8_t lstaccdate_h; // last access date high byte + uint8_t startclus_h_l; // high word of first cluster, low byte (FAT32) + uint8_t startclus_h_h; // high word of first cluster, high byte (FAT32) + uint8_t wrttime_l; // last write time low byte + uint8_t wrttime_h; // last write time high byte + uint8_t wrtdate_l; // last write date low byte + uint8_t wrtdate_h; // last write date high byte + uint8_t startclus_l_l; // low word of first cluster, low byte + uint8_t startclus_l_h; // low word of first cluster, high byte + uint8_t filesize_0; // file size, low byte + uint8_t filesize_1; // + uint8_t filesize_2; // + uint8_t filesize_3; // file size, high byte +} DIRENT, *PDIRENT; + +/* + Partition table entry structure +*/ +typedef struct __attribute__ ((__packed__)) _tagPTINFO { + uint8_t active; // 0x80 if partition active + uint8_t start_h; // starting head + uint8_t start_cs_l; // starting cylinder and sector (low byte) + uint8_t start_cs_h; // starting cylinder and sector (high byte) + uint8_t type; // type ID byte + uint8_t end_h; // ending head + uint8_t end_cs_l; // ending cylinder and sector (low byte) + uint8_t end_cs_h; // ending cylinder and sector (high byte) + uint8_t start_0; // starting sector# (low byte) + uint8_t start_1; // + uint8_t start_2; // + uint8_t start_3; // starting sector# (high byte) + uint8_t size_0; // size of partition (low byte) + uint8_t size_1; // + uint8_t size_2; // + uint8_t size_3; // size of partition (high byte) +} PTINFO, *PPTINFO; + +/* + Master Boot Record structure +*/ +typedef struct __attribute__ ((__packed__)) _tagMBR { + uint8_t bootcode[0x1be]; // boot sector + PTINFO ptable[4]; // four partition table structures + uint8_t sig_55; // 0x55 signature byte + uint8_t sig_aa; // 0xaa signature byte +} MBR, *PMBR; + +/* + BIOS Parameter Block structure (FAT12/16) +*/ +typedef struct __attribute__ ((__packed__)) _tagBPB { + uint8_t bytepersec_l; // bytes per sector low byte (0x00) + uint8_t bytepersec_h; // bytes per sector high byte (0x02) + uint8_t secperclus; // sectors per cluster (1,2,4,8,16,32,64,128 are valid) + uint8_t reserved_l; // reserved sectors low byte + uint8_t reserved_h; // reserved sectors high byte + uint8_t numfats; // number of FAT copies (2) + uint8_t rootentries_l; // number of root dir entries low byte (0x00 normally) + uint8_t rootentries_h; // number of root dir entries high byte (0x02 normally) + uint8_t sectors_s_l; // small num sectors low byte + uint8_t sectors_s_h; // small num sectors high byte + uint8_t mediatype; // media descriptor byte + uint8_t secperfat_l; // sectors per FAT low byte + uint8_t secperfat_h; // sectors per FAT high byte + uint8_t secpertrk_l; // sectors per track low byte + uint8_t secpertrk_h; // sectors per track high byte + uint8_t heads_l; // heads low byte + uint8_t heads_h; // heads high byte + uint8_t hidden_0; // hidden sectors low byte + uint8_t hidden_1; // (note - this is the number of MEDIA sectors before + uint8_t hidden_2; // first sector of VOLUME - we rely on the MBR instead) + uint8_t hidden_3; // hidden sectors high byte + uint8_t sectors_l_0; // large num sectors low byte + uint8_t sectors_l_1; // + uint8_t sectors_l_2; // + uint8_t sectors_l_3; // large num sectors high byte +} BPB, *PBPB; + +/* + Extended BIOS Parameter Block structure (FAT12/16) +*/ +typedef struct __attribute__ ((__packed__)) _tagEBPB { + uint8_t unit; // int 13h drive# + uint8_t head; // archaic, used by Windows NT-class OSes for flags + uint8_t signature; // 0x28 or 0x29 + uint8_t serial_0; // serial# + uint8_t serial_1; // serial# + uint8_t serial_2; // serial# + uint8_t serial_3; // serial# + uint8_t label[11]; // volume label + uint8_t system[8]; // filesystem ID +} EBPB, *PEBPB; + +/* + Extended BIOS Parameter Block structure (FAT32) +*/ +typedef struct __attribute__ ((__packed__)) _tagEBPB32 { + uint8_t fatsize_0; // big FAT size in sectors low byte + uint8_t fatsize_1; // + uint8_t fatsize_2; // + uint8_t fatsize_3; // big FAT size in sectors high byte + uint8_t extflags_l; // extended flags low byte + uint8_t extflags_h; // extended flags high byte + uint8_t fsver_l; // filesystem version (0x00) low byte + uint8_t fsver_h; // filesystem version (0x00) high byte + uint8_t root_0; // cluster of root dir, low byte + uint8_t root_1; // + uint8_t root_2; // + uint8_t root_3; // cluster of root dir, high byte + uint8_t fsinfo_l; // sector pointer to FSINFO within reserved area, low byte (2) + uint8_t fsinfo_h; // sector pointer to FSINFO within reserved area, high byte (0) + uint8_t bkboot_l; // sector pointer to backup boot sector within reserved area, low byte (6) + uint8_t bkboot_h; // sector pointer to backup boot sector within reserved area, high byte (0) + uint8_t reserved[12]; // reserved, should be 0 + + uint8_t unit; // int 13h drive# + uint8_t head; // archaic, used by Windows NT-class OSes for flags + uint8_t signature; // 0x28 or 0x29 + uint8_t serial_0; // serial# + uint8_t serial_1; // serial# + uint8_t serial_2; // serial# + uint8_t serial_3; // serial# + uint8_t label[11]; // volume label + uint8_t system[8]; // filesystem ID +} EBPB32, *PEBPB32; + +/* + Logical Boot Record structure (volume boot sector) +*/ +typedef struct __attribute__ ((__packed__)) _tagLBR { + uint8_t jump[3]; // JMP instruction + uint8_t oemid[8]; // OEM ID, space-padded + BPB bpb; // BIOS Parameter Block + union { + EBPB ebpb; // FAT12/16 Extended BIOS Parameter Block + EBPB32 ebpb32; // FAT32 Extended BIOS Parameter Block + } ebpb; + uint8_t code[420]; // boot sector code + uint8_t sig_55; // 0x55 signature byte + uint8_t sig_aa; // 0xaa signature byte +} LBR, *PLBR; + +/* + Volume information structure (Internal to DOSFS) +*/ +typedef struct __attribute__ ((__packed__)) _tagVOLINFO { + uint8_t unit; // unit on which this volume resides + uint8_t filesystem; // formatted filesystem + +// These two fields aren't very useful, so support for them has been commented out to +// save memory. (Note that the "system" tag is not actually used by DOS to determine +// filesystem type - that decision is made entirely on the basis of how many clusters +// the drive contains. DOSFS works the same way). +// See tag: OEMID in dosfs.c +// uint8_t oemid[9]; // OEM ID ASCIIZ +// uint8_t system[9]; // system ID ASCIIZ + uint8_t label[12]; // volume label ASCIIZ + uint32_t startsector; // starting sector of filesystem + uint8_t secperclus; // sectors per cluster + uint16_t reservedsecs; // reserved sectors + uint32_t numsecs; // number of sectors in volume + uint32_t secperfat; // sectors per FAT + uint16_t rootentries; // number of root dir entries + + uint32_t numclusters; // number of clusters on drive + + // The fields below are PHYSICAL SECTOR NUMBERS. + uint32_t fat1; // starting sector# of FAT copy 1 + uint32_t rootdir; // starting sector# of root directory (FAT12/FAT16) or cluster (FAT32) + uint32_t dataarea; // starting sector# of data area (cluster #2) +} VOLINFO, *PVOLINFO; + +/* + Flags in DIRINFO.flags +*/ +#define DFS_DI_BLANKENT 0x01 // Searching for blank entry + +/* + Directory search structure (Internal to DOSFS) +*/ +typedef struct __attribute__ ((__packed__)) _tagDIRINFO { + uint32_t currentcluster; // current cluster in dir + uint8_t currentsector; // current sector in cluster + uint8_t currententry; // current dir entry in sector + uint8_t *scratch; // ptr to user-supplied scratch buffer (one sector) + uint8_t flags; // internal DOSFS flags +} DIRINFO, *PDIRINFO; + +/* + File handle structure (Internal to DOSFS) +*/ +typedef struct __attribute__ ((__packed__)) _tagFILEINFO { + PVOLINFO volinfo; // VOLINFO used to open this file + uint32_t dirsector; // physical sector containing dir entry of this file + uint8_t diroffset; // # of this entry within the dir sector + uint8_t mode; // mode in which this file was opened + uint32_t firstcluster; // first cluster of file + uint32_t filelen; // byte length of file + + uint32_t cluster; // current cluster + uint32_t pointer; // current (BYTE) pointer +} FILEINFO, *PFILEINFO; + +/* + Get starting sector# of specified partition on drive #unit + NOTE: This code ASSUMES an MBR on the disk. + scratchsector should point to a SECTOR_SIZE scratch area + Returns 0xffffffff for any error. + If pactive is non-NULL, this function also returns the partition active flag. + If pptype is non-NULL, this function also returns the partition type. + If psize is non-NULL, this function also returns the partition size. +*/ +uint32_t DFS_GetPtnStart(uint8_t unit, uint8_t *scratchsector, uint8_t pnum, uint8_t *pactive, uint8_t *pptype, uint32_t *psize); + +/* + Retrieve volume info from BPB and store it in a VOLINFO structure + You must provide the unit and starting sector of the filesystem, and + a pointer to a sector buffer for scratch + Attempts to read BPB and glean information about the FS from that. + Returns 0 OK, nonzero for any error. +*/ +uint32_t DFS_GetVolInfo(uint8_t unit, uint8_t *scratchsector, uint32_t startsector, PVOLINFO volinfo); + +/* + Open a directory for enumeration by DFS_GetNextDirEnt + You must supply a populated VOLINFO (see DFS_GetVolInfo) + The empty string or a string containing only the directory separator are + considered to be the root directory. + Returns 0 OK, nonzero for any error. +*/ +uint32_t DFS_OpenDir(PVOLINFO volinfo, uint8_t *dirname, PDIRINFO dirinfo); + +/* + Get next entry in opened directory structure. Copies fields into the dirent + structure, updates dirinfo. Note that it is the _caller's_ responsibility to + handle the '.' and '..' entries. + A deleted file will be returned as a NULL entry (first char of filename=0) + by this code. Filenames beginning with 0x05 will be translated to 0xE5 + automatically. Long file name entries will be returned as NULL. + returns DFS_EOF if there are no more entries, DFS_OK if this entry is valid, + or DFS_ERRMISC for a media error +*/ +uint32_t DFS_GetNext(PVOLINFO volinfo, PDIRINFO dirinfo, PDIRENT dirent); + +/* + Open a file for reading or writing. You supply populated VOLINFO, a path to the file, + mode (DFS_READ or DFS_WRITE) and an empty fileinfo structure. You also need to + provide a pointer to a sector-sized scratch buffer. + Returns various DFS_* error states. If the result is DFS_OK, fileinfo can be used + to access the file from this point on. +*/ +uint32_t DFS_OpenFile(PVOLINFO volinfo, uint8_t *path, uint8_t mode, uint8_t *scratch, PFILEINFO fileinfo); + +/* + Read an open file + You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a + pointer to a SECTOR_SIZE scratch buffer. + Note that returning DFS_EOF is not an error condition. This function updates the + successcount field with the number of bytes actually read. +*/ +uint32_t DFS_ReadFile(PFILEINFO fileinfo, uint8_t *scratch, uint8_t *buffer, uint32_t *successcount, uint32_t len); + +/* + Write an open file + You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a + pointer to a SECTOR_SIZE scratch buffer. + This function updates the successcount field with the number of bytes actually written. +*/ +uint32_t DFS_WriteFile(PFILEINFO fileinfo, uint8_t *scratch, uint8_t *buffer, uint32_t *successcount, uint32_t len); + +/* + Seek file pointer to a given position + This function does not return status - refer to the fileinfo->pointer value + to see where the pointer wound up. + Requires a SECTOR_SIZE scratch buffer +*/ +void DFS_Seek(PFILEINFO fileinfo, uint32_t offset, uint8_t *scratch); + +/* + Delete a file + scratch must point to a sector-sized buffer +*/ +uint32_t DFS_UnlinkFile(PVOLINFO volinfo, uint8_t *path, uint8_t *scratch); + +uint32_t DFS_GetFAT(PVOLINFO volinfo, uint8_t *scratch, uint32_t *scratchcache, uint32_t cluster); +uint8_t *DFS_DirToCanonical(uint8_t *dest, uint8_t *src); + +// If we are building a host-emulation version, include host support +#ifdef HOSTVER +#include "hostemu.h" +#endif + +#endif // _DOSFS_H |