Subversion Repositories HelenOS

Rev

Rev 4360 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4360 Rev 4687
1
#!/usr/bin/env python
1
#!/usr/bin/env python
2
#
2
#
3
# Copyright (c) 2008 Martin Decky
3
# Copyright (c) 2008 Martin Decky
4
# All rights reserved.
4
# All rights reserved.
5
#
5
#
6
# Redistribution and use in source and binary forms, with or without
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions
7
# modification, are permitted provided that the following conditions
8
# are met:
8
# are met:
9
#
9
#
10
# - Redistributions of source code must retain the above copyright
10
# - Redistributions of source code must retain the above copyright
11
#   notice, this list of conditions and the following disclaimer.
11
#   notice, this list of conditions and the following disclaimer.
12
# - Redistributions in binary form must reproduce the above copyright
12
# - Redistributions in binary form must reproduce the above copyright
13
#   notice, this list of conditions and the following disclaimer in the
13
#   notice, this list of conditions and the following disclaimer in the
14
#   documentation and/or other materials provided with the distribution.
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
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.
16
#   derived from this software without specific prior written permission.
17
#
17
#
18
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
19
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
24
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
27
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
#
28
#
29
"""
29
"""
30
FAT creator
30
FAT creator
31
"""
31
"""
32
 
32
 
33
import sys
33
import sys
34
import os
34
import os
35
import random
35
import random
36
import xstruct
36
import xstruct
37
import array
37
import array
38
 
38
 
39
exclude_names = set(['.svn'])
39
exclude_names = set(['.svn'])
40
 
40
 
41
def align_up(size, alignment):
41
def align_up(size, alignment):
42
    "Return size aligned up to alignment"
42
    "Return size aligned up to alignment"
43
   
43
   
44
    if (size % alignment == 0):
44
    if (size % alignment == 0):
45
        return size
45
        return size
46
   
46
   
47
    return (((size / alignment) + 1) * alignment)
47
    return (((size / alignment) + 1) * alignment)
48
 
48
 
49
def subtree_size(root, cluster_size, dirent_size):
49
def subtree_size(root, cluster_size, dirent_size):
50
    "Recursive directory walk and calculate size"
50
    "Recursive directory walk and calculate size"
51
   
51
   
52
    size = 0
52
    size = 0
53
    files = 2
53
    files = 2
54
   
54
   
55
    for name in os.listdir(root):
55
    for name in os.listdir(root):
56
        canon = os.path.join(root, name)
56
        canon = os.path.join(root, name)
57
       
57
       
58
        if (os.path.isfile(canon) and (not name in exclude_names)):
58
        if (os.path.isfile(canon) and (not name in exclude_names)):
59
            size += align_up(os.path.getsize(canon), cluster_size)
59
            size += align_up(os.path.getsize(canon), cluster_size)
60
            files += 1
60
            files += 1
61
       
61
       
62
        if (os.path.isdir(canon) and (not name in exclude_names)):
62
        if (os.path.isdir(canon) and (not name in exclude_names)):
63
            size += subtree_size(canon, cluster_size, dirent_size)
63
            size += subtree_size(canon, cluster_size, dirent_size)
64
            files += 1
64
            files += 1
65
   
65
   
66
    return size + align_up(files * dirent_size, cluster_size)
66
    return size + align_up(files * dirent_size, cluster_size)
67
 
67
 
68
def root_entries(root):
68
def root_entries(root):
69
    "Return number of root directory entries"
69
    "Return number of root directory entries"
70
   
70
   
71
    return len(os.listdir(root))
71
    return len(os.listdir(root))
72
 
72
 
73
def write_file(path, outf, cluster_size, data_start, fat, reserved_clusters):
73
def write_file(path, outf, cluster_size, data_start, fat, reserved_clusters):
74
    "Store the contents of a file"
74
    "Store the contents of a file"
75
   
75
   
76
    size = os.path.getsize(path)
76
    size = os.path.getsize(path)
77
    prev = -1
