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