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