77
    prev = -1
78
    first = 0
78
    first = 0
79
   
79
   
80
    inf = file(path, "r")
80
    inf = file(path, "r")
81
    rd = 0;
81
    rd = 0;
82
    while (rd < size):
82
    while (rd < size):
83
        empty_cluster = fat.index(0)
83
        empty_cluster = fat.index(0)
84
        fat[empty_cluster] = 0xffff
84
        fat[empty_cluster] = 0xffff
85
       
85
       
86
        if (prev != -1):
86
        if (prev != -1):
87
            fat[prev] = empty_cluster
87
            fat[prev] = empty_cluster
88
        else:
88
        else:
89
            first = empty_cluster
89
            first = empty_cluster
90
       
90
       
91
        prev = empty_cluster
91
        prev = empty_cluster
92
       
92
       
93
        data = inf.read(cluster_size);
93
        data = inf.read(cluster_size);
94
        outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size)
94
        outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size)
95
        outf.write(data)
95
        outf.write(data)
96
        rd += len(data)
96
        rd += len(data)
97
    inf.close()
97
    inf.close()
98
   
98
   
99
    return first, size
99
    return first, size
100
 
100
 
101
def write_directory(directory, outf, cluster_size, data_start, fat, reserved_clusters, dirent_size, empty_cluster):
101
def write_directory(directory, outf, cluster_size, data_start, fat, reserved_clusters, dirent_size, empty_cluster):
102
    "Store the contents of a directory"
102
    "Store the contents of a directory"
103
   
103
   
104
    length = len(directory)
104
    length = len(directory)
105
    size = length * dirent_size
105
    size = length * dirent_size
106
    prev = -1
106
    prev = -1
107
    first = 0
107
    first = 0
108
   
108
   
109
    i = 0
109
    i = 0
110
    rd = 0;
110
    rd = 0;
111
    while (rd < size):
111
    while (rd < size):
112
        if (prev != -1):
112
        if (prev != -1):
113
            empty_cluster = fat.index(0)
113
            empty_cluster = fat.index(0)
114
            fat[empty_cluster] = 0xffff
114
            fat[empty_cluster] = 0xffff
115
            fat[prev] = empty_cluster
115
            fat[prev] = empty_cluster
116
        else:
116
        else:
117
            first = empty_cluster
117
            first = empty_cluster
118
       
118
       
119
        prev = empty_cluster
119
        prev = empty_cluster
120
       
120
       
121
        data = ''
121
        data = ''
122
        data_len = 0
122
        data_len = 0
123
        while ((i < length) and (data_len < cluster_size)):
123
        while ((i < length) and (data_len < cluster_size)):
124
            if (i == 0):
124
            if (i == 0):
125
                directory[i].cluster = empty_cluster
125
                directory[i].cluster = empty_cluster
126
           
126
           
127
            data += directory[i].pack()
127
            data += directory[i].pack()
128
            data_len += dirent_size
128
            data_len += dirent_size
129
            i += 1
129
            i += 1
130
       
130
       
131
        outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size)
131
        outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size)
132
        outf.write(data)
132
        outf.write(data)
133
        rd += len(data)
133
        rd += len(data)
134
   
134
   
135
    return first, size
135
    return first, size
136
 
136
 
137
DIR_ENTRY = """little:
137
DIR_ENTRY = """little:
138
    char name[8]               /* file name */
138
    char name[8]               /* file name */
139
    char ext[3]                /* file extension */
139
    char ext[3]                /* file extension */
140
    uint8_t attr               /* file attributes */
140
    uint8_t attr               /* file attributes */
141
    uint8_t lcase              /* file name case (NT extension) */
141
    uint8_t lcase              /* file name case (NT extension) */
142
    uint8_t ctime_fine         /* create time (fine resolution) */
142
    uint8_t ctime_fine         /* create time (fine resolution) */
143
    uint16_t ctime             /* create time */
143
    uint16_t ctime             /* create time */
144
    uint16_t cdate             /* create date */
