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


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • tools/mkfat.py

    r87608a5 ra9a6d8d  
    168168"""
    169169
    170 LFN_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 
    181 lchars = 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 
    188 def 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 
    203 def 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:
     170LFN_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.
     183name83_list = []
     184
     185def 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 :
    213196                lfn = True
    214        
    215         if len(ascii_parts) > 0:
    216                 short_name = ascii_parts[0]
    217                 if len(short_name) > 8:
     197
     198        if len(parts) > 0:
     199                name = parts[0]
     200                if len(name) > 8 :
    218201                        lfn = True
    219        
    220         if len(ascii_parts) > 1:
    221                 short_ext = ascii_parts[-1]
    222                 if len(short_ext) > 3:
     202
     203        if len(parts) > 1 :
     204                ext = parts[-1]
     205                if len(ext) > 3 :
    223206                        lfn = True
    224        
    225         if len(ascii_parts) > 2:
     207
     208        if len(parts) > 2 :
    226209                lfn = True
    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        
     210
     211        if (lfn == False) :
     212                return (name.ljust(8)[0:8], ext.ljust(3)[0:3], False)
     213
    232214        # For filenames with multiple extensions, we treat the last one
    233215        # as the actual extension. The rest of the filename is stripped
    234216        # of dots and concatenated to form the short name
    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:
     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 :
    247230                        break
    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 
    252 def 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 
    274 def 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 
    283 def create_dirent(name, name83_list, directory, cluster, size):
    284         short_name, short_ext, lfn = fat_name83(name, name83_list)
     231                       
     232        name83_list.append(name + ext) 
     233
     234        return (name.ljust(8)[0:8], ext.ljust(3)[0:3], True)
     235
     236def 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
     249def 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
     263def create_dirent(name, directory, cluster, size):
    285264       
    286265        dir_entry = xstruct.create(DIR_ENTRY)
    287266       
    288         dir_entry.name = short_name
    289         dir_entry.ext = short_ext
    290        
     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
    291272        if (directory):
    292273                dir_entry.attr = 0x30
     
    308289                dir_entry.size = size
    309290       
     291
    310292        if not lfn:
    311293                return [dir_entry]
    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()
     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
    325313        return entries
    326314
     
    367355       
    368356        directory = []
    369         name83_list = []
    370        
    371         if not head:
     357       
     358        if (not head):
    372359                # Directory cluster preallocation
    373360                empty_cluster = fat.index(0)
    374                 fat[empty_cluster] = 0xFFFF
     361                fat[empty_cluster] = 0xffff
    375362               
    376363                directory.append(create_dot_dirent(empty_cluster))
     
    379366                empty_cluster = 0
    380367       
    381         for item in listdir_items(root):
     368        for item in listdir_items(root):               
    382369                if item.is_file:
    383370                        rv = write_file(item, outf, cluster_size, data_start, fat, reserved_clusters)
    384                         directory.extend(create_dirent(item.name, name83_list, False, rv[0], rv[1]))
     371                        directory.extend(create_dirent(item.name, False, rv[0], rv[1]))
    385372                elif item.is_dir:
    386373                        rv = recursion(False, item.path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
    387                         directory.extend(create_dirent(item.name, name83_list, True, rv[0], rv[1]))
    388        
    389         if head:
     374                        directory.extend(create_dirent(item.name, True, rv[0], rv[1]))
     375       
     376        if (head):
    390377                outf.seek(root_start)
    391378                for dir_entry in directory:
     
    444431        extra_bytes = int(sys.argv[1])
    445432       
    446         path = os.path.abspath(sys.argv[2].decode())
     433        path = os.path.abspath(sys.argv[2])
    447434        if (not os.path.isdir(path)):
    448435                print("<PATH> must be a directory")
     
    542529       
    543530        outf.close()
    544 
     531       
    545532if __name__ == '__main__':
    546533        main()
Note: See TracChangeset for help on using the changeset viewer.