| Tim Windelschmidt | 6d33a43 | 2025-02-04 14:34:25 +0100 | [diff] [blame] | 1 | // Copyright The Monogon Project Authors. |
| 2 | // SPDX-License-Identifier: Apache-2.0 |
| 3 | |
| Lorenz Brun | bd2ce6d | 2022-07-22 00:00:13 +0000 | [diff] [blame] | 4 | package fat32 |
| 5 | |
| 6 | const ( |
| 7 | // FAT32 entries are only 28 bits |
| 8 | fatMask = 0x0fffffff |
| 9 | // Free entries are 0 |
| 10 | fatFree = 0x0 |
| 11 | // Entry at the end of a cluster chain |
| 12 | fatEOF = 0x0ffffff8 |
| 13 | ) |
| 14 | |
| 15 | // FAT32 Boot Sector and BIOS Parameter Block. This structure is 512 bytes long, |
| 16 | // even if the logical block size is longer. The rest should be filled up with |
| 17 | // zeroes. |
| 18 | type bootSector struct { |
| 19 | // Jump instruction to boot code. |
| 20 | JmpInstruction [3]byte |
| 21 | // Creator name. "MSWIN4.1" recommended for compatibility. |
| 22 | OEMName [8]byte |
| 23 | // Count of bytes per block (i.e. logical block size) |
| 24 | // Must be one of 512, 1024, 2048 or 4096 |
| 25 | BlockSize uint16 |
| 26 | // Number of blocks per allocation unit (cluster). |
| 27 | // Must be a power of 2 that is greater than 0. |
| 28 | BlocksPerCluster uint8 |
| 29 | // Number of reserved blocks in the reserved region of the volume starting |
| 30 | // at the first block of the volume. This field must not be 0. |
| 31 | ReservedBlocks uint16 |
| 32 | // The count of FAT data structures on the volume. This field should always |
| 33 | // contain the value of 2 for any FAT volume of any type. |
| 34 | NumFATs uint8 |
| 35 | _ [4]byte |
| 36 | // Legacy value for media determination, must be 0xf8. |
| 37 | MediaCode uint8 |
| 38 | _ [2]byte |
| 39 | // Number of sectors per track for 0x13 interrupts. |
| 40 | SectorsPerTrack uint16 |
| 41 | // Number of heads for 0x13 interrupts. |
| 42 | NumHeads uint16 |
| 43 | // Count of hidden blocks preceding the partition that contains this FAT |
| 44 | // volume. |
| 45 | HiddenBlocks uint32 |
| 46 | // Total count of blocks on the volume. |
| 47 | TotalBlocks uint32 |
| 48 | // Count of blocks per FAT. |
| 49 | BlocksPerFAT uint32 |
| 50 | // Flags for FAT32 |
| 51 | Flags uint16 |
| 52 | _ [2]byte |
| 53 | // Cluster number of the first cluster of the root directory. Usually 2. |
| 54 | RootClusterNumber uint32 |
| 55 | // Block number of the FSINFO structure in the reserved area. |
| 56 | FSInfoBlock uint16 |
| 57 | // Block number of the copy of the boot record in the reserved area. |
| 58 | BackupStartBlock uint16 |
| 59 | _ [12]byte |
| 60 | // Drive number for 0x13 interrupts. |
| 61 | DriveNumber uint8 |
| 62 | _ [1]byte |
| 63 | BootSignature uint8 |
| 64 | // ID of this filesystem |
| 65 | ID uint32 |
| 66 | // Human-readable label of this filesystem, padded with spaces (0x20) |
| 67 | Label [11]byte |
| 68 | // Always set to ASCII "FAT32 " |
| 69 | Type [8]byte |
| 70 | _ [420]byte |
| 71 | // Always 0x55, 0xAA |
| 72 | Signature [2]byte |
| 73 | } |
| 74 | |
| 75 | // Special block (usually at block 1) containing additional metadata, |
| 76 | // specifically the number of free clusters and the next free cluster. |
| 77 | // Always 512 bytes, rest of the block should be padded with zeroes. |
| 78 | type fsinfo struct { |
| 79 | // Validates that this is an FSINFO block. Always 0x52, 0x52, 0x61, 0x41 |
| 80 | LeadSignature [4]byte |
| 81 | _ [480]byte |
| 82 | // Another signature. Always 0x72, 0x72, 0x41, 0x61 |
| 83 | StructSignature [4]byte |
| 84 | // Last known number of free clusters on the volume. |
| 85 | FreeCount uint32 |
| 86 | // Next free cluster hint. All 1's is interpreted as undefined. |
| 87 | NextFreeCluster uint32 |
| 88 | _ [14]byte |
| 89 | // One more signature. Always 0x55, 0xAA. |
| 90 | TrailingSignature [2]byte |
| 91 | } |
| 92 | |
| 93 | // Directory entry |
| 94 | type dirEntry struct { |
| 95 | // DOS 8.3 file name. |
| 96 | DOSName [11]byte |
| 97 | // Attribtes of the file or directory, 0x0f reserved to mark entry as a |
| 98 | // LFN entry (see lfnEntry below) |
| 99 | Attributes uint8 |
| 100 | _ byte |
| 101 | CreationTenMilli uint8 // Actually 10ms units, 0-199 range |
| 102 | CreationTime uint16 |
| 103 | CreationDate uint16 |
| 104 | _ [2]byte |
| 105 | FirstClusterHigh uint16 |
| 106 | LastWrittenToTime uint16 |
| 107 | LastWrittenToDate uint16 |
| 108 | FirstClusterLow uint16 |
| 109 | FileSize uint32 |
| 110 | } |
| 111 | |
| 112 | const ( |
| 113 | // lastSequenceNumberFlag is logically-ORed with the sequence number of the |
| 114 | // last Long File Name entry to mark it as such. |
| 115 | lastSequenceNumberFlag = 0x40 |
| 116 | // codepointsPerEntry is the number of UTF-16 codepoints that fit into a |
| 117 | // single Long File Name entry. |
| 118 | codepointsPerEntry = 5 + 6 + 2 |
| 119 | ) |
| 120 | |
| 121 | // VFAT long file name prepended entry |
| 122 | type lfnEntry struct { |
| 123 | SequenceNumber uint8 |
| 124 | // First 5 UTF-16 code units |
| 125 | NamePart1 [5]uint16 |
| 126 | // Attributes (must be 0x0f) |
| 127 | Attributes uint8 |
| 128 | _ byte |
| 129 | // Checksum of the 8.3 name. |
| 130 | Checksum uint8 |
| 131 | // Next 6 UTF-16 code units |
| 132 | NamePart2 [6]uint16 |
| 133 | _ [2]byte |
| 134 | // Next 2 UTF-16 code units |
| 135 | NamePart3 [2]uint16 |
| 136 | } |