~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to uspace/srv/fs/fat/fat_ops.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2008 Jakub Jermar
 
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"
 
39
#include "fat_dentry.h"
 
40
#include "fat_fat.h"
 
41
#include "../../vfs/vfs.h"
 
42
#include <libfs.h>
 
43
#include <libblock.h>
 
44
#include <ipc/ipc.h>
 
45
#include <ipc/services.h>
 
46
#include <ipc/devmap.h>
 
47
#include <async.h>
 
48
#include <errno.h>
 
49
#include <string.h>
 
50
#include <byteorder.h>
 
51
#include <adt/hash_table.h>
 
52
#include <adt/list.h>
 
53
#include <assert.h>
 
54
#include <fibril_sync.h>
 
55
#include <sys/mman.h>
 
56
#include <align.h>
 
57
 
 
58
#define FAT_NODE(node)  ((node) ? (fat_node_t *) (node)->data : NULL)
 
59
#define FS_NODE(node)   ((node) ? (node)->bp : NULL)
 
60
 
 
61
/** Mutex protecting the list of cached free FAT nodes. */
 
62
static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
 
63
 
 
64
/** List of cached free FAT nodes. */
 
65
static LIST_INITIALIZE(ffn_head);
 
66
 
 
67
static void fat_node_initialize(fat_node_t *node)
 
68
{
 
69
        fibril_mutex_initialize(&node->lock);
 
70
        node->bp = NULL;
 
71
        node->idx = NULL;
 
72
        node->type = 0;
 
73
        link_initialize(&node->ffn_link);
 
74
        node->size = 0;
 
75
        node->lnkcnt = 0;
 
76
        node->refcnt = 0;
 
77
        node->dirty = false;
 
78
}
 
79
 
 
80
static void fat_node_sync(fat_node_t *node)
 
