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