boot.odin (2766B)
1 package ntfs 2 3 import "core:math/bits" 4 5 Boot_Sector :: struct { 6 bytes_per_sector: u32, 7 sectors_per_cluster: u32, 8 bytes_per_cluster: u32, 9 total_sectors: u64, 10 mft_lcn: u64, // first cluster of $MFT 11 mft_mirror_lcn: u64, 12 record_size: u32, // bytes per FILE record, normally 1024 13 index_block_size: u32, // bytes per directory index block, normally 4096 14 serial: u64, 15 } 16 17 /* 18 Parse the first sector of an NTFS volume. `b` must hold at least 512 bytes. 19 20 Two fields use an encoding worth knowing about. Sectors-per-cluster and 21 clusters-per-record are single bytes; values of 0x80 and above are negative exponents, 22 so 0xF6 means 2^(256-0xF6) = 2^10 = 1024 bytes. This lets a cluster (up to 2 MiB) or a 23 record be smaller or larger than the other without a wider field. 24 */ 25 parse_boot_sector :: proc(b: []byte) -> (bs: Boot_Sector, err: Error) { 26 if len(b) < 512 { 27 return {}, .Bad_Boot_Sector 28 } 29 if string(b[3:11]) != "NTFS " { 30 return {}, .Not_Ntfs 31 } 32 if b[0x1FE] != 0x55 || b[0x1FF] != 0xAA { 33 return {}, .Bad_Boot_Sector 34 } 35 36 bs.bytes_per_sector = u32(rd16(b, 0x0B)) 37 bs.sectors_per_cluster = decode_shift_byte(b[0x0D]) 38 bs.total_sectors = rd64(b, 0x28) 39 bs.mft_lcn = rd64(b, 0x30) 40 bs.mft_mirror_lcn = rd64(b, 0x38) 41 bs.serial = rd64(b, 0x48) 42 43 if bs.bytes_per_sector < 256 || bs.bytes_per_sector > 4096 || !is_pow2(bs.bytes_per_sector) { 44 return {}, .Bad_Boot_Sector 45 } 46 if bs.sectors_per_cluster == 0 || !is_pow2(bs.sectors_per_cluster) { 47 return {}, .Bad_Boot_Sector 48 } 49 bs.bytes_per_cluster = bs.bytes_per_sector * bs.sectors_per_cluster 50 51 bs.record_size = decode_size_byte(b[0x40], bs.bytes_per_cluster) 52 bs.index_block_size = decode_size_byte(b[0x44], bs.bytes_per_cluster) 53 54 // A record must be a whole number of sectors so it can be read directly from the 55 // volume, and at least two fixup blocks so the update sequence array has something 56 // to protect. 57 if bs.record_size < 512 || 58 !is_pow2(bs.record_size) || 59 bs.record_size % bs.bytes_per_sector != 0 { 60 return {}, .Bad_Boot_Sector 61 } 62 if bs.mft_lcn == 0 || bs.total_sectors == 0 { 63 return {}, .Bad_Boot_Sector 64 } 65 return bs, .None 66 } 67 68 // Byte values below 0x80 are literal counts; values at or above are 2^(256-v). 69 @(private) 70 decode_shift_byte :: proc "contextless" (v: byte) -> u32 { 71 if v < 0x80 { 72 return u32(v) 73 } 74 return u32(1) << uint(256 - int(v)) 75 } 76 77 // Clusters-per-X fields: positive is a cluster count, negative is a byte exponent. 78 @(private) 79 decode_size_byte :: proc "contextless" (v: byte, bytes_per_cluster: u32) -> u32 { 80 if v < 0x80 { 81 return u32(v) * bytes_per_cluster 82 } 83 return u32(1) << uint(256 - int(v)) 84 } 85 86 @(private) 87 is_pow2 :: proc "contextless" (v: u32) -> bool { 88 return v != 0 && bits.count_ones(v) == 1 89 }