Subversion Repositories HelenOS

Rev

Rev 3509 | Rev 3523 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #!/usr/bin/env python
  2. #
  3. # Copyright (c) 2008 Martin Decky
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. #
  10. # - Redistributions of source code must retain the above copyright
  11. #   notice, this list of conditions and the following disclaimer.
  12. # - Redistributions in binary form must reproduce the above copyright
  13. #   notice, this list of conditions and the following disclaimer in the
  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
  16. #   derived from this software without specific prior written permission.
  17. #
  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
  20. # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  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
  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
  27. # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. #
  29. """
  30. FAT creator
  31. """
  32.  
  33. import sys
  34. import os
  35. import random
  36. import xstruct
  37.  
  38. def align_up(size, alignment):
  39.     "Return size aligned up to alignment"
  40.    
  41.     if (size % alignment == 0):
  42.         return size
  43.    
  44.     return (((size / alignment) + 1) * alignment)
  45.  
  46. def subtree_size(root, cluster_size):
  47.     "Recursive directory walk and calculate size"
  48.    
  49.     size = 0
  50.     files = 0
  51.    
  52.     for name in os.listdir(root):
  53.         canon = os.path.join(root, name)
  54.        
  55.         if (os.path.isfile(canon)):
  56.             size += align_up(os.path.getsize(canon), cluster_size)
  57.             files += 1
  58.        
  59.         if (os.path.isdir(canon)):
  60.             size += subtree_size(canon, cluster_size)
  61.             files += 1
  62.    
  63.     return size + align_up(files * 32, cluster_size)
  64.  
  65. def root_entries(root):
  66.     "Return number of root directory entries"
  67.    
  68.     return len(os.listdir(root))
  69.  
  70. BOOT_SECTOR = """little:
  71.     uint8_t jmp[3]             /* jump instruction */
  72.     char oem[8]                /* OEM string */
  73.     uint16_t sector            /* bytes per sector */
  74.     uint8_t cluster            /* sectors per cluster */
  75.     uint16_t reserved          /* reserved sectors */
  76.     uint8_t fats               /* number of FATs */
  77.     uint16_t rootdir           /* root directory entries */
  78.     uint16_t sectors           /* total number of sectors */
  79.     uint8_t descriptor         /* media descriptor */
  80.     uint16_t fat_sectors       /* sectors per single FAT */
  81.     uint16_t track_sectors     /* sectors per track */
  82.     uint16_t heads             /* number of heads */
  83.     uint32_t hidden            /* hidden sectors */
  84.     uint32_t sectors_big       /* total number of sectors (if sectors == 0) */
  85.    
  86.     /* Extended BIOS Parameter Block */
  87.     uint8_t drive              /* physical drive number */
  88.     padding[1]                 /* reserved (current head) */
  89.     uint8_t extboot_signature  /* extended boot signature */
  90.     uint32_t serial            /* serial number */
  91.     char label[11]             /* volume label */
  92.     char fstype[8]             /* filesystem type */
  93.     padding[448]               /* boot code */
  94.     uint8_t boot_signature[2]  /* boot signature */
  95. """
  96.  
  97. EMPTY_SECTOR = """little:
  98.     padding[512]
  99. """
  100.  
  101. def usage(prname):
  102.     "Print usage syntax"
  103.     print prname + " <PATH> <IMAGE>"
  104.  
  105. def main():
  106.     if (len(sys.argv) < 3):
  107.         usage(sys.argv[0])
  108.         return
  109.    
  110.     path = os.path.abspath(sys.argv[1])
  111.     if (not os.path.isdir(path)):
  112.         print "<PATH> must be a directory"
  113.         return
  114.    
  115.     sector_size = 512
  116.     cluster_size = 4096
  117.    
  118.     root_size = align_up(root_entries(sys.argv[1]) * 32, sector_size)
  119.     size = subtree_size(sys.argv[1], cluster_size)
  120.     fat_size = align_up(size / cluster_size * 2, sector_size)
  121.    
  122.     sectors = (cluster_size + 2 * fat_size + root_size + size) / sector_size
  123.    
  124.     outf = file(sys.argv[2], "w")
  125.    
  126.     boot_sector = xstruct.create(BOOT_SECTOR)
  127.     boot_sector.jmp = [0xEB, 0x3C, 0x90]
  128.     boot_sector.oem = "MSDOS5.0"
  129.     boot_sector.sector = sector_size
  130.     boot_sector.cluster = cluster_size / sector_size
  131.     boot_sector.reserved = cluster_size / sector_size
  132.     boot_sector.fats = 2
  133.     boot_sector.rootdir = root_size / 32
  134.     boot_sector.sectors = (sectors if (sectors <= 65535) else 0)
  135.     boot_sector.descriptor = 0xF8
  136.     boot_sector.fat_sectors = fat_size / sector_size
  137.     boot_sector.track_sectors = 63
  138.     boot_sector.heads = 6
  139.     boot_sector.hidden = 0
  140.     boot_sector.sectors_big = (sectors if (sectors > 65535) else 0)
  141.    
  142.     boot_sector.drive = 0x80
  143.     boot_sector.extboot_signature = 0x29
  144.     boot_sector.serial = random.randint(0, 0xFFFFFFFF)
  145.     boot_sector.label = "HELENOS"
  146.     boot_sector.fstype = "FAT16   "
  147.     boot_sector.boot_signature = [0x55, 0xAA]
  148.    
  149.     outf.write(boot_sector.pack())
  150.    
  151.     empty_sector = xstruct.create(EMPTY_SECTOR)
  152.    
  153.     # Reserved sectors (boot_sector.reserved - boot_sector)
  154.     for i in range(1, boot_sector.reserved):
  155.         outf.write(empty_sector.pack())
  156.    
  157.     # FAT tables
  158.     for i in range(0, boot_sector.fats):
  159.         for j in range(0, boot_sector.fat_sectors):
  160.             outf.write(empty_sector.pack())
  161.    
  162.     # Root directory
  163.     for i in range(0, root_size / sector_size):
  164.         outf.write(empty_sector.pack())
  165.    
  166.     # Data
  167.     for i in range(0, size / sector_size):
  168.         outf.write(empty_sector.pack())
  169.    
  170.     outf.close()
  171.    
  172. if __name__ == '__main__':
  173.     main()
  174.