Files
ViperOS/Scripts/check_disk.py
2026-07-19 12:38:20 +08:00

92 lines
3.5 KiB
Python

import struct
f = open(r'd:\Users\TermiNexus\Desktop\TransPyC\ViperOS\disk.img', 'rb')
f.seek(0)
first_sector = f.read(512)
first_byte = first_sector[0]
if first_byte == 0xEB or first_byte == 0xE9:
lba_start = 0
bpb = first_sector
else:
ptype = struct.unpack_from('<B', first_sector, 450)[0]
lba_start = struct.unpack_from('<I', first_sector, 454)[0]
f.seek(lba_start * 512)
bpb = f.read(512)
bytes_per_sec = struct.unpack_from('<H', bpb, 11)[0]
sec_per_clus = struct.unpack_from('<B', bpb, 13)[0]
rsvd = struct.unpack_from('<H', bpb, 14)[0]
num_fats = struct.unpack_from('<B', bpb, 16)[0]
root_clus = struct.unpack_from('<I', bpb, 44)[0]
fat_size = struct.unpack_from('<I', bpb, 36)[0]
data_start = rsvd + num_fats * fat_size
print(f'BPS={bytes_per_sec} SPC={sec_per_clus} rsvd={rsvd} NF={num_fats} root_clus={root_clus} fat_size={fat_size} data_start={data_start}')
def read_dir(f, lba_start, data_start, sec_per_clus, bytes_per_sec, cluster, indent=" ", depth=0):
if depth > 5:
return
cluster_sec = data_start + (cluster - 2) * sec_per_clus
f.seek((lba_start + cluster_sec) * 512)
dir_data = f.read(sec_per_clus * bytes_per_sec)
off = 0
lfn_parts = {}
while off < len(dir_data):
first = dir_data[off]
if first == 0:
break
if first == 0xE5:
off += 32
lfn_parts = {}
continue
attr = dir_data[off + 11]
if attr == 0x0F: # LFN entry
seq = first & 0x3F
lfn_chars = []
for i in range(5):
c = struct.unpack_from('<H', dir_data, off + 2 + i * 2)[0]
if c != 0xFFFF and c != 0:
lfn_chars.append(chr(c))
for i in range(6):
c = struct.unpack_from('<H', dir_data, off + 14 + i * 2)[0]
if c != 0xFFFF and c != 0:
lfn_chars.append(chr(c))
for i in range(2):
c = struct.unpack_from('<H', dir_data, off + 28 + i * 2)[0]
if c != 0xFFFF and c != 0:
lfn_chars.append(chr(c))
lfn_parts[seq] = ''.join(lfn_chars)
off += 32
continue
if attr == 8: # Volume label
off += 32
lfn_parts = {}
continue
name_bytes = dir_data[off:off + 11]
name_str = name_bytes.decode('ascii', errors='replace')
nt_case = dir_data[off + 12]
clus_hi = struct.unpack_from('<H', dir_data, off + 20)[0]
clus_lo = struct.unpack_from('<H', dir_data, off + 26)[0]
clus = (clus_hi << 16) | clus_lo
fsize = struct.unpack_from('<I', dir_data, off + 28)[0]
# Reconstruct LFN
lfn = ''
if lfn_parts:
lfn = ''.join(lfn_parts.get(i, '') for i in sorted(lfn_parts.keys()))
case_info = ""
if nt_case & 0x08:
case_info += " [base_lower]"
if nt_case & 0x10:
case_info += " [ext_lower]"
print(f'{indent}SFN=[{name_str}] NT=0x{nt_case:02X}{case_info} LFN="{lfn}" attr=0x{attr:02X} clus={clus} size={fsize}')
if attr & 0x10 and clus >= 2:
# Skip . and .. entries
sfn_name = name_str.rstrip()
if sfn_name != '.' and sfn_name != '..':
read_dir(f, lba_start, data_start, sec_per_clus, bytes_per_sec, clus, indent + " ", depth + 1)
off += 32
lfn_parts = {}
read_dir(f, lba_start, data_start, sec_per_clus, bytes_per_sec, root_clus)
f.close()