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