source: mainline/tools/mkfat.py@ 9f95a80

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9f95a80 was 8bc6fcf, checked in by Martin Decky <martin@…>, 17 years ago

create a working (albeit empty) FAT16 filesystem

  • Property mode set to 100755
File size: 5.4 KB
Line 
1#!/usr/bin/env python
2#
3# Copyright (c) 2008 Martin Decky
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9#
10# - Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer.
12# - Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions and the following disclaimer in the
14# documentation and/or other materials provided with the distribution.
15# - The name of the author may not be used to endorse or promote products
16# derived from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29"""
30FAT creator
31"""
32
33import sys
34import os
35import random
36import xstruct
37
38def align_up(size, alignment):
39 "Return size aligned up to alignment"
40
41 if (size % alignment == 0):
42 return size
43
44 return (((size / alignment) + 1) * alignment)
45
46def subtree_size(root, cluster_size):
47 "Recursive directory walk and calculate size"
48
49 size = 0
50 files = 0
51
52 for name in os.listdir(root):
53 canon = os.path.join(root, name)
54
55 if (os.path.isfile(canon)):
56 size += align_up(os.path.getsize(canon), cluster_size)
57 files += 1
58
59 if (os.path.isdir(canon)):
60 size += subtree_size(canon, cluster_size)
61 files += 1
62
63 return size + align_up(files * 32, cluster_size)
64
65def root_entries(root):
66 "Return number of root directory entries"
67
68 return len(os.listdir(root))
69
70BOOT_SECTOR = """little:
71 uint8_t jmp[3] /* jump instruction */
72 char oem[8] /* OEM string */
73 uint16_t sector /* bytes per sector */
74 uint8_t cluster /* sectors per cluster */
75 uint16_t reserved /* reserved sectors */
76 uint8_t fats /* number of FATs */
77 uint16_t rootdir /* root directory entries */
78 uint16_t sectors /* total number of sectors */
79 uint8_t descriptor /* media descriptor */
80 uint16_t fat_sectors /* sectors per single FAT */
81 uint16_t track_sectors /* sectors per track */
82 uint16_t heads /* number of heads */
83 uint32_t hidden /* hidden sectors */
84 uint32_t sectors_big /* total number of sectors (if sectors == 0) */
85
86 /* Extended BIOS Parameter Block */
87 uint8_t drive /* physical drive number */
88 padding[1] /* reserved (current head) */
89 uint8_t extboot_signature /* extended boot signature */
90 uint32_t serial /* serial number */
91 char label[11] /* volume label */
92 char fstype[8] /* filesystem type */
93 padding[448] /* boot code */
94 uint8_t boot_signature[2] /* boot signature */
95"""
96
97EMPTY_SECTOR = """little:
98 padding[512]
99"""
100
101def usage(prname):
102 "Print usage syntax"
103 print prname + " <PATH> <IMAGE>"
104
105def main():
106 if (len(sys.argv) < 3):
107 usage(sys.argv[0])
108 return
109
110 path = os.path.abspath(sys.argv[1])
111 if (not os.path.isdir(path)):
112 print "<PATH> must be a directory"
113 return
114
115 sector_size = 512
116 cluster_size = 4096
117
118 root_size = align_up(root_entries(sys.argv[1]) * 32, sector_size)
119 size = subtree_size(sys.argv[1], cluster_size)
120 fat_size = align_up(size / cluster_size * 2, sector_size)
121
122 sectors = (cluster_size + 2 * fat_size + root_size + size) / sector_size
123
124 outf = file(sys.argv[2], "w")
125
126 boot_sector = xstruct.create(BOOT_SECTOR)
127 boot_sector.jmp = [0xEB, 0x3C, 0x90]
128 boot_sector.oem = "MSDOS5.0"
129 boot_sector.sector = sector_size
130 boot_sector.cluster = cluster_size / sector_size
131 boot_sector.reserved = cluster_size / sector_size
132 boot_sector.fats = 2
133 boot_sector.rootdir = root_size / 32
134 boot_sector.sectors = (sectors if (sectors <= 65535) else 0)
135 boot_sector.descriptor = 0xF8
136 boot_sector.fat_sectors = fat_size / sector_size
137 boot_sector.track_sectors = 63
138 boot_sector.heads = 6
139 boot_sector.hidden = 0
140 boot_sector.sectors_big = (sectors if (sectors > 65535) else 0)
141
142 boot_sector.drive = 0x80
143 boot_sector.extboot_signature = 0x29
144 boot_sector.serial = random.randint(0, 0xFFFFFFFF)
145 boot_sector.label = "HELENOS"
146 boot_sector.fstype = "FAT16 "
147 boot_sector.boot_signature = [0x55, 0xAA]
148
149 outf.write(boot_sector.pack())
150
151 empty_sector = xstruct.create(EMPTY_SECTOR)
152
153 # Reserved sectors (boot_sector.reserved - boot_sector)
154 for i in range(1, boot_sector.reserved):
155 outf.write(empty_sector.pack())
156
157 # FAT tables
158 for i in range(0, boot_sector.fats):
159 for j in range(0, boot_sector.fat_sectors):
160 outf.write(empty_sector.pack())
161
162 # Root directory
163 for i in range(0, root_size / sector_size):
164 outf.write(empty_sector.pack())
165
166 # Data
167 for i in range(0, size / sector_size):
168 outf.write(empty_sector.pack())
169
170 outf.close()
171
172if __name__ == '__main__':
173 main()
Note: See TracBrowser for help on using the repository browser.