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 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 ((size / mydata->sect_size) > 0) { 556 if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) { 557 debug("Error writing data\n"); 558 return -1; 559 } 560 } 561 562 if (size % mydata->sect_size) { 563 __u8 tmpbuf[mydata->sect_size]; 564 565 idx = size / mydata->sect_size; 566 buffer += idx * mydata->sect_size; 567 memcpy(tmpbuf, buffer, size % mydata->sect_size); 568 569 if (disk_write(startsect + idx, 1, tmpbuf) < 0) { 570 debug("Error writing data\n"); 571 return -1; 572 } 573 574 return 0; 575 } 576 577 return 0; 578 } 579 580 /* 581 * Find the first empty cluster 582 */ 583 static int find_empty_cluster(fsdata *mydata) 584 { 585 __u32 fat_val, entry = 3; 586 587 while (1) { 588 fat_val = get_fatent_value(mydata, entry); 589 if (fat_val == 0) 590 break; 591 entry++; 592 } 593 594 return entry; 595 } 596 597 /* 598 * Write directory entries in 'get_dentfromdir_block' to block device 599 */ 600 static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) 601 { 602 int dir_newclust = 0; 603 604 if (set_cluster(mydata, dir_curclust, 605 get_dentfromdir_block, 606 mydata->clust_size * mydata->sect_size) != 0) { 607 printf("error: wrinting directory entry\n"); 608 return; 609 } 610 dir_newclust = find_empty_cluster(mydata); 611 set_fatent_value(mydata, dir_curclust, dir_newclust); 612 if (mydata->fatsize == 32) 613 set_fatent_value(mydata, dir_newclust, 0xffffff8); 614 else if (mydata->fatsize == 16) 615 set_fatent_value(mydata, dir_newclust, 0xfff8); 616 617 dir_curclust = dir_newclust; 618 619 if (flush_fat_buffer(mydata) < 0) 620 return; 621 622 memset(get_dentfromdir_block, 0x00, 623 mydata->clust_size * mydata->sect_size); 624 625 *dentptr = (dir_entry *) get_dentfromdir_block; 626 } 627 628 /* 629 * Set empty cluster from 'entry' to the end of a file 630 */ 631 static int clear_fatent(fsdata *mydata, __u32 entry) 632 { 633 __u32 fat_val; 634 635 while (1) { 636 fat_val = get_fatent_value(mydata, entry); 637 if (fat_val != 0) 638 set_fatent_value(mydata, entry, 0); 639 else 640 break; 641 642 if (fat_val == 0xfffffff || fat_val == 0xffff) 643 break; 644 645 entry = fat_val; 646 } 647 648 /* Flush fat buffer */ 649 if (flush_fat_buffer(mydata) < 0) 650 return -1; 651 652 return 0; 653 } 654 655 /* 656 * Write at most 'maxsize' bytes from 'buffer' into 657 * the file associated with 'dentptr' 658 * Return the number of bytes read or -1 on fatal errors. 659 */ 660 static int 661 set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, 662 unsigned long maxsize) 663 { 664 unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; 665 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; 666 __u32 curclust = START(dentptr); 667 __u32 endclust = 0, newclust = 0; 668 unsigned long actsize; 669 670 debug("Filesize: %ld bytes\n", filesize); 671 672 if (maxsize > 0 && filesize > maxsize) 673 filesize = maxsize; 674 675 debug("%ld bytes\n", filesize); 676 677 actsize = bytesperclust; 678 endclust = curclust; 679 do { 680 /* search for consecutive clusters */ 681 while (actsize < filesize) { 682 newclust = determine_fatent(mydata, endclust); 683 684 if ((newclust - 1) != endclust) 685 goto getit; 686 687 if (CHECK_CLUST(newclust, mydata->fatsize)) { 688 debug("curclust: 0x%x\n", newclust); 689 debug("Invalid FAT entry\n"); 690 return gotsize; 691 } 692 endclust = newclust; 693 actsize += bytesperclust; 694 } 695 /* actsize >= file size */ 696 actsize -= bytesperclust; 697 /* set remaining clusters */ 698 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 699 debug("error: writing cluster\n"); 700 return -1; 701 } 702 703 /* set remaining bytes */ 704 gotsize += (int)actsize; 705 filesize -= actsize; 706 buffer += actsize; 707 actsize = filesize; 708 709 if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) { 710 debug("error: writing cluster\n"); 711 return -1; 712 } 713 gotsize += actsize; 714 715 /* Mark end of file in FAT */ 716 if (mydata->fatsize == 16) 717 newclust = 0xffff; 718 else if (mydata->fatsize == 32) 719 newclust = 0xfffffff; 720 set_fatent_value(mydata, endclust, newclust); 721 722 return gotsize; 723 getit: 724 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 725 debug("error: writing cluster\n"); 726 return -1; 727 } 728 gotsize += (int)actsize; 729 filesize -= actsize; 730 buffer += actsize; 731 732 if (CHECK_CLUST(curclust, mydata->fatsize)) { 733 debug("curclust: 0x%x\n", curclust); 734 debug("Invalid FAT entry\n"); 735 return gotsize; 736 } 737 actsize = bytesperclust; 738 curclust = endclust = newclust; 739 } while (1); 740 } 741 742 /* 743 * Fill dir_entry 744 */ 745 static void fill_dentry(fsdata *mydata, dir_entry *dentptr, 746 const char *filename, __u32 start_cluster, __u32 size, __u8 attr) 747 { 748 if (mydata->fatsize == 32) 749 dentptr->starthi = 750 cpu_to_le16((start_cluster & 0xffff0000) >> 16); 751 dentptr->start = cpu_to_le16(start_cluster & 0xffff); 752 dentptr->size = cpu_to_le32(size); 753 754 dentptr->attr = attr; 755 756 set_name(dentptr, filename); 757 } 758 759 /* 760 * Check whether adding a file makes the file system to 761 * exceed the size of the block device 762 * Return -1 when overflow occurs, otherwise return 0 763 */ 764 static int check_overflow(fsdata *mydata, __u32 clustnum, unsigned long size) 765 { 766 __u32 startsect, sect_num; 767 768 if (clustnum > 0) { 769 startsect = mydata->data_begin + 770 clustnum * mydata->clust_size; 771 } else { 772 startsect = mydata->rootdir_sect; 773 } 774 775 sect_num = size / mydata->sect_size; 776 if (size % mydata->sect_size) 777 sect_num++; 778 779 if (startsect + sect_num > cur_part_info.start + total_sector) 780 return -1; 781 782 return 0; 783 } 784 785 /* 786 * Check if adding several entries exceed one cluster boundary 787 */ 788 static int is_next_clust(fsdata *mydata, dir_entry *dentptr) 789 { 790 int cur_position; 791 792 cur_position = (__u8 *)dentptr - get_dentfromdir_block; 793 794 if (cur_position >= mydata->clust_size * mydata->sect_size) 795 return 1; 796 else 797 return 0; 798 } 799 800 static dir_entry *empty_dentptr; 801 /* 802 * Find a directory entry based on filename or start cluster number 803 * If the directory entry is not found, 804 * the new position for writing a directory entry will be returned 805 */ 806 static dir_entry *find_directory_entry(fsdata *mydata, int startsect, 807 char *filename, dir_entry *retdent, __u32 start) 808 { 809 __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; 810 811 debug("get_dentfromdir: %s\n", filename); 812 813 while (1) { 814 dir_entry *dentptr; 815 816 int i; 817 818 if (get_cluster(mydata, curclust, get_dentfromdir_block, 819 mydata->clust_size * mydata->sect_size) != 0) { 820 printf("Error: reading directory block\n"); 821 return NULL; 822 } 823 824 dentptr = (dir_entry *)get_dentfromdir_block; 825 826 dir_curclust = curclust; 827 828 for (i = 0; i < DIRENTSPERCLUST; i++) { 829 char s_name[14], l_name[VFAT_MAXLEN_BYTES]; 830 831 l_name[0] = '\0'; 832 if (dentptr->name[0] == DELETED_FLAG) { 833 dentptr++; 834 if (is_next_clust(mydata, dentptr)) 835 break; 836 continue; 837 } 838 if ((dentptr->attr & ATTR_VOLUME)) { 839 if (vfat_enabled && 840 (dentptr->attr & ATTR_VFAT) && 841 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 842 get_long_file_name(mydata, curclust, 843 get_dentfromdir_block, 844 &dentptr, l_name); 845 debug("vfatname: |%s|\n", l_name); 846 } else { 847 /* Volume label or VFAT entry */ 848 dentptr++; 849 if (is_next_clust(mydata, dentptr)) 850 break; 851 continue; 852 } 853 } 854 if (dentptr->name[0] == 0) { 855 debug("Dentname == NULL - %d\n", i); 856 empty_dentptr = dentptr; 857 return NULL; 858 } 859 860 get_name(dentptr, s_name); 861 862 if (strcmp(filename, s_name) 863 && strcmp(filename, l_name)) { 864 debug("Mismatch: |%s|%s|\n", 865 s_name, l_name); 866 dentptr++; 867 if (is_next_clust(mydata, dentptr)) 868 break; 869 continue; 870 } 871 872 memcpy(retdent, dentptr, sizeof(dir_entry)); 873 874 debug("DentName: %s", s_name); 875 debug(", start: 0x%x", START(dentptr)); 876 debug(", size: 0x%x %s\n", 877 FAT2CPU32(dentptr->size), 878 (dentptr->attr & ATTR_DIR) ? 879 "(DIR)" : ""); 880 881 return dentptr; 882 } 883 884 curclust = get_fatent_value(mydata, dir_curclust); 885 if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) { 886 empty_dentptr = dentptr; 887 return NULL; 888 } 889 if (CHECK_CLUST(curclust, mydata->fatsize)) { 890 debug("curclust: 0x%x\n", curclust); 891 debug("Invalid FAT entry\n"); 892 return NULL; 893 } 894 } 895 896 return NULL; 897 } 898 899 static int do_fat_write(const char *filename, void *buffer, 900 unsigned long size) 901 { 902 dir_entry *dentptr, *retdent; 903 __u32 startsect; 904 __u32 start_cluster; 905 boot_sector bs; 906 volume_info volinfo; 907 fsdata datablock; 908 fsdata *mydata = &datablock; 909 int cursect; 910 int ret = -1, name_len; 911 char l_filename[VFAT_MAXLEN_BYTES]; 912 int write_size = size; 913 914 dir_curclust = 0; 915 916 if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { 917 debug("error: reading boot sector\n"); 918 return -1; 919 } 920 921 total_sector = bs.total_sect; 922 if (total_sector == 0) 923 total_sector = cur_part_info.size; 924 925 if (mydata->fatsize == 32) 926 mydata->fatlength = bs.fat32_length; 927 else 928 mydata->fatlength = bs.fat_length; 929 930 mydata->fat_sect = bs.reserved; 931 932 cursect = mydata->rootdir_sect 933 = mydata->fat_sect + mydata->fatlength * bs.fats; 934 num_of_fats = bs.fats; 935 936 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; 937 mydata->clust_size = bs.cluster_size; 938 939 if (mydata->fatsize == 32) { 940 mydata->data_begin = mydata->rootdir_sect - 941 (mydata->clust_size * 2); 942 } else { 943 int rootdir_size; 944 945 rootdir_size = ((bs.dir_entries[1] * (int)256 + 946 bs.dir_entries[0]) * 947 sizeof(dir_entry)) / 948 mydata->sect_size; 949 mydata->data_begin = mydata->rootdir_sect + 950 rootdir_size - 951 (mydata->clust_size * 2); 952 } 953 954 mydata->fatbufnum = -1; 955 mydata->fatbuf = malloc(FATBUFSIZE); 956 if (mydata->fatbuf == NULL) { 957 debug("Error: allocating memory\n"); 958 return -1; 959 } 960 961 if (disk_read(cursect, 962 (mydata->fatsize == 32) ? 963 (mydata->clust_size) : 964 PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { 965 debug("Error: reading rootdir block\n"); 966 goto exit; 967 } 968 dentptr = (dir_entry *) do_fat_read_at_block; 969 970 name_len = strlen(filename); 971 if (name_len >= VFAT_MAXLEN_BYTES) 972 name_len = VFAT_MAXLEN_BYTES - 1; 973 974 memcpy(l_filename, filename, name_len); 975 l_filename[name_len] = 0; /* terminate the string */ 976 downcase(l_filename); 977 978 startsect = mydata->rootdir_sect; 979 retdent = find_directory_entry(mydata, startsect, 980 l_filename, dentptr, 0); 981 if (retdent) { 982 /* Update file size and start_cluster in a directory entry */ 983 retdent->size = cpu_to_le32(size); 984 start_cluster = FAT2CPU16(retdent->start); 985 if (mydata->fatsize == 32) 986 start_cluster |= 987 (FAT2CPU16(retdent->starthi) << 16); 988 989 ret = check_overflow(mydata, start_cluster, size); 990 if (ret) { 991 printf("Error: %ld overflow\n", size); 992 goto exit; 993 } 994 995 ret = clear_fatent(mydata, start_cluster); 996 if (ret) { 997 printf("Error: clearing FAT entries\n"); 998 goto exit; 999 } 1000 1001 ret = set_contents(mydata, retdent, buffer, size); 1002 if (ret < 0) { 1003 printf("Error: writing contents\n"); 1004 goto exit; 1005 } 1006 write_size = ret; 1007 debug("attempt to write 0x%x bytes\n", write_size); 1008 1009 /* Flush fat buffer */ 1010 ret = flush_fat_buffer(mydata); 1011 if (ret) { 1012 printf("Error: flush fat buffer\n"); 1013 goto exit; 1014 } 1015 1016 /* Write directory table to device */ 1017 ret = set_cluster(mydata, dir_curclust, 1018 get_dentfromdir_block, 1019 mydata->clust_size * mydata->sect_size); 1020 if (ret) { 1021 printf("Error: writing directory entry\n"); 1022 goto exit; 1023 } 1024 } else { 1025 /* Set short name to set alias checksum field in dir_slot */ 1026 set_name(empty_dentptr, filename); 1027 fill_dir_slot(mydata, &empty_dentptr, filename); 1028 1029 ret = start_cluster = find_empty_cluster(mydata); 1030 if (ret < 0) { 1031 printf("Error: finding empty cluster\n"); 1032 goto exit; 1033 } 1034 1035 ret = check_overflow(mydata, start_cluster, size); 1036 if (ret) { 1037 printf("Error: %ld overflow\n", size); 1038 goto exit; 1039 } 1040 1041 /* Set attribute as archieve for regular file */ 1042 fill_dentry(mydata, empty_dentptr, filename, 1043 start_cluster, size, 0x20); 1044 1045 ret = set_contents(mydata, empty_dentptr, buffer, size); 1046 if (ret < 0) { 1047 printf("Error: writing contents\n"); 1048 goto exit; 1049 } 1050 write_size = ret; 1051 debug("attempt to write 0x%x bytes\n", write_size); 1052 1053 /* Flush fat buffer */ 1054 ret = flush_fat_buffer(mydata); 1055 if (ret) { 1056 printf("Error: flush fat buffer\n"); 1057 goto exit; 1058 } 1059 1060 /* Write directory table to device */ 1061 ret = set_cluster(mydata, dir_curclust, 1062 get_dentfromdir_block, 1063 mydata->clust_size * mydata->sect_size); 1064 if (ret) { 1065 printf("Error: writing directory entry\n"); 1066 goto exit; 1067 } 1068 } 1069 1070 exit: 1071 free(mydata->fatbuf); 1072 return ret < 0 ? ret : write_size; 1073 } 1074 1075 int file_fat_write(const char *filename, void *buffer, unsigned long maxsize) 1076 { 1077 printf("writing %s\n", filename); 1078 return do_fat_write(filename, buffer, maxsize); 1079 } 1080