Changeset a35b458 in mainline for tools/mkext2.py
- Timestamp:
- 2018-03-02T20:10:49Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f1380b7
- Parents:
- 3061bc1
- git-author:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-02-28 17:38:31)
- git-committer:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-03-02 20:10:49)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
tools/mkext2.py
r3061bc1 ra35b458 77 77 uint32_t rev_major /* Major revision level */ 78 78 padding[4] /* default reserved uid and gid */ 79 79 80 80 /* Following is for ext2 revision 1 only */ 81 81 uint32_t first_inode … … 130 130 def __init__(self, filename, block_groups, blocks_per_group, inodes_per_group, block_size, inode_size, reserved_inode_count): 131 131 "Initialize the filesystem writer" 132 132 133 133 outf = open(filename, "w+b") 134 134 # Set the correct size of the image, so that we can read arbitrary position … … 172 172 lpf_dir.add(self.root_inode.as_dirent('..')) 173 173 lpf_dir.finish() 174 174 175 175 def init_gdt(self): 176 176 "Initialize block group descriptor table" 177 177 178 178 self.superblock_positions = [] 179 179 self.gdt = [] … … 202 202 gde.directory_inode_count = 0 203 203 self.gdt.append(gde) 204 204 205 205 def mark_block_cb(self, block): 206 206 "Called after a block has been allocated" 207 207 208 208 self.gdt[block // self.blocks_per_group].free_block_count -= 1 209 209 210 210 def mark_inode_cb(self, index, directory=False): 211 211 "Called after an inode has been allocated" 212 212 213 213 index -= 1 214 214 gde = self.gdt[index // self.inodes_per_group] … … 216 216 if directory: 217 217 gde.directory_inode_count += 1 218 218 219 219 def seek_to_block(self, block, offset=0): 220 220 "Seek to offset bytes after the start of the given block" 221 221 222 222 if offset < 0 or offset > self.block_size: 223 223 raise Exception("Invalid in-block offset") 224 224 self.outf.seek(block * self.block_size + offset) 225 225 226 226 def seek_to_inode(self, index): 227 227 "Seek to the start of the inode structure for the inode number index" 228 228 229 229 index -= 1 230 230 if index < 0: … … 235 235 block = base_block + (offset // self.block_size) 236 236 self.seek_to_block(block, offset % self.block_size) 237 237 238 238 def subtree_add(self, inode, parent_inode, dirpath, is_root=False): 239 239 "Recursively add files to the filesystem" 240 240 241 241 dir_writer = DirWriter(inode) 242 242 dir_writer.add(inode.as_dirent('.')) 243 243 dir_writer.add(parent_inode.as_dirent('..')) 244 244 245 245 if is_root: 246 246 dir_writer.add(self.lost_plus_found.as_dirent('lost+found')) … … 255 255 child_inode = Inode(self, newidx, Inode.TYPE_DIR) 256 256 self.subtree_add(child_inode, inode, item.path) 257 257 258 258 dir_writer.add(child_inode.as_dirent(item.name)) 259 259 self.write_inode(child_inode) 260 260 261 261 dir_writer.finish() 262 262 263 263 def write_inode(self, inode): 264 264 "Write inode information into the inode table" 265 265 266 266 self.seek_to_inode(inode.index) 267 267 self.outf.write(inode.pack()) … … 269 269 def write_gdt(self): 270 270 "Write group descriptor table at the current file position" 271 271 272 272 for gde in self.gdt: 273 273 data = bytes(gde.pack()) 274 274 self.outf.write(data) 275 275 self.outf.seek(GDE_SIZE-len(data), os.SEEK_CUR) 276 276 277 277 def write_superblock(self, block_group): 278 278 "Write superblock at the current position" 279 279 280 280 sb = xstruct.create(STRUCT_SUPERBLOCK) 281 281 sb.total_inode_count = self.total_inode_count … … 312 312 sb.volume_name = 'HelenOS rdimage\0' 313 313 self.outf.write(bytes(sb.pack())) 314 314 315 315 def write_all_metadata(self): 316 316 "Write superblocks, block group tables, block and inode bitmaps" 317 317 318 318 bbpg = self.blocks_per_group // 8 319 319 bipg = self.inodes_per_group // 8 320 320 def window(arr, index, size): 321 321 return arr[index * size:(index + 1) * size] 322 322 323 323 for bg_index in xrange(len(self.gdt)): 324 324 sbpos = self.superblock_positions[bg_index] 325 325 sbblock = (sbpos + 1023) // self.block_size 326 326 gde = self.gdt[bg_index] 327 327 328 328 self.outf.seek(sbpos) 329 329 self.write_superblock(bg_index) 330 330 331 331 self.seek_to_block(sbblock+1) 332 332 self.write_gdt() 333 333 334 334 self.seek_to_block(gde.block_bitmap_block) 335 335 self.outf.write(window(self.block_allocator.bitmap, bg_index, bbpg)) 336 336 337 337 self.seek_to_block(gde.inode_bitmap_block) 338 338 self.outf.write(window(self.inode_allocator.bitmap, bg_index, bipg)) 339 339 340 340 def close(self): 341 341 "Write all remaining data to the filesystem and close the file" 342 342 343 343 self.write_inode(self.root_inode) 344 344 self.write_inode(self.lost_plus_found) … … 354 354 self.bitmap = array.array('B', [0] * (count // 8)) 355 355 self.mark_cb = None 356 356 357 357 def __contains__(self, item): 358 358 "Check if the item is already used" 359 359 360 360 bitidx = item - self.base 361 361 return get_bit(self.bitmap[bitidx // 8], bitidx % 8) 362 362 363 363 def alloc(self, **options): 364 364 "Allocate a new item" 365 365 366 366 while self.nextidx < self.count and (self.base + self.nextidx) in self: 367 367 self.nextidx += 1 … … 372 372 self.mark_used(item, **options) 373 373 return item 374 374 375 375 def mark_used(self, item, **options): 376 376 "Mark the specified item as used" 377 377 378 378 bitidx = item - self.base 379 379 if item in self: … … 384 384 if self.mark_cb: 385 385 self.mark_cb(item, **options) 386 386 387 387 def mark_used_all(self, items, **options): 388 388 "Mark all specified items as used" 389 389 390 390 for item in items: 391 391 self.mark_used(item, **options) … … 395 395 TYPE_DIR = 2 396 396 TYPE2MODE = {TYPE_FILE: 8, TYPE_DIR: 4} 397 397 398 398 def __init__(self, fs, index, typ): 399 399 self.fs = fs … … 406 406 self.type = typ 407 407 self.refcount = 0 408 408 409 409 def as_dirent(self, name): 410 410 "Return a DirEntry corresponding to this inode" 411 411 self.refcount += 1 412 412 return DirEntry(name, self.index, self.type) 413 413 414 414 def new_block(self, data=True): 415 415 "Get a new block index from allocator and count it here as belonging to the file" 416 416 417 417 block = self.fs.block_allocator.alloc() 418 418 self.blocks += 1 419 419 return block 420 420 421 421 def get_or_add_block(self, block): 422 422 "Get or add a real block to the file" 423 423 424 424 if block < 12: 425 425 return self.get_or_add_block_direct(block) 426 426 return self.get_or_add_block_indirect(block) 427 427 428 428 def get_or_add_block_direct(self, block): 429 429 "Get or add a real block to the file (direct blocks)" 430 430 431 431 if self.direct[block] == None: 432 432 self.direct[block] = self.new_block() 433 433 return self.direct[block] 434 434 435 435 def get_or_add_block_indirect(self, block): 436 436 "Get or add a real block to the file (indirect blocks)" 437 437 438 438 # Determine the indirection level for the desired block 439 439 level = None … … 444 444 445 445 assert level != None 446 446 447 447 # Compute offsets for the topmost level 448 448 block_offset_in_level = block - self.fs.indirect_limits[level-1]; … … 452 452 current_block.block_id = self.indirect[level-1] 453 453 offset_in_block = block_offset_in_level // self.fs.indirect_blocks_per_level[level-1] 454 454 455 455 # Navigate through other levels 456 456 while level > 0: 457 457 assert offset_in_block < self.fs.block_ids_per_block 458 458 459 459 level -= 1 460 460 461 461 self.fs.seek_to_block(current_block.block_id, offset_in_block*4) 462 462 current_block.unpack(self.fs.outf.read(4)) 463 463 464 464 if current_block.block_id == 0: 465 465 # The block does not exist, so alloc one and write it there … … 467 467 current_block.block_id = self.new_block(data=(level==0)) 468 468 self.fs.outf.write(current_block.pack()) 469 469 470 470 # If we are on the last level, break here as 471 471 # there is no next level to visit 472 472 if level == 0: 473 473 break 474 474 475 475 # Visit the next level 476 476 block_offset_in_level %= self.fs.indirect_blocks_per_level[level]; … … 478 478 479 479 return current_block.block_id 480 480 481 481 def do_seek(self): 482 482 "Perform a seek to the position indicated by self.pos" 483 483 484 484 block = self.pos // self.fs.block_size 485 485 real_block = self.get_or_add_block(block) 486 486 offset = self.pos % self.fs.block_size 487 487 self.fs.seek_to_block(real_block, offset) 488 488 489 489 def write(self, data): 490 490 "Write a piece of data (arbitrarily long) as the contents of the inode" 491 491 492 492 data_pos = 0 493 493 while data_pos < len(data): … … 499 499 data_pos += bytes_to_write 500 500 self.size = max(self.pos, self.size) 501 501 502 502 def align_size_to_block(self): 503 503 "Align the size of the inode up to block size" 504 504 505 505 self.size = align_up(self.size, self.fs.block_size) 506 506 507 507 def align_pos(self, bytes): 508 508 "Align the current position up to bytes boundary" 509 509 510 510 self.pos = align_up(self.pos, bytes) 511 511 512 512 def set_pos(self, pos): 513 513 "Set the current position" 514 514 515 515 self.pos = pos 516 516 517 517 def pack(self): 518 518 "Pack the inode structure and return the result" 519 519 520 520 data = xstruct.create(STRUCT_INODE) 521 521 data.mode = (Inode.TYPE2MODE[self.type] << 12) … … 546 546 data.group_id_high = 0 547 547 return data.pack() 548 548 549 549 class DirEntry: 550 550 "Represents a linked list directory entry" 551 551 552 552 def __init__(self, name, inode, typ): 553 553 self.name = name.encode('UTF-8') … … 555 555 self.skip = None 556 556 self.type = typ 557 557 558 558 def size(self): 559 559 "Return size of the entry in bytes" 560 560 561 561 return align_up(8 + len(self.name)+1, 4) 562 562 563 563 def write(self, inode): 564 564 "Write the directory entry into the inode" 565 565 566 566 head = xstruct.create(STRUCT_DIR_ENTRY_HEAD) 567 567 head.inode = self.inode … … 575 575 class DirWriter: 576 576 "Manages writing directory entries into an inode (alignment, etc.)" 577 577 578 578 def __init__(self, inode): 579 579 self.pos = 0 … … 581 581 self.prev_entry = None 582 582 self.prev_pos = None 583 583 584 584 def prev_write(self): 585 585 "Write a previously remembered entry" 586 586 587 587 if self.prev_entry: 588 588 self.prev_entry.skip = self.pos - self.prev_pos … … 590 590 self.prev_entry.write(self.inode) 591 591 self.inode.set_pos(self.pos) 592 592 593 593 def add(self, entry): 594 594 "Add a directory entry to the directory" 595 595 596 596 size = entry.size() 597 597 block_size = self.inode.fs.block_size … … 602 602 self.prev_pos = self.pos 603 603 self.pos += size 604 604 605 605 def finish(self): 606 606 "Write the last entry and finish writing the directory contents" 607 607 608 608 if not self.inode: 609 609 return … … 614 614 def subtree_stats(root, block_size): 615 615 "Recursively calculate statistics" 616 616 617 617 blocks = 0 618 618 inodes = 1 619 619 dir_writer = DirWriter(None) 620 620 621 621 for item in listdir_items(root): 622 622 inodes += 1 … … 627 627 blocks += subtree_blocks 628 628 inodes += subtree_inodes 629 629 630 630 dir_writer.finish() 631 631 blocks += count_up(dir_writer.pos, block_size) … … 640 640 usage(sys.argv[0]) 641 641 return 642 642 643 643 if (not sys.argv[1].isdigit()): 644 644 print("<EXTRA_BYTES> must be a number") 645 645 return 646 646 647 647 extra_bytes = int(sys.argv[1]) 648 648 649 649 path = os.path.abspath(sys.argv[2]) 650 650 if (not os.path.isdir(path)): 651 651 print("<PATH> must be a directory") 652 652 return 653 653 654 654 block_size = 4096 655 655 inode_size = 128 … … 657 657 blocks_per_group = 1024 658 658 inodes_per_group = 512 659 659 660 660 blocks, inodes = subtree_stats(path, block_size) 661 661 blocks += count_up(extra_bytes, block_size) 662 662 inodes += reserved_inode_count 663 663 664 664 inodes_per_group = align_up(inodes_per_group, 8) 665 665 blocks_per_group = align_up(blocks_per_group, 8) 666 666 667 667 inode_table_blocks_per_group = (inodes_per_group * inode_size) // block_size 668 668 inode_bitmap_blocks_per_group = count_up(inodes_per_group // 8, block_size) … … 673 673 free_blocks_per_group -= block_bitmap_blocks_per_group 674 674 free_blocks_per_group -= 10 # one for SB and some reserve for GDT 675 675 676 676 block_groups = max(count_up(inodes, inodes_per_group), count_up(blocks, free_blocks_per_group)) 677 677 678 678 fs = Filesystem(sys.argv[3], block_groups, blocks_per_group, inodes_per_group, 679 679 block_size, inode_size, reserved_inode_count) 680 680 681 681 fs.subtree_add(fs.root_inode, fs.root_inode, path, is_root=True) 682 682 fs.close() 683 683 684 684 if __name__ == '__main__': 685 685 main()
Note:
See TracChangeset
for help on using the changeset viewer.