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