1 /* 2 * fat_write.c 3 * 4 * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <command.h> 11 #include <config.h> 12 #include <fat.h> 13 #include <asm/byteorder.h> 14 #include <part.h> 15 #include <linux/ctype.h> 16 #include <div64.h> 17 #include <linux/math64.h> 18 #include "fat.c" 19 20 static void uppercase(char *str, int len) 21 { 22 int i; 23 24 for (i = 0; i < len; i++) { 25 *str = toupper(*str); 26 str++; 27 } 28 } 29 30 static int total_sector; 31 static int disk_write(__u32 block, __u32 nr_blocks, void *buf) 32 { 33 ulong ret; 34 35 if (!cur_dev) 36 return -1; 37 38 if (cur_part_info.start + block + nr_blocks > 39 cur_part_info.start + total_sector) { 40 printf("error: overflow occurs\n"); 41 return -1; 42 } 43 44 ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf); 45 if (nr_blocks && ret == 0) 46 return -1; 47 48 return ret; 49 } 50 51 /* 52 * Set short name in directory entry 53 */ 54 static void set_name(dir_entry *dirent, const char *filename) 55 { 56 char s_name[VFAT_MAXLEN_BYTES]; 57 char *period; 58 int period_location, len, i, ext_num; 59 60 if (filename == NULL) 61 return; 62 63 len = strlen(filename); 64 if (len == 0) 65 return; 66 67 strcpy(s_name, filename); 68 uppercase(s_name, len); 69 70 period = strchr(s_name, '.'); 71 if (period == NULL) { 72 period_location = len; 73 ext_num = 0; 74 } else { 75 period_location = period - s_name; 76 ext_num = len - period_location - 1; 77 } 78 79 /* Pad spaces when the length of file name is shorter than eight */ 80 if (period_location < 8) { 81 memcpy(dirent->name, s_name, period_location); 82 for (i = period_location; i < 8; i++) 83 dirent->name[i] = ' '; 84 } else if (period_location == 8) { 85 memcpy(dirent->name, s_name, period_location); 86 } else { 87 memcpy(dirent->name, s_name, 6); 88 dirent->name[6] = '~'; 89 dirent->name[7] = '1'; 90 } 91 92 if (ext_num < 3) { 93 memcpy(dirent->ext, s_name + period_location + 1, ext_num); 94 for (i = ext_num; i < 3; i++) 95 dirent->ext[i] = ' '; 96 } else 97 memcpy(dirent->ext, s_name + period_location + 1, 3); 98 99 debug("name : %s\n", dirent->name); 100 debug("ext : %s\n", dirent->ext); 101 } 102 103 static __u8 num_of_fats; 104 /* 105 * Write fat buffer into block device 106 */ 107 static int flush_dirty_fat_buffer(fsdata *mydata) 108 { 109 int getsize = FATBUFBLOCKS; 110 __u32 fatlength = mydata->fatlength; 111 __u8 *bufptr = mydata->fatbuf; 112 __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS; 113 114 debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum, 115 (int)mydata->fat_dirty); 116 117 if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1)) 118 return 0; 119 120 startblock += mydata->fat_sect; 121 122 if (getsize > fatlength) 123 getsize = fatlength; 124 125 /* Write FAT buf */ 126 if (disk_write(startblock, getsize, bufptr) < 0) { 127 debug("error: writing FAT blocks\n"); 128 return -1; 129 } 130 131 if (num_of_fats == 2) { 132 /* Update corresponding second FAT blocks */ 133 startblock += mydata->fatlength; 134 if (disk_write(startblock, getsize, bufptr) < 0) { 135 debug("error: writing second FAT blocks\n"); 136 return -1; 137 } 138 } 139 mydata->fat_dirty = 0; 140 141 return 0; 142 } 143 144 /* 145 * Get the entry at index 'entry' in a FAT (12/16/32) table. 146 * On failure 0x00 is returned. 147 * When bufnum is changed, write back the previous fatbuf to the disk. 148 */ 149 static __u32 get_fatent_value(fsdata *mydata, __u32 entry) 150 { 151 __u32 bufnum; 152 __u32 off16, offset; 153 __u32 ret = 0x00; 154 __u16 val1, val2; 155 156 if (CHECK_CLUST(entry, mydata->fatsize)) { 157 printf("Error: Invalid FAT entry: 0x%08x\n", entry); 158 return ret; 159 } 160 161 switch (mydata->fatsize) { 162 case 32: 163 bufnum = entry / FAT32BUFSIZE; 164 offset = entry - bufnum * FAT32BUFSIZE; 165 break; 166 case 16: 167 bufnum = entry / FAT16BUFSIZE; 168 offset = entry - bufnum * FAT16BUFSIZE; 169 break; 170 case 12: 171 bufnum = entry / FAT12BUFSIZE; 172 offset = entry - bufnum * FAT12BUFSIZE; 173 break; 174 175 default: 176 /* Unsupported FAT size */ 177 return ret; 178 } 179 180 debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", 181 mydata->fatsize, entry, entry, offset, offset); 182 183 /* Read a new block of FAT entries into the cache. */ 184 if (bufnum != mydata->fatbufnum) { 185 int getsize = FATBUFBLOCKS; 186 __u8 *bufptr = mydata->fatbuf; 187 __u32 fatlength = mydata->fatlength; 188 __u32 startblock = bufnum * FATBUFBLOCKS; 189 190 if (getsize > fatlength) 191 getsize = fatlength; 192 193 startblock += mydata->fat_sect; /* Offset from start of disk */ 194 195 /* Write back the fatbuf to the disk */ 196 if (flush_dirty_fat_buffer(mydata) < 0) 197 return -1; 198 199 if (disk_read(startblock, getsize, bufptr) < 0) { 200 debug("Error reading FAT blocks\n"); 201 return ret; 202 } 203 mydata->fatbufnum = bufnum; 204 } 205 206 /* Get the actual entry from the table */ 207 switch (mydata->fatsize) { 208 case 32: 209 ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); 210 break; 211 case 16: 212 ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); 213 break; 214 case 12: 215 off16 = (offset * 3) / 4; 216 217 switch (offset & 0x3) { 218 case 0: 219 ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); 220 ret &= 0xfff; 221 break; 222 case 1: 223 val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); 224 val1 &= 0xf000; 225 val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); 226 val2 &= 0x00ff; 227 ret = (val2 << 4) | (val1 >> 12); 228 break; 229 case 2: 230 val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); 231 val1 &= 0xff00; 232 val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); 233 val2 &= 0x000f; 234 ret = (val2 << 8) | (val1 >> 8); 235 break; 236 case 3: 237 ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); 238 ret = (ret & 0xfff0) >> 4; 239 break; 240 default: 241 break; 242 } 243 break; 244 } 245 debug("FAT%d: ret: %08x, entry: %08x, offset: %04x\n", 246 mydata->fatsize, ret, entry, offset); 247 248 return ret; 249 } 250 251 /* 252 * Set the file name information from 'name' into 'slotptr', 253 */ 254 static int str2slot(dir_slot *slotptr, const char *name, int *idx) 255 { 256 int j, end_idx = 0; 257 258 for (j = 0; j <= 8; j += 2) { 259 if (name[*idx] == 0x00) { 260 slotptr->name0_4[j] = 0; 261 slotptr->name0_4[j + 1] = 0; 262 end_idx++; 263 goto name0_4; 264 } 265 slotptr->name0_4[j] = name[*idx]; 266 (*idx)++; 267 end_idx++; 268 } 269 for (j = 0; j <= 10; j += 2) { 270 if (name[*idx] == 0x00) { 271 slotptr->name5_10[j] = 0; 272 slotptr->name5_10[j + 1] = 0; 273 end_idx++; 274 goto name5_10; 275 } 276 slotptr->name5_10[j] = name[*idx]; 277 (*idx)++; 278 end_idx++; 279 } 280 for (j = 0; j <= 2; j += 2) { 281 if (name[*idx] == 0x00) { 282 slotptr->name11_12[j] = 0; 283 slotptr->name11_12[j + 1] = 0; 284 end_idx++; 285 goto name11_12; 286 } 287 slotptr->name11_12[j] = name[*idx]; 288 (*idx)++; 289 end_idx++; 290 } 291 292 if (name[*idx] == 0x00) 293 return 1; 294 295 return 0; 296 /* Not used characters are filled with 0xff 0xff */ 297 name0_4: 298 for (; end_idx < 5; end_idx++) { 299 slotptr->name0_4[end_idx * 2] = 0xff; 300 slotptr->name0_4[end_idx * 2 + 1] = 0xff; 301 } 302 end_idx = 5; 303 name5_10: 304 end_idx -= 5; 305 for (; end_idx < 6; end_idx++) { 306 slotptr->name5_10[end_idx * 2] = 0xff; 307 slotptr->name5_10[end_idx * 2 + 1] = 0xff; 308 } 309 end_idx = 11; 310 name11_12: 311 end_idx -= 11; 312 for (; end_idx < 2; end_idx++) { 313 slotptr->name11_12[end_idx * 2] = 0xff; 314 slotptr->name11_12[end_idx * 2 + 1] = 0xff; 315 } 316 317 return 1; 318 } 319 320 static int is_next_clust(fsdata *mydata, dir_entry *dentptr); 321 static void flush_dir_table(fsdata *mydata, dir_entry **dentptr); 322 323 /* 324 * Fill dir_slot entries with appropriate name, id, and attr 325 * The real directory entry is returned by 'dentptr' 326 */ 327 static void 328 fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) 329 { 330 __u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)]; 331 dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer; 332 __u8 counter = 0, checksum; 333 int idx = 0, ret; 334 335 /* Get short file name checksum value */ 336 checksum = mkcksum((*dentptr)->name, (*dentptr)->ext); 337 338 do { 339 memset(slotptr, 0x00, sizeof(dir_slot)); 340 ret = str2slot(slotptr, l_name, &idx); 341 slotptr->id = ++counter; 342 slotptr->attr = ATTR_VFAT; 343 slotptr->alias_checksum = checksum; 344 slotptr++; 345 } while (ret == 0); 346 347 slotptr--; 348 slotptr->id |= LAST_LONG_ENTRY_MASK; 349 350 while (counter >= 1) { 351 if (is_next_clust(mydata, *dentptr)) { 352 /* A new cluster is allocated for directory table */ 353 flush_dir_table(mydata, dentptr); 354 } 355 memcpy(*dentptr, slotptr, sizeof(dir_slot)); 356 (*dentptr)++; 357 slotptr--; 358 counter--; 359 } 360 361 if (is_next_clust(mydata, *dentptr)) { 362 /* A new cluster is allocated for directory table */ 363 flush_dir_table(mydata, dentptr); 364 } 365 } 366 367 static __u32 dir_curclust; 368 369 /* 370 * Extract the full long filename starting at 'retdent' (which is really 371 * a slot) into 'l_name'. If successful also copy the real directory entry 372 * into 'retdent' 373 * If additional adjacent cluster for directory entries is read into memory, 374 * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and 375 * the location of the real directory entry is returned by 'retdent' 376 * Return 0 on success, -1 otherwise. 377 */ 378 static int 379 get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster, 380 dir_entry **retdent, char *l_name) 381 { 382 dir_entry *realdent; 383 dir_slot *slotptr = (dir_slot *)(*retdent); 384 dir_slot *slotptr2 = NULL; 385 __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? 386 PREFETCH_BLOCKS : 387 mydata->clust_size); 388 __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; 389 int idx = 0, cur_position = 0; 390 391 if (counter > VFAT_MAXSEQ) { 392 debug("Error: VFAT name is too long\n"); 393 return -1; 394 } 395 396 while ((__u8 *)slotptr < buflimit) { 397 if (counter == 0) 398 break; 399 if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) 400 return -1; 401 slotptr++; 402 counter--; 403 } 404 405 if ((__u8 *)slotptr >= buflimit) { 406 if (curclust == 0) 407 return -1; 408 curclust = get_fatent_value(mydata, dir_curclust); 409 if (CHECK_CLUST(curclust, mydata->fatsize)) { 410 debug("curclust: 0x%x\n", curclust); 411 printf("Invalid FAT entry\n"); 412 return -1; 413 } 414 415 dir_curclust = curclust; 416 417 if (get_cluster(mydata, curclust, get_contents_vfatname_block, 418 mydata->clust_size * mydata->sect_size) != 0) { 419 debug("Error: reading directory block\n"); 420 return -1; 421 } 422 423 slotptr2 = (dir_slot *)get_contents_vfatname_block; 424 while (counter > 0) { 425 if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) 426 & 0xff) != counter) 427 return -1; 428 slotptr2++; 429 counter--; 430 } 431 432 /* Save the real directory entry */ 433 realdent = (dir_entry *)slotptr2; 434 while ((__u8 *)slotptr2 > get_contents_vfatname_block) { 435 slotptr2--; 436 slot2str(slotptr2, l_name, &idx); 437 } 438 } else { 439 /* Save the real directory entry */ 440 realdent = (dir_entry *)slotptr; 441 } 442 443 do { 444 slotptr--; 445 if (slot2str(slotptr, l_name, &idx)) 446 break; 447 } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); 448 449 l_name[idx] = '\0'; 450 if (*l_name == DELETED_FLAG) 451 *l_name = '\0'; 452 else if (*l_name == aRING) 453 *l_name = DELETED_FLAG; 454 downcase(l_name); 455 456 /* Return the real directory entry */ 457 *retdent = realdent; 458 459 if (slotptr2) { 460 memcpy(get_dentfromdir_block, get_contents_vfatname_block, 461 mydata->clust_size * mydata->sect_size); 462 cur_position = (__u8 *)realdent - get_contents_vfatname_block; 463 *retdent = (dir_entry *) &get_dentfromdir_block[cur_position]; 464 } 465 466 return 0; 467 } 468 469 /* 470 * Set the entry at index 'entry' in a FAT (16/32) table. 471 */ 472 static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) 473 { 474 __u32 bufnum, offset; 475 476 switch (mydata->fatsize) { 477 case 32: 478 bufnum = entry / FAT32BUFSIZE; 479 offset = entry - bufnum * FAT32BUFSIZE; 480 break; 481 case 16: 482 bufnum = entry / FAT16BUFSIZE; 483 offset = entry - bufnum * FAT16BUFSIZE; 484 break; 485 default: 486 /* Unsupported FAT size */ 487 return -1; 488 } 489 490 /* Read a new block of FAT entries into the cache. */ 491 if (bufnum != mydata->fatbufnum) { 492 int getsize = FATBUFBLOCKS; 493 __u8 *bufptr = mydata->fatbuf; 494 __u32 fatlength = mydata->fatlength; 495 __u32 startblock = bufnum * FATBUFBLOCKS; 496 497 fatlength *= mydata->sect_size; 498 startblock += mydata->fat_sect; 499 500 if (getsize > fatlength) 501 getsize = fatlength; 502 503 if (flush_dirty_fat_buffer(mydata) < 0) 504 return -1; 505 506 if (disk_read(startblock, getsize, bufptr) < 0) { 507 debug("Error reading FAT blocks\n"); 508 return -1; 509 } 510 mydata->fatbufnum = bufnum; 511 } 512 513 /* Mark as dirty */ 514 mydata->fat_dirty = 1; 515 516 /* Set the actual entry */ 517 switch (mydata->fatsize) { 518 case 32: 519 ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value); 520 break; 521 case 16: 522 ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value); 523 break; 524 default: 525 return -1; 526 } 527 528 return 0; 529 } 530 531 /* 532 * Determine the next free cluster after 'entry' in a FAT (16/32) table 533 * and link it to 'entry'. EOC marker is not set on returned entry. 534 */ 535 static __u32 determine_fatent(fsdata *mydata, __u32 entry) 536 { 537 __u32 next_fat, next_entry = entry + 1; 538 539 while (1) { 540 next_fat = get_fatent_value(mydata, next_entry); 541 if (next_fat == 0) { 542 /* found free entry, link to entry */ 543 set_fatent_value(mydata, entry, next_entry); 544 break; 545 } 546 next_entry++; 547 } 548 debug("FAT%d: entry: %08x, entry_value: %04x\n", 549 mydata->fatsize, entry, next_entry); 550 551 return next_entry; 552 } 553 554 /* 555 * Write at most 'size' bytes from 'buffer' into the specified cluster. 556 * Return 0 on success, -1 otherwise. 557 */ 558 static int 559 set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, 560 unsigned long size) 561 { 562 __u32 idx = 0; 563 __u32 startsect; 564 int ret; 565 566 if (clustnum > 0) 567 startsect = mydata->data_begin + 568 clustnum * mydata->clust_size; 569 else 570 startsect = mydata->rootdir_sect; 571 572 debug("clustnum: %d, startsect: %d\n", clustnum, startsect); 573 574 if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { 575 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); 576 577 printf("FAT: Misaligned buffer address (%p)\n", buffer); 578 579 while (size >= mydata->sect_size) { 580 memcpy(tmpbuf, buffer, mydata->sect_size); 581 ret = disk_write(startsect++, 1, tmpbuf); 582 if (ret != 1) { 583 debug("Error writing data (got %d)\n", ret); 584 return -1; 585 } 586 587 buffer += mydata->sect_size; 588 size -= mydata->sect_size; 589 } 590 } else if (size >= mydata->sect_size) { 591 idx = size / mydata->sect_size; 592 ret = disk_write(startsect, idx, buffer); 593 if (ret != idx) { 594 debug("Error writing data (got %d)\n", ret); 595 return -1; 596 } 597 598 startsect += idx; 599 idx *= mydata->sect_size; 600 buffer += idx; 601 size -= idx; 602 } 603 604 if (size) { 605 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); 606 607 memcpy(tmpbuf, buffer, size); 608 ret = disk_write(startsect, 1, tmpbuf); 609 if (ret != 1) { 610 debug("Error writing data (got %d)\n", ret); 611 return -1; 612 } 613 } 614 615 return 0; 616 } 617 618 /* 619 * Find the first empty cluster 620 */ 621 static int find_empty_cluster(fsdata *mydata) 622 { 623 __u32 fat_val, entry = 3; 624 625 while (1) { 626 fat_val = get_fatent_value(mydata, entry); 627 if (fat_val == 0) 628 break; 629 entry++; 630 } 631 632 return entry; 633 } 634 635 /* 636 * Write directory entries in 'get_dentfromdir_block' to block device 637 */ 638 static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) 639 { 640 int dir_newclust = 0; 641 642 if (set_cluster(mydata, dir_curclust, 643 get_dentfromdir_block, 644 mydata->clust_size * mydata->sect_size) != 0) { 645 printf("error: wrinting directory entry\n"); 646 return; 647 } 648 dir_newclust = find_empty_cluster(mydata); 649 set_fatent_value(mydata, dir_curclust, dir_newclust); 650 if (mydata->fatsize == 32) 651 set_fatent_value(mydata, dir_newclust, 0xffffff8); 652 else if (mydata->fatsize == 16) 653 set_fatent_value(mydata, dir_newclust, 0xfff8); 654 655 dir_curclust = dir_newclust; 656 657 if (flush_dirty_fat_buffer(mydata) < 0) 658 return; 659 660 memset(get_dentfromdir_block, 0x00, 661 mydata->clust_size * mydata->sect_size); 662 663 *dentptr = (dir_entry *) get_dentfromdir_block; 664 } 665 666 /* 667 * Set empty cluster from 'entry' to the end of a file 668 */ 669 static int clear_fatent(fsdata *mydata, __u32 entry) 670 { 671 __u32 fat_val; 672 673 while (1) { 674 fat_val = get_fatent_value(mydata, entry); 675 if (fat_val != 0) 676 set_fatent_value(mydata, entry, 0); 677 else 678 break; 679 680 if (fat_val == 0xfffffff || fat_val == 0xffff) 681 break; 682 683 entry = fat_val; 684 } 685 686 /* Flush fat buffer */ 687 if (flush_dirty_fat_buffer(mydata) < 0) 688 return -1; 689 690 return 0; 691 } 692 693 /* 694 * Write at most 'maxsize' bytes from 'buffer' into 695 * the file associated with 'dentptr' 696 * Update the number of bytes written in *gotsize and return 0 697 * or return -1 on fatal errors. 698 */ 699 static int 700 set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, 701 loff_t maxsize, loff_t *gotsize) 702 { 703 loff_t filesize = FAT2CPU32(dentptr->size); 704 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; 705 __u32 curclust = START(dentptr); 706 __u32 endclust = 0, newclust = 0; 707 loff_t actsize; 708 709 *gotsize = 0; 710 debug("Filesize: %llu bytes\n", filesize); 711 712 if (maxsize > 0 && filesize > maxsize) 713 filesize = maxsize; 714 715 debug("%llu bytes\n", filesize); 716 717 if (!curclust) { 718 if (filesize) { 719 debug("error: nonempty clusterless file!\n"); 720 return -1; 721 } 722 return 0; 723 } 724 725 actsize = bytesperclust; 726 endclust = curclust; 727 do { 728 /* search for consecutive clusters */ 729 while (actsize < filesize) { 730 newclust = determine_fatent(mydata, endclust); 731 732 if ((newclust - 1) != endclust) 733 goto getit; 734 735 if (CHECK_CLUST(newclust, mydata->fatsize)) { 736 debug("newclust: 0x%x\n", newclust); 737 debug("Invalid FAT entry\n"); 738 return 0; 739 } 740 endclust = newclust; 741 actsize += bytesperclust; 742 } 743 744 /* set remaining bytes */ 745 actsize = filesize; 746 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 747 debug("error: writing cluster\n"); 748 return -1; 749 } 750 *gotsize += actsize; 751 752 /* Mark end of file in FAT */ 753 if (mydata->fatsize == 16) 754 newclust = 0xffff; 755 else if (mydata->fatsize == 32) 756 newclust = 0xfffffff; 757 set_fatent_value(mydata, endclust, newclust); 758 759 return 0; 760 getit: 761 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 762 debug("error: writing cluster\n"); 763 return -1; 764 } 765 *gotsize += actsize; 766 filesize -= actsize; 767 buffer += actsize; 768 769 if (CHECK_CLUST(newclust, mydata->fatsize)) { 770 debug("newclust: 0x%x\n", newclust); 771 debug("Invalid FAT entry\n"); 772 return 0; 773 } 774 actsize = bytesperclust; 775 curclust = endclust = newclust; 776 } while (1); 777 } 778 779 /* 780 * Set start cluster in directory entry 781 */ 782 static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr, 783 __u32 start_cluster) 784 { 785 if (mydata->fatsize == 32) 786 dentptr->starthi = 787 cpu_to_le16((start_cluster & 0xffff0000) >> 16); 788 dentptr->start = cpu_to_le16(start_cluster & 0xffff); 789 } 790 791 /* 792 * Fill dir_entry 793 */ 794 static void fill_dentry(fsdata *mydata, dir_entry *dentptr, 795 const char *filename, __u32 start_cluster, __u32 size, __u8 attr) 796 { 797 set_start_cluster(mydata, dentptr, start_cluster); 798 dentptr->size = cpu_to_le32(size); 799 800 dentptr->attr = attr; 801 802 set_name(dentptr, filename); 803 } 804 805 /* 806 * Check whether adding a file makes the file system to 807 * exceed the size of the block device 808 * Return -1 when overflow occurs, otherwise return 0 809 */ 810 static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) 811 { 812 __u32 startsect, sect_num, offset; 813 814 if (clustnum > 0) { 815 startsect = mydata->data_begin + 816 clustnum * mydata->clust_size; 817 } else { 818 startsect = mydata->rootdir_sect; 819 } 820 821 sect_num = div_u64_rem(size, mydata->sect_size, &offset); 822 823 if (offset != 0) 824 sect_num++; 825 826 if (startsect + sect_num > cur_part_info.start + total_sector) 827 return -1; 828 return 0; 829 } 830 831 /* 832 * Check if adding several entries exceed one cluster boundary 833 */ 834 static int is_next_clust(fsdata *mydata, dir_entry *dentptr) 835 { 836 int cur_position; 837 838 cur_position = (__u8 *)dentptr - get_dentfromdir_block; 839 840 if (cur_position >= mydata->clust_size * mydata->sect_size) 841 return 1; 842 else 843 return 0; 844 } 845 846 static dir_entry *empty_dentptr; 847 /* 848 * Find a directory entry based on filename or start cluster number 849 * If the directory entry is not found, 850 * the new position for writing a directory entry will be returned 851 */ 852 static dir_entry *find_directory_entry(fsdata *mydata, int startsect, 853 char *filename, dir_entry *retdent, __u32 start) 854 { 855 __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; 856 857 debug("get_dentfromdir: %s\n", filename); 858 859 while (1) { 860 dir_entry *dentptr; 861 862 int i; 863 864 if (get_cluster(mydata, curclust, get_dentfromdir_block, 865 mydata->clust_size * mydata->sect_size) != 0) { 866 printf("Error: reading directory block\n"); 867 return NULL; 868 } 869 870 dentptr = (dir_entry *)get_dentfromdir_block; 871 872 dir_curclust = curclust; 873 874 for (i = 0; i < DIRENTSPERCLUST; i++) { 875 char s_name[14], l_name[VFAT_MAXLEN_BYTES]; 876 877 l_name[0] = '\0'; 878 if (dentptr->name[0] == DELETED_FLAG) { 879 dentptr++; 880 if (is_next_clust(mydata, dentptr)) 881 break; 882 continue; 883 } 884 if ((dentptr->attr & ATTR_VOLUME)) { 885 if (vfat_enabled && 886 (dentptr->attr & ATTR_VFAT) && 887 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 888 get_long_file_name(mydata, curclust, 889 get_dentfromdir_block, 890 &dentptr, l_name); 891 debug("vfatname: |%s|\n", l_name); 892 } else { 893 /* Volume label or VFAT entry */ 894 dentptr++; 895 if (is_next_clust(mydata, dentptr)) 896 break; 897 continue; 898 } 899 } 900 if (dentptr->name[0] == 0) { 901 debug("Dentname == NULL - %d\n", i); 902 empty_dentptr = dentptr; 903 return NULL; 904 } 905 906 get_name(dentptr, s_name); 907 908 if (strcmp(filename, s_name) 909 && strcmp(filename, l_name)) { 910 debug("Mismatch: |%s|%s|\n", 911 s_name, l_name); 912 dentptr++; 913 if (is_next_clust(mydata, dentptr)) 914 break; 915 continue; 916 } 917 918 memcpy(retdent, dentptr, sizeof(dir_entry)); 919 920 debug("DentName: %s", s_name); 921 debug(", start: 0x%x", START(dentptr)); 922 debug(", size: 0x%x %s\n", 923 FAT2CPU32(dentptr->size), 924 (dentptr->attr & ATTR_DIR) ? 925 "(DIR)" : ""); 926 927 return dentptr; 928 } 929 930 /* 931 * In FAT16/12, the root dir is locate before data area, shows 932 * in following: 933 * ------------------------------------------------------------- 934 * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | 935 * ------------------------------------------------------------- 936 * 937 * As a result if curclust is in Root dir, it is a negative 938 * number or 0, 1. 939 * 940 */ 941 if (mydata->fatsize != 32 && (int)curclust <= 1) { 942 /* Current clust is in root dir, set to next clust */ 943 curclust++; 944 if ((int)curclust <= 1) 945 continue; /* continue to find */ 946 947 /* Reach the end of root dir */ 948 empty_dentptr = dentptr; 949 return NULL; 950 } 951 952 curclust = get_fatent_value(mydata, dir_curclust); 953 if (IS_LAST_CLUST(curclust, mydata->fatsize)) { 954 empty_dentptr = dentptr; 955 return NULL; 956 } 957 if (CHECK_CLUST(curclust, mydata->fatsize)) { 958 debug("curclust: 0x%x\n", curclust); 959 debug("Invalid FAT entry\n"); 960 return NULL; 961 } 962 } 963 964 return NULL; 965 } 966 967 static int do_fat_write(const char *filename, void *buffer, loff_t size, 968 loff_t *actwrite) 969 { 970 dir_entry *dentptr, *retdent; 971 __u32 startsect; 972 __u32 start_cluster; 973 boot_sector bs; 974 volume_info volinfo; 975 fsdata datablock; 976 fsdata *mydata = &datablock; 977 int cursect; 978 int ret = -1, name_len; 979 char l_filename[VFAT_MAXLEN_BYTES]; 980 981 *actwrite = size; 982 dir_curclust = 0; 983 984 if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { 985 debug("error: reading boot sector\n"); 986 return -1; 987 } 988 989 total_sector = bs.total_sect; 990 if (total_sector == 0) 991 total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ 992 993 if (mydata->fatsize == 32) 994 mydata->fatlength = bs.fat32_length; 995 else 996 mydata->fatlength = bs.fat_length; 997 998 mydata->fat_sect = bs.reserved; 999 1000 cursect = mydata->rootdir_sect 1001 = mydata->fat_sect + mydata->fatlength * bs.fats; 1002 num_of_fats = bs.fats; 1003 1004 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; 1005 mydata->clust_size = bs.cluster_size; 1006 1007 if (mydata->fatsize == 32) { 1008 mydata->data_begin = mydata->rootdir_sect - 1009 (mydata->clust_size * 2); 1010 } else { 1011 int rootdir_size; 1012 1013 rootdir_size = ((bs.dir_entries[1] * (int)256 + 1014 bs.dir_entries[0]) * 1015 sizeof(dir_entry)) / 1016 mydata->sect_size; 1017 mydata->data_begin = mydata->rootdir_sect + 1018 rootdir_size - 1019 (mydata->clust_size * 2); 1020 } 1021 1022 mydata->fatbufnum = -1; 1023 mydata->fat_dirty = 0; 1024 mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); 1025 if (mydata->fatbuf == NULL) { 1026 debug("Error: allocating memory\n"); 1027 return -1; 1028 } 1029 1030 if (disk_read(cursect, 1031 (mydata->fatsize == 32) ? 1032 (mydata->clust_size) : 1033 PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { 1034 debug("Error: reading rootdir block\n"); 1035 goto exit; 1036 } 1037 dentptr = (dir_entry *) do_fat_read_at_block; 1038 1039 name_len = strlen(filename); 1040 if (name_len >= VFAT_MAXLEN_BYTES) 1041 name_len = VFAT_MAXLEN_BYTES - 1; 1042 1043 memcpy(l_filename, filename, name_len); 1044 l_filename[name_len] = 0; /* terminate the string */ 1045 downcase(l_filename); 1046 1047 startsect = mydata->rootdir_sect; 1048 retdent = find_directory_entry(mydata, startsect, 1049 l_filename, dentptr, 0); 1050 if (retdent) { 1051 /* Update file size and start_cluster in a directory entry */ 1052 retdent->size = cpu_to_le32(size); 1053 start_cluster = START(retdent); 1054 1055 if (start_cluster) { 1056 if (size) { 1057 ret = check_overflow(mydata, start_cluster, 1058 size); 1059 if (ret) { 1060 printf("Error: %llu overflow\n", size); 1061 goto exit; 1062 } 1063 } 1064 1065 ret = clear_fatent(mydata, start_cluster); 1066 if (ret) { 1067 printf("Error: clearing FAT entries\n"); 1068 goto exit; 1069 } 1070 1071 if (!size) 1072 set_start_cluster(mydata, retdent, 0); 1073 } else if (size) { 1074 ret = start_cluster = find_empty_cluster(mydata); 1075 if (ret < 0) { 1076 printf("Error: finding empty cluster\n"); 1077 goto exit; 1078 } 1079 1080 ret = check_overflow(mydata, start_cluster, size); 1081 if (ret) { 1082 printf("Error: %llu overflow\n", size); 1083 goto exit; 1084 } 1085 1086 set_start_cluster(mydata, retdent, start_cluster); 1087 } 1088 } else { 1089 /* Set short name to set alias checksum field in dir_slot */ 1090 set_name(empty_dentptr, filename); 1091 fill_dir_slot(mydata, &empty_dentptr, filename); 1092 1093 if (size) { 1094 ret = start_cluster = find_empty_cluster(mydata); 1095 if (ret < 0) { 1096 printf("Error: finding empty cluster\n"); 1097 goto exit; 1098 } 1099 1100 ret = check_overflow(mydata, start_cluster, size); 1101 if (ret) { 1102 printf("Error: %llu overflow\n", size); 1103 goto exit; 1104 } 1105 } else { 1106 start_cluster = 0; 1107 } 1108 1109 /* Set attribute as archieve for regular file */ 1110 fill_dentry(mydata, empty_dentptr, filename, 1111 start_cluster, size, 0x20); 1112 1113 retdent = empty_dentptr; 1114 } 1115 1116 ret = set_contents(mydata, retdent, buffer, size, actwrite); 1117 if (ret < 0) { 1118 printf("Error: writing contents\n"); 1119 goto exit; 1120 } 1121 debug("attempt to write 0x%llx bytes\n", *actwrite); 1122 1123 /* Flush fat buffer */ 1124 ret = flush_dirty_fat_buffer(mydata); 1125 if (ret) { 1126 printf("Error: flush fat buffer\n"); 1127 goto exit; 1128 } 1129 1130 /* Write directory table to device */ 1131 ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block, 1132 mydata->clust_size * mydata->sect_size); 1133 if (ret) 1134 printf("Error: writing directory entry\n"); 1135 1136 exit: 1137 free(mydata->fatbuf); 1138 return ret; 1139 } 1140 1141 int file_fat_write(const char *filename, void *buffer, loff_t offset, 1142 loff_t maxsize, loff_t *actwrite) 1143 { 1144 if (offset != 0) { 1145 printf("Error: non zero offset is currently not supported.\n"); 1146 return -1; 1147 } 1148 1149 printf("writing %s\n", filename); 1150 return do_fat_write(filename, buffer, maxsize, actwrite); 1151 } 1152