from __future__ import with_statement
import sys
import os
import subprocess
import struct
from msdosfs import *
from HexDump import HexDump
class LaunchError(Exception):
def __init__(self, returncode):
self.returncode = returncode
if returncode < 0:
self.message = "Program exited with signal %d" % -returncode
else:
self.message = "Program exited with status %d" % returncode
def __str__(self):
return self.message
class FailureExpected(Exception):
def __init__(self, s):
self.s = s
def __str__(self):
return self.s
def launch(args, **kwargs):
print "launch:", args, kwargs
p = subprocess.Popen(args, **kwargs)
stdout, stderr = p.communicate()
if p.returncode != 0:
raise LaunchError(p.returncode)
return stdout, stderr
def test_fat32(dir, fsck, newfs):
dmg = os.path.join(dir, 'Test20GB.sparseimage')
launch('hdiutil create -size 20g -type SPARSE -layout NONE'.split()+[dmg])
newfs_opts = "-F 32 -b 4096 -v TEST20GB".split()
disk = launch(['hdiutil', 'attach', '-nomount', dmg], stdout=subprocess.PIPE)[0].rstrip()
rdisk = disk.replace('/dev/disk', '/dev/rdisk')
test_quick(rdisk, fsck, newfs, newfs_opts)
test_bad_args(rdisk, fsck, newfs, newfs_opts)
test_maxmem(rdisk, fsck, newfs, newfs_opts)
test_empty(rdisk, fsck, newfs, newfs_opts)
test_boot_sector(rdisk, fsck, newfs, newfs_opts)
test_boot_fat32(rdisk, fsck, newfs, newfs_opts) test_fsinfo(rdisk, fsck, newfs, newfs_opts) fat_too_small(rdisk, fsck, newfs, newfs_opts)
orphan_clusters(rdisk, fsck, newfs, newfs_opts)
file_excess_clusters(rdisk, fsck, newfs, newfs_opts)
file_bad_clusters(rdisk, fsck, newfs, newfs_opts)
dir_bad_start(rdisk, fsck, newfs, newfs_opts)
root_bad_start(rdisk, fsck, newfs, newfs_opts) root_bad_first_cluster(rdisk, fsck, newfs, newfs_opts) dir_size_dots(rdisk, fsck, newfs, newfs_opts)
long_name(rdisk, fsck, newfs, newfs_opts)
past_end_of_dir(rdisk, fsck, newfs, newfs_opts)
fat_bad_0_or_1(rdisk, fsck, newfs, newfs_opts)
fat_mark_clean_corrupt(rdisk, fsck, newfs, newfs_opts)
fat_mark_clean_ok(rdisk, fsck, newfs, newfs_opts)
file_4GB(rdisk, fsck, newfs, newfs_opts)
file_4GB_excess_clusters(rdisk, fsck, newfs, newfs_opts)
launch(['diskutil', 'eject', disk])
os.remove(dmg)
def test_fat16(dir, fsck, newfs):
dmg = os.path.join(dir, 'Test160MB.dmg')
f = file(dmg, "w")
f.truncate(160*1024*1024)
f.close
newfs_opts = "-F 16 -b 4096 -v TEST160MB".split()
disk = launch(['hdiutil', 'attach', '-nomount', dmg], stdout=subprocess.PIPE)[0].rstrip()
rdisk = disk.replace('/dev/disk', '/dev/rdisk')
test_quick(rdisk, fsck, newfs, newfs_opts)
test_bad_args(rdisk, fsck, newfs, newfs_opts)
test_maxmem(rdisk, fsck, newfs, newfs_opts)
test_empty(rdisk, fsck, newfs, newfs_opts)
test_boot_sector(rdisk, fsck, newfs, newfs_opts)
fat_too_small(rdisk, fsck, newfs, newfs_opts)
orphan_clusters(rdisk, fsck, newfs, newfs_opts)
file_excess_clusters(rdisk, fsck, newfs, newfs_opts)
file_bad_clusters(rdisk, fsck, newfs, newfs_opts)
dir_bad_start(rdisk, fsck, newfs, newfs_opts)
dir_size_dots(rdisk, fsck, newfs, newfs_opts)
long_name(rdisk, fsck, newfs, newfs_opts)
past_end_of_dir(rdisk, fsck, newfs, newfs_opts)
fat_bad_0_or_1(rdisk, fsck, newfs, newfs_opts)
fat_mark_clean_corrupt(rdisk, fsck, newfs, newfs_opts)
fat_mark_clean_ok(rdisk, fsck, newfs, newfs_opts)
launch(['diskutil', 'eject', disk])
os.remove(dmg)
def test_fat12(dir, fsck, newfs):
dmg = os.path.join(dir, 'Test15MB.dmg')
f = file(dmg, "w")
f.truncate(15*1024*1024)
f.close
newfs_opts = "-F 12 -b 4096 -v TEST15MB".split()
disk = launch(['hdiutil', 'attach', '-nomount', dmg], stdout=subprocess.PIPE)[0].rstrip()
rdisk = disk.replace('/dev/disk', '/dev/rdisk')
test_quick(rdisk, fsck, newfs, newfs_opts)
test_bad_args(rdisk, fsck, newfs, newfs_opts)
test_maxmem(rdisk, fsck, newfs, newfs_opts)
test_empty(rdisk, fsck, newfs, newfs_opts)
test_boot_sector(rdisk, fsck, newfs, newfs_opts)
fat_too_small(rdisk, fsck, newfs, newfs_opts)
orphan_clusters(rdisk, fsck, newfs, newfs_opts)
file_excess_clusters(rdisk, fsck, newfs, newfs_opts)
file_bad_clusters(rdisk, fsck, newfs, newfs_opts)
dir_bad_start(rdisk, fsck, newfs, newfs_opts)
dir_size_dots(rdisk, fsck, newfs, newfs_opts)
long_name(rdisk, fsck, newfs, newfs_opts)
past_end_of_dir(rdisk, fsck, newfs, newfs_opts)
fat_bad_0_or_1(rdisk, fsck, newfs, newfs_opts)
launch(['diskutil', 'eject', disk])
os.remove(dmg)
def test_empty(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
launch([fsck, '-n', disk])
def orphan_clusters(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
v.allocate(7, 100)
v.allocate(23, 150)
v.allocate(1, 190)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-p', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def file_excess_clusters(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
head=v.allocate(7)
v.root().mkfile('FOO', head=head, length=6*v.bytesPerCluster)
head=v.allocate(1)
v.root().mkfile('BAR', head=head, length=0)
clusters = v.fat.find(9)
head = v.fat.chain(clusters)
v.root().mkfile('LINK1', head=head, length=8*v.bytesPerCluster+1)
head = v.fat.allocate(3, last=clusters[7])
v.root().mkfile('LINK2', head=head, length=2*v.bytesPerCluster+3)
head = v.fat.allocate(5, last=clusters[8])
v.root().mkfile('LINK3', head=head, length=3*v.bytesPerCluster+5)
if v.fsinfo:
v.fsinfo.allocate(9+3+5)
head = v.allocate(11, last=CLUST_BAD)
v.root().mkfile('BAD3', head=head, length=8*v.bytesPerCluster+300)
head = v.allocate(8, last=CLUST_FREE)
v.root().mkfile('FREE1', head=head, length=6*v.bytesPerCluster+100)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def file_bad_clusters(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
clusters = v.fat.find(5)
to_free = clusters[2]
head = v.fat.chain(clusters)
v.root().mkfile('FILE1', head=head, length=6*v.bytesPerCluster+111)
if v.fsinfo:
v.fsinfo.allocate(5)
clusters = v.fat.find(5)
head = v.fat.chain(clusters)
v.root().mkfile('FILE2', head=head, length=4*v.bytesPerCluster+222)
v.fat[clusters[2]] = CLUST_RSRVD
if v.fsinfo:
v.fsinfo.allocate(5)
clusters = v.fat.find(5)
head = v.fat.chain(clusters)
v.root().mkfile('FILE3', head=head, length=4*v.bytesPerCluster+333)
v.fat[clusters[2]] = 1
if v.fsinfo:
v.fsinfo.allocate(5)
clusters = v.fat.find(5)
head = v.fat.chain(clusters)
v.root().mkfile('FILE4', head=head, length=4*v.bytesPerCluster+44)
v.fat[clusters[2]] = clusters[1]
if v.fsinfo:
v.fsinfo.allocate(5)
v.root().mkfile('FILE5', head=CLUST_FREE, length=4*v.bytesPerCluster+55)
v.root().mkfile('FILE6', head=CLUST_BAD, length=4*v.bytesPerCluster+66)
v.root().mkfile('FILE7', head=CLUST_RSRVD-1, length=4*v.bytesPerCluster+77)
head = v.allocate(5)
v.root().mkfile('FOO', head=head, length=4*v.bytesPerCluster+99)
v.root().mkfile('FILE8', head=head, length=4*v.bytesPerCluster+88)
v.fat[to_free] = CLUST_FREE
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def dir_bad_start(disk, fsck, newfs, newfs_opts):
def mkdir(parent, name, head):
bytes = make_long_dirent(name, ATTR_DIRECTORY, head=head)
slots = len(bytes)/32
slot = parent.find_slots(slots, grow=True)
parent.write_slots(slot, bytes)
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
root = v.root()
mkdir(root, 'DIR1', CLUST_FREE)
mkdir(root, 'DIR2', CLUST_RSRVD)
mkdir(root, 'DIR3', CLUST_BAD)
mkdir(root, 'DIR4', CLUST_EOF)
mkdir(root, 'DIR5', 1)
mkdir(root, 'DIR6', v.clusters+2)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def root_bad_start(disk, fsck, newfs, newfs_opts):
def set_root_start(disk, head):
dev = file(disk, "r+")
dev.seek(0)
bytes = dev.read(512)
bytes = bytes[0:44] + struct.pack("<I", head) + bytes[48:]
dev.seek(0)
dev.write(bytes)
dev.close()
del dev
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
clusters = v.clusters
v.flush()
del v
f.close()
del f
for head in [CLUST_FREE, CLUST_RSRVD, CLUST_BAD, CLUST_EOF, 1, clusters+2]:
set_root_start(disk, head)
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
try:
launch([fsck, '-y', disk])
except LaunchError:
pass
try:
launch(['/sbin/fsck_msdos', '-n', disk])
except LaunchError:
pass
def root_bad_first_cluster(disk, fsck, newfs, newfs_opts):
for link in [CLUST_FREE, CLUST_RSRVD, CLUST_BAD]:
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
v.fat[v.rootCluster] = link
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def dir_size_dots(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
root = v.root()
child = root.mkdir('CHILD')
grand = child.mkdir('GRAND')
dir = root.mkdir('BADSIZE', length=666)
dir = root.mkdir('BADDOT')
fields = parse_dirent(dir.read_slots(0))
fields['head'] = fields['head'] + 30
dir.write_slots(0, make_dirent(**fields))
dir = root.mkdir('DOTDOT.NZ')
fields = parse_dirent(dir.read_slots(0))
fields['head'] = 47
dir.write_slots(0, make_dirent(**fields))
dir = child.mkdir('DOTDOT.ZER')
fields = parse_dirent(dir.read_slots(0))
fields['head'] = 0
dir.write_slots(0, make_dirent(**fields))
dir = grand.mkdir('DOTDOT.BAD')
fields = parse_dirent(dir.read_slots(0))
fields['head'] = fields['head'] + 30
dir.write_slots(0, make_dirent(**fields))
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def long_name(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
root = v.root()
bytes = make_long_dirent('Test1GB', ATTR_VOLUME_ID)
root.write_slots(0, bytes)
root.mkfile('The quick brown fox jumped over the lazy dog')
root.mkfile('foo.bar')
bytes = make_long_dirent('Greetings and felicitations my friends', ATTR_ARCHIVE)
bytes = bytes[0:-32] + 'HELLO ' + bytes[-21:]
assert len(bytes) % 32 == 0
slots = len(bytes) / 32
slot = root.find_slots(slots)
root.write_slots(slot, bytes)
subdir = root.mkdir('SubDir')
bytes = make_long_dirent('To be or not to be', ATTR_ARCHIVE)[32:]
slots = len(bytes) / 32
slot = subdir.find_slots(slots)
subdir.write_slots(slot, bytes)
bytes = make_long_dirent('A Man a Plan a Canal Panama', ATTR_ARCHIVE)
bytes = bytes[:32] + bytes[64:]
slots = len(bytes) / 32
slot = subdir.find_slots(slots)
subdir.write_slots(slot, bytes)
bytes = make_long_dirent('We the People in order to form a more perfect union', ATTR_ARCHIVE)
bytes = bytes[0:-64] + bytes[-32:]
slots = len(bytes) / 32
slot = subdir.find_slots(slots)
subdir.write_slots(slot, bytes)
subdir = root.mkdir('Bad Orders')
bytes = make_long_dirent('One is the loneliest number', ATTR_ARCHIVE)
bytes = chr(ord(bytes[0])+7) + bytes[1:]
slots = len(bytes) / 32
slot = subdir.find_slots(slots)
subdir.write_slots(slot, bytes)
bytes = make_long_dirent('It takes two to tango or so they say', ATTR_ARCHIVE)
bytes = bytes[:32] + chr(ord(bytes[32])+7) + bytes[33:]
slots = len(bytes) / 32
slot = subdir.find_slots(slots)
subdir.write_slots(slot, bytes)
bytes = make_long_dirent('Threes Company becomes Threes A Crowd', ATTR_ARCHIVE)
bytes = bytes[:-64] + chr(ord(bytes[-64])+7) + bytes[-63:]
slots = len(bytes) / 32
slot = subdir.find_slots(slots)
subdir.write_slots(slot, bytes)
bytes = make_long_dirent('Four score and seven years ago', ATTR_ARCHIVE)
bytes = bytes[0:-32] assert len(bytes) % 32 == 0
slots = len(bytes) / 32
slot = root.find_slots(slots)
root.write_slots(slot, bytes)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def past_end_of_dir(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
root = v.root()
subdir = root.mkdir('SubDir')
subdir.mkfile('Good Sub File')
root.mkfile('Good Root File')
slotEOF = root.find_slots(1)
root.mkfile('EOF')
root.mkfile('BADFILE')
root.mkdir('Bad Dir')
root.mkfile('Bad File 2')
root.write_slots(slotEOF, '\x00' * 32)
slotEOF = subdir.find_slots(1)
subdir.mkfile('EOF')
subdir.mkfile('BADFILE')
subdir.mkdir('Bad Dir')
subdir.mkfile('Bad File 2')
subdir.write_slots(slotEOF, '\x00' * 32)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def fat_bad_0_or_1(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
v.fat[0] = 0
v.fat[1] = 1
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch(['/sbin/fsck_msdos', '-n', disk])
def fat_mark_clean_corrupt(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
if v.type == 32:
v.fat[1] = v.fat[1] & 0x07FFFFFF
else:
v.fat[1] = v.fat[1] & 0x7FFF
v.allocate(3)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
f = file(disk, "r")
v = msdosfs(f)
if v.type == 32:
clean = v.fat[1] & 0x08000000
else:
clean = v.fat[1] & 0x8000
if not clean:
raise RuntimeError("Volume still dirty!")
v.flush()
del v
f.close()
del f
launch(['/sbin/fsck_msdos', '-n', disk])
def fat_mark_clean_ok(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
f = file(disk, "r+")
v = msdosfs(f)
if v.type == 32:
v.fat[1] = v.fat[1] & 0x07FFFFFF
else:
v.fat[1] = v.fat[1] & 0x7FFF
v.flush()
del v
f.close()
del f
stdout, stderr = launch([fsck, '-n', disk], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert "\nMARK FILE SYSTEM CLEAN? no\n" in stdout
assert "\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n" in stdout
stdout, stderr = launch([fsck, '-y', disk], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert "\nMARK FILE SYSTEM CLEAN? yes\n" in stdout
assert "\nMARKING FILE SYSTEM CLEAN\n" in stdout
f = file(disk, "r")
v = msdosfs(f)
if v.type == 32:
clean = v.fat[1] & 0x08000000
else:
clean = v.fat[1] & 0x8000
if not clean:
raise RuntimeError("Volume still dirty!")
v.flush()
del v
f.close()
del f
launch(['/sbin/fsck_msdos', '-n', disk])
def file_4GB(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
print "# Creating a 4GiB file. This may take some time."
f = file(disk, "r+")
v = msdosfs(f)
four_GB = 4*1024*1024*1024
clusters = four_GB / v.bytesPerCluster
head = v.allocate(clusters)
v.root().mkfile('4GB', head=head, length=four_GB-100)
v.flush()
del v
f.close()
del f
launch([fsck, '-n', disk])
def file_4GB_excess_clusters(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
print "# Creating a 4GiB+ file. This may take some time."
f = file(disk, "r+")
v = msdosfs(f)
four_GB = 4*1024*1024*1024
clusters = four_GB / v.bytesPerCluster
head=v.allocate(clusters+7)
v.root().mkfile('FOO', head=head, length=5*v.bytesPerCluster-100)
head=v.allocate(clusters+3)
v.root().mkfile('BAR', head=head, length=four_GB-30)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
launch([fsck, '-y', disk])
launch([fsck, '-n', disk])
def test_quick(disk, fsck, newfs, newfs_opts):
assert newfs_opts[1] in ["12", "16", "32"]
launch([newfs]+newfs_opts+[disk])
launch([fsck, '-q', disk])
f = file(disk, "r+")
v = msdosfs(f)
if newfs_opts[1] in ["16", "32"]:
if newfs_opts[1] == "16":
v.fat[1] &= 0x7FFF
else:
v.fat[1] &= 0x07FFFFFF
else:
v.allocate(3)
v.flush()
del v
f.close()
del f
try:
launch([fsck, '-q', disk])
except LaunchError:
pass
else:
raise FailureExpected("Volume not dirty?")
def test_maxmem(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
launch([fsck, '-M', '1m', disk])
launch([fsck, '-M', '900k', disk])
def test_bad_args(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
try:
launch([fsck, '-M', 'foo', disk])
except LaunchError:
pass
else:
raise FailureExpected("Expected bad argument: -M foo")
try:
launch([fsck, '-p', '-M', 'foo', disk])
except LaunchError:
pass
else:
raise FailureExpected("Expected bad argument: -p -M foo")
try:
launch([fsck, '-M', '1x', disk])
except LaunchError:
pass
else:
raise FailureExpected("Expected bad argument: -M 1x")
try:
launch([fsck, '-z', disk])
except LaunchError:
pass
else:
raise FailureExpected("Expected bad argument: -z")
try:
launch([fsck])
except LaunchError:
pass
else:
raise FailureExpected("Expected usage (no disk given)")
def test_boot_sector(disk, fsck, newfs, newfs_opts):
def bad_jump(bytes):
return 'H+' + bytes[2:]
def bad_sector_size(bytes):
return bytes[0:11] + '\xff\x03' + bytes[13:]
def bad_sec_per_clust(bytes):
return bytes[0:13] + '\x07' + bytes[14:]
for func, reason in [(bad_jump,"Bad boot jump"),
(bad_sector_size, "Bad sector size"),
(bad_sec_per_clust, "Bad sectors per cluster")]:
launch([newfs]+newfs_opts+[disk])
with open(disk, "r+") as f:
bytes = f.read(512)
f.seek(0)
bytes = func(bytes)
f.write(bytes)
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
else:
raise FailureExpected(reason)
def test_boot_fat32(disk, fsck, newfs, newfs_opts):
def bad_root_count(bytes):
return bytes[0:17] + '\x00\x02' + bytes[19:]
def bad_version(bytes):
return bytes[0:42] + '\x00\x01' + bytes[44:]
for func, reason in [(bad_root_count,"Bad root entry count"),
(bad_version, "Bad filesystem version")]:
launch([newfs]+newfs_opts+[disk])
with open(disk, "r+") as f:
bytes = f.read(512)
f.seek(0)
bytes = func(bytes)
f.write(bytes)
try:
launch([fsck, '-n', disk])
except LaunchError:
pass
else:
raise FailureExpected(reason)
def test_fsinfo(disk, fsck, newfs, newfs_opts):
def bad_leading_sig(bytes):
return 'RRAA' + bytes[4:]
def bad_sig2(bytes):
return bytes[0:484] + 'rraa' + bytes[488:]
def bad_trailing_sig(bytes):
return bytes[0:508] + '\xff\x00\xaa\x55' + bytes[512:]
def bad_free_count(bytes):
return bytes[0:488] + '\xfe\xed\xfa\xce' + bytes[492:]
launch([newfs]+newfs_opts+[disk])
with open(disk, "r+") as f:
bytes = f.read(512)
fsinfo = ord(bytes[48]) + 256 * ord(bytes[49])
for func, reason in [(bad_leading_sig, "Bad leading signature"),
(bad_sig2, "Bad structure signature"),
(bad_trailing_sig, "Bad trailing signature"),
(bad_free_count, "Bad free cluster count")]:
launch([newfs]+newfs_opts+[disk])
with open(disk, "r+") as f:
f.seek(fsinfo * 512)
bytes = f.read(512)
f.seek(fsinfo * 512)
bytes = func(bytes)
f.write(bytes)
launch([fsck, '-y', disk])
launch([fsck, '-n', disk])
def fat_too_small(disk, fsck, newfs, newfs_opts):
launch([newfs]+newfs_opts+[disk])
with open(disk, "r+") as f:
bytes = f.read(512)
numFATs = ord(bytes[16])
reserved = ord(bytes[14]) + 256 * ord(bytes[15])
if bytes[22:24] != '\x00\x00':
fat_sectors = struct.unpack("<H", bytes[22:24])[0]
bytes = bytes[0:22] + struct.pack("<H", fat_sectors - 1) + bytes[24:]
else:
fat_sectors = struct.unpack("<I", bytes[36:40])[0]
bytes = bytes[0:36] + struct.pack("<I", fat_sectors - 1) + bytes[40:]
f.seek(0)
f.write(bytes)
f.seek(512 * (reserved + numFATs * fat_sectors))
bytes = f.read(65536)
f.seek(512 * (reserved + numFATs * fat_sectors - numFATs))
f.write(bytes)
launch([fsck, '-y', disk]) launch([fsck, '-n', disk])
if __name__ == '__main__':
dir = '/tmp'
fsck = 'fsck_msdos'
newfs = 'newfs_msdos'
if len(sys.argv) > 1:
fsck = sys.argv[1]
if len(sys.argv) > 2:
dir = sys.argv[2]
if len(sys.argv) > 3:
print "%s: Too many arguments!" % sys.argv[0]
print "Usage: %s [<fsck_msdos> [<tmp_dir>]]"
sys.exit(1)
test_fat32(dir, fsck, newfs)
test_fat16(dir, fsck, newfs)
test_fat12(dir, fsck, newfs)
print "\nSuccess!"