144
    uint16_t cdate             /* create date */
145
    uint16_t adate             /* access date */
145
    uint16_t adate             /* access date */
146
    padding[2]                 /* EA-index */
146
    padding[2]                 /* EA-index */
147
    uint16_t mtime             /* modification time */
147
    uint16_t mtime             /* modification time */
148
    uint16_t mdate             /* modification date */
148
    uint16_t mdate             /* modification date */
149
    uint16_t cluster           /* first cluster */
149
    uint16_t cluster           /* first cluster */
150
    uint32_t size              /* file size */
150
    uint32_t size              /* file size */
151
"""
151
"""
152
 
152
 
153
DOT_DIR_ENTRY = """little:
153
DOT_DIR_ENTRY = """little:
154
    uint8_t signature          /* 0x2e signature */
154
    uint8_t signature          /* 0x2e signature */
155
    char name[7]               /* empty */
155
    char name[7]               /* empty */
156
    char ext[3]                /* empty */
156
    char ext[3]                /* empty */
157
    uint8_t attr               /* file attributes */
157
    uint8_t attr               /* file attributes */
158
    padding[1]                 /* reserved for NT */
158
    padding[1]                 /* reserved for NT */
159
    uint8_t ctime_fine         /* create time (fine resolution) */
159
    uint8_t ctime_fine         /* create time (fine resolution) */
160
    uint16_t ctime             /* create time */
160
    uint16_t ctime             /* create time */
161
    uint16_t cdate             /* create date */
161
    uint16_t cdate             /* create date */
162
    uint16_t adate             /* access date */
162
    uint16_t adate             /* access date */
163
    padding[2]                 /* EA-index */
163
    padding[2]                 /* EA-index */
164
    uint16_t mtime             /* modification time */
164
    uint16_t mtime             /* modification time */
165
    uint16_t mdate             /* modification date */
165
    uint16_t mdate             /* modification date */
166
    uint16_t cluster           /* first cluster */
166
    uint16_t cluster           /* first cluster */
167
    uint32_t size              /* file size */
167
    uint32_t size              /* file size */
168
"""
168
"""
169
 
169
 
170
DOTDOT_DIR_ENTRY = """little:
170
DOTDOT_DIR_ENTRY = """little:
171
    uint8_t signature[2]       /* 0x2e signature */
171
    uint8_t signature[2]       /* 0x2e signature */
172
    char name[6]               /* empty */
172
    char name[6]               /* empty */
173
    char ext[3]                /* empty */
173
    char ext[3]                /* empty */
174
    uint8_t attr               /* file attributes */
174
    uint8_t attr               /* file attributes */
175
    padding[1]                 /* reserved for NT */
175
    padding[1]                 /* reserved for NT */
176
    uint8_t ctime_fine         /* create time (fine resolution) */
176
    uint8_t ctime_fine         /* create time (fine resolution) */
177
    uint16_t ctime             /* create time */
177
    uint16_t ctime             /* create time */
178
    uint16_t cdate             /* create date */
178
    uint16_t cdate             /* create date */
179
    uint16_t adate             /* access date */
179
    uint16_t adate             /* access date */
180
    padding[2]                 /* EA-index */
180
    padding[2]                 /* EA-index */
181
    uint16_t mtime             /* modification time */
181
    uint16_t mtime             /* modification time */
182
    uint16_t mdate             /* modification date */
182
    uint16_t mdate             /* modification date */
183
    uint16_t cluster           /* first cluster */
183
    uint16_t cluster           /* first cluster */
184
    uint32_t size              /* file size */
184
    uint32_t size              /* file size */
185
"""
185
"""
186
 
186
 
187
def mangle_fname(name):
187
def mangle_fname(name):
188
    # FIXME: filter illegal characters
188
    # FIXME: filter illegal characters
189
    parts = name.split('.')
189
    parts = name.split('.')
190
   
190
   
191
    if (len(parts) > 0):
191
    if (len(parts) > 0):
192
        fname = parts[0]
