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