Subversion Repositories HelenOS

Rev

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

Rev 3425 Rev 3536
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
def align_up(size, alignment):
-
 
40
    "Return size aligned up to alignment"
-
 
41
   
-
 
42
    if (size % alignment == 0):
-
 
43
        return size
-
 
44
   
-
 
45
    return (((size / alignment) + 1) * alignment)
-
 
46
 
-
 
47
def subtree_size(root, cluster_size, dirent_size):
-
 
48
    "Recursive directory walk and calculate size"
-
 
49
   
-
 
50
    size = 0
-
 
51
    files = 2
-
 
52
   
-
 
53
    for name in os.listdir(root):
-
 
54
        canon = os.path.join(root, name)
-
 
55
       
-
 
56
        if (os.path.isfile(canon)):
-
 
57
            size += align_up(os.path.getsize(canon), cluster_size)
-
 
58
            files += 1
-
 
59
       
-
 
60
        if (os.path.isdir(canon)):
-
 
61
            size += subtree_size(canon, cluster_size, dirent_size)
-
 
62
            files += 1
-
 
63
   
-
 
64
    return size + align_up(files * dirent_size, cluster_size)
-
 
65
 
-
 
66
def root_entries(root):
-
 
67
    "Return number of root directory entries"
-
 
68
   
-
 
69
    return len(os.listdir(root))
-
 
70
 
-
 
71
def write_file(path, outf, cluster_size, data_start, fat, reserved_clusters):
-
 
72
    "Store the contents of a file"
-
 
73
   
-
 
74
    size = os.path.getsize(path)
-
 
75
    prev = -1
-
 
76
    first = 0
-
 
77
   
-
 
78
    inf = file(path, "r")
-
 
79
    rd = 0;
-
 
80
    while (rd < size):
-
 
81
        empty_cluster = fat.index(0)
-
 
82
        fat[empty_cluster] = 0xffff
-
 
83
       
-
 
84
        if (prev != -1):
-
 
85
            fat[prev] = empty_cluster
-
 
86
        else:
-
 
87
            first = empty_cluster
-
 
88
       
-
 
89
        prev = empty_cluster
-
 
90
       
-
 
91
        data = inf.read(cluster_size);
-
 
92
        outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size)
-
 
93
        outf.write(data)
-
 
94
        rd += len(data)
-
 
95
    inf.close()
-
 
96
   
-
 
97
    return first, size
-
 
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
 
-
 
135
DIR_ENTRY = """little:
-
 
136
    char name[8]               /* file name */
-
 
137
    char ext[3]                /* file extension */
-
 
138
    uint8_t attr               /* file attributes */
-
 
139
    padding[1]                 /* reserved for NT */
-
 
140
    uint8_t ctime_fine         /* create time (fine resolution) */
-
 
141
    uint16_t ctime             /* create time */
-
 
142
    uint16_t cdate             /* create date */
-
 
143
    uint16_t adate             /* access date */
-
 
144
    padding[2]                 /* EA-index */
-
 
145
    uint16_t mtime             /* modification time */
-
 
146
    uint16_t mdate             /* modification date */
-
 
147
    uint16_t cluster           /* first cluster */
-
 
148
    uint32_t size              /* file size */
-
 
149
"""
-
 
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
 
-
 
185
def mangle_fname(name):
-
 
186
    # FIXME: filter illegal characters
-
 
187
    parts = name.split('.')
-
 
188
   
-
 
189
    if (len(parts) > 0):
-
 
190
        fname = parts[0]
-
 
191
    else:
-
 
192
        fname = ''
-
 
193
       
-
 
194
    return (fname + '          ').upper()[0:8]
-
 
195
 
-
 
196
def mangle_ext(name):
-
 
197
    # FIXME: filter illegal characters
-
 
198
    parts = name.split('.')
-
 
199
   
-
 
200
    if (len(parts) > 1):
-
 
