Rev 2787 | Rev 3011 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2787 | Rev 2925 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* |
1 | /* |
2 | * Copyright (c) 2007 Jakub Jermar |
2 | * Copyright (c) 2008 Jakub Jermar |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
Line 35... | Line 35... | ||
35 | * @brief Implementation of VFS operations for the FAT file system server. |
35 | * @brief Implementation of VFS operations for the FAT file system server. |
36 | */ |
36 | */ |
37 | 37 | ||
38 | #include "fat.h" |
38 | #include "fat.h" |
39 | #include "../../vfs/vfs.h" |
39 | #include "../../vfs/vfs.h" |
- | 40 | #include <libfs.h> |
|
40 | #include <ipc/ipc.h> |
41 | #include <ipc/ipc.h> |
41 | #include <async.h> |
42 | #include <async.h> |
42 | #include <errno.h> |
43 | #include <errno.h> |
- | 44 | #include <string.h> |
|
- | 45 | #include <byteorder.h> |
|
- | 46 | #include <libadt/hash_table.h> |
|
- | 47 | #include <libadt/list.h> |
|
- | 48 | #include <assert.h> |
|
- | 49 | #include <futex.h> |
|
43 | 50 | ||
- | 51 | #define BS_BLOCK 0 |
|
- | 52 | ||
44 | #define PLB_GET_CHAR(i) (fat_reg.plb_ro[(i) % PLB_SIZE]) |
53 | /** List of free FAT nodes that still contain valid data. */ |
- | 54 | LIST_INITIALIZE(ffn_head); |
|
45 | 55 | ||
46 | #define FAT_NAME_LEN 8 |
56 | #define FAT_NAME_LEN 8 |
47 | #define FAT_EXT_LEN 3 |
57 | #define FAT_EXT_LEN 3 |
48 | 58 | ||
49 | #define FAT_PAD ' ' |
59 | #define FAT_PAD ' ' |
Line 51... | Line 61... | ||
51 | #define FAT_DENTRY_UNUSED 0x00 |
61 | #define FAT_DENTRY_UNUSED 0x00 |
52 | #define FAT_DENTRY_E5_ESC 0x05 |
62 | #define FAT_DENTRY_E5_ESC 0x05 |
53 | #define FAT_DENTRY_DOT 0x2e |
63 | #define FAT_DENTRY_DOT 0x2e |
54 | #define FAT_DENTRY_ERASED 0xe5 |
64 | #define FAT_DENTRY_ERASED 0xe5 |
55 | 65 | ||
56 | /** Compare one component of path to a directory entry. |
- | |
57 | * |
- | |
58 | * @param dentry Directory entry to compare the path component with. |
- | |
59 | * @param start Index into PLB where the path component starts. |
- | |
60 | * @param last Index of the last character of the path in PLB. |
- | |
61 | * |
- | |
62 | * @return Zero on failure or delta such that (index + delta) % |
- | |
63 | * PLB_SIZE points to a new path component in PLB. |
- | |
64 | */ |
- | |
65 | static unsigned match_path_component(fat_dentry_t *dentry, unsigned start, |
66 | static void dentry_name_canonify(fat_dentry_t *d, char *buf) |
66 | unsigned last) |
- | |
67 | { |
67 | { |
68 | unsigned cur; /* current position in PLB */ |
- | |
69 | int pos; /* current position in dentry->name or dentry->ext */ |
- | |
70 | bool name_processed = false; |
- | |
71 | bool dot_processed = false; |
- | |
72 | bool ext_processed = false; |
68 | int i; |
73 | 69 | ||
74 | if (last < start) |
- | |
75 | last += PLB_SIZE; |
- | |
76 | for (pos = 0, cur = start; (cur <= last) && (PLB_GET_CHAR(cur) != '/'); |
- | |
77 | pos++, cur++) { |
- | |
78 | if (!name_processed) { |
- | |
79 | if ((pos == FAT_NAME_LEN - 1) || |
70 | for (i = 0; i < FAT_NAME_LEN; i++) { |
80 | (dentry->name[pos + 1] == FAT_PAD)) { |
- | |
81 | /* this is the last character in name */ |
- | |
82 | name_processed = true; |
- | |
83 | } |
- | |
84 | if (dentry->name[0] == FAT_PAD) { |
71 | if (d->name[i] == FAT_PAD) { |
85 | /* name is empty */ |
- | |
86 | name_processed = true; |
- | |
87 | } else if ((pos == 0) && (dentry->name[pos] == |
- | |
88 | FAT_DENTRY_E5_ESC)) { |
- | |
89 | if (PLB_GET_CHAR(cur) == 0xe5) |
- | |
90 | continue; |
- | |
91 | else |
72 | buf++; |
92 | return 0; /* character mismatch */ |
- | |
93 | } else { |
- | |
94 | if (PLB_GET_CHAR(cur) == dentry->name[pos]) |
- | |
95 | continue; |
- | |
96 | else |
73 | break; |
97 | return 0; /* character mismatch */ |
- | |
98 | } |
- | |
99 | } |
74 | } |
- | 75 | if (d->name[i] == FAT_DENTRY_E5_ESC) |
|
- | 76 | *buf++ = 0xe5; |
|
- | 77 | else |
|
100 | if (!dot_processed) { |
78 | *buf++ = d->name[i]; |
- | 79 | } |
|
101 | dot_processed = true; |
80 | if (d->ext[0] != FAT_PAD) |
102 | pos = -1; |
81 | *buf++ = '.'; |
- | 82 | for (i = 0; i < FAT_EXT_LEN; i++) { |
|
103 | if (PLB_GET_CHAR(cur) != '.') |
83 | if (d->ext[i] == FAT_PAD) { |
104 | return 0; |
84 | *buf = '\0'; |
105 | continue; |
85 | return; |
106 | } |
86 | } |
- | 87 | if (d->ext[i] == FAT_DENTRY_E5_ESC) |
|
- | 88 | *buf++ = 0xe5; |
|
- | 89 | else |
|
- | 90 | *buf++ = d->ext[i]; |
|
- | 91 | } |
|
- | 92 | } |
|
- | 93 | ||
- | 94 | /* TODO move somewhere else */ |
|
- | 95 | typedef struct { |
|
- | 96 | void *data; |
|
- | 97 | } block_t; |
|
- | 98 | ||
- | 99 | static block_t *block_get(dev_handle_t dev_handle, off_t offset) |
|
- | 100 | { |
|
- | 101 | return NULL; /* TODO */ |
|
- | 102 | } |
|
- | 103 | ||
- | 104 | static void block_put(block_t *block) |
|
- | 105 | { |
|
- | 106 | /* TODO */ |
|
- | 107 | } |
|
- | 108 | ||
- | 109 | #define FAT_BS(b) ((fat_bs_t *)((b)->data)) |
|
- | 110 | ||
- | 111 | #define FAT_CLST_RES0 0x0000 |
|
- | 112 | #define FAT_CLST_RES1 0x0001 /* internally used to mark root directory */ |
|
- | 113 | #define FAT_CLST_FIRST 0x0002 |
|
- | 114 | #define FAT_CLST_BAD 0xfff7 |
|
- | 115 | #define FAT_CLST_LAST1 0xfff8 |
|
- | 116 | #define FAT_CLST_LAST8 0xffff |
|
- | 117 | ||
- | 118 | #define fat_block_get(np, off) \ |
|
- | 119 | _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off)) |
|
- | 120 | ||
- | 121 | static block_t * |
|
- | 122 | _fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset) |
|
- | 123 | { |
|
- | 124 | block_t *bb; |
|
- | 125 | block_t *b; |
|
- | 126 | unsigned bps; |
|
- | 127 | unsigned spc; |
|
- | 128 | unsigned rscnt; /* block address of the first FAT */ |
|
- | 129 | unsigned fatcnt; |
|
- | 130 | unsigned rde; |
|
- | 131 | unsigned rds; /* root directory size */ |
|
- | 132 | unsigned sf; |
|
- | 133 | unsigned ssa; /* size of the system area */ |
|
- | 134 | unsigned clusters; |
|
- | 135 | fat_cluster_t clst = firstc; |
|
- | 136 | unsigned i; |
|
- | 137 | ||
- | 138 | bb = block_get(dev_handle, BS_BLOCK); |
|
- | 139 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
|
107 | if (!ext_processed) { |
140 | spc = FAT_BS(bb)->spc; |
- | 141 | rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
|
- | 142 | fatcnt = FAT_BS(bb)->fatcnt; |
|
- | 143 | rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max); |
|
- | 144 | sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat); |
|
- | 145 | block_put(bb); |
|
- | 146 | ||
- | 147 | rds = (sizeof(fat_dentry_t) * rde) / bps; |
|
- | 148 | rds += ((sizeof(fat_dentry_t) * rde) % bps != 0); |
|
- | 149 | ssa = rscnt + fatcnt * sf + rds; |
|
- | 150 | ||
108 | if ((pos == FAT_EXT_LEN - 1) || |
151 | if (firstc == FAT_CLST_RES1) { |
- | 152 | /* root directory special case */ |
|
- | 153 | assert(offset < rds); |
|
- | 154 | b = block_get(dev_handle, rscnt + fatcnt * sf + offset); |
|
- | 155 | return b; |
|
- | 156 | } |
|
- | 157 | ||
- | 158 | clusters = offset / spc; |
|
- | 159 | for (i = 0; i < clusters; i++) { |
|
- | 160 | unsigned fsec; /* sector offset relative to FAT1 */ |
|
- | 161 | unsigned fidx; /* FAT1 entry index */ |
|
- | 162 | ||
- | 163 | assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD); |
|
- | 164 | fsec = (clst * sizeof(fat_cluster_t)) / bps; |
|
- | 165 | fidx = clst % (bps / sizeof(fat_cluster_t)); |
|
- | 166 | /* read FAT1 */ |
|
- | 167 | b = block_get(dev_handle, rscnt + fsec); |
|
- | 168 | clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
|
- | 169 | assert(clst != FAT_CLST_BAD); |
|
- | 170 | assert(clst < FAT_CLST_LAST1); |
|
- | 171 | block_put(b); |
|
- | 172 | } |
|
- | 173 | ||
- | 174 | b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc + |
|
- | 175 | offset % spc); |
|
- | 176 | ||
- | 177 | return b; |
|
- | 178 | } |
|
- | 179 | ||
- | 180 | static void fat_node_initialize(fat_node_t *node) |
|
- | 181 | { |
|
- | 182 | node->idx = NULL; |
|
- | 183 | node->type = 0; |
|
- | 184 | link_initialize(&node->ffn_link); |
|
- | 185 | node->size = 0; |
|
- | 186 | node->lnkcnt = 0; |
|
- | 187 | node->refcnt = 0; |
|
- | 188 | node->dirty = false; |
|
- | 189 | } |
|
- | 190 | ||
- | 191 | static uint16_t fat_bps_get(dev_handle_t dev_handle) |
|
- | 192 | { |
|
- | 193 | block_t *bb; |
|
- | 194 | uint16_t bps; |
|
- | 195 | ||
- | 196 | bb = block_get(dev_handle, BS_BLOCK); |
|
- | 197 | assert(bb != NULL); |
|
- | 198 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
|
- | 199 | block_put(bb); |
|
- | 200 | ||
- | 201 | return bps; |
|
- | 202 | } |
|
- | 203 | ||
- | 204 | typedef enum { |
|
- | 205 | FAT_DENTRY_SKIP, |
|
- | 206 | FAT_DENTRY_LAST, |
|
- | 207 | FAT_DENTRY_VALID |
|
- | 208 | } fat_dentry_clsf_t; |
|
- | 209 | ||
- | 210 | static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d) |
|
- | 211 | { |
|
- | 212 | if (d->attr & FAT_ATTR_VOLLABEL) { |
|
- | 213 | /* volume label entry */ |
|
- | 214 | return FAT_DENTRY_SKIP; |
|
- | 215 | } |
|
109 | (dentry->ext[pos + 1] == FAT_PAD)) { |
216 | if (d->name[0] == FAT_DENTRY_ERASED) { |
110 | /* this is the last character in ext */ |
217 | /* not-currently-used entry */ |
- | 218 | return FAT_DENTRY_SKIP; |
|
- | 219 | } |
|
- | 220 | if (d->name[0] == FAT_DENTRY_UNUSED) { |
|
111 | ext_processed = true; |
221 | /* never used entry */ |
- | 222 | return FAT_DENTRY_LAST; |
|
112 | } |
223 | } |
113 | if (dentry->ext[0] == FAT_PAD) { |
224 | if (d->name[0] == FAT_DENTRY_DOT) { |
- | 225 | /* |
|
- | 226 | * Most likely '.' or '..'. |
|
- | 227 | * It cannot occur in a regular file name. |
|
- | 228 | */ |
|
- | 229 | return FAT_DENTRY_SKIP; |
|
- | 230 | } |
|
- | 231 | return FAT_DENTRY_VALID; |
|
- | 232 | } |
|
- | 233 | ||
- | 234 | static void fat_node_sync(fat_node_t *node) |
|
- | 235 | { |
|
- | 236 | /* TODO */ |
|
- | 237 | } |
|
- | 238 | ||
- | 239 | /** Instantiate a FAT in-core node. */ |
|
- | 240 | static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index) |
|
- | 241 | { |
|
- | 242 | fat_idx_t *idx; |
|
- | 243 | block_t *b; |
|
- | 244 | fat_dentry_t *d; |
|
- | 245 | fat_node_t *nodep; |
|
- | 246 | unsigned bps; |
|
- | 247 | unsigned dps; |
|
- | 248 | ||
- | 249 | idx = fat_idx_get_by_index(dev_handle, index); |
|
- | 250 | if (!idx) |
|
- | 251 | return NULL; |
|
- | 252 | ||
- | 253 | if (idx->nodep) { |
|
- | 254 | /* |
|
- | 255 | * We are lucky. |
|
- | 256 | * The node is already instantiated in memory. |
|
- | 257 | */ |
|
- | 258 | if (!idx->nodep->refcnt++) |
|
- | 259 | list_remove(&nodep->ffn_link); |
|
- | 260 | return idx->nodep; |
|
- | 261 | } |
|
- | 262 | ||
- | 263 | /* |
|
114 | /* ext is empty; the match will fail */ |
264 | * We must instantiate the node from the file system. |
- | 265 | */ |
|
- | 266 | ||
- | 267 | assert(idx->pfc); |
|
- | 268 | ||
- | 269 | if (!list_empty(&ffn_head)) { |
|
- | 270 | /* Try to use a cached unused node structure. */ |
|
- | 271 | nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link); |
|
- | 272 | if (nodep->dirty) |
|
115 | ext_processed = true; |
273 | fat_node_sync(nodep); |
- | 274 | list_remove(&nodep->ffn_link); |
|
- | 275 | nodep->idx->nodep = NULL; |
|
- | 276 | } else { |
|
- | 277 | /* Try to allocate a new node structure. */ |
|
- | 278 | nodep = (fat_node_t *)malloc(sizeof(fat_node_t)); |
|
- | 279 | if (!nodep) |
|
- | 280 | return NULL; |
|
- | 281 | } |
|
- | 282 | fat_node_initialize(nodep); |
|
- | 283 | ||
- | 284 | bps = fat_bps_get(dev_handle); |
|
- | 285 | dps = bps / sizeof(fat_dentry_t); |
|
- | 286 | ||
116 | } else if (PLB_GET_CHAR(cur) == dentry->ext[pos]) { |
287 | /* Read the block that contains the dentry of interest. */ |
- | 288 | b = _fat_block_get(dev_handle, idx->pfc, |
|
- | 289 | (idx->pdi * sizeof(fat_dentry_t)) / bps); |
|
- | 290 | assert(b); |
|
- | 291 | ||
- | 292 | d = ((fat_dentry_t *)b->data) + (idx->pdi % dps); |
|
- | 293 | if (d->attr & FAT_ATTR_SUBDIR) { |
|
- | 294 | /* |
|
- | 295 | * The only directory which does not have this bit set is the |
|
- | 296 | * root directory itself. The root directory node is handled |
|
- | 297 | * and initialized elsewhere. |
|
- | 298 | */ |
|
- | 299 | nodep->type = FAT_DIRECTORY; |
|
- | 300 | } else { |
|
- | 301 | nodep->type = FAT_FILE; |
|
- | 302 | } |
|
- | 303 | nodep->firstc = uint16_t_le2host(d->firstc); |
|
- | 304 | nodep->size = uint32_t_le2host(d->size); |
|
- | 305 | nodep->lnkcnt = 1; |
|
- | 306 | nodep->refcnt = 1; |
|
- | 307 | ||
- | 308 | block_put(b); |
|
- | 309 | ||
- | 310 | /* Link the idx structure with the node structure. */ |
|
- | 311 | nodep->idx = idx; |
|
- | 312 | idx->nodep = nodep; |
|
- | 313 | ||
- | 314 | return nodep; |
|
- | 315 | } |
|
- | 316 | ||
- | 317 | static void fat_node_put(void *node) |
|
- | 318 | { |
|
- | 319 | fat_node_t *nodep = (fat_node_t *)node; |
|
- | 320 | ||
- | 321 | if (!--nodep->refcnt) { |
|
- | 322 | list_append(&nodep->ffn_link, &ffn_head); |
|
- | 323 | } |
|
- | 324 | } |
|
- | 325 | ||
- | 326 | static void *fat_create(int flags) |
|
- | 327 | { |
|
- | 328 | return NULL; /* not supported at the moment */ |
|
- | 329 | } |
|
- | 330 | ||
- | 331 | static int fat_destroy(void *node) |
|
- | 332 | { |
|
- | 333 | return ENOTSUP; /* not supported at the moment */ |
|
- | 334 | } |
|
- | 335 | ||
- | 336 | static bool fat_link(void *prnt, void *chld, const char *name) |
|
- | 337 | { |
|
- | 338 | return false; /* not supported at the moment */ |
|
- | 339 | } |
|
- | 340 | ||
- | 341 | static int fat_unlink(void *prnt, void *chld) |
|
- | 342 | { |
|
- | 343 | return ENOTSUP; /* not supported at the moment */ |
|
- | 344 | } |
|
- | 345 | ||
- | 346 | static void *fat_match(void *prnt, const char *component) |
|
- | 347 | { |
|
- | 348 | fat_node_t *parentp = (fat_node_t *)prnt; |
|
- | 349 | char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; |
|
- | 350 | unsigned i, j; |
|
- | 351 | unsigned bps; /* bytes per sector */ |
|
- | 352 | unsigned dps; /* dentries per sector */ |
|
- | 353 | unsigned blocks; |
|
- | 354 | fat_dentry_t *d; |
|
- | 355 | block_t *b; |
|
- | 356 | ||
- | 357 | bps = fat_bps_get(parentp->idx->dev_handle); |
|
- | 358 | dps = bps / sizeof(fat_dentry_t); |
|
- | 359 | blocks = parentp->size / bps + (parentp->size % bps != 0); |
|
- | 360 | for (i = 0; i < blocks; i++) { |
|
- | 361 | unsigned dentries; |
|
- | 362 | ||
- | 363 | b = fat_block_get(parentp, i); |
|
- | 364 | dentries = (i == blocks - 1) ? |
|
- | 365 | parentp->size % sizeof(fat_dentry_t) : |
|
- | 366 | dps; |
|
- | 367 | for (j = 0; j < dentries; j++) { |
|
- | 368 | d = ((fat_dentry_t *)b->data) + j; |
|
- | 369 | switch (fat_classify_dentry(d)) { |
|
- | 370 | case FAT_DENTRY_SKIP: |
|
117 | continue; |
371 | continue; |
- | 372 | case FAT_DENTRY_LAST: |
|
- | 373 | block_put(b); |
|
- | 374 | return NULL; |
|
118 | } else { |
375 | default: |
- | 376 | case FAT_DENTRY_VALID: |
|
- | 377 | dentry_name_canonify(d, name); |
|
- | 378 | break; |
|
- | 379 | } |
|
- | 380 | if (strcmp(name, component) == 0) { |
|
119 | /* character mismatch */ |
381 | /* hit */ |
- | 382 | fat_idx_t *idx = fat_idx_get_by_pos( |
|
- | 383 | parentp->idx->dev_handle, parentp->firstc, |
|
- | 384 | i * dps + j); |
|
- | 385 | if (!idx) { |
|
- | 386 | /* |
|
- | 387 | * Can happen if memory is low or if we |
|
- | 388 | * run out of 32-bit indices. |
|
- | 389 | */ |
|
- | 390 | block_put(b); |
|
- | 391 | return NULL; |
|
- | 392 | } |
|
- | 393 | void *node = fat_node_get(idx->dev_handle, |
|
- | 394 | idx->index); |
|
- | 395 | block_put(b); |
|
120 | return 0; |
396 | return node; |
121 | } |
397 | } |
122 | } |
398 | } |
123 | return 0; /* extra characters in the component */ |
399 | block_put(b); |
124 | } |
400 | } |
- | 401 | ||
- | 402 | return NULL; |
|
- | 403 | } |
|
- | 404 | ||
125 | if (ext_processed || (name_processed && dentry->ext[0] == FAT_PAD)) |
405 | static fs_index_t fat_index_get(void *node) |
- | 406 | { |
|
126 | return cur - start; |
407 | fat_node_t *fnodep = (fat_node_t *)node; |
127 | else |
408 | if (!fnodep) |
128 | return 0; |
409 | return 0; |
- | 410 | return fnodep->idx->index; |
|
129 | } |
411 | } |
130 | 412 | ||
131 | void fat_lookup(ipc_callid_t rid, ipc_call_t *request) |
413 | static size_t fat_size_get(void *node) |
132 | { |
414 | { |
133 | int first = IPC_GET_ARG1(*request); |
415 | return ((fat_node_t *)node)->size; |
134 | int second = IPC_GET_ARG2(*request); |
- | |
135 | int dev_handle = IPC_GET_ARG3(*request); |
- | |
- | 416 | } |
|
136 | 417 | ||
- | 418 | static unsigned fat_lnkcnt_get(void *node) |
|
- | 419 | { |
|
- | 420 | return ((fat_node_t *)node)->lnkcnt; |
|
- | 421 | } |
|
- | 422 | ||
- | 423 | static bool fat_has_children(void *node) |
|
- | 424 | { |
|
- | 425 | fat_node_t *nodep = (fat_node_t *)node; |
|
- | 426 | unsigned bps; |
|
- | 427 | unsigned dps; |
|
- | 428 | unsigned blocks; |
|
- | 429 | block_t *b; |
|
- | 430 | unsigned i, j; |
|
- | 431 | ||
- | 432 | if (nodep->type != FAT_DIRECTORY) |
|
- | 433 | return false; |
|
- | 434 | ||
- | 435 | bps = fat_bps_get(nodep->idx->dev_handle); |
|
- | 436 | dps = bps / sizeof(fat_dentry_t); |
|
- | 437 | ||
- | 438 | blocks = nodep->size / bps + (nodep->size % bps != 0); |
|
- | 439 | ||
- | 440 | for (i = 0; i < blocks; i++) { |
|
- | 441 | unsigned dentries; |
|
- | 442 | fat_dentry_t *d; |
|
137 | 443 | ||
- | 444 | b = fat_block_get(nodep, i); |
|
- | 445 | dentries = (i == blocks - 1) ? |
|
- | 446 | nodep->size % sizeof(fat_dentry_t) : |
|
- | 447 | dps; |
|
- | 448 | for (j = 0; j < dentries; j++) { |
|
- | 449 | d = ((fat_dentry_t *)b->data) + j; |
|
- | 450 | switch (fat_classify_dentry(d)) { |
|
- | 451 | case FAT_DENTRY_SKIP: |
|
- | 452 | continue; |
|
- | 453 | case FAT_DENTRY_LAST: |
|
- | 454 | block_put(b); |
|
- | 455 | return false; |
|
- | 456 | default: |
|
- | 457 | case FAT_DENTRY_VALID: |
|
- | 458 | block_put(b); |
|
- | 459 | return true; |
|
- | 460 | } |
|
- | 461 | block_put(b); |
|
- | 462 | return true; |
|
- | 463 | } |
|
- | 464 | block_put(b); |
|
- | 465 | } |
|
- | 466 | ||
- | 467 | return false; |
|
- | 468 | } |
|
- | 469 | ||
- | 470 | static void *fat_root_get(dev_handle_t dev_handle) |
|
- | 471 | { |
|
- | 472 | return NULL; /* TODO */ |
|
- | 473 | } |
|
- | 474 | ||
- | 475 | static char fat_plb_get_char(unsigned pos) |
|
- | 476 | { |
|
- | 477 | return fat_reg.plb_ro[pos % PLB_SIZE]; |
|
- | 478 | } |
|
- | 479 | ||
- | 480 | static bool fat_is_directory(void *node) |
|
- | 481 | { |
|
- | 482 | return ((fat_node_t *)node)->type == FAT_DIRECTORY; |
|
- | 483 | } |
|
- | 484 | ||
- | 485 | static bool fat_is_file(void *node) |
|
- | 486 | { |
|
- | 487 | return ((fat_node_t *)node)->type == FAT_FILE; |
|
- | 488 | } |
|
- | 489 | ||
- | 490 | /** libfs operations */ |
|
- | 491 | libfs_ops_t fat_libfs_ops = { |
|
- | 492 | .match = fat_match, |
|
- | 493 | .node_get = fat_node_get, |
|
- | 494 | .node_put = fat_node_put, |
|
- | 495 | .create = fat_create, |
|
- | 496 | .destroy = fat_destroy, |
|
- | 497 | .link = fat_link, |
|
- | 498 | .unlink = fat_unlink, |
|
- | 499 | .index_get = fat_index_get, |
|
- | 500 | .size_get = fat_size_get, |
|
- | 501 | .lnkcnt_get = fat_lnkcnt_get, |
|
- | 502 | .has_children = fat_has_children, |
|
- | 503 | .root_get = fat_root_get, |
|
- | 504 | .plb_get_char = fat_plb_get_char, |
|
- | 505 | .is_directory = fat_is_directory, |
|
- | 506 | .is_file = fat_is_file |
|
- | 507 | }; |
|
- | 508 | ||
- | 509 | void fat_lookup(ipc_callid_t rid, ipc_call_t *request) |
|
- | 510 | { |
|
- | 511 | libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
|
138 | } |
512 | } |
139 | 513 | ||
140 | /** |
514 | /** |
141 | * @} |
515 | * @} |
142 | */ |
516 | */ |