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