81
{
 
82
        block_t *b;
 
83
        fat_bs_t *bs;
 
84
        fat_dentry_t *d;
 
85
        uint16_t bps;
 
86
        unsigned dps;
 
87
        
 
88
        assert(node->dirty);
 
89
 
 
90
        bs = block_bb_get(node->idx->dev_handle);
 
91
        bps = uint16_t_le2host(bs->bps);
 
92
        dps = bps / sizeof(fat_dentry_t);
 
93
        
 
94
        /* Read the block that contains the dentry of interest. */
 
95
        b = _fat_block_get(bs, node->idx->dev_handle, node->idx->pfc,
 
96
            (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
 
97
 
 
98
        d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
 
99
 
 
100
        d->firstc = host2uint16_t_le(node->firstc);
 
101
        if (node->type == FAT_FILE) {
 
102
                d->size = host2uint32_t_le(node->size);
 
103
        } else if (node->type == FAT_DIRECTORY) {
 
104
                d->attr = FAT_ATTR_SUBDIR;
 
105
        }
 
106
        
 
107
        /* TODO: update other fields? (e.g time fields) */
 
108
        
 
109
        b->dirty = true;                /* need to sync block */
 
110
        block_put(b);
 
111
}
 
112
 
 
113
static fat_node_t *fat_node_get_new(void)
 
114
{
 
115
        fs_node_t *fn;
 
116
        fat_node_t *nodep;
 
117
 
 
118
        fibril_mutex_lock(&ffn_mutex);
 
119
        if (!list_empty(&ffn_head)) {
 
120
                /* Try to use a cached free node structure. */
 
121
                fat_idx_t *idxp_tmp;
 
122
                nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
 
123
                if (!fibril_mutex_trylock(&nodep->lock))
 
124
                        goto skip_cache;
 
125
                idxp_tmp = nodep->idx;
 
126
                if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
 
127
                        fibril_mutex_unlock(&nodep->lock);
 
128
                        goto skip_cache;
 
129
                }
 
130
                list_remove(&nodep->ffn_link);
 
131
                fibril_mutex_unlock(&ffn_mutex);
 
132
                if (nodep->dirty)
 
133
                        fat_node_sync(nodep);
 
134
                idxp_tmp->nodep = NULL;
 
135
                fibril_mutex_unlock(&nodep->lock);
 
136
                fibril_mutex_unlock(&idxp_tmp->lock);
 
137
                fn = FS_NODE(nodep);
 
138
        } else {
 
139
skip_cache:
 
140
                /* Try to allocate a new node structure. */
 
141
                fibril_mutex_unlock(&ffn_mutex);
 
142
                fn = (fs_node_t *)malloc(sizeof(fs_node_t));
 
143
                if (!fn)
 
144
                        return NULL;
 
145
                nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
 
146
                if (!nodep) {
 
147
                        free(fn);
 
148
                        return NULL;
 
149
                }
 
150
        }
 
151
        fat_node_initialize(nodep);
 
152
        fs_node_initialize(fn);
 
153
        fn->data = nodep;
 
154
        nodep->bp = fn;
 
155
        
 
156
        return nodep;
 
157
}
 
158
 
 
159
/** Internal version of fat_node_get().
 
160
 *
 
161
 * @param idxp          Locked index structure.
 
162
 */
 
163
static fat_node_t *fat_node_get_core(fat_idx_t *idxp)
 
164
{
 
165
        block_t *b;
 
166
        fat_bs_t *bs;
 
167
        fat_dentry_t *d;
 
168
        fat_node_t *nodep = NULL;
 
169
        unsigned bps;
 
170
        unsigned spc;
 
171
        unsigned dps;
 
172
 
 
173
        if (idxp->nodep) {
 
174
                /*
 
175
                 * We are lucky.
 
176
                 * The node is already instantiated in memory.
 
177
                 */
 
178
                fibril_mutex_lock(&idxp->nodep->lock);
 
179
                if (!idxp->nodep->refcnt++)
 
180
                        list_remove(&idxp->nodep->ffn_link);
 
181
                fibril_mutex_unlock(&idxp->nodep->lock);
 
182
                return idxp->nodep;
 
183
        }
 
184
 
 
185
        /*
 
186
         * We must instantiate the node from the file system.
 
187
         */
 
188
        
 
189
        assert(idxp->pfc);
 
190
 
 
191
        nodep = fat_node_get_new();
 
192
        if (!nodep)
 
193
                return NULL;
 
194
 
 
195
        bs = block_bb_get(idxp->dev_handle);
 
196
        bps = uint16_t_le2host(bs->bps);
 
197
        spc = bs->spc;
 
198
        dps = bps / sizeof(fat_dentry_t);
 
199
 
 
200
        /* Read the block that contains the dentry of interest. */
 
201
        b = _fat_block_get(bs, idxp->dev_handle, idxp->pfc,
 
202
            (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
 
203
        assert(b);
 
204
 
 
205
        d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
 
206
        if (d->attr & FAT_ATTR_SUBDIR) {
 
207
                /* 
 
208
                 * The only directory which does not have this bit set is the
 
209
                 * root directory itself. The root directory node is handled
 
210
                 * and initialized elsewhere.
 
211
                 */
 
212
                nodep->type = FAT_DIRECTORY;
 
213
                /*
 
214
                 * Unfortunately, the 'size' field of the FAT dentry is not
 
215
                 * defined for the directory entry type. We must determine the
 
216
                 * size of the directory by walking the FAT.
 
217
                 */
 
218
                nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
 
219
                    uint16_t_le2host(d->firstc));
 
220
        } else {
 
221
                nodep->type = FAT_FILE;
 
222
                nodep->size = uint32_t_le2host(d->size);
 
223
        }
 
224
        nodep->firstc = uint16_t_le2host(d->firstc);
 
225
        nodep->lnkcnt = 1;
 
226
        nodep->refcnt = 1;
 
227
 
 
228
        block_put(b);
 
229
 
 
230
        /* Link the idx structure with the node structure. */
 
231
        nodep->idx = idxp;
 
232
        idxp->nodep = nodep;
 
233
 
 
234
        return nodep;
 
235
}
 
236
 
 
237
/*
 
238
 * Forward declarations of FAT libfs operations.
 
239
 */
 
240
static fs_node_t *fat_node_get(dev_handle_t, fs_index_t);
 
241
static void fat_node_put(fs_node_t *);
 
242
static fs_node_t *fat_create_node(dev_handle_t, int);
 
243
static int fat_destroy_node(fs_node_t *);
 
244
static int fat_link(fs_node_t *, fs_node_t *, const char *);
 
245
static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
 
246
static fs_node_t *fat_match(fs_node_t *, const char *);
 
247
static fs_index_t fat_index_get(fs_node_t *);
 
248
static size_t fat_size_get(fs_node_t *);
 
249
static unsigned fat_lnkcnt_get(fs_node_t *);
 
250
static bool fat_has_children(fs_node_t *);
 
251
static fs_node_t *fat_root_get(dev_handle_t);
 
252
static char fat_plb_get_char(unsigned);
 
253
static bool fat_is_directory(fs_node_t *);
 
254
static bool fat_is_file(fs_node_t *node);
 
255
 
 
256
/*
 
257
 * FAT libfs operations.
 
258
 */
 
259
 
 
260
/** Instantiate a FAT in-core node. */
 
261
fs_node_t *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
 
262
{
 
263
        fat_node_t *nodep;
 
264
        fat_idx_t *idxp;
 
265
 
 
266
        idxp = fat_idx_get_by_index(dev_handle, index);
 
267
        if (!idxp)
 
268
                return NULL;
 
269
        /* idxp->lock held */
 
270
        nodep = fat_node_get_core(idxp);
 
271
        fibril_mutex_unlock(&idxp->lock);
 
272
        return FS_NODE(nodep);
 
273
}
 
274
 
 
275
void fat_node_put(fs_node_t *fn)
 
276
{
 
277
        fat_node_t *nodep = FAT_NODE(fn);
 
278
        bool destroy = false;
 
279
 
 
280
        fibril_mutex_lock(&nodep->lock);
 
281
        if (!--nodep->refcnt) {
 
282
                if (nodep->idx) {
 
283
                        fibril_mutex_lock(&ffn_mutex);
 
284
                        list_append(&nodep->ffn_link, &ffn_head);
 
285
                        fibril_mutex_unlock(&ffn_mutex);
 
286
                } else {
 
287
                        /*
 
288
                         * The node does not have any index structure associated
 
289
                         * with itself. This can only mean that we are releasing
 
290
                         * the node after a failed attempt to allocate the index
 
291
                         * structure for it.
 
292
                         */
 
293
                        destroy = true;
 
294
                }
 
295
        }
 
296
        fibril_mutex_unlock(&nodep->lock);
 
297
        if (destroy) {
 
298
                free(nodep->bp);
 
299
                free(nodep);
 
300
        }
 
301
}
 
302
 
 
303
fs_node_t *fat_create_node(dev_handle_t dev_handle, int flags)
 
304
{
 
305
        fat_idx_t *idxp;
 
306
        fat_node_t *nodep;
 
307
        fat_bs_t *bs;
 
308
        fat_cluster_t mcl, lcl;
 
309
        uint16_t bps;
 
310
        int rc;
 
311
 
 
312
        bs = block_bb_get(dev_handle);
 
313
        bps = uint16_t_le2host(bs->bps);
 
314
        if (flags & L_DIRECTORY) {
 
315
                /* allocate a cluster */
 
316
                rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
 
317
                if (rc != EOK) 
 
318
                        return NULL;
 
319
        }
 
320
 
 
321
        nodep = fat_node_get_new();
 
322
        if (!nodep) {
 
323
                fat_free_clusters(bs, dev_handle, mcl); 
 
324
                return NULL;
 
325
        }
 
326
        idxp = fat_idx_get_new(dev_handle);
 
327
        if (!idxp) {
 
328
                fat_free_clusters(bs, dev_handle, mcl); 
 
329
                fat_node_put(FS_NODE(nodep));
 
330
                return NULL;
 
331
        }
 
332
        /* idxp->lock held */
 
333
        if (flags & L_DIRECTORY) {
 
334
                int i;
 
335
                block_t *b;
 
336
 
 
337
                /*
 
338
                 * Populate the new cluster with unused dentries.
 
339
                 */
 
340
                for (i = 0; i < bs->spc; i++) {
 
341
                        b = _fat_block_get(bs, dev_handle, mcl, i,
 
342
                            BLOCK_FLAGS_NOREAD);
 
343
                        /* mark all dentries as never-used */
 
344
                        memset(b->data, 0, bps);
 
345
                        b->dirty = false;
 
346
                        block_put(b);
 
347
                }
 
348
                nodep->type = FAT_DIRECTORY;
 
349
                nodep->firstc = mcl;
 
350
                nodep->size = bps * bs->spc;
 
351
        } else {
 
352
                nodep->type = FAT_FILE;
 
353
                nodep->firstc = FAT_CLST_RES0;
 
354
                nodep->size = 0;
 
355
        }
 
356
        nodep->lnkcnt = 0;      /* not linked anywhere */
 
357
        nodep->refcnt = 1;
 
358
        nodep->dirty = true;
 
359
 
 
360
        nodep->idx = idxp;
 
361
        idxp->nodep = nodep;
 
362
 
 
363
        fibril_mutex_unlock(&idxp->lock);
 
364
        return FS_NODE(nodep);
 
365
}
 
366
 
 
367
int fat_destroy_node(fs_node_t *fn)
 
368
{
 
369
        fat_node_t *nodep = FAT_NODE(fn);
 
370
        fat_bs_t *bs;
 
371
 
 
372
        /*
 
373
         * The node is not reachable from the file system. This means that the
 
374
         * link count should be zero and that the index structure cannot be
 
375
         * found in the position hash. Obviously, we don't need to lock the node
 
376
         * nor its index structure.
 
377
         */
 
378
        assert(nodep->lnkcnt == 0);
 
379
 
 
380
        /*
 
381
         * The node may not have any children.
 
382
         */
 
383
        assert(fat_has_children(fn) == false);
 
384
 
 
385
        bs = block_bb_get(nodep->idx->dev_handle);
 
386
        if (nodep->firstc != FAT_CLST_RES0) {
 
387
                assert(nodep->size);
 
388
                /* Free all clusters allocated to the node. */
 
389
                fat_free_clusters(bs, nodep->idx->dev_handle, nodep->firstc);
 
390
        }
 
391
 
 
392
        fat_idx_destroy(nodep->idx);
 
393
        free(nodep->bp);
 
394
        free(nodep);
 
395
        return EOK;
 
396
}
 
397
 
 
398
int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
 
399
{
 
400
        fat_node_t *parentp = FAT_NODE(pfn);
 
401
        fat_node_t *childp = FAT_NODE(cfn);
 
402
        fat_dentry_t *d;
 
403
        fat_bs_t *bs;
 
404
        block_t *b;
 
405
        unsigned i, j;
 
406
        uint16_t bps;
 
407
        unsigned dps;
 
408
        unsigned blocks;
 
409
        fat_cluster_t mcl, lcl;
 
410
        int rc;
 
411
 
 
412
        fibril_mutex_lock(&childp->lock);
 
413
        if (childp->lnkcnt == 1) {
 
414
                /*
 
415
                 * On FAT, we don't support multiple hard links.
 
416
                 */
 
417
                fibril_mutex_unlock(&childp->lock);
 
418
                return EMLINK;
 
419
        }
 
420
        assert(childp->lnkcnt == 0);
 
421
        fibril_mutex_unlock(&childp->lock);
 
422
 
 
423
        if (!fat_dentry_name_verify(name)) {
 
424
                /*
 
425
                 * Attempt to create unsupported name.
 
426
                 */
 
427
                return ENOTSUP;
 
428
        }
 
429
 
 
430
        /*
 
431
         * Get us an unused parent node's dentry or grow the parent and allocate
 
432
         * a new one.
 
433
         */
 
434
        
 
435
        fibril_mutex_lock(&parentp->idx->lock);
 
436
        bs = block_bb_get(parentp->idx->dev_handle);
 
437
        bps = uint16_t_le2host(bs->bps);
 
438
        dps = bps / sizeof(fat_dentry_t);
 
439
 
 
440
        blocks = parentp->size / bps;
 
441
 
 
442
        for (i = 0; i < blocks; i++) {
 
443
                b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
 
444
                for (j = 0; j < dps; j++) {
 
445
                        d = ((fat_dentry_t *)b->data) + j;
 
446
                        switch (fat_classify_dentry(d)) {
 
447
                        case FAT_DENTRY_SKIP:
 
448
                        case FAT_DENTRY_VALID:
 
449
                                /* skipping used and meta entries */
 
450
                                continue;
 
451
                        case FAT_DENTRY_FREE:
 
452
                        case FAT_DENTRY_LAST:
 
453
                                /* found an empty slot */
 
454
                                goto hit;
 
455
                        }
 
456
                }
 
457
                block_put(b);
 
458
        }
 
459
        j = 0;
 
460
        
 
461
        /*
 
462
         * We need to grow the parent in order to create a new unused dentry.
 
463
         */
 
464
        if (parentp->idx->pfc == FAT_CLST_ROOT) {
 
465
                /* Can't grow the root directory. */
 
466
                fibril_mutex_unlock(&parentp->idx->lock);
 
467
                return ENOSPC;
 
468
        }
 
469
        rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
 
470
        if (rc != EOK) {
 
471
                fibril_mutex_unlock(&parentp->idx->lock);
 
472
                return rc;
 
473
        }
 
474
        fat_append_clusters(bs, parentp, mcl);
 
475
        b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NOREAD);
 
476
        d = (fat_dentry_t *)b->data;
 
477
        /*
 
478
         * Clear all dentries in the block except for the first one (the first
 
479
         * dentry will be cleared in the next step).
 
480
         */
 
481
        memset(d + 1, 0, bps - sizeof(fat_dentry_t));
 
482
 
 
483
hit:
 
484
        /*
 
485
         * At this point we only establish the link between the parent and the
 
486
         * child.  The dentry, except of the name and the extension, will remain
 
487
         * uninitialized until the corresponding node is synced. Thus the valid
 
488
         * dentry data is kept in the child node structure.
 
489
         */
 
490
        memset(d, 0, sizeof(fat_dentry_t));
 
491
        fat_dentry_name_set(d, name);
 
492
        b->dirty = true;                /* need to sync block */
 
493
        block_put(b);
 
494
        fibril_mutex_unlock(&parentp->idx->lock);
 
495
 
 
496
        fibril_mutex_lock(&childp->idx->lock);
 
497
        
 
498
        /*
 
499
         * If possible, create the Sub-directory Identifier Entry and the
 
500
         * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
 
501
         * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
 
502
         * not use them anyway, so this is rather a sign of our good will.
 
503
         */
 
504
        b = fat_block_get(bs, childp, 0, BLOCK_FLAGS_NONE);
 
505
        d = (fat_dentry_t *)b->data;
 
506
        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
 
507
            str_cmp(d->name, FAT_NAME_DOT) == 0) {
 
508
                memset(d, 0, sizeof(fat_dentry_t));
 
509
                str_cpy(d->name, 8, FAT_NAME_DOT);
 
510
                str_cpy(d->ext, 3, FAT_EXT_PAD);
 
511
                d->attr = FAT_ATTR_SUBDIR;
 
512
                d->firstc = host2uint16_t_le(childp->firstc);
 
513
                /* TODO: initialize also the date/time members. */
 
514
        }
 
515
        d++;
 
516
        if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
 
517
            str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
 
518
                memset(d, 0, sizeof(fat_dentry_t));
 
519
                str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
 
520
                str_cpy(d->ext, 3, FAT_EXT_PAD);
 
521
                d->attr = FAT_ATTR_SUBDIR;
 
522
                d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
 
523
                    host2uint16_t_le(FAT_CLST_RES0) :
 
524
                    host2uint16_t_le(parentp->firstc);
 
525
                /* TODO: initialize also the date/time members. */
 
526
        }
 
