Subversion Repositories HelenOS

Rev

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

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