Changes in tools/mkfat.py [a9a6d8d:87608a5] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • tools/mkfat.py

    ra9a6d8d r87608a5  
    168168"""
    169169
    170 LFN_ENTRY = """little:
    171         uint8_t pos
    172         uint16_t name1[5]
    173         uint8_t attr
    174         uint8_t type
    175         uint8_t csum
    176         uint16_t name2[6]
    177         uint16_t fc
    178         uint16_t name3[2]
    179 """
    180 
    181 # Global variable to hold the file names in 8.3 format. Needed to
    182 # keep track of "number" when creating a short fname from a LFN.
    183 name83_list = []
    184 
    185 def name83(fname):
    186         "Create a 8.3 name for the given fname"
    187 
    188         # FIXME: filter illegal characters
    189         parts = fname.split('.')
    190        
    191         name = ''
    192         ext = ''
    193         lfn = False
    194 
    195         if len(fname) > 11 :
     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 = ''
     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        ascii_parts = ascii_name.split('.')
     208       
     209        short_name = ''
     210        short_ext = ''
     211       
     212        if len(ascii_name) > 11:
    196213                lfn = True
    197 
    198         if len(parts) > 0:
    199                 name = parts[0]
    200                 if len(name) > 8 :
     214       
     215        if len(ascii_parts) > 0:
     216                short_name = ascii_parts[0]
     217                if len(short_name) > 8:
    201218                        lfn = True
    202 
    203         if len(parts) > 1 :
    204                 ext = parts[-1]
    205                 if len(ext) > 3 :
     219       
     220        if len(ascii_parts) > 1:
     221                short_ext = ascii_parts[-1]
     222                if len(short_ext) > 3:
    206223                        lfn = True
    207 
    208         if len(parts) > 2 :
     224       
     225        if len(ascii_parts) > 2:
    209226                lfn = True
    210 
    211         if (lfn == False) :
    212                 return (name.ljust(8)[0:8], ext.ljust(3)[0:3], False)
    213 
     227       
     228        if lfn == False:
     229                name83_list.append(short_name + '.' + short_ext)
     230                return (short_name.ljust(8)[0:8], short_ext.ljust(3)[0:3], False)
     231       
    214232        # For filenames with multiple extensions, we treat the last one
    215233        # as the actual extension. The rest of the filename is stripped
    216234        # of dots and concatenated to form the short name
    217         for _name in parts[1:-1]:
    218                 name = name + _name             
    219 
    220         global name83_list
    221         for number in range(1, 10000) :
    222                 number_str = '~' + str(number)
    223 
    224                 if len(name) + len(number_str) > 8 :
    225                         name = name[0:8 - len(number_str)]
    226 
    227                 name = name + number_str;
    228 
    229                 if (name + ext) not in name83_list :
     235        for part in ascii_parts[1:-1]:
     236                short_name += part
     237       
     238        for number in range(1, 999999):
     239                number_str = ('~' + str(number)).upper()
     240               
     241                if len(short_name) + len(number_str) > 8:
     242                        short_name = short_name[0:8 - len(number_str)]
     243               
     244                short_name += number_str;
     245               
     246                if not (short_name + '.' + short_ext) in name83_list:
    230247                        break
    231                        
    232         name83_list.append(name + ext) 
    233 
    234         return (name.ljust(8)[0:8], ext.ljust(3)[0:3], True)
    235 
    236 def get_utf16(name, l) :
    237         "Create a int array out of a string which we can store in uint16_t arrays"
    238 
    239         bs = [0xFFFF for i in range(l)]
    240 
    241         for i in range(len(name)) :
    242                 bs[i] = ord(name[i])
    243        
    244         if (len(name) < l) :
    245                 bs[len(name)] = 0;
    246        
    247         return bs
    248 
    249 def create_lfn_entry((name, index)) :
    250         entry = xstruct.create(LFN_ENTRY)
    251 
    252         entry.name1 = get_utf16(name[0:5], 5)
    253         entry.name2 = get_utf16(name[5:11], 6)
    254         entry.name3 = get_utf16(name[11:13], 2)
    255         entry.pos = index
    256 
    257         entry.attr = 0xF
    258         entry.fc = 0
    259         entry.type = 0
    260 
    261         return entry
    262 
    263 def create_dirent(name, directory, cluster, size):
     248       
     249        name83_list.append(short_name + '.' + short_ext)
     250        return (short_name.ljust(8)[0:8], short_ext.ljust(3)[0:3], True)
     251
     252def create_lfn_dirent(name, seq, checksum):
     253        "Create LFN directory entry"
     254       
     255        entry = xstruct.create(LFN_DIR_ENTRY)
     256        name_rest = name[26:]
     257       
     258        if len(name_rest) > 0:
     259                entry.seq = seq
     260        else:
     261                entry.seq = seq | 0x40
     262       
     263        entry.name1 = name[0:10]
     264        entry.name2 = name[10:22]
     265        entry.name3 = name[22:26]
     266       
     267        entry.attr = 0x0F
     268        entry.rec_type = 0
     269        entry.checksum = checksum
     270        entry.cluster = 0
     271       
     272        return (entry, name_rest)
     273
     274def lfn_checksum(name):
     275        "Calculate LFN checksum"
     276       
     277        checksum = 0
     278        for i in range(0, 11):
     279                checksum = (((checksum & 1) << 7) + (checksum >> 1) + ord(name[i])) & 0xFF
     280       
     281        return checksum
     282
     283def create_dirent(name, name83_list, directory, cluster, size):
     284        short_name, short_ext, lfn = fat_name83(name, name83_list)
    264285       
    265286        dir_entry = xstruct.create(DIR_ENTRY)
    266287       
    267         dir_entry.name, dir_entry.ext, lfn = name83(name)
    268 
    269         dir_entry.name = dir_entry.name.upper().encode('ascii')
    270         dir_entry.ext = dir_entry.ext.upper().encode('ascii')
    271 
     288        dir_entry.name = short_name
     289        dir_entry.ext = short_ext
     290       
    272291        if (directory):
    273292                dir_entry.attr = 0x30
     
    289308                dir_entry.size = size
    290309       
    291 
    292310        if not lfn:
    293311                return [dir_entry]
    294 
    295         n = len(name) / 13 + 1
    296         names = [(name[i * 13: (i + 1) * 13 + 1], i + 1) for i in range(n)]
    297 
    298         entries = sorted(map (create_lfn_entry, names), reverse = True, key = lambda e : e.pos)
    299         entries[0].pos |= 0x40
    300 
    301         fname11 = dir_entry.name + dir_entry.ext
    302 
    303         csum = 0
    304         for i in range(0, 11) :
    305                 csum = ((csum & 1) << 7) + (csum  >> 1) + ord(fname11[i])
    306                 csum = csum & 0xFF
    307        
    308         for e in entries :
    309                 e.csum = csum;
    310        
    311         entries.append(dir_entry)
    312 
     312       
     313        long_name = name.encode('utf_16_le')
     314        entries = [dir_entry]
     315       
     316        seq = 1
     317        checksum = lfn_checksum(dir_entry.name + dir_entry.ext)
     318       
     319        while len(long_name) > 0:
     320                long_entry, long_name = create_lfn_dirent(long_name, seq, checksum)
     321                entries.append(long_entry)
     322                seq += 1
     323       
     324        entries.reverse()
    313325        return entries
    314326
     
    355367       
    356368        directory = []
    357        
    358         if (not head):
     369        name83_list = []
     370       
     371        if not head:
    359372                # Directory cluster preallocation
    360373                empty_cluster = fat.index(0)
    361                 fat[empty_cluster] = 0xffff
     374                fat[empty_cluster] = 0xFFFF
    362375               
    363376                directory.append(create_dot_dirent(empty_cluster))
     
    366379                empty_cluster = 0
    367380       
    368         for item in listdir_items(root):               
     381        for item in listdir_items(root):
    369382                if item.is_file:
    370383                        rv = write_file(item, outf, cluster_size, data_start, fat, reserved_clusters)
    371                         directory.extend(create_dirent(item.name, False, rv[0], rv[1]))
     384                        directory.extend(create_dirent(item.name, name83_list, False, rv[0], rv[1]))
    372385                elif item.is_dir:
    373386                        rv = recursion(False, item.path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
    374                         directory.extend(create_dirent(item.name, True, rv[0], rv[1]))
    375        
    376         if (head):
     387                        directory.extend(create_dirent(item.name, name83_list, True, rv[0], rv[1]))
     388       
     389        if head:
    377390                outf.seek(root_start)
    378391                for dir_entry in directory:
     
    431444        extra_bytes = int(sys.argv[1])
    432445       
    433         path = os.path.abspath(sys.argv[2])
     446        path = os.path.abspath(sys.argv[2].decode())
    434447        if (not os.path.isdir(path)):
    435448                print("<PATH> must be a directory")
     
    529542       
    530543        outf.close()
    531        
     544
    532545if __name__ == '__main__':
    533546        main()
Note: See TracChangeset for help on using the changeset viewer.