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