192
        fname = parts[0]
193
    else:
193
    else:
194
        fname = ''
194
        fname = ''
195
       
195
       
196
    return (fname + '          ').upper()[0:8]
196
    return (fname + '          ').upper()[0:8]
197
 
197
 
198
def mangle_ext(name):
198
def mangle_ext(name):
199
    # FIXME: filter illegal characters
199
    # FIXME: filter illegal characters
200
    parts = name.split('.')
200
    parts = name.split('.')
201
   
201
   
202
    if (len(parts) > 1):
202
    if (len(parts) > 1):
203
        ext = parts[1]
203
        ext = parts[1]
204
    else:
204
    else:
205
        ext = ''
205
        ext = ''
206
   
206
   
207
    return (ext + '   ').upper()[0:3]
207
    return (ext + '   ').upper()[0:3]
208
 
208
 
209
def create_dirent(name, directory, cluster, size):
209
def create_dirent(name, directory, cluster, size):
210
    dir_entry = xstruct.create(DIR_ENTRY)
210
    dir_entry = xstruct.create(DIR_ENTRY)
211
   
211
   
212
    dir_entry.name = mangle_fname(name)
212
    dir_entry.name = mangle_fname(name)
213
    dir_entry.ext = mangle_ext(name)
213
    dir_entry.ext = mangle_ext(name)
214
   
214
   
215
    if (directory):
215
    if (directory):
216
        dir_entry.attr = 0x30
216
        dir_entry.attr = 0x30
217
    else:
217
    else:
218
        dir_entry.attr = 0x20
218
        dir_entry.attr = 0x20
219
   
219
   
220
    dir_entry.lcase = 0x18
220
    dir_entry.lcase = 0x18
221
    dir_entry.ctime_fine = 0 # FIXME
221
    dir_entry.ctime_fine = 0 # FIXME
222
    dir_entry.ctime = 0 # FIXME
222
    dir_entry.ctime = 0 # FIXME
223
    dir_entry.cdate = 0 # FIXME
223
    dir_entry.cdate = 0 # FIXME
224
    dir_entry.adate = 0 # FIXME
224
    dir_entry.adate = 0 # FIXME
225
    dir_entry.mtime = 0 # FIXME
225
    dir_entry.mtime = 0 # FIXME
226
    dir_entry.mdate = 0 # FIXME
226
    dir_entry.mdate = 0 # FIXME
227
    dir_entry.cluster = cluster
227
    dir_entry.cluster = cluster
228
   
228
   
229
    if (directory):
229
    if (directory):
230
        dir_entry.size = 0
230
        dir_entry.size = 0
231
    else:
231
    else:
232
        dir_entry.size = size
232
        dir_entry.size = size
233
   
233
   
234
    return dir_entry
234
    return dir_entry
235
 
235
 
236
def create_dot_dirent(empty_cluster):
236
def create_dot_dirent(empty_cluster):
237
    dir_entry = xstruct.create(DOT_DIR_ENTRY)
237
    dir_entry = xstruct.create(DOT_DIR_ENTRY)
238
   
238
   
239
    dir_entry.signature = 0x2e
239
    dir_entry.signature = 0x2e
240
    dir_entry.name = '       '
240
    dir_entry.name = '       '
241
    dir_entry.ext = '   '
241
    dir_entry.ext = '   '
242
    dir_entry.attr = 0x10
242
    dir_entry.attr = 0x10
243
   
243
   
244
    dir_entry.ctime_fine = 0 # FIXME
244
    dir_entry.ctime_fine = 0 # FIXME
245
    dir_entry.ctime = 0 # FIXME
245
    dir_entry.ctime = 0 # FIXME
246
    dir_entry.cdate = 0 # FIXME
246
    dir_entry.cdate = 0 # FIXME
247
    dir_entry.adate = 0 # FIXME
247
    dir_entry.adate = 0 # FIXME
248
    dir_entry.mtime = 0 # FIXME
248
    dir_entry.mtime = 0 # FIXME
