Subversion Repositories HelenOS

Rev

Rev 3022 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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