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