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 * Update the number of bytes written in *gotsize and return 0 664 * or return -1 on fatal errors. 665 */ 666 static int 667 set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, 668 loff_t maxsize, loff_t *gotsize) 669 { 670 loff_t filesize = FAT2CPU32(dentptr->size); 671 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; 672 __u32 curclust = START(dentptr); 673 __u32 endclust = 0, newclust = 0; 674 loff_t actsize; 675 676 *gotsize = 0; 677 debug("Filesize: %llu bytes\n", filesize); 678 679 if (maxsize > 0 && filesize > maxsize) 680 filesize = maxsize; 681 682 debug("%llu bytes\n", filesize); 683 684 actsize = bytesperclust; 685 endclust = curclust; 686 do { 687 /* search for consecutive clusters */ 688 while (actsize < filesize) { 689 newclust = determine_fatent(mydata, endclust); 690 691 if ((newclust - 1) != endclust) 692 goto getit; 693 694 if (CHECK_CLUST(newclust, mydata->fatsize)) { 695 debug("curclust: 0x%x\n", newclust); 696 debug("Invalid FAT entry\n"); 697 return 0; 698 } 699 endclust = newclust; 700 actsize += bytesperclust; 701 } 702 /* actsize >= file size */ 703 actsize -= bytesperclust; 704 /* set remaining clusters */ 705 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 706 debug("error: writing cluster\n"); 707 return -1; 708 } 709 710 /* set remaining bytes */ 711 *gotsize += actsize; 712 filesize -= actsize; 713 buffer += actsize; 714 actsize = filesize; 715 716 if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) { 717 debug("error: writing cluster\n"); 718 return -1; 719 } 720 *gotsize += actsize; 721 722 /* Mark end of file in FAT */ 723 if (mydata->fatsize == 16) 724 newclust = 0xffff; 725 else if (mydata->fatsize == 32) 726 newclust = 0xfffffff; 727 set_fatent_value(mydata, endclust, newclust); 728 729 return 0; 730 getit: 731 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 732 debug("error: writing cluster\n"); 733 return -1; 734 } 735 *gotsize += actsize; 736 filesize -= actsize; 737 buffer += actsize; 738 739 if (CHECK_CLUST(curclust, mydata->fatsize)) { 740 debug("curclust: 0x%x\n", curclust); 741 debug("Invalid FAT entry\n"); 742 return 0; 743 } 744 actsize = bytesperclust; 745 curclust = endclust = newclust; 746 } while (1); 747 } 748 749 /* 750 * Fill dir_entry 751 */ 752 static void fill_dentry(fsdata *mydata, dir_entry *dentptr, 753 const char *filename, __u32 start_cluster, __u32 size, __u8 attr) 754 { 755 if (mydata->fatsize == 32) 756 dentptr->starthi = 757 cpu_to_le16((start_cluster & 0xffff0000) >> 16); 758 dentptr->start = cpu_to_le16(start_cluster & 0xffff); 759 dentptr->size = cpu_to_le32(size); 760 761 dentptr->attr = attr; 762 763 set_name(dentptr, filename); 764 } 765 766 /* 767 * Check whether adding a file makes the file system to 768 * exceed the size of the block device 769 * Return -1 when overflow occurs, otherwise return 0 770 */ 771 static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) 772 { 773 __u32 startsect, sect_num; 774 775 if (clustnum > 0) { 776 startsect = mydata->data_begin + 777 clustnum * mydata->clust_size; 778 } else { 779 startsect = mydata->rootdir_sect; 780 } 781 782 sect_num = size / mydata->sect_size; 783 if (size % mydata->sect_size) 784 sect_num++; 785 786 if (startsect + sect_num > cur_part_info.start + total_sector) 787 return -1; 788 789 return 0; 790 } 791 792 /* 793 * Check if adding several entries exceed one cluster boundary 794 */ 795 static int is_next_clust(fsdata *mydata, dir_entry *dentptr) 796 { 797 int cur_position; 798 799 cur_position = (__u8 *)dentptr - get_dentfromdir_block; 800 801 if (cur_position >= mydata->clust_size * mydata->sect_size) 802 return 1; 803 else 804 return 0; 805 } 806 807 static dir_entry *empty_dentptr; 808 /* 809 * Find a directory entry based on filename or start cluster number 810 * If the directory entry is not found, 811 * the new position for writing a directory entry will be returned 812 */ 813 static dir_entry *find_directory_entry(fsdata *mydata, int startsect, 814 char *filename, dir_entry *retdent, __u32 start) 815 { 816 __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; 817 818 debug("get_dentfromdir: %s\n", filename); 819 820 while (1) { 821 dir_entry *dentptr; 822 823 int i; 824 825 if (get_cluster(mydata, curclust, get_dentfromdir_block, 826 mydata->clust_size * mydata->sect_size) != 0) { 827 printf("Error: reading directory block\n"); 828 return NULL; 829 } 830 831 dentptr = (dir_entry *)get_dentfromdir_block; 832 833 dir_curclust = curclust; 834 835 for (i = 0; i < DIRENTSPERCLUST; i++) { 836 char s_name[14], l_name[VFAT_MAXLEN_BYTES]; 837 838 l_name[0] = '\0'; 839 if (dentptr->name[0] == DELETED_FLAG) { 840 dentptr++; 841 if (is_next_clust(mydata, dentptr)) 842 break; 843 continue; 844 } 845 if ((dentptr->attr & ATTR_VOLUME)) { 846 if (vfat_enabled && 847 (dentptr->attr & ATTR_VFAT) && 848 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 849 get_long_file_name(mydata, curclust, 850 get_dentfromdir_block, 851 &dentptr, l_name); 852 debug("vfatname: |%s|\n", l_name); 853 } else { 854 /* Volume label or VFAT entry */ 855 dentptr++; 856 if (is_next_clust(mydata, dentptr)) 857 break; 858 continue; 859 } 860 } 861 if (dentptr->name[0] == 0) { 862 debug("Dentname == NULL - %d\n", i); 863 empty_dentptr = dentptr; 864 return NULL; 865 } 866 867 get_name(dentptr, s_name); 868 869 if (strcmp(filename, s_name) 870 && strcmp(filename, l_name)) { 871 debug("Mismatch: |%s|%s|\n", 872 s_name, l_name); 873 dentptr++; 874 if (is_next_clust(mydata, dentptr)) 875 break; 876 continue; 877 } 878 879 memcpy(retdent, dentptr, sizeof(dir_entry)); 880 881 debug("DentName: %s", s_name); 882 debug(", start: 0x%x", START(dentptr)); 883 debug(", size: 0x%x %s\n", 884 FAT2CPU32(dentptr->size), 885 (dentptr->attr & ATTR_DIR) ? 886 "(DIR)" : ""); 887 888 return dentptr; 889 } 890 891 /* 892 * In FAT16/12, the root dir is locate before data area, shows 893 * in following: 894 * ------------------------------------------------------------- 895 * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | 896 * ------------------------------------------------------------- 897 * 898 * As a result if curclust is in Root dir, it is a negative 899 * number or 0, 1. 900 * 901 */ 902 if (mydata->fatsize != 32 && (int)curclust <= 1) { 903 /* Current clust is in root dir, set to next clust */ 904 curclust++; 905 if ((int)curclust <= 1) 906 continue; /* continue to find */ 907 908 /* Reach the end of root dir */ 909 empty_dentptr = dentptr; 910 return NULL; 911 } 912 913 curclust = get_fatent_value(mydata, dir_curclust); 914 if (IS_LAST_CLUST(curclust, mydata->fatsize)) { 915 empty_dentptr = dentptr; 916 return NULL; 917 } 918 if (CHECK_CLUST(curclust, mydata->fatsize)) { 919 debug("curclust: 0x%x\n", curclust); 920 debug("Invalid FAT entry\n"); 921 return NULL; 922 } 923 } 924 925 return NULL; 926 } 927 928 static int do_fat_write(const char *filename, void *buffer, loff_t size, 929 loff_t *actwrite) 930 { 931 dir_entry *dentptr, *retdent; 932 __u32 startsect; 933 __u32 start_cluster; 934 boot_sector bs; 935 volume_info volinfo; 936 fsdata datablock; 937 fsdata *mydata = &datablock; 938 int cursect; 939 int ret = -1, name_len; 940 char l_filename[VFAT_MAXLEN_BYTES]; 941 942 *actwrite = size; 943 dir_curclust = 0; 944 945 if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { 946 debug("error: reading boot sector\n"); 947 return -1; 948 } 949 950 total_sector = bs.total_sect; 951 if (total_sector == 0) 952 total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ 953 954 if (mydata->fatsize == 32) 955 mydata->fatlength = bs.fat32_length; 956 else 957 mydata->fatlength = bs.fat_length; 958 959 mydata->fat_sect = bs.reserved; 960 961 cursect = mydata->rootdir_sect 962 = mydata->fat_sect + mydata->fatlength * bs.fats; 963 num_of_fats = bs.fats; 964 965 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; 966 mydata->clust_size = bs.cluster_size; 967 968 if (mydata->fatsize == 32) { 969 mydata->data_begin = mydata->rootdir_sect - 970 (mydata->clust_size * 2); 971 } else { 972 int rootdir_size; 973 974 rootdir_size = ((bs.dir_entries[1] * (int)256 + 975 bs.dir_entries[0]) * 976 sizeof(dir_entry)) / 977 mydata->sect_size; 978 mydata->data_begin = mydata->rootdir_sect + 979 rootdir_size - 980 (mydata->clust_size * 2); 981 } 982 983 mydata->fatbufnum = -1; 984 mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); 985 if (mydata->fatbuf == NULL) { 986 debug("Error: allocating memory\n"); 987 return -1; 988 } 989 990 if (disk_read(cursect, 991 (mydata->fatsize == 32) ? 992 (mydata->clust_size) : 993 PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { 994 debug("Error: reading rootdir block\n"); 995 goto exit; 996 } 997 dentptr = (dir_entry *) do_fat_read_at_block; 998 999 name_len = strlen(filename); 1000 if (name_len >= VFAT_MAXLEN_BYTES) 1001 name_len = VFAT_MAXLEN_BYTES - 1; 1002 1003 memcpy(l_filename, filename, name_len); 1004 l_filename[name_len] = 0; /* terminate the string */ 1005 downcase(l_filename); 1006 1007 startsect = mydata->rootdir_sect; 1008 retdent = find_directory_entry(mydata, startsect, 1009 l_filename, dentptr, 0); 1010 if (retdent) { 1011 /* Update file size and start_cluster in a directory entry */ 1012 retdent->size = cpu_to_le32(size); 1013 start_cluster = FAT2CPU16(retdent->start); 1014 if (mydata->fatsize == 32) 1015 start_cluster |= 1016 (FAT2CPU16(retdent->starthi) << 16); 1017 1018 ret = check_overflow(mydata, start_cluster, size); 1019 if (ret) { 1020 printf("Error: %llu overflow\n", size); 1021 goto exit; 1022 } 1023 1024 ret = clear_fatent(mydata, start_cluster); 1025 if (ret) { 1026 printf("Error: clearing FAT entries\n"); 1027 goto exit; 1028 } 1029 1030 ret = set_contents(mydata, retdent, buffer, size, actwrite); 1031 if (ret < 0) { 1032 printf("Error: writing contents\n"); 1033 goto exit; 1034 } 1035 debug("attempt to write 0x%llx bytes\n", *actwrite); 1036 1037 /* Flush fat buffer */ 1038 ret = flush_fat_buffer(mydata); 1039 if (ret) { 1040 printf("Error: flush fat buffer\n"); 1041 goto exit; 1042 } 1043 1044 /* Write directory table to device */ 1045 ret = set_cluster(mydata, dir_curclust, 1046 get_dentfromdir_block, 1047 mydata->clust_size * mydata->sect_size); 1048 if (ret) { 1049 printf("Error: writing directory entry\n"); 1050 goto exit; 1051 } 1052 } else { 1053 /* Set short name to set alias checksum field in dir_slot */ 1054 set_name(empty_dentptr, filename); 1055 fill_dir_slot(mydata, &empty_dentptr, filename); 1056 1057 ret = start_cluster = find_empty_cluster(mydata); 1058 if (ret < 0) { 1059 printf("Error: finding empty cluster\n"); 1060 goto exit; 1061 } 1062 1063 ret = check_overflow(mydata, start_cluster, size); 1064 if (ret) { 1065 printf("Error: %llu overflow\n", size); 1066 goto exit; 1067 } 1068 1069 /* Set attribute as archieve for regular file */ 1070 fill_dentry(mydata, empty_dentptr, filename, 1071 start_cluster, size, 0x20); 1072 1073 ret = set_contents(mydata, empty_dentptr, buffer, size, 1074 actwrite); 1075 if (ret < 0) { 1076 printf("Error: writing contents\n"); 1077 goto exit; 1078 } 1079 debug("attempt to write 0x%llx bytes\n", *actwrite); 1080 1081 /* Flush fat buffer */ 1082 ret = flush_fat_buffer(mydata); 1083 if (ret) { 1084 printf("Error: flush fat buffer\n"); 1085 goto exit; 1086 } 1087 1088 /* Write directory table to device */ 1089 ret = set_cluster(mydata, dir_curclust, 1090 get_dentfromdir_block, 1091 mydata->clust_size * mydata->sect_size); 1092 if (ret) { 1093 printf("Error: writing directory entry\n"); 1094 goto exit; 1095 } 1096 } 1097 1098 exit: 1099 free(mydata->fatbuf); 1100 return ret; 1101 } 1102 1103 int file_fat_write(const char *filename, void *buffer, loff_t offset, 1104 loff_t maxsize, loff_t *actwrite) 1105 { 1106 if (offset != 0) { 1107 printf("Error: non zero offset is currently not suported.\n"); 1108 return -1; 1109 } 1110 1111 printf("writing %s\n", filename); 1112 return do_fat_write(filename, buffer, maxsize, actwrite); 1113 } 1114