201
        ext = parts[1]
-
 
202
    else:
-
 
203
        ext = ''
-
 
204
   
-
 
205
    return (ext + '   ').upper()[0:3]
-
 
206
 
-
 
207
def create_dirent(name, directory, cluster, size):
-
 
208
    dir_entry = xstruct.create(DIR_ENTRY)
-
 
209
   
-
 
210
    dir_entry.name = mangle_fname(name)
-
 
211
    dir_entry.ext = mangle_ext(name)
-
 
212
   
-
 
213
    if (directory):
-
 
214
        dir_entry.attr = 0x30
-
 
215
    else:
-
 
216
        dir_entry.attr = 0x20
-
 
217
   
-
 
218
    dir_entry.ctime_fine = 0 # FIXME
-
 
219
    dir_entry.ctime = 0 # FIXME
-
 
220
    dir_entry.cdate = 0 # FIXME
-
 
221
    dir_entry.adate = 0 # FIXME
-
 
222
    dir_entry.mtime = 0 # FIXME
-
 
223
    dir_entry.mdate = 0 # FIXME
-
 
224
    dir_entry.cluster = cluster
-
 
225
   
-
 
226
    if (directory):
-
 
227
        dir_entry.size = 0
-
 
228
    else:
-
 
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
-
 
268
   
-
 
269
    return dir_entry
-
 
270
 
-
 
271
def recursion(head, root, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, parent_cluster):
-
 
272
    "Recursive directory walk"
-
 
273
   
-
 
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
   
-
 
286
    for name in os.listdir(root):
-
 
287
        canon = os.path.join(root, name)
-
 
288
       
-
 
289
        if (os.path.isfile(canon)):
-
 
290
            rv = write_file(canon, outf, cluster_size, data_start, fat, reserved_clusters)
-
 
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]))
-
 
296
   
-
 
297
    if (head):
-
 
298
        outf.seek(root_start)
-
 
299
        for dir_entry in directory:
-
 
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)
37
 
303
 
38
BOOT_SECTOR = """little:
304
BOOT_SECTOR = """little:
39
    uint8_t jmp[3]             /* jump instruction */
305
    uint8_t jmp[3]             /* jump instruction */
40
    char oem[8]                /* OEM string */
306
    char oem[8]                /* OEM string */
41
    uint16_t sector            /* bytes per sector */
307
    uint16_t sector            /* bytes per sector */
42
    uint8_t cluster            /* sectors per cluster */
308
    uint8_t cluster            /* sectors per cluster */
43
    uint16_t reserved          /* reserved sectors */
309
    uint16_t reserved          /* reserved sectors */
44
    uint8_t fats               /* number of FATs */
310
    uint8_t fats               /* number of FATs */
45
    uint16_t rootdir           /* root directory entries */
311
    uint16_t rootdir           /* root directory entries */
46
    uint16_t sectors           /* total number of sectors */
312
    uint16_t sectors           /* total number of sectors */
47
    uint8_t descriptor         /* media descriptor */
313
    uint8_t descriptor         /* media descriptor */
48
    uint16_t fat_sectors       /* sectors per single FAT */
314
    uint16_t fat_sectors       /* sectors per single FAT */
49
    uint16_t track_sectors     /* sectors per track */
315
    uint16_t track_sectors     /* sectors per track */
50
    uint16_t heads             /* number of heads */
316
    uint16_t heads             /* number of heads */
51
    uint32_t hidden            /* hidden sectors */
317
    uint32_t hidden            /* hidden sectors */
52
    uint32_t sectors_big       /* total number of sectors (if sectors == 0) */
318
    uint32_t sectors_big       /* total number of sectors (if sectors == 0) */
53
   
319
   
54
    /* Extended BIOS Parameter Block */
320
    /* Extended BIOS Parameter Block */
55
    uint8_t drive              /* physical drive number */
321
    uint8_t drive              /* physical drive number */
