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 (vfat_enabled && 823 (dentptr->attr & ATTR_VFAT) && 824 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 825 get_long_file_name(mydata, curclust, 826 get_dentfromdir_block, 827 &dentptr, l_name); 828 debug("vfatname: |%s|\n", l_name); 829 } else { 830 /* Volume label or VFAT entry */ 831 dentptr++; 832 if (is_next_clust(mydata, dentptr)) 833 break; 834 continue; 835 } 836 } 837 if (dentptr->name[0] == 0) { 838 debug("Dentname == NULL - %d\n", i); 839 empty_dentptr = dentptr; 840 return NULL; 841 } 842 843 get_name(dentptr, s_name); 844 845 if (strncasecmp(filename, s_name, sizeof(s_name)) && 846 strncasecmp(filename, l_name, sizeof(l_name))) { 847 debug("Mismatch: |%s|%s|\n", 848 s_name, l_name); 849 dentptr++; 850 if (is_next_clust(mydata, dentptr)) 851 break; 852 continue; 853 } 854 855 memcpy(retdent, dentptr, sizeof(dir_entry)); 856 857 debug("DentName: %s", s_name); 858 debug(", start: 0x%x", START(dentptr)); 859 debug(", size: 0x%x %s\n", 860 FAT2CPU32(dentptr->size), 861 (dentptr->attr & ATTR_DIR) ? 862 "(DIR)" : ""); 863 864 return dentptr; 865 } 866 867 /* 868 * In FAT16/12, the root dir is locate before data area, shows 869 * in following: 870 * ------------------------------------------------------------- 871 * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | 872 * ------------------------------------------------------------- 873 * 874 * As a result if curclust is in Root dir, it is a negative 875 * number or 0, 1. 876 * 877 */ 878 if (mydata->fatsize != 32 && (int)curclust <= 1) { 879 /* Current clust is in root dir, set to next clust */ 880 curclust++; 881 if ((int)curclust <= 1) 882 continue; /* continue to find */ 883 884 /* Reach the end of root dir */ 885 empty_dentptr = dentptr; 886 return NULL; 887 } 888 889 curclust = get_fatent(mydata, dir_curclust); 890 if (IS_LAST_CLUST(curclust, mydata->fatsize)) { 891 empty_dentptr = dentptr; 892 return NULL; 893 } 894 if (CHECK_CLUST(curclust, mydata->fatsize)) { 895 debug("curclust: 0x%x\n", curclust); 896 debug("Invalid FAT entry\n"); 897 return NULL; 898 } 899 } 900 901 return NULL; 902 } 903 904 static int do_fat_write(const char *filename, void *buffer, loff_t size, 905 loff_t *actwrite) 906 { 907 dir_entry *dentptr, *retdent; 908 __u32 startsect; 909 __u32 start_cluster; 910 boot_sector bs; 911 volume_info volinfo; 912 fsdata datablock; 913 fsdata *mydata = &datablock; 914 int cursect; 915 int ret = -1, name_len; 916 char l_filename[VFAT_MAXLEN_BYTES]; 917 918 *actwrite = size; 919 dir_curclust = 0; 920 921 if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { 922 debug("error: reading boot sector\n"); 923 return -1; 924 } 925 926 total_sector = bs.total_sect; 927 if (total_sector == 0) 928 total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ 929 930 if (mydata->fatsize == 32) 931 mydata->fatlength = bs.fat32_length; 932 else 933 mydata->fatlength = bs.fat_length; 934 935 mydata->fat_sect = bs.reserved; 936 937 cursect = mydata->rootdir_sect 938 = mydata->fat_sect + mydata->fatlength * bs.fats; 939 num_of_fats = bs.fats; 940 941 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; 942 mydata->clust_size = bs.cluster_size; 943 944 if (mydata->fatsize == 32) { 945 mydata->data_begin = mydata->rootdir_sect - 946 (mydata->clust_size * 2); 947 } else { 948 int rootdir_size; 949 950 rootdir_size = ((bs.dir_entries[1] * (int)256 + 951 bs.dir_entries[0]) * 952 sizeof(dir_entry)) / 953 mydata->sect_size; 954 mydata->data_begin = mydata->rootdir_sect + 955 rootdir_size - 956 (mydata->clust_size * 2); 957 } 958 959 mydata->fatbufnum = -1; 960 mydata->fat_dirty = 0; 961 mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); 962 if (mydata->fatbuf == NULL) { 963 debug("Error: allocating memory\n"); 964 return -1; 965 } 966 967 if (disk_read(cursect, 968 (mydata->fatsize == 32) ? 969 (mydata->clust_size) : 970 PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { 971 debug("Error: reading rootdir block\n"); 972 goto exit; 973 } 974 dentptr = (dir_entry *) do_fat_read_at_block; 975 976 name_len = strlen(filename); 977 if (name_len >= VFAT_MAXLEN_BYTES) 978 name_len = VFAT_MAXLEN_BYTES - 1; 979 980 memcpy(l_filename, filename, name_len); 981 l_filename[name_len] = 0; /* terminate the string */ 982 downcase(l_filename, INT_MAX); 983 984 startsect = mydata->rootdir_sect; 985 retdent = find_directory_entry(mydata, startsect, 986 l_filename, dentptr, 0); 987 if (retdent) { 988 /* Update file size and start_cluster in a directory entry */ 989 retdent->size = cpu_to_le32(size); 990 start_cluster = START(retdent); 991 992 if (start_cluster) { 993 if (size) { 994 ret = check_overflow(mydata, start_cluster, 995 size); 996 if (ret) { 997 printf("Error: %llu overflow\n", size); 998 goto exit; 999 } 1000 } 1001 1002 ret = clear_fatent(mydata, start_cluster); 1003 if (ret) { 1004 printf("Error: clearing FAT entries\n"); 1005 goto exit; 1006 } 1007 1008 if (!size) 1009 set_start_cluster(mydata, retdent, 0); 1010 } else if (size) { 1011 ret = start_cluster = find_empty_cluster(mydata); 1012 if (ret < 0) { 1013 printf("Error: finding empty cluster\n"); 1014 goto exit; 1015 } 1016 1017 ret = check_overflow(mydata, start_cluster, size); 1018 if (ret) { 1019 printf("Error: %llu overflow\n", size); 1020 goto exit; 1021 } 1022 1023 set_start_cluster(mydata, retdent, start_cluster); 1024 } 1025 } else { 1026 /* Set short name to set alias checksum field in dir_slot */ 1027 set_name(empty_dentptr, filename); 1028 fill_dir_slot(mydata, &empty_dentptr, filename); 1029 1030 if (size) { 1031 ret = start_cluster = find_empty_cluster(mydata); 1032 if (ret < 0) { 1033 printf("Error: finding empty cluster\n"); 1034 goto exit; 1035 } 1036 1037 ret = check_overflow(mydata, start_cluster, size); 1038 if (ret) { 1039 printf("Error: %llu overflow\n", size); 1040 goto exit; 1041 } 1042 } else { 1043 start_cluster = 0; 1044 } 1045 1046 /* Set attribute as archieve for regular file */ 1047 fill_dentry(mydata, empty_dentptr, filename, 1048 start_cluster, size, 0x20); 1049 1050 retdent = empty_dentptr; 1051 } 1052 1053 ret = set_contents(mydata, retdent, buffer, size, actwrite); 1054 if (ret < 0) { 1055 printf("Error: writing contents\n"); 1056 goto exit; 1057 } 1058 debug("attempt to write 0x%llx bytes\n", *actwrite); 1059 1060 /* Flush fat buffer */ 1061 ret = flush_dirty_fat_buffer(mydata); 1062 if (ret) { 1063 printf("Error: flush fat buffer\n"); 1064 goto exit; 1065 } 1066 1067 /* Write directory table to device */ 1068 ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block, 1069 mydata->clust_size * mydata->sect_size); 1070 if (ret) 1071 printf("Error: writing directory entry\n"); 1072 1073 exit: 1074 free(mydata->fatbuf); 1075 return ret; 1076 } 1077 1078 int file_fat_write(const char *filename, void *buffer, loff_t offset, 1079 loff_t maxsize, loff_t *actwrite) 1080 { 1081 if (offset != 0) { 1082 printf("Error: non zero offset is currently not supported.\n"); 1083 return -1; 1084 } 1085 1086 printf("writing %s\n", filename); 1087 return do_fat_write(filename, buffer, maxsize, actwrite); 1088 } 1089