34,7 → 34,6 |
import os |
import random |
import xstruct |
import array |
|
def align_up(size, alignment): |
"Return size aligned up to alignment" |
44,7 → 43,7 |
|
return (((size / alignment) + 1) * alignment) |
|
def subtree_size(root, cluster_size, dirent_size): |
def subtree_size(root, cluster_size): |
"Recursive directory walk and calculate size" |
|
size = 0 |
58,10 → 57,10 |
files += 1 |
|
if (os.path.isdir(canon)): |
size += subtree_size(canon, cluster_size, dirent_size) |
size += subtree_size(canon, cluster_size) |
files += 1 |
|
return size + align_up(files * dirent_size, cluster_size) |
return size + align_up(files * 32, cluster_size) |
|
def root_entries(root): |
"Return number of root directory entries" |
68,99 → 67,6 |
|
return len(os.listdir(root)) |
|
def write_file(path, outf, cluster_size, data_start, fat): |
"Store the contents of a file" |
|
size = os.path.getsize(path) |
prev = -1 |
first = -1 |
|
inf = file(path, "r") |
rd = 0; |
while (rd < size): |
data = inf.read(cluster_size); |
|
empty_cluster = fat.index(0) |
|
fat[empty_cluster] = 0xffff |
if (prev != -1): |
fat[prev] = empty_cluster |
else: |
first = empty_cluster |
|
prev = empty_cluster |
|
outf.seek(data_start + empty_cluster * cluster_size) |
outf.write(data) |
rd += len(data) |
inf.close() |
|
return first, size |
|
DIR_ENTRY = """little: |
char name[8] /* file name */ |
char ext[3] /* file extension */ |
uint8_t attr /* file attributes */ |
padding[1] /* reserved for NT */ |
uint8_t ctime_fine /* create time (fine resolution) */ |
uint16_t ctime /* create time */ |
uint16_t cdate /* create date */ |
uint16_t adate /* access date */ |
padding[2] /* EA-index */ |
uint16_t mtime /* modification time */ |
uint16_t mdate /* modification date */ |
uint16_t cluster /* first cluster */ |
uint32_t size /* file size */ |
""" |
|
def mangle_fname(name): |
# FIXME: filter illegal characters |
fname = (name.split('.')[0] + ' ').upper()[0:8] |
return fname |
|
def mangle_ext(name): |
# FIXME: filter illegal characters |
ext = (name.split('.')[1] + ' ').upper()[0:3] |
return ext |
|
def create_dirent(name, directory, cluster, size): |
dir_entry = xstruct.create(DIR_ENTRY) |
|
dir_entry.name = mangle_fname(name) |
dir_entry.ext = mangle_ext(name) |
|
if (directory): |
dir_entry.attr = 0x30 |
else: |
dir_entry.attr = 0x20 |
|
dir_entry.ctime_fine = 0 # FIXME |
dir_entry.ctime = 0 # FIXME |
dir_entry.cdate = 0 # FIXME |
dir_entry.adate = 0 # FIXME |
dir_entry.mtime = 0 # FIXME |
dir_entry.mdate = 0 # FIXME |
dir_entry.cluster = cluster |
dir_entry.size = size |
|
return dir_entry |
|
def recursion(head, root, outf, cluster_size, root_start, data_start, fat): |
"Recursive directory walk" |
|
directory = [] |
for name in os.listdir(root): |
canon = os.path.join(root, name) |
|
if (os.path.isfile(canon)): |
rv = write_file(canon, outf, cluster_size, data_start, fat) |
directory.append(create_dirent(name, False, rv[0], rv[1])) |
|
if (head): |
outf.seek(root_start) |
for dir_entry in directory: |
outf.write(dir_entry.pack()) |
|
BOOT_SECTOR = """little: |
uint8_t jmp[3] /* jump instruction */ |
char oem[8] /* OEM string */ |
189,13 → 95,9 |
""" |
|
EMPTY_SECTOR = """little: |
padding[512] /* empty sector data */ |
padding[512] |
""" |
|
FAT_ENTRY = """little: |
uint16_t next /* FAT16 entry */ |
""" |
|
def usage(prname): |
"Print usage syntax" |
print prname + " <PATH> <IMAGE>" |
210,32 → 112,15 |
print "<PATH> must be a directory" |
return |
|
fat16_clusters = 4096 |
|
sector_size = 512 |
cluster_size = 4096 |
dirent_size = 32 |
fatent_size = 2 |
fat_count = 2 |
reserved_clusters = 2 |
|
# Make sure the filesystem is large enought for FAT16 |
size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size |
while (size / cluster_size < fat16_clusters): |
if (cluster_size > sector_size): |
cluster_size /= 2 |
size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size |
else: |
size = fat16_clusters * cluster_size + reserved_clusters * cluster_size |
root_size = align_up(root_entries(sys.argv[1]) * 32, sector_size) |
size = subtree_size(sys.argv[1], cluster_size) |
fat_size = align_up(size / cluster_size * 2, sector_size) |
|
root_size = align_up(root_entries(path) * dirent_size, cluster_size) |
sectors = (cluster_size + 2 * fat_size + root_size + size) / sector_size |
|
fat_size = align_up(align_up(size, cluster_size) / cluster_size * fatent_size, sector_size) |
|
sectors = (cluster_size + fat_count * fat_size + root_size + size) / sector_size |
root_start = cluster_size + fat_count * fat_size |
data_start = root_start + root_size |
|
outf = file(sys.argv[2], "w") |
|
boot_sector = xstruct.create(BOOT_SECTOR) |
244,8 → 129,8 |
boot_sector.sector = sector_size |
boot_sector.cluster = cluster_size / sector_size |
boot_sector.reserved = cluster_size / sector_size |
boot_sector.fats = fat_count |
boot_sector.rootdir = root_size / dirent_size |
boot_sector.fats = 2 |
boot_sector.rootdir = root_size / 32 |
boot_sector.sectors = (sectors if (sectors <= 65535) else 0) |
boot_sector.descriptor = 0xF8 |
boot_sector.fat_sectors = fat_size / sector_size |
265,12 → 150,12 |
|
empty_sector = xstruct.create(EMPTY_SECTOR) |
|
# Reserved sectors |
for i in range(1, cluster_size / sector_size): |
# Reserved sectors (boot_sector.reserved - boot_sector) |
for i in range(1, boot_sector.reserved): |
outf.write(empty_sector.pack()) |
|
# FAT tables |
for i in range(0, fat_count): |
for i in range(0, boot_sector.fats): |
for j in range(0, boot_sector.fat_sectors): |
outf.write(empty_sector.pack()) |
|
282,20 → 167,6 |
for i in range(0, size / sector_size): |
outf.write(empty_sector.pack()) |
|
fat = array.array('L', [0] * (fat_size / fatent_size)) |
fat[0] = 0xfff8 |
fat[1] = 0xffff |
|
recursion(True, path, outf, cluster_size, root_start, data_start, fat) |
|
# Store FAT |
fat_entry = xstruct.create(FAT_ENTRY) |
for i in range(0, fat_count): |
outf.seek(cluster_size + i * fat_size) |
for j in range(0, fat_size / fatent_size): |
fat_entry.next = fat[j] |
outf.write(fat_entry.pack()) |
|
outf.close() |
|
if __name__ == '__main__': |