sonar

Scan files at memory bandwidth speed.
Log | Files | Refs

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 }