249
    dir_entry.mdate = 0 # FIXME
249
    dir_entry.mdate = 0 # FIXME
250
    dir_entry.cluster = empty_cluster
250
    dir_entry.cluster = empty_cluster
251
    dir_entry.size = 0
251
    dir_entry.size = 0
252
   
252
   
253
    return dir_entry
253
    return dir_entry
254
 
254
 
255
def create_dotdot_dirent(parent_cluster):
255
def create_dotdot_dirent(parent_cluster):
256
    dir_entry = xstruct.create(DOTDOT_DIR_ENTRY)
256
    dir_entry = xstruct.create(DOTDOT_DIR_ENTRY)
257
   
257
   
258
    dir_entry.signature = [0x2e, 0x2e]
258
    dir_entry.signature = [0x2e, 0x2e]
259
    dir_entry.name = '      '
259
    dir_entry.name = '      '
260
    dir_entry.ext = '   '
260
    dir_entry.ext = '   '
261
    dir_entry.attr = 0x10
261
    dir_entry.attr = 0x10
262
   
262
   
263
    dir_entry.ctime_fine = 0 # FIXME
263
    dir_entry.ctime_fine = 0 # FIXME
264
    dir_entry.ctime = 0 # FIXME
264
    dir_entry.ctime = 0 # FIXME
265
    dir_entry.cdate = 0 # FIXME
265
    dir_entry.cdate = 0 # FIXME
266
    dir_entry.adate = 0 # FIXME
266
    dir_entry.adate = 0 # FIXME
267
    dir_entry.mtime = 0 # FIXME
267
    dir_entry.mtime = 0 # FIXME
268
    dir_entry.mdate = 0 # FIXME
268
    dir_entry.mdate = 0 # FIXME
269
    dir_entry.cluster = parent_cluster
269
    dir_entry.cluster = parent_cluster
270
    dir_entry.size = 0
270
    dir_entry.size = 0
271
   
271
   
272
    return dir_entry
272
    return dir_entry
273
 
273
 
274
def recursion(head, root, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, parent_cluster):
274
def recursion(head, root, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, parent_cluster):
275
    "Recursive directory walk"
275
    "Recursive directory walk"
276
   
276
   
277
    directory = []
277
    directory = []
278
   
278
   
279
    if (not head):
279
    if (not head):
280
        # Directory cluster preallocation
280
        # Directory cluster preallocation
281
        empty_cluster = fat.index(0)
281
        empty_cluster = fat.index(0)
282
        fat[empty_cluster] = 0xffff
282
        fat[empty_cluster] = 0xffff
283
       
283
       
284
        directory.append(create_dot_dirent(empty_cluster))
284
        directory.append(create_dot_dirent(empty_cluster))
285
        directory.append(create_dotdot_dirent(parent_cluster))
285
        directory.append(create_dotdot_dirent(parent_cluster))
286
    else:
286
    else:
287
        empty_cluster = 0
287
        empty_cluster = 0
288
   
288
   
289
    for name in os.listdir(root):
289
    for name in os.listdir(root):
290
        canon = os.path.join(root, name)
290
        canon = os.path.join(root, name)
291
       
291
       
292
        if (os.path.isfile(canon) and (not name in exclude_names)):
292
        if (os.path.isfile(canon) and (not name in exclude_names)):
293
            rv = write_file(canon, outf, cluster_size, data_start, fat, reserved_clusters)
293
            rv = write_file(canon, outf, cluster_size, data_start, fat, reserved_clusters)
294
            directory.append(create_dirent(name, False, rv[0], rv[1]))
294
            directory.append(create_dirent(name, False, rv[0], rv[1]))
295
       
295
       
296
        if (os.path.isdir(canon) and (not name in exclude_names)):
296
        if (os.path.isdir(canon) and (not name in exclude_names)):
