source: mainline/uspace/srv/fs/fat/fat_ops.c@ 50e5b25

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 50e5b25 was 50e5b25, checked in by Jakub Jermar <jakub@…>, 17 years ago

Add implementation of fat_destroy_node() and fat_destroy().

  • Property mode set to 100644
File size: 21.9 KB
RevLine 
[be815bc]1/*
[a2aa1dec]2 * Copyright (c) 2008 Jakub Jermar
[be815bc]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33/**
34 * @file fat_ops.c
35 * @brief Implementation of VFS operations for the FAT file system server.
36 */
37
38#include "fat.h"
[033ef7d3]39#include "fat_dentry.h"
40#include "fat_fat.h"
[6364d3c]41#include "../../vfs/vfs.h"
[a2aa1dec]42#include <libfs.h>
[fc840d9]43#include <libblock.h>
[be815bc]44#include <ipc/ipc.h>
[7a35204a]45#include <ipc/services.h>
46#include <ipc/devmap.h>
[be815bc]47#include <async.h>
48#include <errno.h>
[a2aa1dec]49#include <string.h>
[776f2e6]50#include <byteorder.h>
[e1e3b26]51#include <libadt/hash_table.h>
52#include <libadt/list.h>
53#include <assert.h>
[d9e9caf]54#include <futex.h>
[7a35204a]55#include <sys/mman.h>
[8d32152]56#include <align.h>
[e1e3b26]57
[add5835]58/** Futex protecting the list of cached free FAT nodes. */
59static futex_t ffn_futex = FUTEX_INITIALIZER;
60
61/** List of cached free FAT nodes. */
62static LIST_INITIALIZE(ffn_head);
[6364d3c]63
[e1e3b26]64static void fat_node_initialize(fat_node_t *node)
[a2aa1dec]65{
[add5835]66 futex_initialize(&node->lock, 1);
[869e546]67 node->idx = NULL;
[e1e3b26]68 node->type = 0;
69 link_initialize(&node->ffn_link);
70 node->size = 0;
71 node->lnkcnt = 0;
72 node->refcnt = 0;
73 node->dirty = false;
74}
75
[2c4bbcde]76static void fat_node_sync(fat_node_t *node)
[e1e3b26]77{
[7858bc5f]78 block_t *b;
79 fat_bs_t *bs;
[beb17734]80 fat_dentry_t *d;
81 uint16_t bps;
82 unsigned dps;
83
84 assert(node->dirty);
85
[7858bc5f]86 bs = block_bb_get(node->idx->dev_handle);
87 bps = uint16_t_le2host(bs->bps);
[beb17734]88 dps = bps / sizeof(fat_dentry_t);
89
90 /* Read the block that contains the dentry of interest. */
[7858bc5f]91 b = _fat_block_get(bs, node->idx->dev_handle, node->idx->pfc,
[1d8cdb1]92 (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
[beb17734]93
94 d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
95
96 d->firstc = host2uint16_t_le(node->firstc);
97 if (node->type == FAT_FILE)
98 d->size = host2uint32_t_le(node->size);
99 /* TODO: update other fields? (e.g time fields, attr field) */
100
101 b->dirty = true; /* need to sync block */
102 block_put(b);
[e1e3b26]103}
104
[9a3d5f0]105static fat_node_t *fat_node_get_new(void)
106{
107 fat_node_t *nodep;
108
109 futex_down(&ffn_futex);
110 if (!list_empty(&ffn_head)) {
111 /* Try to use a cached free node structure. */
112 fat_idx_t *idxp_tmp;
113 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
114 if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
115 goto skip_cache;
116 idxp_tmp = nodep->idx;
117 if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
118 futex_up(&nodep->lock);
119 goto skip_cache;
120 }
121 list_remove(&nodep->ffn_link);
122 futex_up(&ffn_futex);
123 if (nodep->dirty)
124 fat_node_sync(nodep);
125 idxp_tmp->nodep = NULL;
126 futex_up(&nodep->lock);
127 futex_up(&idxp_tmp->lock);
128 } else {
129skip_cache:
130 /* Try to allocate a new node structure. */
131 futex_up(&ffn_futex);
132 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
133 if (!nodep)
134 return NULL;
135 }
136 fat_node_initialize(nodep);
137
138 return nodep;
139}
140
[add5835]141/** Internal version of fat_node_get().
142 *
143 * @param idxp Locked index structure.
144 */
145static void *fat_node_get_core(fat_idx_t *idxp)
[e1e3b26]146{
[7858bc5f]147 block_t *b;
148 fat_bs_t *bs;
[4573a79]149 fat_dentry_t *d;
[c06dbf9]150 fat_node_t *nodep = NULL;
[4573a79]151 unsigned bps;
[4f1c0b4]152 unsigned spc;
[4573a79]153 unsigned dps;
154
[add5835]155 if (idxp->nodep) {
[4573a79]156 /*
157 * We are lucky.
158 * The node is already instantiated in memory.
159 */
[add5835]160 futex_down(&idxp->nodep->lock);
161 if (!idxp->nodep->refcnt++)
[c06dbf9]162 list_remove(&idxp->nodep->ffn_link);
[add5835]163 futex_up(&idxp->nodep->lock);
164 return idxp->nodep;
[4573a79]165 }
166
167 /*
168 * We must instantiate the node from the file system.
169 */
170
[add5835]171 assert(idxp->pfc);
[4573a79]172
[9a3d5f0]173 nodep = fat_node_get_new();
174 if (!nodep)
175 return NULL;
[4573a79]176
[7858bc5f]177 bs = block_bb_get(idxp->dev_handle);
178 bps = uint16_t_le2host(bs->bps);
[4f1c0b4]179 spc = bs->spc;
[4573a79]180 dps = bps / sizeof(fat_dentry_t);
181
[2c4bbcde]182 /* Read the block that contains the dentry of interest. */
[7858bc5f]183 b = _fat_block_get(bs, idxp->dev_handle, idxp->pfc,
[1d8cdb1]184 (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
[4573a79]185 assert(b);
186
[add5835]187 d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
[2c4bbcde]188 if (d->attr & FAT_ATTR_SUBDIR) {
189 /*
190 * The only directory which does not have this bit set is the
191 * root directory itself. The root directory node is handled
192 * and initialized elsewhere.
193 */
194 nodep->type = FAT_DIRECTORY;
[2ab1023]195 /*
[e2115311]196 * Unfortunately, the 'size' field of the FAT dentry is not
197 * defined for the directory entry type. We must determine the
198 * size of the directory by walking the FAT.
[2ab1023]199 */
[4f1c0b4]200 nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
201 uint16_t_le2host(d->firstc));
[2c4bbcde]202 } else {
203 nodep->type = FAT_FILE;
[2ab1023]204 nodep->size = uint32_t_le2host(d->size);
[2c4bbcde]205 }
206 nodep->firstc = uint16_t_le2host(d->firstc);
207 nodep->lnkcnt = 1;
208 nodep->refcnt = 1;
209
210 block_put(b);
211
212 /* Link the idx structure with the node structure. */
[add5835]213 nodep->idx = idxp;
214 idxp->nodep = nodep;
[2c4bbcde]215
216 return nodep;
[a2aa1dec]217}
218
[50e5b25]219/*
220 * Forward declarations of FAT libfs operations.
221 */
222static void *fat_node_get(dev_handle_t, fs_index_t);
223static void fat_node_put(void *);
224static void *fat_create_node(dev_handle_t, int);
225static int fat_destroy_node(void *);
226static bool fat_link(void *, void *, const char *);
227static int fat_unlink(void *, void *);
228static void *fat_match(void *, const char *);
229static fs_index_t fat_index_get(void *);
230static size_t fat_size_get(void *);
231static unsigned fat_lnkcnt_get(void *);
232static bool fat_has_children(void *);
233static void *fat_root_get(dev_handle_t);
234static char fat_plb_get_char(unsigned);
235static bool fat_is_directory(void *);
236static bool fat_is_file(void *node);
237
238/*
239 * FAT libfs operations.
240 */
241
[add5835]242/** Instantiate a FAT in-core node. */
[50e5b25]243void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
[add5835]244{
245 void *node;
246 fat_idx_t *idxp;
247
248 idxp = fat_idx_get_by_index(dev_handle, index);
249 if (!idxp)
250 return NULL;
251 /* idxp->lock held */
252 node = fat_node_get_core(idxp);
253 futex_up(&idxp->lock);
254 return node;
255}
256
[50e5b25]257void fat_node_put(void *node)
[06901c6b]258{
[34b3ce3]259 fat_node_t *nodep = (fat_node_t *)node;
[6571b78]260 bool destroy = false;
[34b3ce3]261
[add5835]262 futex_down(&nodep->lock);
[34b3ce3]263 if (!--nodep->refcnt) {
[6571b78]264 if (nodep->idx) {
265 futex_down(&ffn_futex);
266 list_append(&nodep->ffn_link, &ffn_head);
267 futex_up(&ffn_futex);
268 } else {
269 /*
270 * The node does not have any index structure associated
271 * with itself. This can only mean that we are releasing
272 * the node after a failed attempt to allocate the index
273 * structure for it.
274 */
275 destroy = true;
276 }
[34b3ce3]277 }
[add5835]278 futex_up(&nodep->lock);
[6571b78]279 if (destroy)
280 free(node);
[06901c6b]281}
282
[50e5b25]283void *fat_create_node(dev_handle_t dev_handle, int flags)
[80e8482]284{
[6571b78]285 fat_idx_t *idxp;
286 fat_node_t *nodep;
287
288 nodep = fat_node_get_new();
289 if (!nodep)
290 return NULL;
291 idxp = fat_idx_get_new(dev_handle);
292 if (!idxp) {
293 fat_node_put(nodep);
294 return NULL;
295 }
296 /* idxp->lock held */
297 if (flags & L_DIRECTORY) {
298 nodep->type = FAT_DIRECTORY;
299 } else {
300 nodep->type = FAT_FILE;
301 }
302 nodep->size = 0;
303 nodep->firstc = FAT_CLST_RES0;
304 nodep->lnkcnt = 0; /* not linked anywhere */
305 nodep->refcnt = 1;
306
307 nodep->idx = idxp;
308 idxp->nodep = nodep;
309
310 futex_up(&idxp->lock);
311 return nodep;
[80e8482]312}
313
[50e5b25]314int fat_destroy_node(void *node)
[80e8482]315{
[50e5b25]316 fat_node_t *nodep = (fat_node_t *)node;
317 fat_bs_t *bs;
318
319 /*
320 * The node is not reachable from the file system. This means that the
321 * link count should be zero and that the index structure cannot be
322 * found in the position hash. Obviously, we don't need to lock the node
323 * nor its index structure.
324 */
325 assert(nodep->lnkcnt == 0);
326
327 /*
328 * The node may not have any children.
329 */
330 assert(fat_has_children(node) == false);
331
332 bs = block_bb_get(nodep->idx->dev_handle);
333 if (nodep->firstc != FAT_CLST_RES0) {
334 assert(nodep->size);
335 /* Free all clusters allocated to the node. */
336 fat_free_clusters(bs, nodep->idx->dev_handle, nodep->firstc);
337 }
338
339 fat_idx_destroy(nodep->idx);
340 free(nodep);
341 return EOK;
[80e8482]342}
343
[50e5b25]344bool fat_link(void *prnt, void *chld, const char *name)
[80e8482]345{
346 return false; /* not supported at the moment */
347}
348
[50e5b25]349int fat_unlink(void *prnt, void *chld)
[80e8482]350{
351 return ENOTSUP; /* not supported at the moment */
352}
353
[50e5b25]354void *fat_match(void *prnt, const char *component)
[a2aa1dec]355{
[7858bc5f]356 fat_bs_t *bs;
[a2aa1dec]357 fat_node_t *parentp = (fat_node_t *)prnt;
358 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
[79dbc3e]359 unsigned i, j;
[5446bee0]360 unsigned bps; /* bytes per sector */
[79dbc3e]361 unsigned dps; /* dentries per sector */
362 unsigned blocks;
[a2aa1dec]363 fat_dentry_t *d;
[7858bc5f]364 block_t *b;
[79dbc3e]365
[e811bde]366 futex_down(&parentp->idx->lock);
[7858bc5f]367 bs = block_bb_get(parentp->idx->dev_handle);
368 bps = uint16_t_le2host(bs->bps);
[5446bee0]369 dps = bps / sizeof(fat_dentry_t);
[b0247bac]370 blocks = parentp->size / bps;
[79dbc3e]371 for (i = 0; i < blocks; i++) {
[1d8cdb1]372 b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
[b0247bac]373 for (j = 0; j < dps; j++) {
[79dbc3e]374 d = ((fat_dentry_t *)b->data) + j;
[32fb10ed]375 switch (fat_classify_dentry(d)) {
376 case FAT_DENTRY_SKIP:
[79dbc3e]377 continue;
[32fb10ed]378 case FAT_DENTRY_LAST:
[79dbc3e]379 block_put(b);
[e811bde]380 futex_up(&parentp->idx->lock);
[79dbc3e]381 return NULL;
[32fb10ed]382 default:
383 case FAT_DENTRY_VALID:
384 dentry_name_canonify(d, name);
385 break;
[79dbc3e]386 }
[d2e9c47]387 if (stricmp(name, component) == 0) {
[79dbc3e]388 /* hit */
[add5835]389 void *node;
[e811bde]390 /*
391 * Assume tree hierarchy for locking. We
392 * already have the parent and now we are going
393 * to lock the child. Never lock in the oposite
394 * order.
395 */
[4797132]396 fat_idx_t *idx = fat_idx_get_by_pos(
[5a324099]397 parentp->idx->dev_handle, parentp->firstc,
[869e546]398 i * dps + j);
[e811bde]399 futex_up(&parentp->idx->lock);
[4797132]400 if (!idx) {
401 /*
402 * Can happen if memory is low or if we
403 * run out of 32-bit indices.
404 */
405 block_put(b);
406 return NULL;
407 }
[add5835]408 node = fat_node_get_core(idx);
409 futex_up(&idx->lock);
[79dbc3e]410 block_put(b);
411 return node;
412 }
[9119d25]413 }
[79dbc3e]414 block_put(b);
[9119d25]415 }
[cb682eb]416
[e811bde]417 futex_up(&parentp->idx->lock);
[a2aa1dec]418 return NULL;
[6364d3c]419}
420
[50e5b25]421fs_index_t fat_index_get(void *node)
[e1e3b26]422{
423 fat_node_t *fnodep = (fat_node_t *)node;
424 if (!fnodep)
425 return 0;
[869e546]426 return fnodep->idx->index;
[e1e3b26]427}
428
[50e5b25]429size_t fat_size_get(void *node)
[e1e3b26]430{
431 return ((fat_node_t *)node)->size;
432}
433
[50e5b25]434unsigned fat_lnkcnt_get(void *node)
[e1e3b26]435{
436 return ((fat_node_t *)node)->lnkcnt;
437}
438
[50e5b25]439bool fat_has_children(void *node)
[32fb10ed]440{
[7858bc5f]441 fat_bs_t *bs;
[32fb10ed]442 fat_node_t *nodep = (fat_node_t *)node;
443 unsigned bps;
444 unsigned dps;
445 unsigned blocks;
[7858bc5f]446 block_t *b;
[32fb10ed]447 unsigned i, j;
448
449 if (nodep->type != FAT_DIRECTORY)
450 return false;
[b0247bac]451
[add5835]452 futex_down(&nodep->idx->lock);
[7858bc5f]453 bs = block_bb_get(nodep->idx->dev_handle);
454 bps = uint16_t_le2host(bs->bps);
[32fb10ed]455 dps = bps / sizeof(fat_dentry_t);
456
[b0247bac]457 blocks = nodep->size / bps;
[32fb10ed]458
459 for (i = 0; i < blocks; i++) {
460 fat_dentry_t *d;
461
[1d8cdb1]462 b = fat_block_get(bs, nodep, i, BLOCK_FLAGS_NONE);
[b0247bac]463 for (j = 0; j < dps; j++) {
[32fb10ed]464 d = ((fat_dentry_t *)b->data) + j;
465 switch (fat_classify_dentry(d)) {
466 case FAT_DENTRY_SKIP:
467 continue;
468 case FAT_DENTRY_LAST:
469 block_put(b);
[add5835]470 futex_up(&nodep->idx->lock);
[32fb10ed]471 return false;
472 default:
473 case FAT_DENTRY_VALID:
474 block_put(b);
[add5835]475 futex_up(&nodep->idx->lock);
[32fb10ed]476 return true;
477 }
478 block_put(b);
[add5835]479 futex_up(&nodep->idx->lock);
[32fb10ed]480 return true;
481 }
482 block_put(b);
483 }
484
[add5835]485 futex_up(&nodep->idx->lock);
[32fb10ed]486 return false;
487}
488
[50e5b25]489void *fat_root_get(dev_handle_t dev_handle)
[74ea3c6]490{
[689f036]491 return fat_node_get(dev_handle, 0);
[74ea3c6]492}
493
[50e5b25]494char fat_plb_get_char(unsigned pos)
[74ea3c6]495{
496 return fat_reg.plb_ro[pos % PLB_SIZE];
497}
498
[50e5b25]499bool fat_is_directory(void *node)
[e1e3b26]500{
501 return ((fat_node_t *)node)->type == FAT_DIRECTORY;
502}
503
[50e5b25]504bool fat_is_file(void *node)
[e1e3b26]505{
506 return ((fat_node_t *)node)->type == FAT_FILE;
507}
508
[a2aa1dec]509/** libfs operations */
510libfs_ops_t fat_libfs_ops = {
511 .match = fat_match,
512 .node_get = fat_node_get,
[06901c6b]513 .node_put = fat_node_put,
[6571b78]514 .create = fat_create_node,
515 .destroy = fat_destroy_node,
[80e8482]516 .link = fat_link,
517 .unlink = fat_unlink,
[e1e3b26]518 .index_get = fat_index_get,
519 .size_get = fat_size_get,
520 .lnkcnt_get = fat_lnkcnt_get,
[32fb10ed]521 .has_children = fat_has_children,
[74ea3c6]522 .root_get = fat_root_get,
523 .plb_get_char = fat_plb_get_char,
[e1e3b26]524 .is_directory = fat_is_directory,
525 .is_file = fat_is_file
[a2aa1dec]526};
527
[cde485d]528void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
529{
530 dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
[7858bc5f]531 fat_bs_t *bs;
[7a35204a]532 uint16_t bps;
[689f036]533 uint16_t rde;
[cde485d]534 int rc;
535
[7858bc5f]536 /* initialize libblock */
[6284978]537 rc = block_init(dev_handle, BS_SIZE);
[7a35204a]538 if (rc != EOK) {
[6284978]539 ipc_answer_0(rid, rc);
540 return;
541 }
542
543 /* prepare the boot block */
544 rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
545 if (rc != EOK) {
546 block_fini(dev_handle);
547 ipc_answer_0(rid, rc);
[7a35204a]548 return;
549 }
550
[7858bc5f]551 /* get the buffer with the boot sector */
552 bs = block_bb_get(dev_handle);
553
[689f036]554 /* Read the number of root directory entries. */
[7858bc5f]555 bps = uint16_t_le2host(bs->bps);
556 rde = uint16_t_le2host(bs->root_ent_max);
[689f036]557
[7a35204a]558 if (bps != BS_SIZE) {
[7858bc5f]559 block_fini(dev_handle);
[7a35204a]560 ipc_answer_0(rid, ENOTSUP);
561 return;
562 }
563
[f1ba5d6]564 /* Initialize the block cache */
565 rc = block_cache_init(dev_handle, bps, 0 /* XXX */);
566 if (rc != EOK) {
567 block_fini(dev_handle);
568 ipc_answer_0(rid, rc);
569 return;
570 }
571
[cde485d]572 rc = fat_idx_init_by_dev_handle(dev_handle);
573 if (rc != EOK) {
[7858bc5f]574 block_fini(dev_handle);
[cde485d]575 ipc_answer_0(rid, rc);
576 return;
577 }
578
[689f036]579 /* Initialize the root node. */
580 fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
581 if (!rootp) {
[7858bc5f]582 block_fini(dev_handle);
[689f036]583 fat_idx_fini_by_dev_handle(dev_handle);
584 ipc_answer_0(rid, ENOMEM);
585 return;
586 }
587 fat_node_initialize(rootp);
588
589 fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
590 if (!ridxp) {
[7858bc5f]591 block_fini(dev_handle);
[689f036]592 free(rootp);
593 fat_idx_fini_by_dev_handle(dev_handle);
594 ipc_answer_0(rid, ENOMEM);
595 return;
596 }
597 assert(ridxp->index == 0);
598 /* ridxp->lock held */
599
600 rootp->type = FAT_DIRECTORY;
601 rootp->firstc = FAT_CLST_ROOT;
602 rootp->refcnt = 1;
[5ab597d]603 rootp->lnkcnt = 0; /* FS root is not linked */
[689f036]604 rootp->size = rde * sizeof(fat_dentry_t);
605 rootp->idx = ridxp;
606 ridxp->nodep = rootp;
607
608 futex_up(&ridxp->lock);
609
[5ab597d]610 ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
[cde485d]611}
612
613void fat_mount(ipc_callid_t rid, ipc_call_t *request)
614{
615 ipc_answer_0(rid, ENOTSUP);
616}
617
[be815bc]618void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
619{
[a2aa1dec]620 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
[be815bc]621}
622
[4bf40f6]623void fat_read(ipc_callid_t rid, ipc_call_t *request)
624{
625 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
626 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
627 off_t pos = (off_t)IPC_GET_ARG3(*request);
628 fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
[7858bc5f]629 fat_bs_t *bs;
[cb682eb]630 uint16_t bps;
[79d031b]631 size_t bytes;
[7858bc5f]632 block_t *b;
[79d031b]633
[4bf40f6]634 if (!nodep) {
635 ipc_answer_0(rid, ENOENT);
636 return;
637 }
638
639 ipc_callid_t callid;
640 size_t len;
[6808614]641 if (!ipc_data_read_receive(&callid, &len)) {
[4bf40f6]642 fat_node_put(nodep);
643 ipc_answer_0(callid, EINVAL);
644 ipc_answer_0(rid, EINVAL);
645 return;
646 }
647
[7858bc5f]648 bs = block_bb_get(dev_handle);
649 bps = uint16_t_le2host(bs->bps);
[cb682eb]650
[4bf40f6]651 if (nodep->type == FAT_FILE) {
[ddd1219]652 /*
653 * Our strategy for regular file reads is to read one block at
654 * most and make use of the possibility to return less data than
655 * requested. This keeps the code very simple.
656 */
[0d974d8]657 if (pos >= nodep->size) {
[7d861950]658 /* reading beyond the EOF */
659 bytes = 0;
[0d974d8]660 (void) ipc_data_read_finalize(callid, NULL, 0);
661 } else {
662 bytes = min(len, bps - pos % bps);
663 bytes = min(bytes, nodep->size - pos);
[1d8cdb1]664 b = fat_block_get(bs, nodep, pos / bps,
665 BLOCK_FLAGS_NONE);
[0d974d8]666 (void) ipc_data_read_finalize(callid, b->data + pos % bps,
667 bytes);
668 block_put(b);
669 }
[4bf40f6]670 } else {
[ddd1219]671 unsigned bnum;
672 off_t spos = pos;
673 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
674 fat_dentry_t *d;
675
[4bf40f6]676 assert(nodep->type == FAT_DIRECTORY);
[ddd1219]677 assert(nodep->size % bps == 0);
678 assert(bps % sizeof(fat_dentry_t) == 0);
679
680 /*
681 * Our strategy for readdir() is to use the position pointer as
682 * an index into the array of all dentries. On entry, it points
683 * to the first unread dentry. If we skip any dentries, we bump
684 * the position pointer accordingly.
685 */
686 bnum = (pos * sizeof(fat_dentry_t)) / bps;
687 while (bnum < nodep->size / bps) {
688 off_t o;
689
[1d8cdb1]690 b = fat_block_get(bs, nodep, bnum, BLOCK_FLAGS_NONE);
[ddd1219]691 for (o = pos % (bps / sizeof(fat_dentry_t));
692 o < bps / sizeof(fat_dentry_t);
693 o++, pos++) {
694 d = ((fat_dentry_t *)b->data) + o;
695 switch (fat_classify_dentry(d)) {
696 case FAT_DENTRY_SKIP:
697 continue;
698 case FAT_DENTRY_LAST:
699 block_put(b);
700 goto miss;
701 default:
702 case FAT_DENTRY_VALID:
703 dentry_name_canonify(d, name);
704 block_put(b);
705 goto hit;
706 }
707 }
708 block_put(b);
709 bnum++;
710 }
711miss:
[4bf40f6]712 fat_node_put(nodep);
[ddd1219]713 ipc_answer_0(callid, ENOENT);
714 ipc_answer_1(rid, ENOENT, 0);
[4bf40f6]715 return;
[ddd1219]716hit:
717 (void) ipc_data_read_finalize(callid, name, strlen(name) + 1);
718 bytes = (pos - spos) + 1;
[4bf40f6]719 }
720
721 fat_node_put(nodep);
[79d031b]722 ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
[4bf40f6]723}
724
[c947dda]725void fat_write(ipc_callid_t rid, ipc_call_t *request)
726{
[8d32152]727 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
728 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
729 off_t pos = (off_t)IPC_GET_ARG3(*request);
730 fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
[7858bc5f]731 fat_bs_t *bs;
[8d32152]732 size_t bytes;
[7858bc5f]733 block_t *b;
[8d32152]734 uint16_t bps;
735 unsigned spc;
[913a821c]736 unsigned bpc; /* bytes per cluster */
[b4b7187]737 off_t boundary;
[1d8cdb1]738 int flags = BLOCK_FLAGS_NONE;
[8d32152]739
740 if (!nodep) {
741 ipc_answer_0(rid, ENOENT);
742 return;
743 }
744
745 ipc_callid_t callid;
746 size_t len;
747 if (!ipc_data_write_receive(&callid, &len)) {
748 fat_node_put(nodep);
749 ipc_answer_0(callid, EINVAL);
750 ipc_answer_0(rid, EINVAL);
751 return;
752 }
753
[913a821c]754 bs = block_bb_get(dev_handle);
755 bps = uint16_t_le2host(bs->bps);
756 spc = bs->spc;
757 bpc = bps * spc;
758
[8d32152]759 /*
760 * In all scenarios, we will attempt to write out only one block worth
761 * of data at maximum. There might be some more efficient approaches,
762 * but this one greatly simplifies fat_write(). Note that we can afford
763 * to do this because the client must be ready to handle the return
764 * value signalizing a smaller number of bytes written.
765 */
766 bytes = min(len, bps - pos % bps);
[1d8cdb1]767 if (bytes == bps)
768 flags |= BLOCK_FLAGS_NOREAD;
[8d32152]769
[913a821c]770 boundary = ROUND_UP(nodep->size, bpc);
[b4b7187]771 if (pos < boundary) {
[8d32152]772 /*
773 * This is the easier case - we are either overwriting already
774 * existing contents or writing behind the EOF, but still within
775 * the limits of the last cluster. The node size may grow to the
776 * next block size boundary.
777 */
[7858bc5f]778 fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
[1d8cdb1]779 b = fat_block_get(bs, nodep, pos / bps, flags);
[8d32152]780 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
781 bytes);
782 b->dirty = true; /* need to sync block */
[6f2dfd1]783 block_put(b);
[8d32152]784 if (pos + bytes > nodep->size) {
785 nodep->size = pos + bytes;
786 nodep->dirty = true; /* need to sync node */
787 }
[ac49f5d1]788 ipc_answer_2(rid, EOK, bytes, nodep->size);
[8d32152]789 fat_node_put(nodep);
790 return;
791 } else {
792 /*
793 * This is the more difficult case. We must allocate new
794 * clusters for the node and zero them out.
795 */
[6f2dfd1]796 int status;
[8d32152]797 unsigned nclsts;
[8334a427]798 fat_cluster_t mcl, lcl;
799
[913a821c]800 nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
[6f2dfd1]801 /* create an independent chain of nclsts clusters in all FATs */
[913a821c]802 status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
[6f2dfd1]803 if (status != EOK) {
804 /* could not allocate a chain of nclsts clusters */
805 fat_node_put(nodep);
806 ipc_answer_0(callid, status);
807 ipc_answer_0(rid, status);
808 return;
809 }
810 /* zero fill any gaps */
[7858bc5f]811 fat_fill_gap(bs, nodep, mcl, pos);
[1d8cdb1]812 b = _fat_block_get(bs, dev_handle, lcl, (pos / bps) % spc,
813 flags);
[6f2dfd1]814 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
815 bytes);
[b4b7187]816 b->dirty = true; /* need to sync block */
[6f2dfd1]817 block_put(b);
818 /*
819 * Append the cluster chain starting in mcl to the end of the
820 * node's cluster chain.
821 */
[7858bc5f]822 fat_append_clusters(bs, nodep, mcl);
[6f2dfd1]823 nodep->size = pos + bytes;
[b4b7187]824 nodep->dirty = true; /* need to sync node */
[ac49f5d1]825 ipc_answer_2(rid, EOK, bytes, nodep->size);
[6f2dfd1]826 fat_node_put(nodep);
827 return;
[8d32152]828 }
[c947dda]829}
830
[6c71a1f]831void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
832{
[8334a427]833 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
834 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
835 size_t size = (off_t)IPC_GET_ARG3(*request);
836 fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
[913a821c]837 fat_bs_t *bs;
838 uint16_t bps;
839 uint8_t spc;
840 unsigned bpc; /* bytes per cluster */
[8334a427]841 int rc;
842
843 if (!nodep) {
844 ipc_answer_0(rid, ENOENT);
845 return;
846 }
847
[913a821c]848 bs = block_bb_get(dev_handle);
849 bps = uint16_t_le2host(bs->bps);
850 spc = bs->spc;
851 bpc = bps * spc;
852
[8334a427]853 if (nodep->size == size) {
854 rc = EOK;
855 } else if (nodep->size < size) {
856 /*
[913a821c]857 * The standard says we have the freedom to grow the node.
[8334a427]858 * For now, we simply return an error.
859 */
860 rc = EINVAL;
[913a821c]861 } else if (ROUND_UP(nodep->size, bpc) == ROUND_UP(size, bpc)) {
862 /*
863 * The node will be shrunk, but no clusters will be deallocated.
864 */
865 nodep->size = size;
866 nodep->dirty = true; /* need to sync node */
867 rc = EOK;
[8334a427]868 } else {
869 /*
[913a821c]870 * The node will be shrunk, clusters will be deallocated.
[8334a427]871 */
[913a821c]872 if (size == 0) {
873 fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
874 } else {
875 fat_cluster_t lastc;
876 (void) fat_cluster_walk(bs, dev_handle, nodep->firstc,
877 &lastc, (size - 1) / bpc);
878 fat_chop_clusters(bs, nodep, lastc);
879 }
880 nodep->size = size;
881 nodep->dirty = true; /* need to sync node */
882 rc = EOK;
[8334a427]883 }
884 fat_node_put(nodep);
885 ipc_answer_0(rid, rc);
886 return;
[6c71a1f]887}
888
[50e5b25]889void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
890{
891 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
892 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
893 int rc;
894
895 fat_node_t *nodep = fat_node_get(dev_handle, index);
896 if (!nodep) {
897 ipc_answer_0(rid, ENOENT);
898 return;
899 }
900
901 rc = fat_destroy_node(nodep);
902 ipc_answer_0(rid, rc);
903}
904
[be815bc]905/**
906 * @}
907 */
Note: See TracBrowser for help on using the repository browser.