1/* 2 * Copyright (c) 2009, 2011, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <string.h> 11#include <barrelfish/types.h> 12#include <barrelfish/barrelfish.h> 13#include <barrelfish/nameservice_client.h> 14#include <vfs/vfs_path.h> 15#include <errors/errno.h> 16#include <dev/fat_bpb_dev.h> 17#include <dev/fat16_ebpb_dev.h> 18#include <dev/fat32_ebpb_dev.h> 19#include <dev/fat_direntry_dev.h> 20#include <if/ata_rw28_defs.h> 21#include <if/ata_rw28_ahci_defs.h> 22#include <if/ata_rw28_defs.h> 23#include <ahci/ahci.h> 24#include "vfs_fat_conv.h" 25#include "vfs_backends.h" 26#include "vfs_ops.h" 27#include "vfs_cache.h" 28 29//#define FAT_DEBUG 1 30#if defined(FAT_DEBUG) || defined(VFS_DEBUG) || defined(GLOBAL_DEBUG) 31# define FAT_DEBUG_ENABLED 32 33# ifdef FAT_DEBUG 34# undef FAT_DEBUG 35# endif 36 37# define FAT_DEBUG_P() printf("fat:%s: ", __func__) 38# define FAT_DEBUG(s) \ 39 printf("fat:%s: " s "\n", __func__) 40# define FAT_DEBUG_F(s, x...) \ 41 printf("fat:%s: " s "\n", __func__, x) 42# define TRACE_ENTER \ 43 printf("fat: entering %s\n", __func__) 44# define TRACE_ENTER_F(s, x...) \ 45 printf("fat: entering %s: " s "\n", __func__, x) 46 47#else 48 49# ifdef FAT_DEBUG_ENABLED 50# undef FAT_DEBUG_ENABLED 51# endif 52 53# define FAT_DEBUG_P() ((void)0) 54# define FAT_DEBUG(s) ((void)0) 55# define FAT_DEBUG_F(s, x...) ((void)0) 56# define TRACE_ENTER ((void)0) 57# define TRACE_ENTER_F(s, x...) ((void)0) 58 59#endif 60 61#define DUMP_DEV(dev_t, dev_p, buf_s) do { \ 62 char dump_dev_buf__[(buf_s)]; \ 63 dev_t ## _pr(dump_dev_buf__, (buf_s)-1, (dev_p)); \ 64 dump_dev_buf__[(buf_s)-1] = 0; \ 65 printf("%s\n", dump_dev_buf__); \ 66} while(0) 67 68#ifndef CEIL_DIV 69#define CEIL_DIV(x, d) (((x) + ((d)-1)) / (d)) 70#endif 71 72#define fat_direntry_size 32 73 74#define cluster_for_offset(offset, mount) \ 75 ((offset) / ((mount)->block_size * (mount)->cluster_size)) 76 77#define offset_from_cluster(offset, mount) \ 78 ((offset) % ((mount)->block_size * (mount)->cluster_size)) 79 80#define cluster_to_block(cluster, mount) \ 81 ((mount)->clusters_start + (((cluster) - 2) * (mount)->cluster_size)) 82 83#define cluster_entry_size(mount) \ 84 ((mount)->fat_type == FAT_TYPE_FAT16 ? sizeof(uint16_t) : sizeof(uint32_t)) 85 86#define fat_block_for_cluster(cluster, mount) \ 87 ((cluster) * cluster_entry_size(mount) / (mount)->block_size) 88 89#define fat_offset_for_cluster(cluster, mount) \ 90 ((cluster) * cluster_entry_size(mount) % (mount)->block_size) 91 92// NOTE: specification says max 255 chars, but format in principle seems to 93// allow 260, so be on the safe side 94#define LFN_CHAR_COUNT 260 95#define LFN_MAX_LENGTH 255 96#define DOSFN_MAX_LEN_UTF8 40 97 98#define ASCII_MAX 127 99 100struct fat_dirsearch { 101 size_t index; 102 fat_direntry_t *parent_direntry; 103 uint8_t *data; 104 size_t data_index; 105 size_t data_key; 106}; 107 108struct fat_handle_common { 109 struct vfs_handle common; 110 uint8_t dirent_data[fat_direntry_size]; 111 fat_direntry_t dirent; 112}; 113 114struct fat_handle { 115 struct fat_handle_common h; 116 size_t offset; 117}; 118 119struct fat_dirhandle { 120 struct fat_handle_common h; 121 struct fat_dirsearch search; 122}; 123 124enum { 125 FAT_TYPE_FAT16 = 16, 126 FAT_TYPE_FAT32 = 32, 127}; 128 129struct fat_mount { 130 struct ata_rw28_binding *ata_rw28_binding; 131 struct ahci_binding *ahci_binding; 132 errval_t bind_err; 133 134 int fat_type; 135 size_t startblock; 136 uint8_t bootsec_data[512]; 137 fat_bpb_t bpb; 138 union { 139 fat16_ebpb_t f16; 140 fat32_ebpb_t f32; 141 } ebpb; 142 143 struct fs_cache *block_cache; 144 struct fs_cache *cluster_cache; 145 146 size_t block_count; 147 size_t block_size; // bytes 148 size_t cluster_size; // blocks 149 size_t fat_start; // blocks 150 size_t fat_size; // blocks 151 size_t rootdir_start; // blocks. 0 implies rootdir in clusters 152 size_t rootdir_cluster; 153 size_t clusters_start; // blocks 154 uint32_t last_cluster_start; // cluster 155}; 156 157static errval_t 158acquire_or_read(struct fat_mount *mount, struct fs_cache *cache, 159 uint32_t idx, uint8_t **data, size_t block, size_t size) 160{ 161 TRACE_ENTER_F("idx=%"PRIu32", block=%zu, size=%zu", idx, block, size); 162 163 uint8_t *data_; 164 errval_t err; 165 166 err = fs_cache_acquire(cache, idx, (void**)&data_); 167 if (err_is_fail(err) && err != FS_CACHE_NOTPRESENT) { 168 return err; 169 } 170 else if (err == FS_CACHE_NOTPRESENT) { 171 size_t read_size; 172 data_ = malloc(size); 173 err = mount->ata_rw28_binding->rpc_tx_vtbl.read_dma(mount->ata_rw28_binding, 174 size, block, data_, &read_size); 175 if (err_is_fail(err)) { 176 return err; 177 } 178 assert(size == read_size); 179 180 err = fs_cache_put(cache, idx, data_); 181 if (err_is_fail(err)) { 182 return err; 183 } 184 } 185 186 *data = data_; 187 return SYS_ERR_OK; 188} 189 190static errval_t 191acquire_block(struct fat_mount *mount, size_t block, uint8_t **data) 192{ 193 return acquire_or_read(mount, mount->block_cache, 194 block, data, block, mount->block_size); 195} 196 197static errval_t 198release_block(struct fat_mount *mount, size_t block) 199{ 200 return fs_cache_release(mount->block_cache, block); 201} 202 203static errval_t 204acquire_cluster(struct fat_mount *mount, uint32_t cluster, uint8_t **data) 205{ 206 return acquire_or_read(mount, mount->cluster_cache, cluster, data, 207 cluster_to_block(cluster, mount), 208 mount->block_size * mount->cluster_size); 209} 210 211static errval_t 212release_cluster(struct fat_mount *mount, uint32_t cluster) 213{ 214 return fs_cache_release(mount->cluster_cache, cluster); 215} 216 217static void 218dirsearch_initialize(struct fat_dirsearch *search, fat_direntry_t *parent) 219{ 220 memset(search, 0, sizeof(*search)); 221 search->parent_direntry = parent; 222} 223 224static void 225dirsearch_wipe(struct fat_dirsearch *search, struct fat_mount *mount) 226{ 227 errval_t err; 228 if (search->data) { 229 if (!search->parent_direntry && mount->fat_type == FAT_TYPE_FAT16) { 230 // the special rootdir area of FAT16 is handled with the block cache 231 err = release_block(mount, search->data_key); 232 } 233 else { 234 err = release_cluster(mount, search->data_key); 235 } 236 if (err_is_fail(err)) { 237 // this should not happen 238 USER_PANIC_ERR(err, "could not release search data cache"); 239 } 240 } 241 memset(search, 0, sizeof(*search)); 242} 243 244static uint32_t 245next_cluster(struct fat_mount *mount, uint32_t cluster, uint32_t *rescluster) 246{ 247 TRACE_ENTER; 248 errval_t err; 249 250 // calculate block and offset 251 size_t cluster_fat_block = fat_block_for_cluster(cluster, mount)+mount->fat_start; 252 size_t cluster_fat_offset = fat_offset_for_cluster(cluster, mount); 253 FAT_DEBUG_F("cluster %"PRIu32" is at fat block %zu + %zu", 254 cluster, cluster_fat_block, cluster_fat_offset); 255 256 // fetch block data 257 uint8_t *data; 258 err = acquire_block(mount, cluster_fat_block, &data); 259 if (err_is_fail(err)) { 260 return err; 261 } 262 263 // lookup cluster in found block 264 uint32_t result; 265 if (mount->fat_type == FAT_TYPE_FAT16) { 266 result = *(uint16_t*)(data+cluster_fat_offset); 267 } 268 else { 269 result = *(uint32_t*)(data+cluster_fat_offset); 270 } 271 272 // release cache ref 273 err = release_block(mount, cluster_fat_block); 274 if (err_is_fail(err)) { 275 return err; 276 } 277 278 FAT_DEBUG_F("next cluster is %"PRIu32, result); 279 *rescluster = result; 280 return SYS_ERR_OK; 281} 282 283static void 284update_lfn(const uint8_t *entry_data, fat_direntry_t *entry, 285 uint16_t lfn_data[LFN_CHAR_COUNT]) 286{ 287 TRACE_ENTER; 288 uint8_t seq_nr = entry_data[0]; 289 FAT_DEBUG_F("updating lfn data from entry with seq_nr 0x%x", (int)seq_nr); 290 if (seq_nr & 0x40) { 291 // first entry, reset lfn_data 292 FAT_DEBUG("first entry, resetting lfn_data"); 293 memset(lfn_data, 0, LFN_CHAR_COUNT*sizeof(*lfn_data)); 294 } 295 /* 296 if (seq_nr & 0x80) { 297 // entry is deleted 298 printf("entry is deleted"); 299 return; 300 } 301 */ 302 303 // remove flag bits from sequence number, make 0-based 304 seq_nr = (seq_nr & 0x1f) - 1; 305 static const size_t chars_per_lfn_entry = 13; 306 307 // chars 0-4 are 16-bit words from offset 0x1 308 for (size_t i = 0; i < 5; i++) { 309 uint16_t c = *(uint16_t*)(entry_data + 0x1 + i*2); 310 lfn_data[seq_nr*chars_per_lfn_entry+0+i] = c; 311 } 312 // chars 5-10 are 16-bit words from offset 0xe 313 for (size_t i = 0; i < 6; i++) { 314 uint16_t c = *(uint16_t*)(entry_data + 0xe + i*2); 315 lfn_data[seq_nr*chars_per_lfn_entry+5+i] = c; 316 } 317 // chars 11-12 are 16-bit words from offset 0x1c 318 for (size_t i = 0; i < 2; i++) { 319 uint16_t c = *(uint16_t*)(entry_data + 0x1c + i*2); 320 lfn_data[seq_nr*chars_per_lfn_entry+11+i] = c; 321 } 322} 323 324static errval_t 325next_f16_rootdir_block(struct fat_mount *mount, struct fat_dirsearch *search, 326 uint8_t **data) 327{ 328 TRACE_ENTER; 329 errval_t err = SYS_ERR_OK; 330 assert(!search->parent_direntry); 331 assert(mount->fat_type == FAT_TYPE_FAT16); 332 333 // check that index is within number of valid root entries 334 size_t search_end = fat_bpb_rtc_rd(&mount->bpb); 335 if (search->index >= search_end) { 336 return FS_ERR_INDEX_BOUNDS; 337 } 338 339 // calculate block index 340 size_t bytes_offset = search->index * fat_direntry_size; 341 size_t block_index = bytes_offset / mount->block_size; 342 size_t block_offset = bytes_offset % mount->block_size; 343 FAT_DEBUG_F("search index %zu at block %zu + %zu", 344 search->index, block_index, block_offset); 345 346 if (!search->data || search->data_index != block_index) { 347 FAT_DEBUG("need new block data"); 348 349 // determine block 350 size_t block = mount->rootdir_start + block_index; 351 FAT_DEBUG_F("file block %zu is block %zu", block_index, block); 352 353 // fetch new block data 354 uint8_t *new_data; 355 err = acquire_block(mount, block, &new_data); 356 if (err_is_fail(err)) { 357 return err; 358 } 359 360 // free old block data 361 if (search->data) { 362 err = release_block(mount, search->data_key); 363 if (err_is_fail(err)) { 364 release_block(mount, block); 365 return err; 366 } 367 } 368 369 search->data = new_data; 370 search->data_index = block_index; 371 search->data_key = block; 372 } 373 374 *data = search->data + block_offset; 375 return SYS_ERR_OK; 376} 377 378static errval_t 379next_subdir_block(struct fat_mount *mount, struct fat_dirsearch *search, 380 uint8_t **data) 381{ 382 TRACE_ENTER; 383 errval_t err = SYS_ERR_OK; 384 assert(search->parent_direntry || mount->fat_type == FAT_TYPE_FAT32); 385 386 // calculate block index 387 size_t bytes_offset = search->index * fat_direntry_size; 388 size_t block_index = bytes_offset / mount->block_size; 389 size_t cluster_index = block_index / mount->cluster_size; 390 size_t cluster_offset = bytes_offset % 391 (mount->block_size * mount->cluster_size); 392 FAT_DEBUG_F("search index %zu at cluster %zu + %zu", 393 search->index, cluster_index, cluster_offset); 394 395 if (!search->data || search->data_index != cluster_index) { 396 FAT_DEBUG("need new block data"); 397 398 // get start cluster of direntry data 399 uint32_t cluster = 0; 400 if (search->parent_direntry) { 401 if (mount->fat_type == FAT_TYPE_FAT32) { 402 cluster = (uint32_t)fat_direntry_starth_rd(search->parent_direntry) << 16; 403 } 404 cluster += fat_direntry_start_rd(search->parent_direntry); 405 } 406 else { 407 cluster = mount->rootdir_cluster; 408 } 409 410 // determine cluster corresponding to cluster_index 411 for (size_t clsidx = cluster_index; 412 cluster < mount->last_cluster_start && clsidx > 0; 413 clsidx--) 414 { 415 err = next_cluster(mount, cluster, &cluster); 416 if (err_is_fail(err)) { 417 return err; 418 } 419 } 420 FAT_DEBUG_F("dir cluster %zu is cluster %"PRIu32, cluster_index, cluster); 421 if (cluster >= mount->last_cluster_start) { 422 return FS_ERR_INDEX_BOUNDS; 423 } 424 425 // read new cluster data 426 uint8_t *new_data; 427 err = acquire_cluster(mount, cluster, &new_data); 428 if (err_is_fail(err)) { 429 return err; 430 } 431 432 // free old data 433 if (search->data) { 434 err = release_cluster(mount, search->data_key); 435 if (err_is_fail(err)) { 436 USER_PANIC_ERR(err, "could not release dir data cache"); 437 } 438 } 439 440 search->data = new_data; 441 search->data_index = cluster_index; 442 search->data_key = cluster; 443 } 444 445 *data = search->data + cluster_offset; 446 return SYS_ERR_OK; 447} 448 449static errval_t 450read_next_direntry(struct fat_mount *mount, struct fat_dirsearch *search, 451 char dosfn[12], uint16_t lfn_data[LFN_CHAR_COUNT], bool *has_lfn, 452 uint8_t direntry_data[fat_direntry_size]) 453{ 454 TRACE_ENTER; 455 errval_t err = SYS_ERR_OK; 456 bool has_lfn_ = false; 457 458 for ( ; ; search->index++) { 459 FAT_DEBUG_F("checking search index %zu", search->index); 460 461 uint8_t *entry_data = NULL; 462 bool special_rootdir = !search->parent_direntry && 463 mount->fat_type == FAT_TYPE_FAT16; 464 if (special_rootdir) { 465 err = next_f16_rootdir_block(mount, search, &entry_data); 466 } 467 else { 468 err = next_subdir_block(mount, search, &entry_data); 469 } 470 if (err_is_fail(err)) { 471 return err; 472 } 473 474 fat_direntry_t entry; 475 fat_direntry_initialize(&entry, (char*)entry_data); 476 477 // check for various kinds of non-regular entries 478 if (fat_direntry_fn_rd(&entry, 0) == 0xe5) { 479 // 0xe5 implies deleted, skip 480 FAT_DEBUG("found 0xe5 direntry"); 481 has_lfn_ = false; 482 continue; 483 } 484 else if (fat_direntry_attr_rd(&entry) == 0xf) { 485 // (attr == ro | hidden | system | volume) implies long filename 486 FAT_DEBUG("found lfn direntry"); 487 if (entry_data[0] & 0x40 && !(entry_data[0] & 0x80)) { 488 // first lfn entry and not deleted implies next real entry has a lfn 489 has_lfn_ = true; 490 } 491 update_lfn(entry_data, &entry, lfn_data); 492 continue; 493 } 494 else if (!entry_data[0]) { 495 // entries with names starting at 0 have never been allocated, so 496 // later entries are unused too 497 FAT_DEBUG("found clean direntry"); 498 return FS_ERR_INDEX_BOUNDS; 499 } 500 else if (fat_direntry_start_rd(&entry) == 0 && 501 !fat_direntry_attr_dir_rdf(&entry)) { 502 // entries with starting cluster 0 should only occur in directory 503 // and lfn entries. lfn entries are already handled, so something 504 // weird is going on if we get here. 505 FAT_DEBUG("found non-lfn/dir direntry with start cluster 0"); 506 continue; 507 } 508 509#ifdef FAT_DEBUG_ENABLED 510 FAT_DEBUG_P(); 511 // dump found names 512 printf("8.3 entry: \""); 513 for (uint8_t *p = entry_data; p < entry_data+11; p++) { 514 putchar(*p); 515 } 516 printf("\", lfn entry: "); 517 if (has_lfn_) { 518 putchar('"'); 519 for (uint16_t *p = lfn_data; *p && p < lfn_data+LFN_CHAR_COUNT; p++) { 520 putchar(*p > ASCII_MAX ? '?' : (char)*p); 521 } 522 putchar('"'); 523 } 524 else { 525 printf("(none)"); 526 } 527 putchar('\n'); 528#endif 529 530 // at this point, we've found a real entry 531 memcpy(dosfn, entry_data, 11); 532 dosfn[11] = 0; 533 *has_lfn = has_lfn_; 534 memcpy(direntry_data, entry_data, fat_direntry_size); 535 search->index++; 536 return SYS_ERR_OK; 537 } 538 return FS_ERR_INDEX_BOUNDS; 539} 540 541static errval_t 542find_path(struct fat_mount *mount, const char *path, 543 uint8_t direntry[fat_direntry_size]) 544{ 545 TRACE_ENTER_F("\"%s\"", path); 546 errval_t err = SYS_ERR_OK; 547 const char *part_begin = path, *part_end; 548 549 fat_direntry_t parent_entry; 550 fat_direntry_t *parent = NULL; 551 552 do { 553 if (*part_begin == '/') { 554 part_begin++; 555 } 556 for (part_end = part_begin+1; *part_end && *part_end != '/'; part_end++) ; 557 558 size_t part_len = part_end - part_begin; 559#ifdef FAT_DEBUG_ENABLED 560 { 561 char part[part_len+1]; 562 strncpy(part, part_begin, part_len); 563 part[part_len]=0; 564 FAT_DEBUG_F("part \"%s\"", part); 565 } 566#endif 567 568 struct fat_dirsearch search; 569 dirsearch_initialize(&search, parent); 570 571 char dosfn[12]; 572 uint16_t lfn_data[LFN_CHAR_COUNT]; 573 bool has_lfn; 574 char buf[LFN_CHAR_COUNT + 1]; 575 576 do { 577 578 err = read_next_direntry(mount, &search, dosfn, lfn_data, 579 &has_lfn, direntry); 580 if (err_is_fail(err)) { 581 dirsearch_wipe(&search, mount); 582 if (err == FS_ERR_INDEX_BOUNDS) { 583 err = FS_ERR_NOTFOUND; 584 } 585 return err; 586 } 587 588 if (has_lfn) { 589 // In theory, FAT long file names allow a maximum of 255 590 // UTF-16 characters, but as Barrelfish does not have a clear 591 // notion of any UTF encoding, we do not support opening files 592 // with file names that are not pure ASCII. 593 // Additionally, when reading directory entries we replace any 594 // non-ASCII characters in file names with question marks (cf. 595 // dir_read_next()). 596 size_t len; 597 for (len = 0; len < LFN_CHAR_COUNT; len++) { 598 if (!lfn_data[len] || lfn_data[len] > ASCII_MAX) { 599 break; 600 } 601 } 602 // have non-ASCII char in LFN, ignore file when looking up 603 // path for opening. 604 if (len < LFN_CHAR_COUNT && lfn_data[len] > ASCII_MAX) { 605 continue; 606 } 607 // here: LFN is pure ASCII, and thus we can cast the 608 // UTF-16-encoded UTF characters to ASCII chars without having 609 // to worry about them not fitting. We also properly 610 // zero-terminate the new ASCII LFN. 611 assert(len <= LFN_CHAR_COUNT); 612 for (size_t i = 0; i < len; ++i) { 613 buf[i] = (char)lfn_data[i]; 614 } 615 buf[len] = 0; 616 } 617 else { 618 if (dos2unixfn((const unsigned char*)dosfn, (unsigned char*)buf, LFN_CHAR_COUNT)) { 619 // TODO: handle error 620 } 621 } 622 623 FAT_DEBUG_F("comparing part to %s", buf); 624 bool match = strncmp(part_begin, buf, part_len) == 0 && buf[part_len] == 0; 625 if (match) { 626 break; 627 } 628 629 } while (1); 630 631 parent = &parent_entry; 632 fat_direntry_initialize(parent, (char*)direntry); 633 634 dirsearch_wipe(&search, mount); 635 part_begin = part_end; 636 } while(*part_begin); 637 638 return SYS_ERR_OK; 639} 640 641static errval_t 642openhandle(struct fat_mount *mount, const char *path, struct fat_handle_common *handle) 643{ 644 TRACE_ENTER; 645 errval_t err = SYS_ERR_OK; 646 647 err = find_path(mount, path, handle->dirent_data); 648 if (err_is_fail(err)) { 649 return err; 650 } 651 652 fat_direntry_initialize(&handle->dirent, (char*)handle->dirent_data); 653 654#ifdef FAT_DEBUG_ENABLED 655 /*DUMP_DEV(fat_direntry, &handle->dirent, 4096);*/ 656#endif 657 658 return SYS_ERR_OK; 659} 660 661static errval_t 662open(void *st, const char *path, vfs_handle_t *fhandle) 663{ 664 TRACE_ENTER_F("\"%s\"", path); 665 errval_t err = SYS_ERR_OK; 666 struct fat_handle *handle = NULL; 667 struct fat_mount *mount = st; 668 669 handle = calloc(1, sizeof(*handle)); 670 if (!handle) { 671 err = LIB_ERR_MALLOC_FAIL; 672 goto error; 673 } 674 675 err = openhandle(mount, path, &handle->h); 676 if (err_is_fail(err)) { 677 goto error; 678 } 679 680 if (fat_direntry_attr_dir_rdf(&handle->h.dirent)) { 681 err = FS_ERR_NOTFILE; 682 goto error; 683 } 684 685 *fhandle = handle; 686 goto end; 687 688error: 689 free(handle); 690 691end: 692 return err; 693} 694 695static errval_t 696create(void *st, const char *path, vfs_handle_t *handle) 697{ 698 TRACE_ENTER; 699 return LIB_ERR_NOT_IMPLEMENTED; 700} 701 702static errval_t 703fat_remove(void *st, const char *path) 704{ 705 TRACE_ENTER; 706 return LIB_ERR_NOT_IMPLEMENTED; 707} 708 709static errval_t 710read(void *st, vfs_handle_t fhandle, void *buffer, size_t bytes, size_t *bytes_read) 711{ 712 TRACE_ENTER; 713 errval_t err; 714 struct fat_handle *handle = fhandle; 715 struct fat_mount *mount = st; 716 size_t file_size = fat_direntry_size_rd(&handle->h.dirent); 717 size_t offset = handle->offset; 718 719 assert(bytes_read); 720 *bytes_read = 0; 721 722 // limited requested bytes to remaining file size 723 size_t file_remainder = file_size - handle->offset; 724 if (bytes > file_remainder) { 725 bytes = file_remainder; 726 } 727 if (bytes == 0) { 728 return SYS_ERR_OK; 729 } 730 FAT_DEBUG_F("reading %zu bytes", bytes); 731 732 fat_direntry_t *dirent = &handle->h.dirent; 733 int isdir = fat_direntry_attr_dir_rdf(dirent); 734 if (isdir) { 735 return FS_ERR_NOTFILE; 736 } 737 738 size_t remaining = bytes; 739 do { 740 // split read offset into cluster index and offset within cluster 741 size_t cluster_index = cluster_for_offset(offset, mount); 742 size_t cluster_offset = offset_from_cluster(offset, mount); 743 FAT_DEBUG_F("reading from file cluster %zu + %zu", 744 cluster_index, cluster_offset); 745 746 // determin read size, only read single cluster and not beyond end of file 747 size_t read_size = remaining; 748 size_t cluster_remainder = mount->cluster_size * mount->block_size - cluster_offset; 749 if (cluster_remainder < read_size) { 750 read_size = cluster_remainder; 751 } 752 file_remainder = fat_direntry_size_rd(dirent) - offset; 753 if (file_remainder < read_size) { 754 read_size = file_remainder; 755 } 756 FAT_DEBUG_F("reading %zu from cluster (clus_rem=%zu, f_rem=%zu)", 757 read_size, cluster_remainder, file_remainder); 758 759 // determine cluster corresponding to cluster_index 760 uint32_t cluster = fat_direntry_start_rd(dirent); 761 if (mount->fat_type == FAT_TYPE_FAT32) { 762 cluster += (uint32_t)fat_direntry_starth_rd(dirent) << 16; 763 } 764 for (size_t clsidx = cluster_index; clsidx > 0; clsidx--) { 765 err = next_cluster(mount, cluster, &cluster); 766 if (err_is_fail(err)) { 767 return err; 768 } 769 } 770 FAT_DEBUG_F("file cluster %zu is cluster %"PRIu32, cluster_index, cluster); 771 assert(cluster < mount->last_cluster_start); 772 773 // fetch data and copy into buffer 774 uint8_t *data; 775 err = acquire_cluster(mount, cluster, &data); 776 if (err_is_fail(err)) { 777 return err; 778 } 779 memcpy(buffer, data+cluster_offset, read_size); 780 err = release_cluster(mount, cluster); 781 if (err_is_fail(err)) { 782 // should not happen 783 USER_PANIC_ERR(err, "could not release file cluster cache"); 784 } 785 786 // update variables for successful read 787 buffer = (char *)buffer + read_size; 788 remaining -= read_size; 789 *bytes_read += read_size; 790 offset += read_size; 791 792 FAT_DEBUG_F("read of cluster %"PRIu32" completed", cluster); 793 } while (remaining); 794 795 // read completed, update handle's offset 796 FAT_DEBUG_F("read of %zu bytes completed", bytes); 797 handle->offset = offset; 798 return SYS_ERR_OK; 799} 800 801static errval_t 802write(void *st, vfs_handle_t handle, const void *buffer, size_t bytes, 803 size_t *bytes_written) 804{ 805 TRACE_ENTER; 806 return LIB_ERR_NOT_IMPLEMENTED; 807} 808 809static errval_t 810fat_truncate(void *st, vfs_handle_t handle, size_t bytes) 811{ 812 TRACE_ENTER; 813 return LIB_ERR_NOT_IMPLEMENTED; 814} 815 816static errval_t 817seek(void *st, vfs_handle_t fhandle, enum vfs_seekpos whence, off_t offset) 818{ 819 TRACE_ENTER; 820 821 struct fat_handle *handle = fhandle; 822 size_t size = fat_direntry_size_rd(&handle->h.dirent); 823 size_t base = 0; 824 825 switch (whence) { 826 case VFS_SEEK_SET: base = 0; break; 827 case VFS_SEEK_CUR: base = handle->offset; break; 828 case VFS_SEEK_END: base = size; break; 829 default: USER_PANIC("invalid whence argument to fat seek"); break; 830 } 831 832 if (offset < 0 && (-offset) > base) { 833 handle->offset = 0; 834 } 835 else if (base + offset > size) { 836 handle->offset = size; 837 } 838 else { 839 handle->offset = base + offset; 840 } 841 842 return SYS_ERR_OK; 843} 844 845static errval_t 846tell(void *st, vfs_handle_t fhandle, size_t *pos) 847{ 848 TRACE_ENTER; 849 850 struct fat_handle *handle = fhandle; 851 *pos = handle->offset; 852 853 return SYS_ERR_OK; 854} 855 856static errval_t 857stat(void *st, vfs_handle_t handle, struct vfs_fileinfo *info) 858{ 859 TRACE_ENTER; 860 861 struct fat_handle_common *fhc = handle; 862 863 if (fat_direntry_attr_dir_rdf(&fhc->dirent)) { 864 info->type = VFS_DIRECTORY; 865 info->size = 0; // TODO: something more useful? 866 } 867 else { 868 info->type = VFS_FILE; 869 info->size = fat_direntry_size_rd(&fhc->dirent); 870 } 871 872 return SYS_ERR_OK;; 873} 874 875static errval_t 876close(void *st, vfs_handle_t fhandle) 877{ 878 TRACE_ENTER; 879 struct fat_handle *handle = fhandle; 880 881 free(handle); 882 return SYS_ERR_OK; 883} 884 885static errval_t 886mkdir(void *st, const char *path) 887{ 888 TRACE_ENTER_F("\"%s\"", path); 889 // fail if already present 890 return LIB_ERR_NOT_IMPLEMENTED; 891} 892 893static errval_t 894rmdir(void *st, const char *path) 895{ 896 TRACE_ENTER_F("\"%s\"", path); 897 // fail if not empty 898 return LIB_ERR_NOT_IMPLEMENTED; 899} 900 901static errval_t 902opendir(void *st, const char *path, vfs_handle_t *dhandle) 903{ 904 TRACE_ENTER_F("\"%s\"", path); 905 errval_t err = SYS_ERR_OK; 906 struct fat_dirhandle *new_handle = NULL; 907 struct fat_mount *mount = st; 908 909 new_handle = calloc(1, sizeof(*new_handle)); 910 if (!new_handle) { 911 err = LIB_ERR_MALLOC_FAIL; 912 goto error; 913 } 914 915 if (!path[0] || (path[0] == '/' && path[1] == '\0')) { 916 FAT_DEBUG("got opendir for root"); 917 *dhandle = new_handle; 918 goto end; 919 } 920 921 err = openhandle(mount, path, &new_handle->h); 922 if (err_is_fail(err)) { 923 goto error; 924 } 925 926 if (!fat_direntry_attr_dir_rdf(&new_handle->h.dirent)) { 927 err = FS_ERR_NOTDIR; 928 goto error; 929 } 930 FAT_DEBUG_F("directory %s found", path); 931 932 dirsearch_initialize(&new_handle->search, &new_handle->h.dirent); 933 934 *dhandle = new_handle; 935 goto end; 936 937error: 938 free(new_handle); 939 940end: 941 return err; 942} 943 944static errval_t 945dir_read_next(void *st, vfs_handle_t dhandle, char **name, struct vfs_fileinfo *info) 946{ 947 TRACE_ENTER; 948 errval_t err = SYS_ERR_OK; 949 950 struct fat_dirhandle *handle = dhandle; 951 struct fat_mount *mount = st; 952 953 FAT_DEBUG_F("handle->search.index = %zu", handle->search.index); 954 955 char dosfn[12]; 956 uint16_t lfn_data[LFN_CHAR_COUNT]; 957 bool has_lfn; 958 uint8_t dirent_data[fat_direntry_size]; 959 fat_direntry_t dirent; 960 961 // read next direntry 962 err = read_next_direntry(mount, &handle->search, dosfn, lfn_data, 963 &has_lfn, dirent_data); 964 if (err_is_fail(err)) { 965 return err; 966 } 967 fat_direntry_initialize(&dirent, (char*)dirent_data); 968 969 if (has_lfn) { 970 // In theory, FAT long file names allow a maximum of 255 UTF-16 971 // characters, but as Barrelfish does not have a clear notion of any 972 // UTF encoding, we replace non-ASCII characters with question marks 973 // when reading directory entries for a directory listing. 974 // Additionally we do not support opening files with names that 975 // contain non-ASCII characters (cf. find_path()). 976 size_t len; 977 for (len = 0; len < LFN_CHAR_COUNT; len++) { 978 if (!lfn_data[len]) { 979 break; 980 } 981 } 982 char *buf = malloc(len+1); 983 if (!buf) { 984 return LIB_ERR_MALLOC_FAIL; 985 } 986 for (size_t i = 0; i < len; ++i) { 987 if (lfn_data[i] > ASCII_MAX) { 988 buf[i] = '?'; 989 } 990 else { 991 buf[i] = (char)lfn_data[i]; 992 } 993 } 994 buf[len] = 0; 995 *name = buf; 996 } 997 else { 998 char *buf = malloc(DOSFN_MAX_LEN_UTF8); 999 dos2unixfn((const unsigned char*)dosfn, (unsigned char*)buf, DOSFN_MAX_LEN_UTF8); 1000 *name = buf; 1001 } 1002 1003#ifdef FAT_DEBUG_ENABLED 1004 /*DUMP_DEV(fat_direntry, &dirent, 4096);*/ 1005#endif 1006 1007 bool isdir = fat_direntry_attr_dir_rdf(&dirent); 1008 info->type = isdir ? VFS_DIRECTORY : VFS_FILE; 1009 info->size = fat_direntry_size_rd(&dirent); 1010 return SYS_ERR_OK; 1011} 1012 1013static errval_t 1014closedir(void *st, vfs_handle_t dhandle) 1015{ 1016 TRACE_ENTER; 1017 errval_t err = SYS_ERR_OK; 1018 struct fat_mount *mount = st; 1019 struct fat_dirhandle *handle = dhandle; 1020 1021 dirsearch_wipe(&handle->search, mount); 1022 free(handle); 1023 1024 return err; 1025} 1026 1027struct vfs_ops fat_ops = { 1028 .open = open, 1029 .create = create, 1030 .remove = fat_remove, 1031 .read = read, 1032 .write = write, 1033 .truncate = fat_truncate, 1034 .seek = seek, 1035 .tell = tell, 1036 .stat = stat, 1037 .close = close, 1038 .opendir = opendir, 1039 .dir_read_next = dir_read_next, 1040 .closedir = closedir, 1041 .mkdir = mkdir, 1042 .rmdir = rmdir, 1043}; 1044 1045#if defined(__x86_64__) || defined(__i386__) 1046static void 1047ahci_init_cb(void *st, errval_t err, struct ahci_binding *b) 1048{ 1049 TRACE_ENTER; 1050 struct fat_mount *mount = st; 1051 1052 if (err_is_fail(err)) { 1053 mount->bind_err = err; 1054 return; 1055 } 1056 1057 mount->ahci_binding = b; 1058} 1059 1060static void 1061ahci_close_cb(void *arg) 1062{ 1063 *(bool *)arg = true; 1064} 1065 1066#elif defined(__pandaboard__) 1067 1068static void 1069bind_cb(void *st, errval_t err, struct ata_rw28_binding *b) 1070{ 1071 printf("%s:%d\n", __FUNCTION__, __LINE__); 1072 1073 if (err_is_fail(err)) { 1074 USER_PANIC_ERR(err, "bind failed"); 1075 } 1076 1077 struct fat_mount *mount = (struct fat_mount*) st; 1078 1079 ata_rw28_binding_init(b); 1080 mount->ata_rw28_binding = b; 1081} 1082#endif 1083 1084errval_t 1085vfs_fat_mount(const char *uri, void **retst, struct vfs_ops **retops) 1086{ 1087 TRACE_ENTER; 1088 errval_t err; 1089 // format: scheme://port[+offset] 1090 1091 int type; 1092 if (strncmp(uri, "fat16://", 8) == 0) { 1093 type = FAT_TYPE_FAT16; 1094 } 1095 else if (strncmp(uri, "fat32://", 8) == 0) { 1096 type = FAT_TYPE_FAT32; 1097 } 1098 else { 1099 return VFS_ERR_BAD_URI; 1100 } 1101 // skip scheme 1102 const char *puri = uri + 8; 1103 1104 // parse port 1105 if (*puri < '0' || *puri > '9') { 1106 return VFS_ERR_BAD_URI; 1107 } 1108 size_t port = 0, startblock = 0; 1109 while (*puri >= '0' && *puri <= '9') { 1110 port = port*10 + (*puri++ - '0'); 1111 } 1112 if (*puri == '+') { 1113 // parse offset 1114 puri++; 1115 if (*puri < '0' || *puri > '9') { 1116 return VFS_ERR_BAD_URI; 1117 } 1118 while (*puri >= '0' && *puri <= '9') { 1119 startblock = startblock*10 + (*puri++ - '0'); 1120 } 1121 } 1122 if (*puri != 0) { 1123 return VFS_ERR_BAD_URI; 1124 } 1125 1126 FAT_DEBUG_F("got mount for port %zu, offset %zu", port, startblock); 1127 1128 struct fat_mount *mount = calloc(1, sizeof(struct fat_mount)); 1129 if (!mount) { 1130 return LIB_ERR_MALLOC_FAIL; 1131 } 1132 mount->fat_type = type; 1133 mount->startblock = startblock; 1134 1135 // TODO(gz): We should probably decouple the FAT implementation from 1136 // all ATA related stuff to avoid these preprocessor hacks 1137#if defined(__x86_64__) || defined(__i386__) 1138 err = ahci_init(port, ahci_init_cb, mount, get_default_waitset()); 1139 if (err_is_fail(err)) { 1140 goto ahci_init_failed; 1141 } 1142 1143 while (!mount->ahci_binding && err_is_ok(mount->bind_err)) { 1144 messages_wait_and_handle_next(); 1145 } 1146 if (err_is_fail(mount->bind_err)) { 1147 err = mount->bind_err; 1148 goto ahci_init_failed; 1149 } 1150 1151 FAT_DEBUG("ahci_init completed"); 1152 1153 struct ahci_ata_rw28_binding *ahci_ata_rw28_binding; 1154 ahci_ata_rw28_binding = calloc(1, sizeof(struct ahci_ata_rw28_binding)); 1155 err = ahci_ata_rw28_init(ahci_ata_rw28_binding, 1156 get_default_waitset(), mount->ahci_binding); 1157 if (err_is_fail(err)) { 1158 goto ata_rw28_init_failed; 1159 } 1160 FAT_DEBUG("ahci_ata_rw28_init completed"); 1161 mount->ata_rw28_binding = (struct ata_rw28_binding*)ahci_ata_rw28_binding; 1162 ata_rw28_rpc_client_init(mount->ata_rw28_binding); 1163 FAT_DEBUG("ata_rw28_binding_init completed"); 1164#elif defined(__pandaboard__) 1165 FAT_DEBUG("wait for mmchs service\n"); 1166 iref_t iref; 1167 err = nameservice_blocking_lookup("mmchs", &iref); 1168 if (err_is_fail(err)) { 1169 USER_PANIC_ERR(err, "nameservice_blocking_lookup failed"); 1170 } 1171 err = ata_rw28_bind(iref, 1172 bind_cb, 1173 mount, 1174 get_default_waitset(), 1175 IDC_BIND_FLAGS_DEFAULT); 1176 if (err_is_fail(err)) { 1177 USER_PANIC_ERR(err, "bind failed"); 1178 } 1179 1180 while(mount->ata_rw28_binding == NULL) { 1181 event_dispatch(get_default_waitset()); 1182 } 1183 1184 FAT_DEBUG("ata_rw28 initialized.\n"); 1185#endif 1186 size_t size; 1187 // read data from fat boot sector 1188 uint8_t *data = malloc(ata_rw28__read_dma_block_response_buffer_MAX_ARGUMENT_SIZE); 1189 err = mount->ata_rw28_binding->rpc_tx_vtbl.read_dma_block(mount->ata_rw28_binding, 1190 mount->startblock, mount->bootsec_data, &size); 1191 if (err_is_fail(err)) { 1192 goto bootsec_read_failed; 1193 } 1194 assert(size == 512); 1195#ifdef FAT_DEBUG_ENABLED 1196 FAT_DEBUG("dumping sector 0 raw"); 1197 for (size_t i = 0; i < size; i+=16) { 1198 printf("%02x %02x %02x %02x %02x %02x %02x %02x " 1199 "%02x %02x %02x %02x %02x %02x %02x %02x\n", 1200 data[i+0], data[i+1], data[i+2], data[i+3], 1201 data[i+4], data[i+5], data[i+6], data[i+7], 1202 data[i+8], data[i+9], data[i+10], data[i+11], 1203 data[i+12], data[i+13], data[i+14], data[i+15] 1204 ); 1205 } 1206 FAT_DEBUG("end sector 0 dump"); 1207#endif 1208 1209 data = NULL; 1210 1211 if (memcmp(mount->bootsec_data+0x1FE, "\x55\xAA", 2) != 0) { 1212 FAT_DEBUG_F("boot sector check bytes do not match, expected 0x55 0xAA," 1213 " got 0x%02x 0x%02x", mount->bootsec_data[0x1FE], 1214 mount->bootsec_data[0x1FF]); 1215 goto fs_check_failed; 1216 } 1217 1218 fat_bpb_initialize(&mount->bpb, (mackerel_addr_t)&mount->bootsec_data); 1219 mount->block_size = fat_bpb_bps_rd(&mount->bpb); 1220 mount->cluster_size = fat_bpb_spc_rd(&mount->bpb); 1221 mount->fat_start = mount->startblock + fat_bpb_rsvs_rd(&mount->bpb); 1222 size_t ssc = fat_bpb_ssc_rd(&mount->bpb), lsc = fat_bpb_lsc_rd(&mount->bpb); 1223 if (ssc && lsc) { 1224 FAT_DEBUG_F("both small and large sector count are nonzero:" 1225 " ssc=%zu, lsc=%zu", ssc, lsc); 1226 goto fs_check_failed; 1227 } 1228 else if (ssc) { 1229 mount->block_count = ssc; 1230 } 1231 else if (lsc) { 1232 mount->block_count = lsc; 1233 } 1234 else { 1235 FAT_DEBUG("both small and large sector count are zero"); 1236 goto fs_check_failed; 1237 } 1238#ifdef FAT_DEBUG_ENABLED 1239 DUMP_DEV(fat_bpb, &mount->bpb, 4096); 1240#endif 1241 1242 if (mount->fat_type == FAT_TYPE_FAT16) { 1243 fat16_ebpb_initialize(&mount->ebpb.f16, (char*)&mount->bootsec_data); 1244#ifdef FAT_DEBUG_ENABLED 1245 DUMP_DEV(fat16_ebpb, &mount->ebpb.f16, 4096); 1246#endif 1247 uint8_t signature = fat16_ebpb_ebs_rd(&mount->ebpb.f16); 1248 if (signature == 0x28) { 1249 FAT_DEBUG("FAT16 EBPB signature 0x28 indicates unsupported FAT type"); 1250 goto fs_check_failed; 1251 } 1252 if (signature != 0x29) { 1253 FAT_DEBUG_F("FAT16 EBPB signature does not match, expected 0x29," 1254 " got 0x%02x", signature); 1255 goto fs_check_failed; 1256 } 1257 mount->fat_size = fat_bpb_spf_rd(&mount->bpb); 1258 mount->rootdir_start = mount->fat_start + 1259 fat_bpb_fatc_rd(&mount->bpb) * mount->fat_size; 1260 mount->clusters_start = mount->rootdir_start + 1261 CEIL_DIV(fat_bpb_rtc_rd(&mount->bpb) * fat_direntry_size, 1262 fat_bpb_bps_rd(&mount->bpb)); 1263 mount->last_cluster_start = 0xfff8; 1264 } 1265 else { 1266 fat32_ebpb_initialize(&mount->ebpb.f32, (char*)&mount->bootsec_data); 1267#ifdef FAT_DEBUG_ENABLED 1268 DUMP_DEV(fat32_ebpb, &mount->ebpb.f32, 4096); 1269#endif 1270 uint8_t signature = fat32_ebpb_ebs_rd(&mount->ebpb.f32); 1271 if (signature != 0x29) { 1272 FAT_DEBUG_F("FAT32 EBPB signature does not match, expected 0x29," 1273 " got 0x%02x", signature); 1274 goto fs_check_failed; 1275 } 1276 mount->fat_size = fat32_ebpb_spf_rd(&mount->ebpb.f32); 1277 mount->rootdir_cluster = fat32_ebpb_rtst_rd(&mount->ebpb.f32); 1278 mount->clusters_start = mount->fat_start + 1279 fat_bpb_fatc_rd(&mount->bpb) * mount->fat_size; 1280 mount->last_cluster_start = 0xfffffff8; 1281 1282 size_t fs_info_sector = fat32_ebpb_fsis_rd(&mount->ebpb.f32); 1283 if (fs_info_sector <= 0 || fs_info_sector >= mount->block_count) { 1284 FAT_DEBUG_F("File System Information Sector out of range," 1285 " block=%zu, block_count=%zu", fs_info_sector, 1286 mount->block_count); 1287 goto fs_check_failed; 1288 } 1289 struct ata_rw28_read_dma_block_response__rx_args reply; 1290 mount->ata_rw28_binding->rpc_tx_vtbl.read_dma_block(mount->ata_rw28_binding, 1291 mount->startblock + fs_info_sector, reply.buffer , 1292 &reply.buffer_size); 1293 if (memcmp(reply.buffer+0, "RRaA", 4) != 0 || 1294 memcmp(reply.buffer+0x1e4, "rrAa", 4) != 0) 1295 { 1296 FAT_DEBUG_F("File System Information Sector signatures do not match," 1297 " %"PRIx32", %"PRIx32, *(uint32_t*)(reply.buffer+0), 1298 *(uint32_t*)(reply.buffer+0x1e4)); 1299 goto fs_check_failed; 1300 } 1301 if (memcmp(reply.buffer+0x1fe, "\x55\xAA", 2) != 0) { 1302 FAT_DEBUG("File System Information Sector check bytes do not match"); 1303 goto fs_check_failed; 1304 } 1305#ifdef FAT_DEBUG_ENABLED 1306 FAT_DEBUG("dumping FSIS"); 1307 printf("nr of free clusters: %"PRIu32"\n", *(uint32_t*)(reply.buffer+0x1e8)); 1308 printf("most recently allocated cluster: %"PRIu32"\n", 1309 *(uint32_t*)(reply.buffer+0x1ec)); 1310 printf("----------------\n"); 1311#endif 1312 data = NULL; 1313 } 1314 1315#ifdef FAT_DEBUG_ENABLED 1316 FAT_DEBUG("dumping mount variables"); 1317#define D(v) printf("%-18s %zu\n", #v ":", mount-> v ) 1318 D(block_size); 1319 D(cluster_size); 1320 D(fat_start); 1321 D(fat_size); 1322 D(rootdir_start); 1323 D(rootdir_cluster); 1324 D(clusters_start); 1325#undef D 1326 printf("----------------\n"); 1327#endif 1328 1329 err = fs_cache_init(1<<7, 1<<8, &mount->block_cache); 1330 if (err_is_fail(err)) { 1331 goto cache_init_failed; 1332 } 1333 err = fs_cache_init(1<<7, 1<<8, &mount->cluster_cache); 1334 if (err_is_fail(err)) { 1335 goto cache_init_failed; 1336 } 1337 1338 *retops = &fat_ops; 1339 *retst = mount; 1340 return SYS_ERR_OK; 1341 1342cache_init_failed: 1343 if (mount->block_cache) { 1344 fs_cache_free(mount->block_cache); 1345 } 1346 if (mount->cluster_cache) { 1347 fs_cache_free(mount->cluster_cache); 1348 } 1349 1350 goto bootsec_read_failed; 1351 1352fs_check_failed: 1353 err = FAT_ERR_BAD_FS; 1354 1355bootsec_read_failed: 1356 if (data) { 1357 free(data); 1358 } 1359 data = NULL; 1360 1361#if defined(__x86_64__) || defined(__i386__) 1362ata_rw28_init_failed: 1363 free(ahci_ata_rw28_binding); 1364 bool closed = false; 1365 errval_t err2 = ahci_close(mount->ahci_binding, MKCLOSURE(ahci_close_cb, &closed)); 1366 if (err_is_ok(err2)) { 1367 while (!closed) { 1368 event_dispatch(mount->ahci_binding->waitset); 1369 } 1370 } 1371 // TODO: bindings leak? how to close flounder connection? 1372 1373ahci_init_failed: 1374 free(mount); 1375#endif 1376 1377 return err; 1378 1379} 1380