Changes in uspace/srv/fs/fat/fat_ops.c [1940326:efcebe1] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/fs/fat/fat_ops.c
r1940326 refcebe1 1 1 /* 2 2 * Copyright (c) 2008 Jakub Jermar 3 * Copyright (c) 2011 Oleg Romanenko4 3 * All rights reserved. 5 4 * … … 30 29 /** @addtogroup fs 31 30 * @{ 32 */ 31 */ 33 32 34 33 /** … … 40 39 #include "fat_dentry.h" 41 40 #include "fat_fat.h" 42 #include "fat_directory.h"43 41 #include "../../vfs/vfs.h" 44 42 #include <libfs.h> … … 58 56 #include <align.h> 59 57 #include <malloc.h> 60 #include <str.h>61 58 62 59 #define FAT_NODE(node) ((node) ? (fat_node_t *) (node)->data : NULL) … … 107 104 node->dirty = false; 108 105 node->lastc_cached_valid = false; 109 node->lastc_cached_value = 0;106 node->lastc_cached_value = FAT_CLST_LAST1; 110 107 node->currc_cached_valid = false; 111 108 node->currc_cached_bn = 0; 112 node->currc_cached_value = 0;109 node->currc_cached_value = FAT_CLST_LAST1; 113 110 } 114 111 … … 119 116 fat_dentry_t *d; 120 117 int rc; 121 118 122 119 assert(node->dirty); 123 120 124 121 bs = block_bb_get(node->idx->devmap_handle); 125 122 126 123 /* Read the block that contains the dentry of interest. */ 127 124 rc = _fat_block_get(&b, bs, node->idx->devmap_handle, node->idx->pfc, … … 139 136 d->attr = FAT_ATTR_SUBDIR; 140 137 } 141 138 142 139 /* TODO: update other fields? (e.g time fields) */ 143 140 144 141 b->dirty = true; /* need to sync block */ 145 142 rc = block_put(b); … … 258 255 fn->data = nodep; 259 256 nodep->bp = fn; 260 257 261 258 *nodepp = nodep; 262 259 return EOK; … … 294 291 * We must instantiate the node from the file system. 295 292 */ 296 293 297 294 assert(idxp->pfc); 298 295 … … 312 309 313 310 d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs)); 314 if (FAT_IS_FAT32(bs)) {315 nodep->firstc = uint16_t_le2host(d->firstc_lo) |316 (uint16_t_le2host(d->firstc_hi) << 16);317 }318 else319 nodep->firstc = uint16_t_le2host(d->firstc);320 321 311 if (d->attr & FAT_ATTR_SUBDIR) { 322 /* 312 /* 323 313 * The only directory which does not have this bit set is the 324 314 * root directory itself. The root directory node is handled … … 326 316 */ 327 317 nodep->type = FAT_DIRECTORY; 328 329 318 /* 330 319 * Unfortunately, the 'size' field of the FAT dentry is not … … 332 321 * size of the directory by walking the FAT. 333 322 */ 334 uint32_t clusters; 335 rc = fat_clusters_get(&clusters, bs, idxp->devmap_handle, nodep->firstc); 323 uint16_t clusters; 324 rc = fat_clusters_get(&clusters, bs, idxp->devmap_handle, 325 uint16_t_le2host(d->firstc)); 336 326 if (rc != EOK) { 337 327 (void) block_put(b); … … 344 334 nodep->size = uint32_t_le2host(d->size); 345 335 } 346 336 nodep->firstc = uint16_t_le2host(d->firstc); 347 337 nodep->lnkcnt = 1; 348 338 nodep->refcnt = 1; … … 373 363 int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component) 374 364 { 365 fat_bs_t *bs; 375 366 fat_node_t *parentp = FAT_NODE(pfn); 376 char name[FAT_LFN_NAME_SIZE]; 367 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; 368 unsigned i, j; 369 unsigned blocks; 377 370 fat_dentry_t *d; 378 371 devmap_handle_t devmap_handle; 372 block_t *b; 379 373 int rc; 380 374 … … 382 376 devmap_handle = parentp->idx->devmap_handle; 383 377 fibril_mutex_unlock(&parentp->idx->lock); 384 385 fat_directory_t di; 386 rc = fat_directory_open(parentp, &di); 387 if (rc != EOK) 388 return rc; 389 390 while (fat_directory_read(&di, name, &d) == EOK) { 391 if (fat_dentry_namecmp(name, component) == 0) { 392 /* hit */ 393 fat_node_t *nodep; 394 aoff64_t o = di.pos % (BPS(di.bs) / sizeof(fat_dentry_t)); 395 fat_idx_t *idx = fat_idx_get_by_pos(devmap_handle, 396 parentp->firstc, di.bnum * DPS(di.bs) + o); 397 if (!idx) { 398 /* 399 * Can happen if memory is low or if we 400 * run out of 32-bit indices. 401 */ 402 rc = fat_directory_close(&di); 403 return (rc == EOK) ? ENOMEM : rc; 378 379 bs = block_bb_get(devmap_handle); 380 blocks = parentp->size / BPS(bs); 381 for (i = 0; i < blocks; i++) { 382 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 383 if (rc != EOK) 384 return rc; 385 for (j = 0; j < DPS(bs); j++) { 386 d = ((fat_dentry_t *)b->data) + j; 387 switch (fat_classify_dentry(d)) { 388 case FAT_DENTRY_SKIP: 389 case FAT_DENTRY_FREE: 390 continue; 391 case FAT_DENTRY_LAST: 392 /* miss */ 393 rc = block_put(b); 394 *rfn = NULL; 395 return rc; 396 default: 397 case FAT_DENTRY_VALID: 398 fat_dentry_name_get(d, name); 399 break; 404 400 } 405 rc = fat_node_get_core(&nodep, idx); 406 fibril_mutex_unlock(&idx->lock); 407 if (rc != EOK) { 408 (void) fat_directory_close(&di); 401 if (fat_dentry_namecmp(name, component) == 0) { 402 /* hit */ 403 fat_node_t *nodep; 404 fat_idx_t *idx = fat_idx_get_by_pos(devmap_handle, 405 parentp->firstc, i * DPS(bs) + j); 406 if (!idx) { 407 /* 408 * Can happen if memory is low or if we 409 * run out of 32-bit indices. 410 */ 411 rc = block_put(b); 412 return (rc == EOK) ? ENOMEM : rc; 413 } 414 rc = fat_node_get_core(&nodep, idx); 415 fibril_mutex_unlock(&idx->lock); 416 if (rc != EOK) { 417 (void) block_put(b); 418 return rc; 419 } 420 *rfn = FS_NODE(nodep); 421 rc = block_put(b); 422 if (rc != EOK) 423 (void) fat_node_put(*rfn); 409 424 return rc; 410 425 } 411 *rfn = FS_NODE(nodep); 412 rc = fat_directory_close(&di); 413 if (rc != EOK) 414 (void) fat_node_put(*rfn); 415 return rc; 416 } else { 417 rc = fat_directory_next(&di); 418 if (rc != EOK) 419 break; 420 } 421 } 422 (void) fat_directory_close(&di); 426 } 427 rc = block_put(b); 428 if (rc != EOK) 429 return rc; 430 } 431 423 432 *rfn = NULL; 424 433 return EOK; … … 512 521 rc = fat_idx_get_new(&idxp, devmap_handle); 513 522 if (rc != EOK) { 514 (void) fat_free_clusters(bs, devmap_handle, mcl); 523 (void) fat_free_clusters(bs, devmap_handle, mcl); 515 524 (void) fat_node_put(FS_NODE(nodep)); 516 525 return rc; … … 582 591 fat_bs_t *bs; 583 592 block_t *b; 584 fat_directory_t di; 585 fat_dentry_t de; 593 unsigned i, j; 594 unsigned blocks; 595 fat_cluster_t mcl, lcl; 586 596 int rc; 587 597 … … 597 607 fibril_mutex_unlock(&childp->lock); 598 608 599 if (!fat_valid_name(name)) 609 if (!fat_dentry_name_verify(name)) { 610 /* 611 * Attempt to create unsupported name. 612 */ 600 613 return ENOTSUP; 601 614 } 615 616 /* 617 * Get us an unused parent node's dentry or grow the parent and allocate 618 * a new one. 619 */ 620 602 621 fibril_mutex_lock(&parentp->idx->lock); 603 622 bs = block_bb_get(parentp->idx->devmap_handle); 604 rc = fat_directory_open(parentp, &di); 605 if (rc != EOK) 606 return rc; 607 623 624 blocks = parentp->size / BPS(bs); 625 626 for (i = 0; i < blocks; i++) { 627 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 628 if (rc != EOK) { 629 fibril_mutex_unlock(&parentp->idx->lock); 630 return rc; 631 } 632 for (j = 0; j < DPS(bs); j++) { 633 d = ((fat_dentry_t *)b->data) + j; 634 switch (fat_classify_dentry(d)) { 635 case FAT_DENTRY_SKIP: 636 case FAT_DENTRY_VALID: 637 /* skipping used and meta entries */ 638 continue; 639 case FAT_DENTRY_FREE: 640 case FAT_DENTRY_LAST: 641 /* found an empty slot */ 642 goto hit; 643 } 644 } 645 rc = block_put(b); 646 if (rc != EOK) { 647 fibril_mutex_unlock(&parentp->idx->lock); 648 return rc; 649 } 650 } 651 j = 0; 652 653 /* 654 * We need to grow the parent in order to create a new unused dentry. 655 */ 656 if (parentp->firstc == FAT_CLST_ROOT) { 657 /* Can't grow the root directory. */ 658 fibril_mutex_unlock(&parentp->idx->lock); 659 return ENOSPC; 660 } 661 rc = fat_alloc_clusters(bs, parentp->idx->devmap_handle, 1, &mcl, &lcl); 662 if (rc != EOK) { 663 fibril_mutex_unlock(&parentp->idx->lock); 664 return rc; 665 } 666 rc = fat_zero_cluster(bs, parentp->idx->devmap_handle, mcl); 667 if (rc != EOK) { 668 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl); 669 fibril_mutex_unlock(&parentp->idx->lock); 670 return rc; 671 } 672 rc = fat_append_clusters(bs, parentp, mcl, lcl); 673 if (rc != EOK) { 674 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl); 675 fibril_mutex_unlock(&parentp->idx->lock); 676 return rc; 677 } 678 parentp->size += BPS(bs) * SPC(bs); 679 parentp->dirty = true; /* need to sync node */ 680 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE); 681 if (rc != EOK) { 682 fibril_mutex_unlock(&parentp->idx->lock); 683 return rc; 684 } 685 d = (fat_dentry_t *)b->data; 686 687 hit: 608 688 /* 609 689 * At this point we only establish the link between the parent and the … … 612 692 * dentry data is kept in the child node structure. 613 693 */ 614 memset(&de, 0, sizeof(fat_dentry_t)); 615 616 rc = fat_directory_write(&di, name, &de); 617 if (rc!=EOK) 618 return rc; 619 rc = fat_directory_close(&di); 620 if (rc!=EOK) 621 return rc; 622 694 memset(d, 0, sizeof(fat_dentry_t)); 695 fat_dentry_name_set(d, name); 696 b->dirty = true; /* need to sync block */ 697 rc = block_put(b); 623 698 fibril_mutex_unlock(&parentp->idx->lock); 624 if (rc != EOK) 699 if (rc != EOK) 625 700 return rc; 626 701 627 702 fibril_mutex_lock(&childp->idx->lock); 628 703 629 704 if (childp->type == FAT_DIRECTORY) { 630 705 /* … … 645 720 d = (fat_dentry_t *) b->data; 646 721 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) || 647 ( bcmp(d->name, FAT_NAME_DOT, FAT_NAME_LEN)) == 0) {722 (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) { 648 723 memset(d, 0, sizeof(fat_dentry_t)); 649 724 memcpy(d->name, FAT_NAME_DOT, FAT_NAME_LEN); … … 655 730 d++; 656 731 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) || 657 ( bcmp(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN) == 0)) {732 (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) { 658 733 memset(d, 0, sizeof(fat_dentry_t)); 659 734 memcpy(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN); 660 735 memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN); 661 736 d->attr = FAT_ATTR_SUBDIR; 662 d->firstc = (parentp->firstc == FAT_ ROOT_CLST(bs)) ?663 host2uint16_t_le(FAT_CLST_R OOTPAR) :737 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ? 738 host2uint16_t_le(FAT_CLST_RES0) : 664 739 host2uint16_t_le(parentp->firstc); 665 740 /* TODO: initialize also the date/time members. */ … … 675 750 676 751 childp->idx->pfc = parentp->firstc; 677 childp->idx->pdi = di.pos; /* di.pos holds absolute position of SFN entry */752 childp->idx->pdi = i * DPS(bs) + j; 678 753 fibril_mutex_unlock(&childp->idx->lock); 679 754 … … 695 770 fat_node_t *parentp = FAT_NODE(pfn); 696 771 fat_node_t *childp = FAT_NODE(cfn); 772 fat_bs_t *bs; 773 fat_dentry_t *d; 774 block_t *b; 697 775 bool has_children; 698 776 int rc; … … 700 778 if (!parentp) 701 779 return EBUSY; 702 780 703 781 rc = fat_has_children(&has_children, cfn); 704 782 if (rc != EOK) … … 711 789 assert(childp->lnkcnt == 1); 712 790 fibril_mutex_lock(&childp->idx->lock); 713 714 fat_directory_t di; 715 rc = fat_directory_open(parentp,&di); 716 if (rc != EOK) 791 bs = block_bb_get(childp->idx->devmap_handle); 792 793 rc = _fat_block_get(&b, bs, childp->idx->devmap_handle, childp->idx->pfc, 794 NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs), 795 BLOCK_FLAGS_NONE); 796 if (rc != EOK) 717 797 goto error; 718 rc = fat_directory_seek(&di, childp->idx->pdi); 719 if (rc != EOK) 720 goto error; 721 rc = fat_directory_erase(&di); 722 if (rc != EOK) 723 goto error; 724 rc = fat_directory_close(&di); 798 d = (fat_dentry_t *)b->data + 799 (childp->idx->pdi % (BPS(bs) / sizeof(fat_dentry_t))); 800 /* mark the dentry as not-currently-used */ 801 d->name[0] = FAT_DENTRY_ERASED; 802 b->dirty = true; /* need to sync block */ 803 rc = block_put(b); 725 804 if (rc != EOK) 726 805 goto error; … … 741 820 742 821 error: 743 (void) fat_directory_close(&di); 822 fibril_mutex_unlock(&parentp->idx->lock); 823 fibril_mutex_unlock(&childp->lock); 744 824 fibril_mutex_unlock(&childp->idx->lock); 745 fibril_mutex_unlock(&childp->lock);746 fibril_mutex_unlock(&parentp->lock);747 825 return rc; 748 826 } … … 761 839 return EOK; 762 840 } 763 841 764 842 fibril_mutex_lock(&nodep->idx->lock); 765 843 bs = block_bb_get(nodep->idx->devmap_handle); … … 769 847 for (i = 0; i < blocks; i++) { 770 848 fat_dentry_t *d; 771 849 772 850 rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE); 773 851 if (rc != EOK) { … … 797 875 if (rc != EOK) { 798 876 fibril_mutex_unlock(&nodep->idx->lock); 799 return rc; 877 return rc; 800 878 } 801 879 } … … 868 946 fat_bs_t *bs; 869 947 int rc; 870 948 871 949 /* Check for option enabling write through. */ 872 950 if (str_cmp(opts, "wtcache") == 0) … … 889 967 /* get the buffer with the boot sector */ 890 968 bs = block_bb_get(devmap_handle); 891 969 892 970 if (BPS(bs) != BS_SIZE) { 893 971 block_fini(devmap_handle); … … 925 1003 return ENOMEM; 926 1004 } 927 928 1005 fs_node_initialize(rfn); 929 1006 fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t)); … … 950 1027 951 1028 rootp->type = FAT_DIRECTORY; 952 rootp->firstc = FAT_ ROOT_CLST(bs);1029 rootp->firstc = FAT_CLST_ROOT; 953 1030 rootp->refcnt = 1; 954 1031 rootp->lnkcnt = 0; /* FS root is not linked */ 955 956 if (FAT_IS_FAT32(bs)) { 957 uint32_t clusters; 958 rc = fat_clusters_get(&clusters, bs, devmap_handle, rootp->firstc); 959 if (rc != EOK) { 960 free(rfn); 961 free(rootp); 962 (void) block_cache_fini(devmap_handle); 963 block_fini(devmap_handle); 964 fat_idx_fini_by_devmap_handle(devmap_handle); 965 return ENOTSUP; 966 } 967 rootp->size = BPS(bs) * SPC(bs) * clusters; 968 } else 969 rootp->size = RDE(bs) * sizeof(fat_dentry_t); 970 1032 rootp->size = RDE(bs) * sizeof(fat_dentry_t); 971 1033 rootp->idx = ridxp; 972 1034 ridxp->nodep = rootp; 973 1035 rootp->bp = rfn; 974 1036 rfn->data = rootp; 975 1037 976 1038 fibril_mutex_unlock(&ridxp->lock); 977 1039 … … 1002 1064 return EBUSY; 1003 1065 } 1004 1066 1005 1067 /* 1006 1068 * Put the root node and force it to the FAT free node list. … … 1079 1141 } 1080 1142 } else { 1143 unsigned bnum; 1081 1144 aoff64_t spos = pos; 1082 char name[FAT_ LFN_NAME_SIZE];1145 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; 1083 1146 fat_dentry_t *d; 1084 1147 … … 1087 1150 assert(BPS(bs) % sizeof(fat_dentry_t) == 0); 1088 1151 1089 fat_directory_t di; 1090 rc = fat_directory_open(nodep, &di); 1091 if (rc != EOK) goto err; 1092 rc = fat_directory_seek(&di, pos); 1093 if (rc != EOK) { 1094 (void) fat_directory_close(&di); 1095 goto err; 1096 } 1097 1098 rc = fat_directory_read(&di, name, &d); 1099 if (rc == EOK) goto hit; 1100 if (rc == ENOENT) goto miss; 1101 1102 err: 1103 (void) fat_node_put(fn); 1104 async_answer_0(callid, rc); 1105 return rc; 1106 1152 /* 1153 * Our strategy for readdir() is to use the position pointer as 1154 * an index into the array of all dentries. On entry, it points 1155 * to the first unread dentry. If we skip any dentries, we bump 1156 * the position pointer accordingly. 1157 */ 1158 bnum = (pos * sizeof(fat_dentry_t)) / BPS(bs); 1159 while (bnum < nodep->size / BPS(bs)) { 1160 aoff64_t o; 1161 1162 rc = fat_block_get(&b, bs, nodep, bnum, 1163 BLOCK_FLAGS_NONE); 1164 if (rc != EOK) 1165 goto err; 1166 for (o = pos % (BPS(bs) / sizeof(fat_dentry_t)); 1167 o < BPS(bs) / sizeof(fat_dentry_t); 1168 o++, pos++) { 1169 d = ((fat_dentry_t *)b->data) + o; 1170 switch (fat_classify_dentry(d)) { 1171 case FAT_DENTRY_SKIP: 1172 case FAT_DENTRY_FREE: 1173 continue; 1174 case FAT_DENTRY_LAST: 1175 rc = block_put(b); 1176 if (rc != EOK) 1177 goto err; 1178 goto miss; 1179 default: 1180 case FAT_DENTRY_VALID: 1181 fat_dentry_name_get(d, name); 1182 rc = block_put(b); 1183 if (rc != EOK) 1184 goto err; 1185 goto hit; 1186 } 1187 } 1188 rc = block_put(b); 1189 if (rc != EOK) 1190 goto err; 1191 bnum++; 1192 } 1107 1193 miss: 1108 rc = fat_directory_close(&di);1109 if (rc!=EOK)1110 goto err;1111 1194 rc = fat_node_put(fn); 1112 1195 async_answer_0(callid, rc != EOK ? rc : ENOENT); … … 1114 1197 return rc != EOK ? rc : ENOENT; 1115 1198 1199 err: 1200 (void) fat_node_put(fn); 1201 async_answer_0(callid, rc); 1202 return rc; 1203 1116 1204 hit: 1117 pos = di.pos;1118 rc = fat_directory_close(&di);1119 if (rc!=EOK)1120 goto err;1121 1205 (void) async_data_read_finalize(callid, name, str_size(name) + 1); 1122 bytes = (pos - spos) +1;1206 bytes = (pos - spos) + 1; 1123 1207 } 1124 1208 … … 1140 1224 int flags = BLOCK_FLAGS_NONE; 1141 1225 int rc; 1142 1226 1143 1227 rc = fat_node_get(&fn, devmap_handle, index); 1144 1228 if (rc != EOK) … … 1147 1231 return ENOENT; 1148 1232 nodep = FAT_NODE(fn); 1149 1233 1150 1234 ipc_callid_t callid; 1151 1235 size_t len; … … 1163 1247 * but this one greatly simplifies fat_write(). Note that we can afford 1164 1248 * to do this because the client must be ready to handle the return 1165 * value signalizing a smaller number of bytes written. 1166 */ 1249 * value signalizing a smaller number of bytes written. 1250 */ 1167 1251 bytes = min(len, BPS(bs) - pos % BPS(bs)); 1168 1252 if (bytes == BPS(bs)) 1169 1253 flags |= BLOCK_FLAGS_NOREAD; 1170 1254 1171 1255 boundary = ROUND_UP(nodep->size, BPC(bs)); 1172 1256 if (pos < boundary) { … … 1211 1295 */ 1212 1296 unsigned nclsts; 1213 fat_cluster_t mcl, lcl; 1214 1297 fat_cluster_t mcl, lcl; 1298 1215 1299 nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs); 1216 1300 /* create an independent chain of nclsts clusters in all FATs */ … … 1296 1380 nodep->size = size; 1297 1381 nodep->dirty = true; /* need to sync node */ 1298 rc = EOK; 1382 rc = EOK; 1299 1383 } else { 1300 1384 /* … … 1317 1401 nodep->size = size; 1318 1402 nodep->dirty = true; /* need to sync node */ 1319 rc = EOK; 1403 rc = EOK; 1320 1404 } 1321 1405 out: … … 1360 1444 if (!fn) 1361 1445 return ENOENT; 1362 1446 1363 1447 fat_node_t *nodep = FAT_NODE(fn); 1364 1448 1365 1449 nodep->dirty = true; 1366 1450 rc = fat_node_sync(nodep); 1367 1451 1368 1452 fat_node_put(fn); 1369 1453 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.