56
    padding[1]                 /* reserved (current head) */
322
    padding[1]                 /* reserved (current head) */
57
    uint8_t extboot_signature  /* extended boot signature */
323
    uint8_t extboot_signature  /* extended boot signature */
58
    uint32_t serial            /* serial number */
324
    uint32_t serial            /* serial number */
59
    char label[11]             /* volume label */
325
    char label[11]             /* volume label */
60
    char fstype[8]             /* filesystem type */
326
    char fstype[8]             /* filesystem type */
61
    padding[448]               /* boot code */
327
    padding[448]               /* boot code */
62
    uint8_t boot_signature[2]  /* boot signature */
328
    uint8_t boot_signature[2]  /* boot signature */
63
"""
329
"""
64
 
330
 
-
 
331
EMPTY_SECTOR = """little:
-
 
332
    padding[512]               /* empty sector data */
-
 
333
"""
-
 
334
 
-
 
335
FAT_ENTRY = """little:
-
 
336
    uint16_t next              /* FAT16 entry */
-
 
337
"""
-
 
338
 
65
def usage(prname):
339
def usage(prname):
66
    "Print usage syntax"
340
    "Print usage syntax"
67
    print prname + " <PATH> <IMAGE>"
341
    print prname + " <PATH> <IMAGE>"
68
 
342
 
69
def main():
343
def main():
70
    if (len(sys.argv) < 3):
344
    if (len(sys.argv) < 3):
71
        usage(sys.argv[0])
345
        usage(sys.argv[0])
72
        return
346
        return
73
   
347
   
74
    path = os.path.abspath(sys.argv[1])
348
    path = os.path.abspath(sys.argv[1])
75
    if (not os.path.isdir(path)):
349
    if (not os.path.isdir(path)):
76
        print "<PATH> must be a directory"
350
        print "<PATH> must be a directory"
77
        return
351
        return
78
   
352
   
-
 
353
    fat16_clusters = 4096
-
 
354
    min_cluster_size = 1024
-
 
355
   
-
 
356
    sector_size = 512
-
 
357
    cluster_size = 4096
-
 
358
    dirent_size = 32
-
 
359
    fatent_size = 2
-
 
360
    fat_count = 2
-
 
361
    reserved_clusters = 2
-
 
362
   
-
 
363
    # Make sure the filesystem is large enought for FAT16
-
 
364
    size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
-
 
365
    while (size / cluster_size < fat16_clusters):
-
 
366
        if (cluster_size > min_cluster_size):
-
 
367
            cluster_size /= 2
-
 
368
            size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
-
 
369
        else:
-
 
370
            size = fat16_clusters * cluster_size + reserved_clusters * cluster_size
-
 
371
   
-
 
372
    root_size = align_up(root_entries(path) * dirent_size, cluster_size)
-
 
373
   
-
 
374
    fat_size = align_up(align_up(size, cluster_size) / cluster_size * fatent_size, sector_size)
-
 
375
   
-
 
376
    sectors = (cluster_size + fat_count * fat_size + root_size + size) / sector_size
-
 
377
    root_start = cluster_size + fat_count * fat_size
-
 
378
    data_start = root_start + root_size
-
 
379
   
79
    outf = file(sys.argv[2], "w")
380
    outf = file(sys.argv[2], "w")
80
   
381
   
81
    boot_sector = xstruct.create(BOOT_SECTOR)
382
    boot_sector = xstruct.create(BOOT_SECTOR)
82
    boot_sector.jmp = [0xEB, 0x3C, 0x90]
383
    boot_sector.jmp = [0xEB, 0x3C, 0x90]
83
    boot_sector.oem = "MSDOS5.0"
384
    boot_sector.oem = "MSDOS5.0"
84
    boot_sector.sector = 512
385
    boot_sector.sector = sector_size
85
    boot_sector.cluster = 8 # 4096 bytes per cluster
