375 lines
15 KiB
C
Executable File
375 lines
15 KiB
C
Executable File
/*
|
|
DOSFS Embedded FAT-Compatible Filesystem
|
|
(C) 2005 Lewin A.R.W. Edwards (sysadm@zws.com)
|
|
*/
|
|
|
|
#ifndef _DOSFS_H
|
|
#define _DOSFS_H
|
|
|
|
#include <stdint.h>
|
|
|
|
//===================================================================
|
|
// 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)
|
|
*/
|
|
typedef struct _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 _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 _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 _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 _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 _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 _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 _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 _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 _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);
|
|
|
|
// If we are building a host-emulation version, include host support
|
|
#ifdef HOSTVER
|
|
#include "hostemu.h"
|
|
#endif
|
|
|
|
#endif // _DOSFS_H
|