92 lines
3.5 KiB
Python
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()
|