527
        b->dirty = true;                /* need to sync block */
 
528
        block_put(b);
 
529
 
 
530
        childp->idx->pfc = parentp->firstc;
 
531
        childp->idx->pdi = i * dps + j;
 
532
        fibril_mutex_unlock(&childp->idx->lock);
 
533
 
 
534
        fibril_mutex_lock(&childp->lock);
 
535
        childp->lnkcnt = 1;
 
536
        childp->dirty = true;           /* need to sync node */
 
537
        fibril_mutex_unlock(&childp->lock);
 
538
 
 
539
        /*
 
540
         * Hash in the index structure into the position hash.
 
541
         */
 
542
        fat_idx_hashin(childp->idx);
 
543
 
 
544
        return EOK;
 
545
}
 
546
 
 
547
int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
 
548
{
 
549
        fat_node_t *parentp = FAT_NODE(pfn);
 
550
        fat_node_t *childp = FAT_NODE(cfn);
 
551
        fat_bs_t *bs;
 
552
        fat_dentry_t *d;
 
553
        uint16_t bps;
 
554
        block_t *b;
 
555
 
 
556
        if (!parentp)
 
557
                return EBUSY;
 
558
        
 
559
        if (fat_has_children(cfn))
 
560
                return ENOTEMPTY;
 
561
 
 
562
        fibril_mutex_lock(&parentp->lock);
 
563
        fibril_mutex_lock(&childp->lock);
 
564
        assert(childp->lnkcnt == 1);
 
565
        fibril_mutex_lock(&childp->idx->lock);
 
566
        bs = block_bb_get(childp->idx->dev_handle);
 
567
        bps = uint16_t_le2host(bs->bps);
 
568
 
 
569
        b = _fat_block_get(bs, childp->idx->dev_handle, childp->idx->pfc,
 
570
            (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
 
571
            BLOCK_FLAGS_NONE);
 
572
        d = (fat_dentry_t *)b->data +
 
573
            (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
 
574
        /* mark the dentry as not-currently-used */
 
575
        d->name[0] = FAT_DENTRY_ERASED;
 
576
        b->dirty = true;                /* need to sync block */
 
577
        block_put(b);
 
578
 
 
579
        /* remove the index structure from the position hash */
 
580
        fat_idx_hashout(childp->idx);
 
581
        /* clear position information */
 
582
        childp->idx->pfc = FAT_CLST_RES0;
 
583
        childp->idx->pdi = 0;
 
584
        fibril_mutex_unlock(&childp->idx->lock);
 
585
        childp->lnkcnt = 0;
 
586
        childp->dirty = true;
 
587
        fibril_mutex_unlock(&childp->lock);
 
588
        fibril_mutex_unlock(&parentp->lock);
 
589
 
 
590
        return EOK;
 
591
}
 
592
 
 
593
fs_node_t *fat_match(fs_node_t *pfn, const char *component)
 
594
{
 
595
        fat_bs_t *bs;
 
596
        fat_node_t *parentp = FAT_NODE(pfn);
 
597
        char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
 
598
        unsigned i, j;
 
599
        unsigned bps;           /* bytes per sector */
 
600
        unsigned dps;           /* dentries per sector */
 
601
        unsigned blocks;
 
602
        fat_dentry_t *d;
 
603
        block_t *b;
 
604
 
 
605
        fibril_mutex_lock(&parentp->idx->lock);
 
606
        bs = block_bb_get(parentp->idx->dev_handle);
 
607
        bps = uint16_t_le2host(bs->bps);
 
608
        dps = bps / sizeof(fat_dentry_t);
 
609
        blocks = parentp->size / bps;
 
610
        for (i = 0; i < blocks; i++) {
 
611
                b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
 
612
                for (j = 0; j < dps; j++) { 
 
613
                        d = ((fat_dentry_t *)b->data) + j;
 
614
                        switch (fat_classify_dentry(d)) {
 
615
                        case FAT_DENTRY_SKIP:
 
616
                        case FAT_DENTRY_FREE:
 
617
                                continue;
 
618
                        case FAT_DENTRY_LAST:
 
619
                                block_put(b);
 
620
                                fibril_mutex_unlock(&parentp->idx->lock);
 
621
                                return NULL;
 
622
                        default:
 
623
                        case FAT_DENTRY_VALID:
 
624
                                fat_dentry_name_get(d, name);
 
625
                                break;
 
626
                        }
 
627
                        if (fat_dentry_namecmp(name, component) == 0) {
 
628
                                /* hit */
 
629
                                fat_node_t *nodep;
 
630
                                /*
 
631
                                 * Assume tree hierarchy for locking.  We
 
632
                                 * already have the parent and now we are going
 
633
                                 * to lock the child.  Never lock in the oposite
 
634
                                 * order.
 
635
                                 */
 
636
                                fat_idx_t *idx = fat_idx_get_by_pos(
 
637
                                    parentp->idx->dev_handle, parentp->firstc,
 
638
                                    i * dps + j);
 
639
                                fibril_mutex_unlock(&parentp->idx->lock);
 
640
                                if (!idx) {
 
641
                                        /*
 
642
                                         * Can happen if memory is low or if we
 
643
                                         * run out of 32-bit indices.
 
644
                                         */
 
645
                                        block_put(b);
 
646
                                        return NULL;
 
647
                                }
 
648
                                nodep = fat_node_get_core(idx);
 
649
                                fibril_mutex_unlock(&idx->lock);
 
650
                                block_put(b);
 
651
                                return FS_NODE(nodep);
 
652
                        }
 
653
                }
 
654
                block_put(b);
 
655
        }
 
656
 
 
657
        fibril_mutex_unlock(&parentp->idx->lock);
 
658
        return NULL;
 
659
}
 
660
 
 
661
fs_index_t fat_index_get(fs_node_t *fn)
 
662
{
 
663
        return FAT_NODE(fn)->idx->index;
 
664
}
 
665
 
 
666
size_t fat_size_get(fs_node_t *fn)
 
667
{
 
668
        return FAT_NODE(fn)->size;
 
669
}
 
670
 
 
671
unsigned fat_lnkcnt_get(fs_node_t *fn)
 
672
{
 
673
        return FAT_NODE(fn)->lnkcnt;
 
674
}
 
675
 
 
676
bool fat_has_children(fs_node_t *fn)
 
677
{
 
678
        fat_bs_t *bs;
 
679
        fat_node_t *nodep = FAT_NODE(fn);
 
680
        unsigned bps;
 
681
        unsigned dps;
 
682
        unsigned blocks;
 
683
        block_t *b;
 
684
        unsigned i, j;
 
685
 
 
686
        if (nodep->type != FAT_DIRECTORY)
 
687
                return false;
 
688
        
 
689
        fibril_mutex_lock(&nodep->idx->lock);
 
690
        bs = block_bb_get(nodep->idx->dev_handle);
 
691
        bps = uint16_t_le2host(bs->bps);
 
692
        dps = bps / sizeof(fat_dentry_t);
 
693
 
 
694
        blocks = nodep->size / bps;
 
695
 
 
696
        for (i = 0; i < blocks; i++) {
 
697
                fat_dentry_t *d;
 
698
        
 
699
                b = fat_block_get(bs, nodep, i, BLOCK_FLAGS_NONE);
 
700
                for (j = 0; j < dps; j++) {
 
701
                        d = ((fat_dentry_t *)b->data) + j;
 
702
                        switch (fat_classify_dentry(d)) {
 
703
                        case FAT_DENTRY_SKIP:
 
704
                        case FAT_DENTRY_FREE:
 
705
                                continue;
 
706
                        case FAT_DENTRY_LAST:
 
707
                                block_put(b);
 
708
                                fibril_mutex_unlock(&nodep->idx->lock);
 
709
                                return false;
 
710
                        default:
 
711
                        case FAT_DENTRY_VALID:
 
712
                                block_put(b);
 
713
                                fibril_mutex_unlock(&nodep->idx->lock);
 
714
                                return true;
 
715
                        }
 
716
                        block_put(b);
 
717
                        fibril_mutex_unlock(&nodep->idx->lock);
 
718
                        return true;
 
719
                }
 
720
                block_put(b);
 
721
        }
 
722
 
 
723
        fibril_mutex_unlock(&nodep->idx->lock);
 
724
        return false;
 
725
}
 
726
 
 
727
fs_node_t *fat_root_get(dev_handle_t dev_handle)
 
728
{
 
729
        return fat_node_get(dev_handle, 0);
 
730
}
 
731
 
 
732
char fat_plb_get_char(unsigned pos)
 
733
{
 
734
        return fat_reg.plb_ro[pos % PLB_SIZE];
 
735
}
 
736
 
 
737
bool fat_is_directory(fs_node_t *fn)
 
738
{
 
739
        return FAT_NODE(fn)->type == FAT_DIRECTORY;
 
740
}
 
741
 
 
742
bool fat_is_file(fs_node_t *fn)
 
743
{
 
744
        return FAT_NODE(fn)->type == FAT_FILE;
 
745
}
 
746
 
 
747
/** libfs operations */
 
748
libfs_ops_t fat_libfs_ops = {
 
749
        .match = fat_match,
 
750
        .node_get = fat_node_get,
 
751
        .node_put = fat_node_put,
 
752
        .create = fat_create_node,
 
753
        .destroy = fat_destroy_node,
 
754
        .link = fat_link,
 
755
        .unlink = fat_unlink,
 
756
        .index_get = fat_index_get,
 
757
        .size_get = fat_size_get,
 
758
        .lnkcnt_get = fat_lnkcnt_get,
 
759
        .has_children = fat_has_children,
 
760
        .root_get = fat_root_get,
 
761
        .plb_get_char = fat_plb_get_char,
 
762
        .is_directory = fat_is_directory,
 
763
        .is_file = fat_is_file
 
764
};
 
765
 
 
766
/*
 
767
 * VFS operations.
 
768
 */
 
769
 
 
770
void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
 
771
{
 
772
        dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
 
773
        enum cache_mode cmode;
 
774
        fat_bs_t *bs;
 
775
        uint16_t bps;
 
776
        uint16_t rde;
 
777
        int rc;
 
778
 
 
779
        /* accept the mount options */
 
780
        ipc_callid_t callid;
 
781
        size_t size;
 
782
        if (!ipc_data_write_receive(&callid, &size)) {
 
783
                ipc_answer_0(callid, EINVAL);
 
784
                ipc_answer_0(rid, EINVAL);
 
785
                return;
 
786
        }
 
787
        char *opts = malloc(size + 1);
 
788
        if (!opts) {
 
789
                ipc_answer_0(callid, ENOMEM);
 
790
                ipc_answer_0(rid, ENOMEM);
 
791
                return;
 
792
        }
 
793
        ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
 
794
        if (retval != EOK) {
 
795
                ipc_answer_0(rid, retval);
 
796
                free(opts);
 
797
                return;
 
798
        }
 
799
        opts[size] = '\0';
 
800
 
 
801
        /* Check for option enabling write through. */
 
802
        if (str_cmp(opts, "wtcache") == 0)
 
803
                cmode = CACHE_MODE_WT;
 
804
        else
 
805
                cmode = CACHE_MODE_WB;
 
806
 
 
807
        /* initialize libblock */
 
808
        rc = block_init(dev_handle, BS_SIZE);
 
809
        if (rc != EOK) {
 
810
                ipc_answer_0(rid, rc);
 
811
                return;
 
812
        }
 
813
 
 
814
        /* prepare the boot block */
 
815
        rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
 
816
        if (rc != EOK) {
 
817
                block_fini(dev_handle);
 
818
                ipc_answer_0(rid, rc);
 
819
                return;
 
820
        }
 
821
 
 
822
        /* get the buffer with the boot sector */
 
823
        bs = block_bb_get(dev_handle);
 
824
        
 
825
        /* Read the number of root directory entries. */
 
826
        bps = uint16_t_le2host(bs->bps);
 
827
        rde = uint16_t_le2host(bs->root_ent_max);
 
828
 
 
829
        if (bps != BS_SIZE) {
 
830
                block_fini(dev_handle);
 
831
                ipc_answer_0(rid, ENOTSUP);
 
832
                return;
 
833
        }
 
834
 
 
835
        /* Initialize the block cache */
 
836
        rc = block_cache_init(dev_handle, bps, 0 /* XXX */, cmode);
 
837
        if (rc != EOK) {
 
838
                block_fini(dev_handle);
 
839
                ipc_answer_0(rid, rc);
 
840
                return;
 
841
        }
 
842
 
 
843
        rc = fat_idx_init_by_dev_handle(dev_handle);
 
844
        if (rc != EOK) {
 
845
                block_fini(dev_handle);
 
846
                ipc_answer_0(rid, rc);
 
847
                return;
 
848
        }
 
849
 
 
850
        /* Initialize the root node. */
 
851
        fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
 
852
        if (!rfn) {
 
853
                block_fini(dev_handle);
 
854
                fat_idx_fini_by_dev_handle(dev_handle);
 
855
                ipc_answer_0(rid, ENOMEM);
 
856
                return;
 
857
        }
 
858
        fs_node_initialize(rfn);
 
859
        fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
 
860
        if (!rootp) {
 
861
                free(rfn);
 
862
                block_fini(dev_handle);
 
863
                fat_idx_fini_by_dev_handle(dev_handle);
 
864
                ipc_answer_0(rid, ENOMEM);
 
865
                return;
 
866
        }
 
867
        fat_node_initialize(rootp);
 
868
 
 
869
        fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
 
870
        if (!ridxp) {
 
871
                free(rfn);
 
872
                free(rootp);
 
873
                block_fini(dev_handle);
 
874
                fat_idx_fini_by_dev_handle(dev_handle);
 
875
                ipc_answer_0(rid, ENOMEM);
 
876
                return;
 
877
        }
 
878
        assert(ridxp->index == 0);
 
879
        /* ridxp->lock held */
 
880
 
 
881
        rootp->type = FAT_DIRECTORY;
 
882
        rootp->firstc = FAT_CLST_ROOT;
 
883
        rootp->refcnt = 1;
 
884
        rootp->lnkcnt = 0;      /* FS root is not linked */
 
885
        rootp->size = rde * sizeof(fat_dentry_t);
 
886
        rootp->idx = ridxp;
 
887
        ridxp->nodep = rootp;
 
888
        rootp->bp = rfn;
 
889
        rfn->data = rootp;
 
890
        
 
891
        fibril_mutex_unlock(&ridxp->lock);
 
892
 
 
893
        ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
 
894
}
 
895
 
 
896
void fat_mount(ipc_callid_t rid, ipc_call_t *request)
 
897
{
 
898
        libfs_mount(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
 
899
}
 
900
 
 
901
void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
 
902
{
 
903
        libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
 
904
}
 
905
 
 
906
void fat_read(ipc_callid_t rid, ipc_call_t *request)
 
907
{
 
908
        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
 
909
        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 
910
        off_t pos = (off_t)IPC_GET_ARG3(*request);
 
911
        fs_node_t *fn = fat_node_get(dev_handle, index);
 
912
        fat_node_t *nodep;
 
913
        fat_bs_t *bs;
 
914
        uint16_t bps;
 
915
        size_t bytes;
 
916
        block_t *b;
 
917
 
 
918
        if (!fn) {
 
919
                ipc_answer_0(rid, ENOENT);
 
920
                return;
 
921
        }
 
922
        nodep = FAT_NODE(fn);
 
923
 
 
924
        ipc_callid_t callid;
 
925
        size_t len;
 
926
        if (!ipc_data_read_receive(&callid, &len)) {
 
927
                fat_node_put(fn);
 
928
                ipc_answer_0(callid, EINVAL);
 
929
                ipc_answer_0(rid, EINVAL);
 
930
                return;
 
931
        }
 
932
 
 
933
        bs = block_bb_get(dev_handle);
 
934
        bps = uint16_t_le2host(bs->bps);
 
935
 
 
936
        if (nodep->type == FAT_FILE) {
 
937
                /*
 
938
                 * Our strategy for regular file reads is to read one block at
 
939
                 * most and make use of the possibility to return less data than
 
940
                 * requested. This keeps the code very simple.
 
941
                 */
 
942
                if (pos >= nodep->size) {
 
943
                        /* reading beyond the EOF */
 
944
                        bytes = 0;
 
945
                        (void) ipc_data_read_finalize(callid, NULL, 0);
 
946
                } else {
 
947
                        bytes = min(len, bps - pos % bps);
 
948
                        bytes = min(bytes, nodep->size - pos);
 
949
                        b = fat_block_get(bs, nodep, pos / bps,
 
950
                            BLOCK_FLAGS_NONE);
 
951
                        (void) ipc_data_read_finalize(callid, b->data + pos % bps,
 
952
                            bytes);
 
953
                        block_put(b);
 
954
                }
 
955
        } else {
 
956
                unsigned bnum;
 
957
                off_t spos = pos;
 
958
                char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
 
959
                fat_dentry_t *d;
 
960
 
 
961
                assert(nodep->type == FAT_DIRECTORY);
 
962
                assert(nodep->size % bps == 0);
 
963
                assert(bps % sizeof(fat_dentry_t) == 0);
 
964
 
 
965
                /*
 
966
                 * Our strategy for readdir() is to use the position pointer as
 
967
                 * an index into the array of all dentries. On entry, it points
 
968
                 * to the first unread dentry. If we skip any dentries, we bump
 
969
                 * the position pointer accordingly.
 
970
                 */
 
971
                bnum = (pos * sizeof(fat_dentry_t)) / bps;
 
972
                while (bnum < nodep->size / bps) {
 
973
                        off_t o;
 
974
 
 
975
                        b = fat_block_get(bs, nodep, bnum, BLOCK_FLAGS_NONE);
 
976
                        for (o = pos % (bps / sizeof(fat_dentry_t));
 
977
                            o < bps / sizeof(fat_dentry_t);
 
978
                            o++, pos++) {
 
979
                                d = ((fat_dentry_t *)b->data) + o;
 
980
                                switch (fat_classify_dentry(d)) {
 
981
                                case FAT_DENTRY_SKIP:
 
982
                                case FAT_DENTRY_FREE:
 
983
                                        continue;
 
984
                                case FAT_DENTRY_LAST:
 
985
                                        block_put(b);
 
986
                                        goto miss;
 
987
                                default:
 
988
                                case FAT_DENTRY_VALID:
 
989
                                        fat_dentry_name_get(d, name);
 
990
                                        block_put(b);
 
991
                                        goto hit;
 
992
                                }
 
993
                        }
 
994
                        block_put(b);
 
995
                        bnum++;
 
996
                }
 
997
miss:
 
998
                fat_node_put(fn);
 
999
                ipc_answer_0(callid, ENOENT);
 
1000
                ipc_answer_1(rid, ENOENT, 0);
 
1001
                return;
 
1002
hit:
 
1003
                (void) ipc_data_read_finalize(callid, name, str_size(name) + 1);
 
1004
                bytes = (pos - spos) + 1;
 
1005
        }
 
1006
 
 
1007
        fat_node_put(fn);
 
1008
        ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
 
1009
}
 
1010
 
 
1011
void fat_write(ipc_callid_t rid, ipc_call_t *request)
 
1012
{
 
1013
        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
 
1014
        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 
1015
        off_t pos = (off_t)IPC_GET_ARG3(*request);
 
1016
        fs_node_t *fn = fat_node_get(dev_handle, index);
 
1017
        fat_node_t *nodep;
 
1018
        fat_bs_t *bs;
 
1019
        size_t bytes;
 
1020
        block_t *b;
 
1021
        uint16_t bps;
 
1022
        unsigned spc;
 
1023
        unsigned bpc;           /* bytes per cluster */
 
1024
        off_t boundary;
 
1025
        int flags = BLOCK_FLAGS_NONE;
 
1026
        
 
1027
        if (!fn) {
 
1028
                ipc_answer_0(rid, ENOENT);
 
1029
                return;
 
1030
        }
 
1031
        nodep = FAT_NODE(fn);
 
1032
        
 
1033
        ipc_callid_t callid;
 
1034
        size_t len;
 
1035
        if (!ipc_data_write_receive(&callid, &len)) {
 
1036
                fat_node_put(fn);
 
1037
                ipc_answer_0(callid, EINVAL);
 
1038
                ipc_answer_0(rid, EINVAL);
 
1039
                return;
 
1040
        }
 
1041
 
 
1042
        bs = block_bb_get(dev_handle);
 
1043
        bps = uint16_t_le2host(bs->bps);
 
1044
        spc = bs->spc;
 
1045
        bpc = bps * spc;
 
1046
 
 
1047
        /*
 
1048
         * In all scenarios, we will attempt to write out only one block worth
 
1049
         * of data at maximum. There might be some more efficient approaches,
 
1050
         * but this one greatly simplifies fat_write(). Note that we can afford
 
1051
         * to do this because the client must be ready to handle the return
 
1052
         * value signalizing a smaller number of bytes written. 
 
1053
         */ 
 
1054
        bytes = min(len, bps - pos % bps);
 
1055
        if (bytes == bps)
 
1056
                flags |= BLOCK_FLAGS_NOREAD;
 
1057
        
 
1058
        boundary = ROUND_UP(nodep->size, bpc);
 
1059
        if (pos < boundary) {
 
1060
                /*
 
1061
                 * This is the easier case - we are either overwriting already
 
1062
                 * existing contents or writing behind the EOF, but still within
 
1063
                 * the limits of the last cluster. The node size may grow to the
 
1064
                 * next block size boundary.
 
1065
                 */
 
1066
                fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
 
1067
                b = fat_block_get(bs, nodep, pos / bps, flags);
 
1068
                (void) ipc_data_write_finalize(callid, b->data + pos % bps,
 
1069
                    bytes);
 
1070
                b->dirty = true;                /* need to sync block */
 
1071
                block_put(b);
 
1072
                if (pos + bytes > nodep->size) {
 
1073
                        nodep->size = pos + bytes;
 
1074
                        nodep->dirty = true;    /* need to sync node */
 
1075
                }
 
1076
                ipc_answer_2(rid, EOK, bytes, nodep->size);     
 
1077
                fat_node_put(fn);
 
1078
                return;
 
1079
        } else {
 
1080
                /*
 
1081
                 * This is the more difficult case. We must allocate new
 
1082
                 * clusters for the node and zero them out.
 
1083
                 */
 
1084
                int status;
 
1085
                unsigned nclsts;
 
1086
                fat_cluster_t mcl, lcl; 
 
1087
 
 
1088
                nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
 
1089
                /* create an independent chain of nclsts clusters in all FATs */
 
1090
                status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
 
1091
                if (status != EOK) {
 
1092
                        /* could not allocate a chain of nclsts clusters */
 
1093
                        fat_node_put(fn);
 
1094
                        ipc_answer_0(callid, status);
 
1095
                        ipc_answer_0(rid, status);
 
1096
                        return;
 
1097
                }
 
1098
                /* zero fill any gaps */
 
1099
                fat_fill_gap(bs, nodep, mcl, pos);
 
1100
                b = _fat_block_get(bs, dev_handle, lcl, (pos / bps) % spc,
 
1101
                    flags);
 
1102
                (void) ipc_data_write_finalize(callid, b->data + pos % bps,
 
1103
                    bytes);
 
1104
                b->dirty = true;                /* need to sync block */
 
1105
                block_put(b);
 
1106
                /*
 
1107
                 * Append the cluster chain starting in mcl to the end of the
 
1108
                 * node's cluster chain.
 
1109
                 */
 
1110
                fat_append_clusters(bs, nodep, mcl);
 
1111
                nodep->size = pos + bytes;
 
1112
                nodep->dirty = true;            /* need to sync node */
 
1113
                ipc_answer_2(rid, EOK, bytes, nodep->size);
 
1114
                fat_node_put(fn);
 
1115
                return;
 
1116
        }
 
1117
}
 
1118
 
 
1119
void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
 
1120
{
 
1121
        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
 
1122
        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 
1123
        size_t size = (off_t)IPC_GET_ARG3(*request);
 
1124
        fs_node_t *fn = fat_node_get(dev_handle, index);
 
1125
        fat_node_t *nodep;
 
1126
        fat_bs_t *bs;
 
1127
        uint16_t bps;
 
1128
        uint8_t spc;
 
1129
        unsigned bpc;   /* bytes per cluster */
 
1130
        int rc;
 
1131
 
 
1132
        if (!fn) {
 
1133
                ipc_answer_0(rid, ENOENT);
 
1134
                return;
 
1135
        }
 
1136
        nodep = FAT_NODE(fn);
 
1137
 
 
1138
        bs = block_bb_get(dev_handle);
 
1139
        bps = uint16_t_le2host(bs->bps);
 
1140
        spc = bs->spc;
 
1141
        bpc = bps * spc;
 
1142
 
 
1143
        if (nodep->size == size) {
 
1144
                rc = EOK;
 
1145
        } else if (nodep->size < size) {
 
1146
                /*
 
1147
                 * The standard says we have the freedom to grow the node.
 
1148
                 * For now, we simply return an error.
 
1149
                 */
 
1150
                rc = EINVAL;
 
1151
        } else if (ROUND_UP(nodep->size, bpc) == ROUND_UP(size, bpc)) {
 
1152
                /*
 
1153
                 * The node will be shrunk, but no clusters will be deallocated.
 
1154
                 */
 
1155
                nodep->size = size;
 
1156
                nodep->dirty = true;            /* need to sync node */
 
1157
                rc = EOK;       
 
1158
        } else {
 
1159
                /*
 
1160
                 * The node will be shrunk, clusters will be deallocated.
 
1161
                 */
 
1162
                if (size == 0) {
 
1163
                        fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
 
1164
                } else {
 
1165
                        fat_cluster_t lastc;
 
1166
                        (void) fat_cluster_walk(bs, dev_handle, nodep->firstc,
 
1167
                            &lastc, (size - 1) / bpc);
 
1168
                        fat_chop_clusters(bs, nodep, lastc);
 
1169
                }
 
1170
                nodep->size = size;
 
1171
                nodep->dirty = true;            /* need to sync node */
 
1172
                rc = EOK;       
 
1173
        }
 
1174
        fat_node_put(fn);
 
1175
        ipc_answer_0(rid, rc);
 
1176
        return;
 
1177
}
 
1178
 
 
1179
void fat_close(ipc_callid_t rid, ipc_call_t *request)
 
1180
{
 
1181
        ipc_answer_0(rid, EOK);
 
1182
}
 
1183
 
 
1184
void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
 
1185
{
 
1186
        dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
 
1187
        fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 
1188
        int rc;
 
1189
 
 
1190
        fs_node_t *fn = fat_node_get(dev_handle, index);
 
1191
        if (!fn) {
 
1192
                ipc_answer_0(rid, ENOENT);
 
1193
                return;
 
1194
        }
 
1195
 
 
1196
        rc = fat_destroy_node(fn);
 
1197
        ipc_answer_0(rid, rc);
 
1198
}
 
1199
 
 
1200
void fat_open_node(ipc_callid_t rid, ipc_call_t *request)
 
1201
{
 
1202
        libfs_open_node(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
 
1203
}
 
1204
 
 
1205
void fat_stat(ipc_callid_t rid, ipc_call_t *request)
 
1206
{
 
1207
        libfs_stat(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
 
1208
}
 
1209
 
 
1210
void fat_sync(ipc_callid_t rid, ipc_call_t *request)
 
1211
{
 
1212
        /* Dummy implementation */
 
1213
        ipc_answer_0(rid, EOK);
 
1214
}
 
1215
 
 
1216
/**
 
1217
 * @}
 
1218
 */