libmount
Version:
Standalone FAT12, FAT16, FAT32, VFAT implementation in JavaScript
573 lines (491 loc) • 14.1 kB
text/typescript
/**
* Mount
*
* @param driver - Driver or Uint8Array
* @param options - Mount options.
* @returns A mounted disk.
*/
export function mount(driver: RandomAccessDriver | Uint8Array, options?: MountOptions): Disk;
/**
* Create partition table
*
* @param partitions - disk partitions
* @returns 512-bytes MBR with partition table at offset 0x01BE
*/
export function fdisk(partitions: Partition[]): DiskSectors;
/**
* Create FAT filesystem
*
* @param capacity - Number of bytes available for the filesystem
* @param options - filesystem options
* @returns filesystem parameters and a list of sectors to write on disk
*/
export function mkfsvfat(capacity: number, options?: VFATOptions): VFATResult | null;
type MountOptions = {
/**
* The OEM Codepage used to decode and encode FAT short names. Default is "latin1".
*/
codepage?: Codepage;
/**
* Disk partition to mount.
*/
partition?: Partition;
};
interface Codepage {
/**
* Decodes an array of bytes into a string.
*/
decode(array: Uint8Array): string;
/**
* Encodes a string into an array bytes.
*/
encode(text: string): Uint8Array;
}
interface Disk {
/**
* @returns Disk capacity in bytes
*/
capacity(): number;
/**
* Retrieves the file system associated with the disk if detected.
* Returning null may indicate the disk is either empty, partitioned, or lacks a known file system.
*
* @returns The file system object if available.
*/
getFileSystem(): FileSystem | null;
/**
* Retrieves an array of MBR partitions on the disk.
* The array may be empty if the disk has no partitions (e.g., like a floppy disk, or empty disk).
*
* @returns An array of MBR partitions.
*/
getPartitions(): Partition[];
/**
* Write the given sectors on disk
*
* @param diskSectors - sectors to write on disk
*/
write(diskSectors: DiskSectors): void;
}
interface FileSystem {
/**
* @returns The name of the file system (e.g. FAT12, FAT16, FAT32).
*/
getName(): string;
/**
* @returns The volume label.
*/
getLabel(): string | null;
setLabel(label: string | null): void;
/**
* @returns OEM Name Identifier. Typically this is some indication of what system formatted the volume.
*/
getOEMName(): string | null;
/**
* @returns The volume serial number.
*/
getId(): number;
/**
* @returns The size of a cluster on the volume in bytes.
*/
getSizeOfCluster(): number;
/**
* @returns Total count of clusters on the volume.
*/
getCountOfClusters(): number;
/**
* @returns Number of free clusters available for allocation.
*/
getFreeClusters(): number;
/**
* @returns The root directory file object.
*/
getRoot(): File;
}
interface File {
/**
* Retrieves the name of the file.
*
* @returns The name of the file.
*/
getName(): string;
/**
* Retrieves the short name (8.3 format) of the file.
*
* @returns The short name of the file.
*/
getShortName(): string;
/**
* Retrieves the absolute path of the file.
*
* @returns The absolute path of the file.
*/
getAbsolutePath(): string;
/**
* Checks if the file is a regular file.
*
* @returns True if the file is a regular file (not a directory), otherwise false.
*/
isRegularFile(): boolean;
/**
* Checks if the file is a directory.
*
* @returns True if the file is a directory (or the root directory), otherwise false.
*/
isDirectory(): boolean;
/**
* Retrieves the size of the file or the total size of all files in a directory.
*
* @returns The file or directory size in bytes.
*/
length(): number;
/**
* Retrieves the size on disk of the current file object.
*
* @returns The file object size in bytes.
*/
getSizeOnDisk(): number;
/**
* yyyy.MM.dd HH:mm:ss
* @returns The time of last modification.
*/
getLastModified(): Date | null;
setLastModified(date: Date | null): void;
/**
* yyyy.MM.dd HH:mm:ss
* @returns The time that the file was created.
*/
getCreationTime(): Date | null;
setCreationTime(date: Date | null): void;
/**
* yyyy.MM.dd
* @returns The time of last access.
*/
getLastAccessTime(): Date | null;
setLastAccessTime(date: Date | null): void;
/**
* Finds the first file matching the given predicate.
*
* @param predicate - The predicate function.
* @returns The first file matching the predicate, or null if not a directory or nothing found.
*/
findFirst(predicate: (file: File) => boolean): File | null;
/**
* Finds all files matching the given predicate.
*
* @param predicate - The predicate function.
* @returns An array of files matching the predicate or null if not a directory.
*/
findAll(predicate: (file: File) => boolean): File[] | null;
/**
* Lists all files in the directory.
*
* @returns An array of files in the directory, or null if not a directory.
*/
listFiles(): File[] | null;
/**
* @returns Linked list of the file clusters
*/
open(): FileIO | null;
/**
* Deletes the file or directory recursive. After deletion, this file becomes unusable.
* Deleting the root directory deletes all files recursive.
*/
delete(): void;
/**
* Retrieves a file object given its path relative to the current file.
*
* @param path - The path to the file.
* @returns The File located at the specified path, otherwise null.
*/
getFile(relativePath: string): File | null;
/**
* Creates a file at the specified path, including any necessary parent directories.
* If the file already exists, returns the existing file.
*
* @param relativePath - Relative path where the file should be created.
* @returns The file located at the specified path if successfully created or already exists, otherwise null.
*/
makeFile(relativePath: string): File | null;
/**
* Creates a directory at the specified path, including any necessary parent directories.
* If the directory already exists, returns the existing directory.
*
* @param relativePath - Relative path where the directory should be created.
* @returns The file located at the specified path if successfully created or already exists, otherwise null.
*/
makeDir(relativePath: string): File | null;
/**
* Moves the current file to the destination path, creating any necessary parent directories.
* - If `dest` points to an existing directory, the current file is moved into that directory.
* - If `dest` does not exist, the current file is renamed to `dest`.
* Root directory cannot be moved or renamed.
*
* @param dest - Absolute or relative to the current file path where the current file should be moved or renamed to.
* @returns The new file object at the destination path if successfully moved or renamed, otherwise null.
*/
moveTo(dest: string): File | null;
}
interface FileIO {
/**
* Set the pointer to the beginning of the file
*/
rewind(): void;
/**
* Skip current file cluster
* @returns number of bytes skipped
*/
skipClus(): number;
/**
* Read current cluster to the buffer
* @param buf - buffer to read
* @returns number of bytes read
*/
readClus(buf: Uint8Array): number;
/**
* Write the buffer to the current cluster
* @param buf - buffer to write
* @returns number of bytes written
*/
writeClus(buf: Uint8Array): number;
/**
* @returns the whole file content
*/
readData(): Uint8Array;
/**
* @param data - the whole file content
*/
writeData(data: Uint8Array): number;
}
type VFATOptions = {
/**
* The volume ID/serial number.
* Valid values are from 0 to 0xffffffff.
* Default depends on current time.
*/
id?: number;
/**
* Boot Sector.
* Only jmpBoot (first 3 bytes) and BootCode (at offset 62 for FAT12/16 or 90 for FAT32) are used.
*/
bs?: Uint8Array;
/**
* The message the user receives on attempts to boot this file system without having properly installed an operating system.
* Max length is 424 for FAT12/16 and 395 for FAT32.
* The bytes will be displayed in your BIOS codepage, usually CP437.
* Default is "Non-system disk or disk error\r\nreplace and strike any key when ready\r\n".
*/
message?: Uint8Array;
/**
* Filesystem type: FAT12, FAT16, or FAT32.
* Default is whatever fits better for the file system size.
*/
type?: string;
/**
* The number of file allocation tables in the file system.
* Valid values are 1 or 2.
* Default is 2.
*/
numFATs?: number;
/**
* Minimum number of entries in the root directory (FAT12/16 only).
* Valid values are from 1 to 512.
* The real RootEntCnt is rounded up to the sector size:
* if rootEntCnt=1 then real RootEntCnt is 16*CEIL(1/16)=16
* if rootEntCnt=112 then real RootEntCnt is 16*CEIL(112/16)=112
* This option is ignored for FAT32.
* Default is 512, except for floppies.
*/
rootEntCnt?: number;
/**
* Number of sectors per cluster. Sector is 512 bytes always.
* For 4k cluster, secPerClus is 8.
* Valid values are 1, 2, 4, 8, 16, 32, 64, or 128.
* Default depends on capacity, but never 128 (64k cluster).
*/
secPerClus?: number;
/**
* The volume label. 11 bytes.
* The bytes will be displayed in your DOS/Windows codepage.
* Default is not set.
*/
label?: Uint8Array;
/**
* Compatibility level.
* Valid range is [0-16].
* Default is 16 (maximum compatibility).
*
* Notes:
* Avoid making volumes of any type that have close to 4085 or 65525 clusters.
* Stay 16 clusters on each side away from these cut-over cluster counts.
* However, LibMount uses Microsoft's FAT type detection which is not spec-compliant.
* For instance, it uses 4078 (!) as the maximum number of clusters for FAT12.
*
* Thus,
* 0 means FAT12 can have from 0 to 4078 clusters. (not spec. compliant)
* 1 means FAT12 can have from 1 to 4085 clusters. (not spec. compliant)
* 2 means FAT12 can have from 2 to 4084 clusters. (spec. compliant)
* ...
* 16 means FAT12 can have from 16 to 4070 clusters. (spec. compliant)
*
* Overall,
* 1. mkfs always creates DOS/Windows compatible images.
* 2. compat=0 or compat=1 can create images which are not spec-compliant in rare cases,
* and some FAT drivers will not correctly detect the filesystem type.
* 3. compat=2 and above create spec-compliant images always,
* but the world is full of FAT code that is wrong,
* and some FAT drivers will not correctly detect the filesystem type.
* 4. compat=16 will create compatible images for all shitty FAT drivers in the world I believe.
*
* Also, note that Microsoft supports FAT32 images with 1, 2 or more clusters,
* and mkfs can create such images, there is no 65525 specification limit.
*/
compat?: number;
// Other BootSector and BiosParameterBlock fields.
/**
* BS_OEMName field. Offset 3. 8 bytes.
* Default is "LIBMNTJS".
*/
oemName?: Uint8Array;
/**
* BPB_Media field. Offset 21. 1 byte.
* Default is 0xF8, except for floppies.
*/
media?: number;
/**
* BPB_SecPerTrk field. Offset 24. 2 bytes.
* Default is 63, except for floppies.
*/
secPerTrk?: number;
/**
* BPB_NumHeads field. Offset 26. 2 bytes.
* Default is 255, except for floppies.
*/
numHeads?: number;
/**
* BPB_HiddSec field. Offset 28. 2 bytes.
* Default is 0.
*/
hiddSec?: number;
};
type VFATResult = {
/**
* New filesystem sectors
*/
sectors: DiskSectors;
/**
* Volume Id/serial number.
*/
id: number;
/**
* FileSystem type: FAT12, FAT16 or FAT32.
*/
type: string;
/**
* Total number of sectors in use.
* totSec = rsvdSecCnt + numFATs * fatSz + rootDirSectors + countOfClusters * sizeOfCluster / bytsPerSec
*/
totSec: number;
/**
* Number of reserved sectors.
*/
rsvdSecCnt: number;
/**
* Number of FATs. 1 or 2.
*/
numFATs: number;
/**
* Number of sectors per FAT.
*/
fatSz: number;
/**
* Number of sectors for Root Directory. Always 0 for FAT32.
*/
rootDirSectors: number;
/**
* Number of clusters.
*/
countOfClusters: number;
/**
* Number of sectors per clusters: 1, 2, 4, 8, 16, 32, 64, or 128.
*/
secPerClus: number;
/**
* Size of sector in bytes: 512 always.
*/
bytsPerSec: number;
};
type Partition = {
/**
* Flag indicating whether the partition is active.
*/
active: boolean;
/**
* Partition Type (e.g. 0xE for FAT).
*/
type: number;
/**
* Offset (in sectors) from the beginning of the disk to the start of the partition.
*/
relativeSectors: number;
/**
* Total sectors in the partition.
*/
totalSectors: number;
};
/**
* A set of sectors which define a filesystem or other disk structures.
*/
type DiskSectors = {
bytsPerSec: number;
zeroRegions: Array<ZeroRegion>;
dataSectors: Array<DataSector>;
};
type ZeroRegion = {
/**
* Sector index, 0-based.
*/
i: number;
/**
* Number of zero sectors.
*/
count: number;
};
type DataSector = {
/**
* Sector index, 0-based.
*/
i: number;
/**
* Sector bytes.
*/
data: Uint8Array;
};
/**
* Random-access storage device driver.
*/
type RandomAccessDriver = {
/**
* Total storage capacity in bytes.
*/
readonly capacity: number;
/**
* Reads data.
*
* @param address - The byte offset to begin reading from. Must be >= 0 and < capacity.
* @param count - The number of bytes to read.
* @returns {Uint8Array} A buffer containing the requested data.
*/
read(address: number, count: number): Uint8Array;
/**
* Writes data. Optional for readonly drivers.
*
* @param address - The byte offset to begin writing to.
* @param data - The buffer containing data to write.
*/
write?(address: number, data: Uint8Array): void;
/**
* Release resources. Options. Not used by libmount.
*/
close?(): void;
};