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