Changeset 238 for trunk/kernel/vfs/fatfs.c
- Timestamp:
- Jul 19, 2017, 3:31:39 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/vfs/fatfs.c
r188 r238 2 2 * fatfs.c - FATFS file system API implementation. 3 3 * 4 * Author Mohamed Lamine Karaoui (2014,2015) 5 * Alain Greiner (2016,2017) 4 * Author Alain Greiner (2016,2017) 6 5 * 7 6 * Copyright (c) UPMC Sorbonne Universites … … 30 29 #include <ppm.h> 31 30 #include <vfs.h> 31 #include <string.h> 32 32 #include <rpc.h> 33 33 #include <mapper.h> … … 46 46 47 47 ////////////////////////////////////////////////////////////////////////////////////////// 48 // FATFS private functions 49 ////////////////////////////////////////////////////////////////////////////////////////// 48 // FATFS private and static functions 49 ////////////////////////////////////////////////////////////////////////////////////////// 50 51 ////////////////////////////////////////////////////////////////////////////////////////// 52 // These functions return the "offset" and "length" values of an 53 // [offset,length] constant defined in the fatfs.h file. 54 ////////////////////////////////////////////////////////////////////////////////////////// 55 56 static inline int get_length( int offset , int length ) { return length; } 57 58 static inline int get_offset( int offset , int length ) { return offset; } 59 50 60 51 61 ////////////////////////////////////////////////////////////////////////////////////////// … … 63 73 } 64 74 65 ///////////////////////////////////////////// 66 error_t fatfs_get_cluster( mapper_t * mapper, 67 uint32_t first_cluster, 68 uint32_t searched_page, 69 uint32_t * cluster ) 70 { 71 page_t * current_page_desc; // pointer on current page descriptor 72 uint32_t * current_page_buffer; // pointer on current page (array of uint32_t) 73 uint32_t current_page_index; // index of current page in mapper 74 uint32_t current_page_offset; // offset of slot in current page 75 uint32_t page_count_in_file; // index of page in file (index in linked list) 76 uint32_t current_cluster; // content of current FAT slot 77 78 // compute number of FAT slots per PPM page 79 uint32_t slots_per_page = CONFIG_PPM_PAGE_SIZE >> 2; 80 81 // initialize loop variable 82 current_page_index = first_cluster / slots_per_page; 83 current_page_offset = first_cluster % slots_per_page; 84 page_count_in_file = 0; 85 86 // scan FAT (i.e. traverse FAT linked list) 87 while( page_count_in_file <= searched_page ) 88 { 89 // get pointer on current page descriptor 90 current_page_desc = mapper_get_page( mapper , current_page_index ); 91 92 if( current_page_desc == NULL ) return EIO; 93 94 // get pointer on buffer for current page 95 current_page_buffer = (uint32_t *)ppm_page2vaddr( current_page_desc ); 96 97 // get FAT slot content 98 current_cluster = current_page_buffer[current_page_offset]; 99 100 // update loop variables 101 current_page_index = current_cluster / slots_per_page; 102 current_page_offset = current_cluster % slots_per_page; 103 page_count_in_file++; 104 } 105 106 // return success 107 *cluster = current_cluster; 108 return 0; 109 110 } // end fatfs_get_cluster() 111 112 /////////////////////////////////////////////////////////////////////////////////////// 113 // This static function return an integer record value (one, two, or four bytes) 75 76 ////////////////////////////////////////////////////////////////////////////////////////// 77 // This function return an integer record value (one, two, or four bytes) 114 78 // from a memory buffer, taking into account endianness. 115 /////////////////////////////////////////////////////////////////////////////////////// 79 ////////////////////////////////////////////////////////////////////////////////////////// 116 80 // @ offset : first byte of record in buffer. 117 81 // @ size : record length in bytes (1/2/4). … … 119 83 // @ little endian : the most significant byte has the highest address when true. 120 84 // @ return the integer value in a 32 bits word. 121 /////////////////////////////////////////////////////////////////////////////////////// 122 static uint32_t get_record_from_buffer( uint32_t offset,123 124 125 85 ////////////////////////////////////////////////////////////////////////////////////////// 86 static uint32_t fatfs_get_record( uint32_t offset, 87 uint32_t size, 88 uint8_t * buffer, 89 uint32_t little_endian ) 126 90 { 127 91 uint32_t n; … … 138 102 return res; 139 103 140 } // end get_record_from_buffer() 141 142 143 144 //////////////////////////////////////////////////////////////////////////////////////// 104 } // end fatfs_get_record() 105 106 ////////////////////////////////////////////////////////////////////////////////////////// 107 // This static function retun in the <name> buffer a short name stored in 108 // a SFN FATFS directory entry. 109 /////////////////////////i//////////////////////////////////////////////////////////////// 110 // @ buffer : pointer on buffer containing the directory entry. 111 // @ name : [out] buffer allocated by the caller. 112 ////////////////////////////////////////////////////////////////////////////////////////// 113 static void fatfs_get_name_from_short( uint8_t * buffer, 114 char * name ) 115 { 116 uint32_t i; 117 uint32_t j = 0; 118 119 // get name 120 for ( i = 0; i < 8 && buffer[i] != ' '; i++ ) 121 { 122 name[j] = to_lower( buffer[i] ); 123 j++; 124 } 125 126 // get extension 127 for ( i = 8; i < 8 + 3 && buffer[i] != ' '; i++ ) 128 { 129 // we entered the loop so there is an extension. add the dot 130 if ( i == 8 ) 131 { 132 name[j] = '.'; 133 j++; 134 } 135 136 name[j] = to_lower( buffer[i] ); 137 j++; 138 } 139 140 name[j] = '\0'; 141 } 142 143 ////////////////////////////////////////////////////////////////////////////////////////// 144 // This static function retun in the <name> buffer a partial name stored in 145 // a LFN FATFS directory entry. 146 /////////////////////////i//////////////////////////////////////////////////////////////// 147 // @ buffer : pointer on buffer containing the directory entry. 148 // @ name : [out] buffer allocated by the caller. 149 ////////////////////////////////////////////////////////////////////////////////////////// 150 static void fatfs_get_name_from_long( uint8_t * buffer, 151 char * name ) 152 { 153 uint32_t name_offset = 0; 154 uint32_t buffer_offset = get_length(LDIR_ORD); 155 uint32_t l_name_1 = get_length(LDIR_NAME_1); 156 uint32_t l_name_2 = get_length(LDIR_NAME_2); 157 uint32_t l_name_3 = get_length(LDIR_NAME_3); 158 uint32_t l_attr = get_length(LDIR_ATTR); 159 uint32_t l_type = get_length(LDIR_TYPE); 160 uint32_t l_chksum = get_length(LDIR_CHKSUM); 161 uint32_t l_rsvd = get_length(LDIR_RSVD); 162 163 uint32_t j = 0; 164 uint32_t eof = 0; 165 166 while ( (buffer_offset != DIR_ENTRY_SIZE) && (!eof) ) 167 { 168 while (j != l_name_1 && !eof ) 169 { 170 if ( (buffer[buffer_offset] == 0x00) || 171 (buffer[buffer_offset] == 0xFF) ) 172 { 173 eof = 1; 174 continue; 175 } 176 name[name_offset] = buffer[buffer_offset]; 177 buffer_offset += 2; 178 j += 2; 179 name_offset++; 180 } 181 182 buffer_offset += (l_attr + l_type + l_chksum); 183 j = 0; 184 185 while (j != l_name_2 && !eof ) 186 { 187 if ( (buffer[buffer_offset] == 0x00) || 188 (buffer[buffer_offset] == 0xFF) ) 189 { 190 eof = 1; 191 continue; 192 } 193 name[name_offset] = buffer[buffer_offset]; 194 buffer_offset += 2; 195 j += 2; 196 name_offset++; 197 } 198 199 buffer_offset += l_rsvd; 200 j = 0; 201 202 while (j != l_name_3 && !eof ) 203 { 204 if ( (buffer[buffer_offset] == 0x00) || 205 (buffer[buffer_offset] == 0xFF) ) 206 { 207 eof = 1; 208 continue; 209 } 210 name[name_offset] = buffer[buffer_offset]; 211 buffer_offset += 2; 212 j += 2; 213 name_offset++; 214 } 215 } 216 name[name_offset] = 0; 217 218 } // end get_name_from_long() 219 220 ////////////////////////////////////////////////////////////////////////////////////////// 145 221 // This function returns the FATFS cluster index of a page identified by its page 146 222 // index in the file, using the FAT mapper. It scans the FAT mapper, starting from the … … 152 228 // in the cluster containing the FAT mapper, and the RPC latency is not critical 153 229 // compared to the device access latency. 154 //////////////////////////////////////////////////////////////////////////////////////// 230 ////////////////////////////////////////////////////////////////////////////////////////// 155 231 // @ ctx : pointer on local FATFS context. 156 232 // @ first_cluster : first cluster allocated to a file in FATFS. … … 158 234 // @ cluster_index : [out] pointer on buffer for FATFS cluster index. 159 235 // @ return 0 if success / return EIO if a FAT cluster miss cannot be solved. 160 //////////////////////////////////////////////////////////////////////////////////////// 236 ////////////////////////////////////////////////////////////////////////////////////////// 161 237 static error_t fatfs_cluster_from_index( fatfs_ctx_t * ctx, 162 238 uint32_t first_cluster, … … 203 279 } // end fatfs_cluster_from_index() 204 280 281 ////////////////////////////////////////////////////////////////////////////////////////// 282 // FATFS specific but public functions (used by RPC_FATFS_GET_CLUSTER) 283 ////////////////////////////////////////////////////////////////////////////////////////// 284 285 ///////////////////////////////////////////// 286 error_t fatfs_get_cluster( mapper_t * mapper, 287 uint32_t first_cluster, 288 uint32_t searched_page, 289 uint32_t * cluster ) 290 { 291 page_t * current_page_desc; // pointer on current page descriptor 292 uint32_t * current_page_buffer; // pointer on current page (array of uint32_t) 293 uint32_t current_page_index; // index of current page in mapper 294 uint32_t current_page_offset; // offset of slot in current page 295 uint32_t page_count_in_file; // index of page in file (index in linked list) 296 uint32_t current_cluster; // content of current FAT slot 297 298 // compute number of FAT slots per PPM page 299 uint32_t slots_per_page = CONFIG_PPM_PAGE_SIZE >> 2; 300 301 // initialize loop variable 302 current_page_index = first_cluster / slots_per_page; 303 current_page_offset = first_cluster % slots_per_page; 304 page_count_in_file = 0; 305 306 // scan FAT (i.e. traverse FAT linked list) 307 while( page_count_in_file <= searched_page ) 308 { 309 // get pointer on current page descriptor 310 current_page_desc = mapper_get_page( mapper , current_page_index ); 311 312 if( current_page_desc == NULL ) return EIO; 313 314 // get pointer on buffer for current page 315 current_page_buffer = (uint32_t *)ppm_page2vaddr( current_page_desc ); 316 317 // get FAT slot content 318 current_cluster = current_page_buffer[current_page_offset]; 319 320 // update loop variables 321 current_page_index = current_cluster / slots_per_page; 322 current_page_offset = current_cluster % slots_per_page; 323 page_count_in_file++; 324 } 325 326 // return success 327 *cluster = current_cluster; 328 return 0; 329 330 } // end fatfs_get_cluster() 205 331 206 332 207 333 208 334 /////////////////////////////////////////////////////////////////////////////////////// 209 // Generic API : the following functions are called by the kernel 335 // Generic API : the following functions are called by the kernel (VFS) 210 336 // and must be defined by all supported file systems. 211 337 /////////////////////////////////////////////////////////////////////////////////////// … … 275 401 276 402 // check sector size from boot record 277 uint32_t sector_size = get_record_from_buffer( BPB_BYTSPERSEC , buffer , 1 );403 uint32_t sector_size = fatfs_get_record( BPB_BYTSPERSEC , buffer , 1 ); 278 404 279 405 nolock_assert( (sector_size == 512) , __FUNCTION__ , … … 281 407 282 408 // check cluster size from boot record 283 uint32_t nb_sectors = get_record_from_buffer( BPB_SECPERCLUS , buffer , 1 );409 uint32_t nb_sectors = fatfs_get_record( BPB_SECPERCLUS , buffer , 1 ); 284 410 285 411 nolock_assert( (nb_sectors == 8) , __FUNCTION__ , … … 287 413 288 414 // check number of FAT copies from boot record 289 uint32_t nb_fats = get_record_from_buffer( BPB_NUMFATS , buffer , 1 );415 uint32_t nb_fats = fatfs_get_record( BPB_NUMFATS , buffer , 1 ); 290 416 291 417 nolock_assert( (nb_fats == 1) , __FUNCTION__ , … … 293 419 294 420 // get & check number of sectors in FAT from boot record 295 uint32_t fat_sectors = get_record_from_buffer( BPB_FAT32_FATSZ32 , buffer , 1 );421 uint32_t fat_sectors = fatfs_get_record( BPB_FAT32_FATSZ32 , buffer , 1 ); 296 422 297 423 nolock_assert( ((fat_sectors & 0xF) == 0) , __FUNCTION__ , … … 299 425 300 426 // get and check root cluster from boot record 301 uint32_t root_cluster = get_record_from_buffer( BPB_FAT32_ROOTCLUS , buffer , 1 );427 uint32_t root_cluster = fatfs_get_record( BPB_FAT32_ROOTCLUS , buffer , 1 ); 302 428 303 429 nolock_assert( (root_cluster == 2) , __FUNCTION__ , … … 305 431 306 432 // get FAT lba from boot record 307 uint32_t fat_lba = get_record_from_buffer( BPB_RSVDSECCNT , buffer , 1 );433 uint32_t fat_lba = fatfs_get_record( BPB_RSVDSECCNT , buffer , 1 ); 308 434 309 435 // release the 512 bytes buffer … … 353 479 } 354 480 355 /////////////////////////////////////// /////////356 static error_t fatfs_access_page( page_t * page,357 bool_t is_read)481 /////////////////////////////////////// 482 error_t fatfs_move_page( page_t * page, 483 bool_t to_mapper ) 358 484 { 359 485 // get memory buffer base address … … 388 514 389 515 // access device 390 if( is_read) error = dev_ioc_read ( buffer , lba , count );391 else error = dev_ioc_write( buffer , lba , count );516 if( to_mapper ) error = dev_ioc_read ( buffer , lba , count ); 517 else error = dev_ioc_write( buffer , lba , count ); 392 518 393 519 if( error ) … … 401 527 } 402 528 403 //////////////////////////////////////////////// 404 error_t fatfs_write_page( struct page_s * page ) 405 { 406 bool_t is_read = false; 407 return fatfs_access_page( page , is_read ); 408 } 409 410 /////////////////////////////////////////////// 411 error_t fatfs_read_page( struct page_s * page ) 412 { 413 bool_t is_read = true; 414 return fatfs_access_page( page , is_read ); 415 } 416 529 ///////////////////////////////////////////////////////////////// 530 error_t fatfs_inode_load( vfs_inode_t * parent_inode, 531 char * name, 532 xptr_t child_inode_xp ) 533 { 534 // Two embedded loops: 535 // - scan the parent mapper pages 536 // - scan the directory entries in each 4 Kbytes page 537 538 fatfs_dmsg("\n[INFO] %s : enter for child <%s> in parent inode %l\n", 539 __FUNCTION__ , name , child_inode_xp ); 540 541 mapper_t * mapper = parent_inode->mapper; 542 543 assert( (mapper != NULL) , __FUNCTION__ , "parent mapper undefined\n"); 544 545 char cname[CONFIG_VFS_MAX_NAME_LENGTH]; // name extracter from each directory entry 546 547 char lfn1[16]; // buffer for one partial cname 548 char lfn2[16]; // buffer for one partial cname 549 char lfn3[16]; // buffer for one partial cname 550 page_t * page; // pointer on current page descriptor 551 uint8_t * base; // pointer on current page base 552 uint32_t offset = 0; // byte offset in page 553 uint32_t index = 0; // page index in mapper 554 uint32_t attr; // directory entry ATTR field 555 uint32_t ord; // directory entry ORD field 556 uint32_t seq; // sequence index 557 uint32_t lfn = 0; // LFN entries number 558 uint32_t size = 0; // searched file/dir size (bytes) 559 uint32_t cluster = 0; // searched file/dir cluster index 560 uint32_t is_dir = 0; // searched file/dir type 561 uint32_t dentry; // directory entry index 562 int32_t found = 0; // not found (0) / name found (1) / end of dir (-1) 563 564 // scan the parent directory mapper 565 while ( found == 0 ) 566 { 567 // get one page 568 page = mapper_get_page( mapper , index ); 569 570 assert( (page != NULL) , __FUNCTION__ , "bad parent mapper\n"); 571 572 // get page base 573 base = ppm_page2vaddr( page ); 574 575 // scan this page until end of directory, end of page, or name found 576 while( (offset < 4096) && (found == 0) ) 577 { 578 attr = fatfs_get_record( DIR_ATTR , base + offset , 0 ); 579 ord = fatfs_get_record( LDIR_ORD , base + offset , 0 ); 580 581 if (ord == NO_MORE_ENTRY) // no more entry => break 582 { 583 found = -1; 584 } 585 else if ( ord == FREE_ENTRY ) // free entry => skip 586 { 587 offset = offset + 32; 588 } 589 else if ( attr == ATTR_LONG_NAME_MASK ) // LFN entry => get partial cname 590 { 591 seq = ord & 0x3; 592 lfn = (seq > lfn) ? seq : lfn; 593 if ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 ); 594 else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 ); 595 else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 ); 596 offset = offset + 32; 597 } 598 else // NORMAL entry 599 { 600 // build the extracted name 601 if ( lfn == 0 ) 602 { 603 fatfs_get_name_from_short( base + offset , cname ); 604 } 605 else if ( lfn == 1 ) 606 { 607 strcpy( cname , lfn1 ); 608 } 609 else if ( lfn == 2 ) 610 { 611 strcpy( cname , lfn1 ); 612 strcpy( cname + 13 , lfn2 ); 613 } 614 else if ( lfn == 3 ) 615 { 616 strcpy( cname , lfn1 ); 617 strcpy( cname + 13 , lfn2 ); 618 strcpy( cname + 26 , lfn3 ); 619 } 620 621 // get dentry arguments if extracted cname == searched name 622 if ( strcmp( name , cname ) == 0 ) 623 { 624 cluster = (fatfs_get_record( DIR_FST_CLUS_HI , base + offset , 1 ) << 16) | 625 (fatfs_get_record( DIR_FST_CLUS_LO , base + offset , 1 ) ) ; 626 dentry = ((index<<12) + offset)>>5; 627 is_dir = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY); 628 size = fatfs_get_record( DIR_FILE_SIZE , base + offset , 1 ); 629 found = 1; 630 } 631 offset = offset + 32; 632 lfn = 0; 633 } 634 } // end loop on directory entries 635 index++; 636 offset = 0; 637 } // end loop on pages 638 639 // analyse the result of scan 640 641 if ( found == -1 ) // found end of directory => failure 642 { 643 fatfs_dmsg("\n[INFO] %s : child <%s> not found in parent inode %l\n", 644 __FUNCTION__ , name , parent_inode_xp ); 645 646 return ENOENT; 647 } 648 else // found searched child name 649 { 650 fatfs_dmsg("\n[INFO] %s : child <%s> found in parent inode %l\n", 651 __FUNCTION__ , name , parent_inode_xp ); 652 653 // get child inode cluster and local pointer 654 cxy_t child_cxy = GET_CXY( child_inode_xp ); 655 vfs_inode_t * child_ptr = (vfs_inode_t *)GET_PTR( child_inode_xp ); 656 657 // update the child inode "type", "size", and "extend" fields 658 vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE; 659 660 hal_remote_sw( XPTR( child_cxy , &child_ptr->type ) , type ); 661 hal_remote_sw( XPTR( child_cxy , &child_ptr->size ) , size ); 662 hal_remote_sw( XPTR( child_cxy , &child_ptr->extend ) , cluster ); 663 664 return 0; 665 } 666 } // end fatfs_inode_load()
Note: See TracChangeset
for help on using the changeset viewer.