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