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