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