Changes in tools/mkfat.py [cc1a727:67435b1] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • tools/mkfat.py

    rcc1a727 r67435b1  
    168168"""
    169169
    170 def mangle_fname(name):
    171         # FIXME: filter illegal characters
    172         parts = name.split('.')
    173        
    174         if len(parts) > 0:
    175                 fname = parts[0]
    176         else:
    177                 fname = ''
    178        
    179         if len(fname) > 8:
    180                 sys.stdout.write("mkfat.py: error: Directory entry " + name +
    181                     " base name is longer than 8 characters\n")
    182                 sys.exit(1);
    183        
    184         return (fname + '          ').upper()[0:8]
    185 
    186 def mangle_ext(name):
    187         # FIXME: filter illegal characters
    188         parts = name.split('.')
    189        
    190         if len(parts) > 1:
    191                 ext = parts[1]
    192         else:
    193                 ext = ''
    194        
    195         if len(parts) > 2:
    196                 sys.stdout.write("mkfat.py: error: Directory entry " + name +
    197                     " has more than one extension\n")
    198                 sys.exit(1);
    199        
    200         if len(ext) > 3:
    201                 sys.stdout.write("mkfat.py: error: Directory entry " + name +
    202                     " extension is longer than 3 characters\n")
    203                 sys.exit(1);
    204        
    205         return (ext + '   ').upper()[0:3]
    206 
    207 def create_dirent(name, directory, cluster, size):
     170LFN_DIR_ENTRY = """little:
     171        uint8_t seq                /* sequence number */
     172        char name1[10]             /* first part of the name */
     173        uint8_t attr               /* attributes */
     174        uint8_t rec_type           /* LFN record type */
     175        uint8_t checksum           /* LFN checksum */
     176        char name2[12]             /* second part of the name */
     177        uint16_t cluster           /* cluster */
     178        char name3[4]              /* third part of the name */
     179"""
     180
     181lchars = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
     182              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
     183              'U', 'V', 'W', 'X', 'Y', 'Z',
     184              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
     185              '!', '#', '$', '%', '&', '\'', '(', ')', '-', '@',
     186              '^', '_', '`', '{', '}', '~', '.'])
     187
     188def fat_lchars(name):
     189        "Filter FAT legal characters"
     190       
     191        filtered_name = b''
     192        filtered = False
     193       
     194        for char in name.encode('ascii', 'replace').upper():
     195                if char in lchars:
     196                        filtered_name += char
     197                else:
     198                        filtered_name += b'_'
     199                        filtered = True
     200       
     201        return (filtered_name, filtered)
     202
     203def fat_name83(name, name83_list):
     204        "Create a 8.3 name for the given name"
     205       
     206        ascii_name, lfn = fat_lchars(name)
     207        # Splitting works only on strings, not on bytes
     208        ascii_parts = ascii_name.decode('utf8').split('.')
     209       
     210        short_name = ''
     211        short_ext = ''
     212       
     213        if len(ascii_name) > 11:
     214                lfn = True
     215       
     216        if len(ascii_parts) > 0:
     217                short_name = ascii_parts[0]
     218                if len(short_name) > 8:
     219                        lfn = True
     220       
     221        if len(ascii_parts) > 1:
     222                short_ext = ascii_parts[-1]
     223                if len(short_ext) > 3:
     224                        lfn = True
     225       
     226        if len(ascii_parts) > 2:
     227                lfn = True
     228       
     229        if lfn == False:
     230                name83_list.append(short_name + '.' + short_ext)
     231                return (short_name.ljust(8)[0:8], short_ext.ljust(3)[0:3], False)
     232       
     233        # For filenames with multiple extensions, we treat the last one
     234        # as the actual extension. The rest of the filename is stripped
     235        # of dots and concatenated to form the short name
     236        for part in ascii_parts[1:-1]:
     237                short_name += part
     238       
     239        for number in range(1, 999999):
     240                number_str = ('~' + str(number)).upper()
     241               
     242                if len(short_name) + len(number_str) > 8:
     243                        short_name = short_name[0:8 - len(number_str)]
     244               
     245                short_name += number_str;
     246               
     247                if not (short_name + '.' + short_ext) in name83_list:
     248                        break
     249       
     250        name83_list.append(short_name + '.' + short_ext)
     251        return (short_name.ljust(8)[0:8], short_ext.ljust(3)[0:3], True)
     252
     253def create_lfn_dirent(name, seq, checksum):
     254        "Create LFN directory entry"
     255       
     256        entry = xstruct.create(LFN_DIR_ENTRY)
     257        name_rest = name[26:]
     258       
     259        if len(name_rest) > 0:
     260                entry.seq = seq
     261        else:
     262                entry.seq = seq | 0x40
     263       
     264        entry.name1 = name[0:10]
     265        entry.name2 = name[10:22]
     266        entry.name3 = name[22:26]
     267       
     268        entry.attr = 0x0F
     269        entry.rec_type = 0
     270        entry.checksum = checksum
     271        entry.cluster = 0
     272       
     273        return (entry, name_rest)
     274
     275def lfn_checksum(name):
     276        "Calculate LFN checksum"
     277       
     278        checksum = 0
     279        for i in range(0, 11):
     280                checksum = (((checksum & 1) << 7) + (checksum >> 1) + ord(name[i])) & 0xFF
     281       
     282        return checksum
     283
     284def create_dirent(name, name83_list, directory, cluster, size):
     285        short_name, short_ext, lfn = fat_name83(name, name83_list)
     286       
    208287        dir_entry = xstruct.create(DIR_ENTRY)
    209288       
    210         dir_entry.name = mangle_fname(name).encode('ascii')
    211         dir_entry.ext = mangle_ext(name).encode('ascii')
     289        dir_entry.name = short_name
     290        dir_entry.ext = short_ext
    212291       
    213292        if (directory):
     
    230309                dir_entry.size = size
    231310       
    232         return dir_entry
     311        if not lfn:
     312                return [dir_entry]
     313       
     314        long_name = name.encode('utf_16_le')
     315        entries = [dir_entry]
     316       
     317        seq = 1
     318        checksum = lfn_checksum(dir_entry.name + dir_entry.ext)
     319       
     320        while len(long_name) > 0:
     321                long_entry, long_name = create_lfn_dirent(long_name, seq, checksum)
     322                entries.append(long_entry)
     323                seq += 1
     324       
     325        entries.reverse()
     326        return entries
    233327
    234328def create_dot_dirent(empty_cluster):
     
    274368       
    275369        directory = []
    276        
    277         if (not head):
     370        name83_list = []
     371       
     372        if not head:
    278373                # Directory cluster preallocation
    279374                empty_cluster = fat.index(0)
    280                 fat[empty_cluster] = 0xffff
     375                fat[empty_cluster] = 0xFFFF
    281376               
    282377                directory.append(create_dot_dirent(empty_cluster))
     
    285380                empty_cluster = 0
    286381       
    287         for item in listdir_items(root):               
     382        for item in listdir_items(root):
    288383                if item.is_file:
    289384                        rv = write_file(item, outf, cluster_size, data_start, fat, reserved_clusters)
    290                         directory.append(create_dirent(item.name, False, rv[0], rv[1]))
     385                        directory.extend(create_dirent(item.name, name83_list, False, rv[0], rv[1]))
    291386                elif item.is_dir:
    292387                        rv = recursion(False, item.path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
    293                         directory.append(create_dirent(item.name, True, rv[0], rv[1]))
    294        
    295         if (head):
     388                        directory.extend(create_dirent(item.name, name83_list, True, rv[0], rv[1]))
     389       
     390        if head:
    296391                outf.seek(root_start)
    297392                for dir_entry in directory:
     
    448543       
    449544        outf.close()
    450        
     545
    451546if __name__ == '__main__':
    452547        main()
Note: See TracChangeset for help on using the changeset viewer.