297
            rv = recursion(False, canon, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
297
            rv = recursion(False, canon, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
298
            directory.append(create_dirent(name, True, rv[0], rv[1]))
298
            directory.append(create_dirent(name, True, rv[0], rv[1]))
299
   
299
   
300
    if (head):
300
    if (head):
301
        outf.seek(root_start)
301
        outf.seek(root_start)
302
        for dir_entry in directory:
302
        for dir_entry in directory:
303
            outf.write(dir_entry.pack())
303
            outf.write(dir_entry.pack())
304
    else:
304
    else:
305
        return write_directory(directory, outf, cluster_size, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
305
        return write_directory(directory, outf, cluster_size, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
306
 
306
 
307
BOOT_SECTOR = """little:
307
BOOT_SECTOR = """little:
308
    uint8_t jmp[3]             /* jump instruction */
308
    uint8_t jmp[3]             /* jump instruction */
309
    char oem[8]                /* OEM string */
309
    char oem[8]                /* OEM string */
310
    uint16_t sector            /* bytes per sector */
310
    uint16_t sector            /* bytes per sector */
311
    uint8_t cluster            /* sectors per cluster */
311
    uint8_t cluster            /* sectors per cluster */
312
    uint16_t reserved          /* reserved sectors */
312
    uint16_t reserved          /* reserved sectors */
313
    uint8_t fats               /* number of FATs */
313
    uint8_t fats               /* number of FATs */
314
    uint16_t rootdir           /* root directory entries */
314
    uint16_t rootdir           /* root directory entries */
315
    uint16_t sectors           /* total number of sectors */
315
    uint16_t sectors           /* total number of sectors */
316
    uint8_t descriptor         /* media descriptor */
316
    uint8_t descriptor         /* media descriptor */
317
    uint16_t fat_sectors       /* sectors per single FAT */
317
    uint16_t fat_sectors       /* sectors per single FAT */
318
    uint16_t track_sectors     /* sectors per track */
318
    uint16_t track_sectors     /* sectors per track */
319
    uint16_t heads             /* number of heads */
319
    uint16_t heads             /* number of heads */
320
    uint32_t hidden            /* hidden sectors */
320
    uint32_t hidden            /* hidden sectors */
321
    uint32_t sectors_big       /* total number of sectors (if sectors == 0) */
321
    uint32_t sectors_big       /* total number of sectors (if sectors == 0) */
322
   
322
   
323
    /* Extended BIOS Parameter Block */
323
    /* Extended BIOS Parameter Block */
324
    uint8_t drive              /* physical drive number */
324
    uint8_t drive              /* physical drive number */
325
    padding[1]                 /* reserved (current head) */
325
    padding[1]                 /* reserved (current head) */
326
    uint8_t extboot_signature  /* extended boot signature */
326
    uint8_t extboot_signature  /* extended boot signature */
327
    uint32_t serial            /* serial number */
327
    uint32_t serial            /* serial number */
328
    char label[11]             /* volume label */
328
    char label[11]             /* volume label */
329
    char fstype[8]             /* filesystem type */
329
    char fstype[8]             /* filesystem type */
330
    padding[448]               /* boot code */
330
    padding[448]               /* boot code */
331
    uint8_t boot_signature[2]  /* boot signature */
331
    uint8_t boot_signature[2]  /* boot signature */
332
"""
332
"""
333
 
333
 
334
EMPTY_SECTOR = """little:
334
EMPTY_SECTOR = """little:
335
    padding[512]               /* empty sector data */
335
    padding[512]               /* empty sector data */
336
"""
336
"""
337
 
337
 
338
FAT_ENTRY = """little:
338
FAT_ENTRY = """little:
339
    uint16_t next              /* FAT16 entry */
339
    uint16_t next              /* FAT16 entry */
340
"""
340
"""
341
 
341
 
342
def usage(prname):
342
def usage(prname):
343
    "Print usage syntax"
343
    "Print usage syntax"
344
    print prname + " <PATH> <IMAGE>"
344
    print prname + " <PATH> <IMAGE>"
345
 
345
 
346
def main():
346
def main():
347
    if (len(sys.argv) < 3):
347
    if (len(sys.argv) < 3):
348
        usage(sys.argv[0])
348
        usage(sys.argv[0])
349
        return
349
        return
350
   
350
   
351
    path = os.path.abspath(sys.argv[1])
351
    path = os.path.abspath(sys.argv[1])
352
    if (not os.path.isdir(path)):
352
    if (not os.path.isdir(path)):
353
        print "<PATH> must be a directory"
353
        print "<PATH> must be a directory"
354
        return
354
        return
355
   
355
   
356
    fat16_clusters = 4096
356
    fat16_clusters = 4096
357
   
357
   
358
    sector_size = 512
358
    sector_size = 512
359
    cluster_size = 4096
359
    cluster_size = 4096
360
    dirent_size = 32
360
    dirent_size = 32
361
    fatent_size = 2
361
    fatent_size = 2
362
    fat_count = 2
362
    fat_count = 2
363
    reserved_clusters = 2
363
    reserved_clusters = 2
364
   
364
   
365
    # Make sure the filesystem is large enought for FAT16
365
    # Make sure the filesystem is large enought for FAT16
366
    size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
366
    size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
367
    while (size / cluster_size < fat16_clusters):
367
    while (size / cluster_size < fat16_clusters):
368
        if (cluster_size > sector_size):
368
        if (cluster_size > sector_size):
369
            cluster_size /= 2
369
            cluster_size /= 2
370
            size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
370
            size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
371
        else:
371
        else:
372
            size = fat16_clusters * cluster_size + reserved_clusters * cluster_size
372
            size = fat16_clusters * cluster_size + reserved_clusters * cluster_size
373
   
373
   
374
    root_size = align_up(root_entries(path) * dirent_size, cluster_size)
374
    root_size = align_up(root_entries(path) * dirent_size, cluster_size)
375
   
375
   
376
    fat_size = align_up(align_up(size, cluster_size) / cluster_size * fatent_size, sector_size)
376
    fat_size = align_up(align_up(size, cluster_size) / cluster_size * fatent_size, sector_size)
377
   
377
   
378
    sectors = (cluster_size + fat_count * fat_size + root_size + size) / sector_size
378
    sectors = (cluster_size + fat_count * fat_size + root_size + size) / sector_size
379
    root_start = cluster_size + fat_count * fat_size
379
    root_start = cluster_size + fat_count * fat_size
380
    data_start = root_start + root_size
380
    data_start = root_start + root_size
381
   
381
   
382
    outf = file(sys.argv[2], "w")
382
    outf = file(sys.argv[2], "w")
383
   
383
   
384
    boot_sector = xstruct.create(BOOT_SECTOR)
384
    boot_sector = xstruct.create(BOOT_SECTOR)
385
    boot_sector.jmp = [0xEB, 0x3C, 0x90]
385
    boot_sector.jmp = [0xEB, 0x3C, 0x90]
386
    boot_sector.oem = "MSDOS5.0"
386
    boot_sector.oem = "MSDOS5.0"
387
    boot_sector.sector = sector_size
387
    boot_sector.sector = sector_size
388
    boot_sector.cluster = cluster_size / sector_size
388
    boot_sector.cluster = cluster_size / sector_size
389
    boot_sector.reserved = cluster_size / sector_size
389
    boot_sector.reserved = cluster_size / sector_size
390
    boot_sector.fats = fat_count
390
    boot_sector.fats = fat_count
391
    boot_sector.rootdir = root_size / dirent_size
391
    boot_sector.rootdir = root_size / dirent_size
392
    if (sectors <= 65535):
392
    if (sectors <= 65535):
393
        boot_sector.sectors = sectors
393
        boot_sector.sectors = sectors
394
    else:
394
    else:
395
        boot_sector.sectors = 0
395
        boot_sector.sectors = 0
396
    boot_sector.descriptor = 0xF8
396
    boot_sector.descriptor = 0xF8
397
    boot_sector.fat_sectors = fat_size / sector_size
397
    boot_sector.fat_sectors = fat_size / sector_size
398
    boot_sector.track_sectors = 63
398
    boot_sector.track_sectors = 63
399
    boot_sector.heads = 6
399
    boot_sector.heads = 6
400
    boot_sector.hidden = 0
400
    boot_sector.hidden = 0
401
    if (sectors > 65535):
401
    if (sectors > 65535):
402
        boot_sector.sectors_big = sectors
402
        boot_sector.sectors_big = sectors
403
    else:
403
    else:
404
        boot_sector.sectors_big = 0
404
        boot_sector.sectors_big = 0
405
   
405
   
406
    boot_sector.drive = 0x80
406
    boot_sector.drive = 0x80
407
    boot_sector.extboot_signature = 0x29
407
    boot_sector.extboot_signature = 0x29
408
    boot_sector.serial = random.randint(0, 0x7fffffff)
408
    boot_sector.serial = random.randint(0, 0x7fffffff)
409
    boot_sector.label = "HELENOS"
409
    boot_sector.label = "HELENOS"
410
    boot_sector.fstype = "FAT16   "
410
    boot_sector.fstype = "FAT16   "
411
    boot_sector.boot_signature = [0x55, 0xAA]
411
    boot_sector.boot_signature = [0x55, 0xAA]
412
   
412
   
413
    outf.write(boot_sector.pack())
413
    outf.write(boot_sector.pack())
414
   
414
   
415
    empty_sector = xstruct.create(EMPTY_SECTOR)
415
    empty_sector = xstruct.create(EMPTY_SECTOR)
416
   
416
   
417
    # Reserved sectors
417
    # Reserved sectors
418
    for i in range(1, cluster_size / sector_size):
418
    for i in range(1, cluster_size / sector_size):
419
        outf.write(empty_sector.pack())
419
        outf.write(empty_sector.pack())
420
   
420
   
421
    # FAT tables
421
    # FAT tables
422
    for i in range(0, fat_count):
422
    for i in range(0, fat_count):
423
        for j in range(0, fat_size / sector_size):
423
        for j in range(0, fat_size / sector_size):
424
            outf.write(empty_sector.pack())
424
            outf.write(empty_sector.pack())
425
   
425
   
426
    # Root directory
426
    # Root directory
427
    for i in range(0, root_size / sector_size):
427
    for i in range(0, root_size / sector_size):
428
        outf.write(empty_sector.pack())
428
        outf.write(empty_sector.pack())
429
   
429
   
430
    # Data
430
    # Data
431
    for i in range(0, size / sector_size):
431
    for i in range(0, size / sector_size):
432
        outf.write(empty_sector.pack())
432
        outf.write(empty_sector.pack())
433
   
433
   
434
    fat = array.array('L', [0] * (fat_size / fatent_size))
434
    fat = array.array('L', [0] * (fat_size / fatent_size))
435
    fat[0] = 0xfff8
435
    fat[0] = 0xfff8
436
    fat[1] = 0xffff
436
    fat[1] = 0xffff
437
   
437
   
438
    recursion(True, path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, 0)
438
    recursion(True, path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, 0)
439
   
439
   
440
    # Store FAT
440
    # Store FAT
441
    fat_entry = xstruct.create(FAT_ENTRY)
441
    fat_entry = xstruct.create(FAT_ENTRY)
442
    for i in range(0, fat_count):
442
    for i in range(0, fat_count):
443
        outf.seek(cluster_size + i * fat_size)
443
        outf.seek(cluster_size + i * fat_size)
444
        for j in range(0, fat_size / fatent_size):
444
        for j in range(0, fat_size / fatent_size):
445
            fat_entry.next = fat[j]
445
            fat_entry.next = fat[j]
446
            outf.write(fat_entry.pack())
446
            outf.write(fat_entry.pack())
447
   
447
   
448
    outf.close()
448
    outf.close()
449
   
449
   
450
if __name__ == '__main__':
450
if __name__ == '__main__':
451
    main()
451
    main()
452
 
452