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