Subversion Repositories HelenOS

Rev

Rev 3524 | Rev 3541 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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