Subversion Repositories HelenOS

Rev

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

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