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 /* 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_contents_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((*dentptr)->name, (*dentptr)->ext); 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_contents_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_contents_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_contents_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_contents_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_contents_vfatname_block, 463 mydata->clust_size * mydata->sect_size); 464 cur_position = (__u8 *)realdent - get_contents_vfatname_block; 465 *retdent = (dir_entry *) &get_dentfromdir_block[cur_position]; 466 } 467 468 return 0; 469 } 470 471 /* 472 * Set the entry at index 'entry' in a FAT (16/32) table. 473 */ 474 static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) 475 { 476 __u32 bufnum, offset; 477 478 switch (mydata->fatsize) { 479 case 32: 480 bufnum = entry / FAT32BUFSIZE; 481 offset = entry - bufnum * FAT32BUFSIZE; 482 break; 483 case 16: 484 bufnum = entry / FAT16BUFSIZE; 485 offset = entry - bufnum * FAT16BUFSIZE; 486 break; 487 default: 488 /* Unsupported FAT size */ 489 return -1; 490 } 491 492 /* Read a new block of FAT entries into the cache. */ 493 if (bufnum != mydata->fatbufnum) { 494 int getsize = FATBUFBLOCKS; 495 __u8 *bufptr = mydata->fatbuf; 496 __u32 fatlength = mydata->fatlength; 497 __u32 startblock = bufnum * FATBUFBLOCKS; 498 499 fatlength *= mydata->sect_size; 500 startblock += mydata->fat_sect; 501 502 if (getsize > fatlength) 503 getsize = fatlength; 504 505 if (mydata->fatbufnum != -1) { 506 if (flush_fat_buffer(mydata) < 0) 507 return -1; 508 } 509 510 if (disk_read(startblock, getsize, bufptr) < 0) { 511 debug("Error reading FAT blocks\n"); 512 return -1; 513 } 514 mydata->fatbufnum = bufnum; 515 } 516 517 /* Set the actual entry */ 518 switch (mydata->fatsize) { 519 case 32: 520 ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value); 521 break; 522 case 16: 523 ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value); 524 break; 525 default: 526 return -1; 527 } 528 529 return 0; 530 } 531 532 /* 533 * Determine the entry value at index 'entry' in a FAT (16/32) table 534 */ 535 static __u32 determine_fatent(fsdata *mydata, __u32 entry) 536 { 537 __u32 next_fat, next_entry = entry + 1; 538 539 while (1) { 540 next_fat = get_fatent_value(mydata, next_entry); 541 if (next_fat == 0) { 542 set_fatent_value(mydata, entry, next_entry); 543 break; 544 } 545 next_entry++; 546 } 547 debug("FAT%d: entry: %08x, entry_value: %04x\n", 548 mydata->fatsize, entry, next_entry); 549 550 return next_entry; 551 } 552 553 /* 554 * Write at most 'size' bytes from 'buffer' into the specified cluster. 555 * Return 0 on success, -1 otherwise. 556 */ 557 static int 558 set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, 559 unsigned long size) 560 { 561 int idx = 0; 562 __u32 startsect; 563 564 if (clustnum > 0) 565 startsect = mydata->data_begin + 566 clustnum * mydata->clust_size; 567 else 568 startsect = mydata->rootdir_sect; 569 570 debug("clustnum: %d, startsect: %d\n", clustnum, startsect); 571 572 if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) { 573 debug("Error writing data\n"); 574 return -1; 575 } 576 577 if (size % mydata->sect_size) { 578 __u8 tmpbuf[mydata->sect_size]; 579 580 idx = size / mydata->sect_size; 581 buffer += idx * mydata->sect_size; 582 memcpy(tmpbuf, buffer, size % mydata->sect_size); 583 584 if (disk_write(startsect + idx, 1, tmpbuf) < 0) { 585 debug("Error writing data\n"); 586 return -1; 587 } 588 589 return 0; 590 } 591 592 return 0; 593 } 594 595 /* 596 * Find the first empty cluster 597 */ 598 static int find_empty_cluster(fsdata *mydata) 599 { 600 __u32 fat_val, entry = 3; 601 602 while (1) { 603 fat_val = get_fatent_value(mydata, entry); 604 if (fat_val == 0) 605 break; 606 entry++; 607 } 608 609 return entry; 610 } 611 612 /* 613 * Write directory entries in 'get_dentfromdir_block' to block device 614 */ 615 static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) 616 { 617 int dir_newclust = 0; 618 619 if (set_cluster(mydata, dir_curclust, 620 get_dentfromdir_block, 621 mydata->clust_size * mydata->sect_size) != 0) { 622 printf("error: wrinting directory entry\n"); 623 return; 624 } 625 dir_newclust = find_empty_cluster(mydata); 626 set_fatent_value(mydata, dir_curclust, dir_newclust); 627 if (mydata->fatsize == 32) 628 set_fatent_value(mydata, dir_newclust, 0xffffff8); 629 else if (mydata->fatsize == 16) 630 set_fatent_value(mydata, dir_newclust, 0xfff8); 631 632 dir_curclust = dir_newclust; 633 634 if (flush_fat_buffer(mydata) < 0) 635 return; 636 637 memset(get_dentfromdir_block, 0x00, 638 mydata->clust_size * mydata->sect_size); 639 640 *dentptr = (dir_entry *) get_dentfromdir_block; 641 } 642 643 /* 644 * Set empty cluster from 'entry' to the end of a file 645 */ 646 static int clear_fatent(fsdata *mydata, __u32 entry) 647 { 648 __u32 fat_val; 649 650 while (1) { 651 fat_val = get_fatent_value(mydata, entry); 652 if (fat_val != 0) 653 set_fatent_value(mydata, entry, 0); 654 else 655 break; 656 657 if (fat_val == 0xfffffff || fat_val == 0xffff) 658 break; 659 660 entry = fat_val; 661 } 662 663 /* Flush fat buffer */ 664 if (flush_fat_buffer(mydata) < 0) 665 return -1; 666 667 return 0; 668 } 669 670 /* 671 * Write at most 'maxsize' bytes from 'buffer' into 672 * the file associated with 'dentptr' 673 * Return the number of bytes read or -1 on fatal errors. 674 */ 675 static int 676 set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, 677 unsigned long maxsize) 678 { 679 unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; 680 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; 681 __u32 curclust = START(dentptr); 682 __u32 endclust = 0, newclust = 0; 683 unsigned long actsize; 684 685 debug("Filesize: %ld bytes\n", filesize); 686 687 if (maxsize > 0 && filesize > maxsize) 688 filesize = maxsize; 689 690 debug("%ld bytes\n", filesize); 691 692 actsize = bytesperclust; 693 endclust = curclust; 694 do { 695 /* search for consecutive clusters */ 696 while (actsize < filesize) { 697 newclust = determine_fatent(mydata, endclust); 698 699 if ((newclust - 1) != endclust) 700 goto getit; 701 702 if (CHECK_CLUST(newclust, mydata->fatsize)) { 703 debug("curclust: 0x%x\n", newclust); 704 debug("Invalid FAT entry\n"); 705 return gotsize; 706 } 707 endclust = newclust; 708 actsize += bytesperclust; 709 } 710 /* actsize >= file size */ 711 actsize -= bytesperclust; 712 /* set remaining clusters */ 713 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 714 debug("error: writing cluster\n"); 715 return -1; 716 } 717 718 /* set remaining bytes */ 719 gotsize += (int)actsize; 720 filesize -= actsize; 721 buffer += actsize; 722 actsize = filesize; 723 724 if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) { 725 debug("error: writing cluster\n"); 726 return -1; 727 } 728 gotsize += actsize; 729 730 /* Mark end of file in FAT */ 731 if (mydata->fatsize == 16) 732 newclust = 0xffff; 733 else if (mydata->fatsize == 32) 734 newclust = 0xfffffff; 735 set_fatent_value(mydata, endclust, newclust); 736 737 return gotsize; 738 getit: 739 if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 740 debug("error: writing cluster\n"); 741 return -1; 742 } 743 gotsize += (int)actsize; 744 filesize -= actsize; 745 buffer += actsize; 746 747 if (CHECK_CLUST(curclust, mydata->fatsize)) { 748 debug("curclust: 0x%x\n", curclust); 749 debug("Invalid FAT entry\n"); 750 return gotsize; 751 } 752 actsize = bytesperclust; 753 curclust = endclust = newclust; 754 } while (1); 755 } 756 757 /* 758 * Fill dir_entry 759 */ 760 static void fill_dentry(fsdata *mydata, dir_entry *dentptr, 761 const char *filename, __u32 start_cluster, __u32 size, __u8 attr) 762 { 763 if (mydata->fatsize == 32) 764 dentptr->starthi = 765 cpu_to_le16((start_cluster & 0xffff0000) >> 16); 766 dentptr->start = cpu_to_le16(start_cluster & 0xffff); 767 dentptr->size = cpu_to_le32(size); 768 769 dentptr->attr = attr; 770 771 set_name(dentptr, filename); 772 } 773 774 /* 775 * Check whether adding a file makes the file system to 776 * exceed the size of the block device 777 * Return -1 when overflow occurs, otherwise return 0 778 */ 779 static int check_overflow(fsdata *mydata, __u32 clustnum, unsigned long size) 780 { 781 __u32 startsect, sect_num; 782 783 if (clustnum > 0) { 784 startsect = mydata->data_begin + 785 clustnum * mydata->clust_size; 786 } else { 787 startsect = mydata->rootdir_sect; 788 } 789 790 sect_num = size / mydata->sect_size; 791 if (size % mydata->sect_size) 792 sect_num++; 793 794 if (startsect + sect_num > cur_part_info.start + total_sector) 795 return -1; 796 797 return 0; 798 } 799 800 /* 801 * Check if adding several entries exceed one cluster boundary 802 */ 803 static int is_next_clust(fsdata *mydata, dir_entry *dentptr) 804 { 805 int cur_position; 806 807 cur_position = (__u8 *)dentptr - get_dentfromdir_block; 808 809 if (cur_position >= mydata->clust_size * mydata->sect_size) 810 return 1; 811 else 812 return 0; 813 } 814 815 static dir_entry *empty_dentptr; 816 /* 817 * Find a directory entry based on filename or start cluster number 818 * If the directory entry is not found, 819 * the new position for writing a directory entry will be returned 820 */ 821 static dir_entry *find_directory_entry(fsdata *mydata, int startsect, 822 char *filename, dir_entry *retdent, __u32 start) 823 { 824 __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; 825 826 debug("get_dentfromdir: %s\n", filename); 827 828 while (1) { 829 dir_entry *dentptr; 830 831 int i; 832 833 if (get_cluster(mydata, curclust, get_dentfromdir_block, 834 mydata->clust_size * mydata->sect_size) != 0) { 835 printf("Error: reading directory block\n"); 836 return NULL; 837 } 838 839 dentptr = (dir_entry *)get_dentfromdir_block; 840 841 dir_curclust = curclust; 842 843 for (i = 0; i < DIRENTSPERCLUST; i++) { 844 char s_name[14], l_name[VFAT_MAXLEN_BYTES]; 845 846 l_name[0] = '\0'; 847 if (dentptr->name[0] == DELETED_FLAG) { 848 dentptr++; 849 if (is_next_clust(mydata, dentptr)) 850 break; 851 continue; 852 } 853 if ((dentptr->attr & ATTR_VOLUME)) { 854 if (vfat_enabled && 855 (dentptr->attr & ATTR_VFAT) && 856 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 857 get_long_file_name(mydata, curclust, 858 get_dentfromdir_block, 859 &dentptr, l_name); 860 debug("vfatname: |%s|\n", l_name); 861 } else { 862 /* Volume label or VFAT entry */ 863 dentptr++; 864 if (is_next_clust(mydata, dentptr)) 865 break; 866 continue; 867 } 868 } 869 if (dentptr->name[0] == 0) { 870 debug("Dentname == NULL - %d\n", i); 871 empty_dentptr = dentptr; 872 return NULL; 873 } 874 875 get_name(dentptr, s_name); 876 877 if (strcmp(filename, s_name) 878 && strcmp(filename, l_name)) { 879 debug("Mismatch: |%s|%s|\n", 880 s_name, l_name); 881 dentptr++; 882 if (is_next_clust(mydata, dentptr)) 883 break; 884 continue; 885 } 886 887 memcpy(retdent, dentptr, sizeof(dir_entry)); 888 889 debug("DentName: %s", s_name); 890 debug(", start: 0x%x", START(dentptr)); 891 debug(", size: 0x%x %s\n", 892 FAT2CPU32(dentptr->size), 893 (dentptr->attr & ATTR_DIR) ? 894 "(DIR)" : ""); 895 896 return dentptr; 897 } 898 899 curclust = get_fatent_value(mydata, dir_curclust); 900 if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) { 901 empty_dentptr = dentptr; 902 return NULL; 903 } 904 if (CHECK_CLUST(curclust, mydata->fatsize)) { 905 debug("curclust: 0x%x\n", curclust); 906 debug("Invalid FAT entry\n"); 907 return NULL; 908 } 909 } 910 911 return NULL; 912 } 913 914 static int do_fat_write(const char *filename, void *buffer, 915 unsigned long size) 916 { 917 dir_entry *dentptr, *retdent; 918 __u32 startsect; 919 __u32 start_cluster; 920 boot_sector bs; 921 volume_info volinfo; 922 fsdata datablock; 923 fsdata *mydata = &datablock; 924 int cursect; 925 int ret = -1, name_len; 926 char l_filename[VFAT_MAXLEN_BYTES]; 927 int write_size = size; 928 929 dir_curclust = 0; 930 931 if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { 932 debug("error: reading boot sector\n"); 933 return -1; 934 } 935 936 total_sector = bs.total_sect; 937 if (total_sector == 0) 938 total_sector = cur_part_info.size; 939 940 if (mydata->fatsize == 32) 941 mydata->fatlength = bs.fat32_length; 942 else 943 mydata->fatlength = bs.fat_length; 944 945 mydata->fat_sect = bs.reserved; 946 947 cursect = mydata->rootdir_sect 948 = mydata->fat_sect + mydata->fatlength * bs.fats; 949 num_of_fats = bs.fats; 950 951 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; 952 mydata->clust_size = bs.cluster_size; 953 954 if (mydata->fatsize == 32) { 955 mydata->data_begin = mydata->rootdir_sect - 956 (mydata->clust_size * 2); 957 } else { 958 int rootdir_size; 959 960 rootdir_size = ((bs.dir_entries[1] * (int)256 + 961 bs.dir_entries[0]) * 962 sizeof(dir_entry)) / 963 mydata->sect_size; 964 mydata->data_begin = mydata->rootdir_sect + 965 rootdir_size - 966 (mydata->clust_size * 2); 967 } 968 969 mydata->fatbufnum = -1; 970 mydata->fatbuf = malloc(FATBUFSIZE); 971 if (mydata->fatbuf == NULL) { 972 debug("Error: allocating memory\n"); 973 return -1; 974 } 975 976 if (disk_read(cursect, 977 (mydata->fatsize == 32) ? 978 (mydata->clust_size) : 979 PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { 980 debug("Error: reading rootdir block\n"); 981 goto exit; 982 } 983 dentptr = (dir_entry *) do_fat_read_at_block; 984 985 name_len = strlen(filename); 986 if (name_len >= VFAT_MAXLEN_BYTES) 987 name_len = VFAT_MAXLEN_BYTES - 1; 988 989 memcpy(l_filename, filename, name_len); 990 l_filename[name_len] = 0; /* terminate the string */ 991 downcase(l_filename); 992 993 startsect = mydata->rootdir_sect; 994 retdent = find_directory_entry(mydata, startsect, 995 l_filename, dentptr, 0); 996 if (retdent) { 997 /* Update file size and start_cluster in a directory entry */ 998 retdent->size = cpu_to_le32(size); 999 start_cluster = FAT2CPU16(retdent->start); 1000 if (mydata->fatsize == 32) 1001 start_cluster |= 1002 (FAT2CPU16(retdent->starthi) << 16); 1003 1004 ret = check_overflow(mydata, start_cluster, size); 1005 if (ret) { 1006 printf("Error: %ld overflow\n", size); 1007 goto exit; 1008 } 1009 1010 ret = clear_fatent(mydata, start_cluster); 1011 if (ret) { 1012 printf("Error: clearing FAT entries\n"); 1013 goto exit; 1014 } 1015 1016 ret = set_contents(mydata, retdent, buffer, size); 1017 if (ret < 0) { 1018 printf("Error: writing contents\n"); 1019 goto exit; 1020 } 1021 write_size = ret; 1022 debug("attempt to write 0x%x bytes\n", write_size); 1023 1024 /* Flush fat buffer */ 1025 ret = flush_fat_buffer(mydata); 1026 if (ret) { 1027 printf("Error: flush fat buffer\n"); 1028 goto exit; 1029 } 1030 1031 /* Write directory table to device */ 1032 ret = set_cluster(mydata, dir_curclust, 1033 get_dentfromdir_block, 1034 mydata->clust_size * mydata->sect_size); 1035 if (ret) { 1036 printf("Error: writing directory entry\n"); 1037 goto exit; 1038 } 1039 } else { 1040 /* Set short name to set alias checksum field in dir_slot */ 1041 set_name(empty_dentptr, filename); 1042 fill_dir_slot(mydata, &empty_dentptr, filename); 1043 1044 ret = start_cluster = find_empty_cluster(mydata); 1045 if (ret < 0) { 1046 printf("Error: finding empty cluster\n"); 1047 goto exit; 1048 } 1049 1050 ret = check_overflow(mydata, start_cluster, size); 1051 if (ret) { 1052 printf("Error: %ld overflow\n", size); 1053 goto exit; 1054 } 1055 1056 /* Set attribute as archieve for regular file */ 1057 fill_dentry(mydata, empty_dentptr, filename, 1058 start_cluster, size, 0x20); 1059 1060 ret = set_contents(mydata, empty_dentptr, buffer, size); 1061 if (ret < 0) { 1062 printf("Error: writing contents\n"); 1063 goto exit; 1064 } 1065 write_size = ret; 1066 debug("attempt to write 0x%x bytes\n", write_size); 1067 1068 /* Flush fat buffer */ 1069 ret = flush_fat_buffer(mydata); 1070 if (ret) { 1071 printf("Error: flush fat buffer\n"); 1072 goto exit; 1073 } 1074 1075 /* Write directory table to device */ 1076 ret = set_cluster(mydata, dir_curclust, 1077 get_dentfromdir_block, 1078 mydata->clust_size * mydata->sect_size); 1079 if (ret) { 1080 printf("Error: writing directory entry\n"); 1081 goto exit; 1082 } 1083 } 1084 1085 exit: 1086 free(mydata->fatbuf); 1087 return ret < 0 ? ret : write_size; 1088 } 1089 1090 int file_fat_write(const char *filename, void *buffer, unsigned long maxsize) 1091 { 1092 printf("writing %s\n", filename); 1093 return do_fat_write(filename, buffer, maxsize); 1094 } 1095