Subversion Repositories HelenOS

Rev

Rev 3386 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3386 Rev 4153
Line 32... Line 32...
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 */
Line 60... Line 328...
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():
Line 74... Line 350...
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()