386
    boot_sector.cluster = cluster_size / sector_size
86
    boot_sector.reserved = 1
387
    boot_sector.reserved = cluster_size / sector_size
87
    boot_sector.fats = 2
388
    boot_sector.fats = fat_count
88
    boot_sector.rootdir = 224 # FIXME: root directory should be sector aligned
389
    boot_sector.rootdir = root_size / dirent_size
-
 
390
    if (sectors <= 65535):
-
 
391
        boot_sector.sectors = sectors
-
 
392
    else:
89
    boot_sector.sectors = 0 # FIXME
393
        boot_sector.sectors = 0
90
    boot_sector.descriptor = 0xF8
394
    boot_sector.descriptor = 0xF8
91
    boot_sector.fat_sectors = 0 # FIXME
395
    boot_sector.fat_sectors = fat_size / sector_size
92
    boot_sector.track_sectors = 0 # FIXME
396
    boot_sector.track_sectors = 63
93
    boot_sector.heads = 0 # FIXME
397
    boot_sector.heads = 6
94
    boot_sector.hidden = 0
398
    boot_sector.hidden = 0
-
 
399
    if (sectors > 65535):
-
 
400
        boot_sector.sectors_big = sectors
-
 
401
    else:
95
    boot_sector.sectors_big = 0 # FIXME
402
        boot_sector.sectors_big = 0
96
   
403
   
97
    boot_sector.drive = 0
404
    boot_sector.drive = 0x80
98
    boot_sector.extboot_signature = 0x29
405
    boot_sector.extboot_signature = 0x29
99
    boot_sector.serial = random.randint(0, 0xFFFFFFFF)
406
    boot_sector.serial = random.randint(0, 0x7fffffff)
100
    boot_sector.label = "HELENOS"
407
    boot_sector.label = "HELENOS"
101
    boot_sector.fstype = "FAT16   "
408
    boot_sector.fstype = "FAT16   "
102
    boot_sector.boot_signature = [0x55, 0xAA]
409
    boot_sector.boot_signature = [0x55, 0xAA]
103
   
410
   
104
    outf.write(boot_sector.pack())
411
    outf.write(boot_sector.pack())
105
   
412
   
-
 
413
    empty_sector = xstruct.create(EMPTY_SECTOR)
-
 
414
   
-
 
415
    # Reserved sectors
-
 
416
    for i in range(1, cluster_size / sector_size):
-
 
417
        outf.write(empty_sector.pack())
-
 
418
   
-
 
419
    # FAT tables
-
 
420
    for i in range(0, fat_count):
-
 
421
        for j in range(0, fat_size / sector_size):
-
 
422
            outf.write(empty_sector.pack())
-
 
423
   
-
 
424
    # Root directory
-
 
425
    for i in range(0, root_size / sector_size):
-
 
426
        outf.write(empty_sector.pack())
-
 
427
   
-
 
428
    # Data
-
 
429
    for i in range(0, size / sector_size):
-
 
430
        outf.write(empty_sector.pack())
-
 
431
   
-
 
432
    fat = array.array('L', [0] * (fat_size / fatent_size))
-
 
433
    fat[0] = 0xfff8
-
 
434
    fat[1] = 0xffff
-
 
435
   
-
 
436
    recursion(True, path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, 0)
-
 
437
   
-
 
438
    # Store FAT
-
 
439
    fat_entry = xstruct.create(FAT_ENTRY)
-
 
440
    for i in range(0, fat_count):
-
 
441
        outf.seek(cluster_size + i * fat_size)
-
 
442
        for j in range(0, fat_size / fatent_size):
-
 
443
            fat_entry.next = fat[j]
-
 
444
            outf.write(fat_entry.pack())
-
 
445
   
106
    outf.close()
446
    outf.close()
107
   
447
   
108
if __name__ == '__main__':
448
if __name__ == '__main__':
109
    main()
449
    main()
110
 
450