Subversion Repositories HelenOS

Rev

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

Rev 3386 Rev 4153
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>
42
#include <ipc/services.h>
45
#include <ipc/services.h>
43
#include <ipc/devmap.h>
46
#include <ipc/devmap.h>
44
#include <async.h>
47
#include <async.h>
45
#include <errno.h>
48
#include <errno.h>
Line 48... Line 51...
48
#include <libadt/hash_table.h>
51
#include <libadt/hash_table.h>
49
#include <libadt/list.h>
52
#include <libadt/list.h>
50
#include <assert.h>
53
#include <assert.h>
51
#include <futex.h>
54
#include <futex.h>
52
#include <sys/mman.h>
55
#include <sys/mman.h>
53
 
-
 
54
#define BS_BLOCK        0
56
#include <align.h>
55
#define BS_SIZE         512
-
 
56
 
57
 
57
/** Futex protecting the list of cached free FAT nodes. */
58
/** Futex protecting the list of cached free FAT nodes. */
58
static futex_t ffn_futex = FUTEX_INITIALIZER;
59
static futex_t ffn_futex = FUTEX_INITIALIZER;
59
 
60
 
60
/** List of cached free FAT nodes. */
61
/** List of cached free FAT nodes. */
61
static LIST_INITIALIZE(ffn_head);
62
static LIST_INITIALIZE(ffn_head);
62
 
63
 
63
#define FAT_NAME_LEN        8
-
 
64
#define FAT_EXT_LEN     3
-
 
65
 
-
 
66
#define FAT_PAD         ' ' 
-
 
67
 
-
 
68
#define FAT_DENTRY_UNUSED   0x00
-
 
69
#define FAT_DENTRY_E5_ESC   0x05
-
 
70
#define FAT_DENTRY_DOT      0x2e
-
 
71
#define FAT_DENTRY_ERASED   0xe5
-
 
72
 
-
 
73
#define min(a, b)       ((a) < (b) ? (a) : (b))
-
 
74
 
-
 
75
static void dentry_name_canonify(fat_dentry_t *d, char *buf)
-
 
76
{
-
 
77
    int i;
-
 
78
 
-
 
79
    for (i = 0; i < FAT_NAME_LEN; i++) {
-
 
80
        if (d->name[i] == FAT_PAD)
-
 
81
            break;
-
 
82
        if (d->name[i] == FAT_DENTRY_E5_ESC)
-
 
83
            *buf++ = 0xe5;
-
 
84
        else
-
 
85
            *buf++ = d->name[i];
-
 
86
    }
-
 
87
    if (d->ext[0] != FAT_PAD)
-
 
88
        *buf++ = '.';
-
 
89
    for (i = 0; i < FAT_EXT_LEN; i++) {
-
 
90
        if (d->ext[i] == FAT_PAD) {
-
 
91
            *buf = '\0';
-
 
92
            return;
-
 
93
        }
-
 
94
        if (d->ext[i] == FAT_DENTRY_E5_ESC)
-
 
95
            *buf++ = 0xe5;
-
 
96
        else
-
 
97
            *buf++ = d->ext[i];
-
 
98
    }
-
 
99
    *buf = '\0';
-
 
100
}
-
 
101
 
-
 
102
static int dev_phone = -1;      /* FIXME */
-
 
103
static void *dev_buffer = NULL;     /* FIXME */
-
 
104
 
-
 
105
/* TODO move somewhere else */
-
 
106
typedef struct {
-
 
107
    void *data;
-
 
108
    size_t size;
-
 
109
} block_t;
-
 
110
 
-
 
111
static block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
-
 
112
{
-
 
113
    /* FIXME */
-
 
114
    block_t *b;
-
 
115
    off_t bufpos = 0;
-
 
116
    size_t buflen = 0;
-
 
117
    off_t pos = offset * bs;
-
 
118
 
-
 
119
    assert(dev_phone != -1);
-
 
120
    assert(dev_buffer);
-
 
121
 
-
 
122
    b = malloc(sizeof(block_t));
-
 
123
    if (!b)
-
 
124
        return NULL;
-
 
125
   
-
 
126
    b->data = malloc(bs);
-
 
127
    if (!b->data) {
-
 
128
        free(b);
-
 
129
        return NULL;
-
 
130
    }
-
 
131
    b->size = bs;
-
 
132
 
-
 
133
    if (!libfs_blockread(dev_phone, dev_buffer, &bufpos, &buflen, &pos,
-
 
134
        b->data, bs, bs)) {
-
 
135
        free(b->data);
-
 
136
        free(b);
-
 
137
        return NULL;
-
 
138
    }
-
 
139
 
-
 
140
    return b;
-
 
141
}
-
 
142
 
-
 
143
static void block_put(block_t *block)
-
 
144
{
-
 
145
    /* FIXME */
-
 
146
    free(block->data);
-
 
147
    free(block);
-
 
148
}
-
 
149
 
-
 
150
#define FAT_BS(b)       ((fat_bs_t *)((b)->data))
-
 
151
 
-
 
152
#define FAT_CLST_RES0   0x0000
-
 
153
#define FAT_CLST_RES1   0x0001
-
 
154
#define FAT_CLST_FIRST  0x0002
-
 
155
#define FAT_CLST_BAD    0xfff7
-
 
156
#define FAT_CLST_LAST1  0xfff8
-
 
157
#define FAT_CLST_LAST8  0xffff
-
 
158
 
-
 
159
/* internally used to mark root directory's parent */
-
 
160
#define FAT_CLST_ROOTPAR    FAT_CLST_RES0
-
 
161
/* internally used to mark root directory */
-
 
162
#define FAT_CLST_ROOT       FAT_CLST_RES1
-
 
163
 
-
 
164
#define fat_block_get(np, off) \
-
 
165
    _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
-
 
166
 
-
 
167
static block_t *
-
 
168
_fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset)
-
 
169
{
-
 
170
    block_t *bb;
-
 
171
    block_t *b;
-
 
172
    unsigned bps;
-
 
173
    unsigned spc;
-
 
174
    unsigned rscnt;     /* block address of the first FAT */
-
 
175
    unsigned fatcnt;
-
 
176
    unsigned rde;
-
 
177
    unsigned rds;       /* root directory size */
-
 
178
    unsigned sf;
-
 
179
    unsigned ssa;       /* size of the system area */
-
 
180
    unsigned clusters;
-
 
181
    fat_cluster_t clst = firstc;
-
 
182
    unsigned i;
-
 
183
 
-
 
184
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
185
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
186
    spc = FAT_BS(bb)->spc;
-
 
187
    rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
-
 
188
    fatcnt = FAT_BS(bb)->fatcnt;
-
 
189
    rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
-
 
190
    sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
-
 
191
    block_put(bb);
-
 
192
 
-
 
193
    rds = (sizeof(fat_dentry_t) * rde) / bps;
-
 
194
    rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
-
 
195
    ssa = rscnt + fatcnt * sf + rds;
-
 
196
 
-
 
197
    if (firstc == FAT_CLST_ROOT) {
-
 
198
        /* root directory special case */
-
 
199
        assert(offset < rds);
-
 
200
        b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps);
-
 
201
        return b;
-
 
202
    }
-
 
203
 
-
 
204
    clusters = offset / spc;
-
 
205
    for (i = 0; i < clusters; i++) {
-
 
206
        unsigned fsec;  /* sector offset relative to FAT1 */
-
 
207
        unsigned fidx;  /* FAT1 entry index */
-
 
208
 
-
 
209
        assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
-
 
210
        fsec = (clst * sizeof(fat_cluster_t)) / bps;
-
 
211
        fidx = clst % (bps / sizeof(fat_cluster_t));
-
 
212
        /* read FAT1 */
-
 
213
        b = block_get(dev_handle, rscnt + fsec, bps);
-
 
214
        clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
-
 
215
        assert(clst != FAT_CLST_BAD);
-
 
216
        assert(clst < FAT_CLST_LAST1);
-
 
217
        block_put(b);
-
 
218
    }
-
 
219
 
-
 
220
    b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
-
 
221
        offset % spc, bps);
-
 
222
 
-
 
223
    return b;
-
 
224
}
-
 
225
 
-
 
226
/** Return number of blocks allocated to a file.
-
 
227
 *
-
 
228
 * @param dev_handle    Device handle of the device with the file.
-
 
229
 * @param firstc    First cluster of the file.
-
 
230
 *
-
 
231
 * @return      Number of blocks allocated to the file.
-
 
232
 */
-
 
233
static uint16_t
-
 
234
_fat_blcks_get(dev_handle_t dev_handle, fat_cluster_t firstc)
-
 
235
{
-
 
236
    block_t *bb;
-
 
237
    block_t *b;
-
 
238
    unsigned bps;
-
 
239
    unsigned spc;
-
 
240
    unsigned rscnt;     /* block address of the first FAT */
-
 
241
    unsigned clusters = 0;
-
 
242
    fat_cluster_t clst = firstc;
-
 
243
 
-
 
244
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
245
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
246
    spc = FAT_BS(bb)->spc;
-
 
247
    rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
-
 
248
    block_put(bb);
-
 
249
 
-
 
250
    if (firstc == FAT_CLST_RES0) {
-
 
251
        /* No space allocated to the file. */
-
 
252
        return 0;
-
 
253
    }
-
 
254
 
-
 
255
    while (clst < FAT_CLST_LAST1) {
-
 
256
        unsigned fsec;  /* sector offset relative to FAT1 */
-
 
257
        unsigned fidx;  /* FAT1 entry index */
-
 
258
 
-
 
259
        assert(clst >= FAT_CLST_FIRST);
-
 
260
        fsec = (clst * sizeof(fat_cluster_t)) / bps;
-
 
261
        fidx = clst % (bps / sizeof(fat_cluster_t));
-
 
262
        /* read FAT1 */
-
 
263
        b = block_get(dev_handle, rscnt + fsec, bps);
-
 
264
        clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
-
 
265
        assert(clst != FAT_CLST_BAD);
-
 
266
        block_put(b);
-
 
267
        clusters++;
-
 
268
    }
-
 
269
 
-
 
270
    return clusters * spc;
-
 
271
}
-
 
272
 
-
 
273
static void fat_node_initialize(fat_node_t *node)
64
static void fat_node_initialize(fat_node_t *node)
274
{
65
{
275
    futex_initialize(&node->lock, 1);
66
    futex_initialize(&node->lock, 1);
276
    node->idx = NULL;
67
    node->idx = NULL;
277
    node->type = 0;
68
    node->type = 0;
Line 280... Line 71...
280
    node->lnkcnt = 0;
71
    node->lnkcnt = 0;
281
    node->refcnt = 0;
72
    node->refcnt = 0;
282
    node->dirty = false;
73
    node->dirty = false;
283
}
74
}
284
 
75
 
285
static uint16_t fat_bps_get(dev_handle_t dev_handle)
76
static void fat_node_sync(fat_node_t *node)
286
{
77
{
287
    block_t *bb;
78
    block_t *b;
-
 
79
    fat_bs_t *bs;
-
 
80
    fat_dentry_t *d;
288
    uint16_t bps;
81
    uint16_t bps;
-
 
82
    unsigned dps;
289
   
83
   
290
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
291
    assert(bb != NULL);
84
    assert(node->dirty);
292
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
293
    block_put(bb);
-
 
294
 
85
 
-
 
86
    bs = block_bb_get(node->idx->dev_handle);
295
    return bps;
87
    bps = uint16_t_le2host(bs->bps);
-
 
88
    dps = bps / sizeof(fat_dentry_t);
296
}
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);
297
 
93
 
298
typedef enum {
-
 
299
    FAT_DENTRY_SKIP,
-
 
300
    FAT_DENTRY_LAST,
-
 
301
    FAT_DENTRY_VALID
-
 
302
} fat_dentry_clsf_t;
94
    d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
303
 
95
 
304
static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
96
    d->firstc = host2uint16_t_le(node->firstc);
305
{
-
 
306
    if (d->attr & FAT_ATTR_VOLLABEL) {
97
    if (node->type == FAT_FILE) {
307
        /* volume label entry */
-
 
308
        return FAT_DENTRY_SKIP;
98
        d->size = host2uint32_t_le(node->size);
309
    }
-
 
310
    if (d->name[0] == FAT_DENTRY_ERASED) {
99
    } else if (node->type == FAT_DIRECTORY) {
311
        /* not-currently-used entry */
-
 
312
        return FAT_DENTRY_SKIP;
100
        d->attr = FAT_ATTR_SUBDIR;
313
    }
-
 
314
    if (d->name[0] == FAT_DENTRY_UNUSED) {
-
 
315
        /* never used entry */
-
 
316
        return FAT_DENTRY_LAST;
-
 
317
    }
101
    }
318
    if (d->name[0] == FAT_DENTRY_DOT) {
-
 
319
        /*
102
   
320
         * Most likely '.' or '..'.
-
 
321
         * It cannot occur in a regular file name.
103
    /* TODO: update other fields? (e.g time fields) */
322
         */
104
   
323
        return FAT_DENTRY_SKIP;
105
    b->dirty = true;        /* need to sync block */
324
    }
-
 
325
    return FAT_DENTRY_VALID;
106
    block_put(b);
326
}
107
}
327
 
108
 
328
static void fat_node_sync(fat_node_t *node)
109
static fat_node_t *fat_node_get_new(void)
329
{
110
{
-
 
111
    fat_node_t *nodep;
-
 
112
 
-
 
113
    futex_down(&ffn_futex);
-
 
114
    if (!list_empty(&ffn_head)) {
-
 
115
        /* Try to use a cached free node structure. */
-
 
116
        fat_idx_t *idxp_tmp;
-
 
117
        nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
-
 
118
        if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
-
 
119
            goto skip_cache;
-
 
120
        idxp_tmp = nodep->idx;
-
 
121
        if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
-
 
122
            futex_up(&nodep->lock);
-
 
123
            goto skip_cache;
-
 
124
        }
-
 
125
        list_remove(&nodep->ffn_link);
-
 
126
        futex_up(&ffn_futex);
-
 
127
        if (nodep->dirty)
-
 
128
            fat_node_sync(nodep);
-
 
129
        idxp_tmp->nodep = NULL;
-
 
130
        futex_up(&nodep->lock);
-
 
131
        futex_up(&idxp_tmp->lock);
330
    /* TODO */
132
    } else {
-
 
133
skip_cache:
-
 
134
        /* Try to allocate a new node structure. */
-
 
135
        futex_up(&ffn_futex);
-
 
136
        nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
-
 
137
        if (!nodep)
-
 
138
            return NULL;
-
 
139
    }
-
 
140
    fat_node_initialize(nodep);
-
 
141
   
-
 
142
    return nodep;
331
}
143
}
332
 
144
 
333
/** Internal version of fat_node_get().
145
/** Internal version of fat_node_get().
334
 *
146
 *
335
 * @param idxp      Locked index structure.
147
 * @param idxp      Locked index structure.
336
 */
148
 */
337
static void *fat_node_get_core(fat_idx_t *idxp)
149
static void *fat_node_get_core(fat_idx_t *idxp)
338
{
150
{
339
    block_t *b;
151
    block_t *b;
-
 
152
    fat_bs_t *bs;
340
    fat_dentry_t *d;
153
    fat_dentry_t *d;
341
    fat_node_t *nodep = NULL;
154
    fat_node_t *nodep = NULL;
342
    unsigned bps;
155
    unsigned bps;
-
 
156
    unsigned spc;
343
    unsigned dps;
157
    unsigned dps;
344
 
158
 
345
    if (idxp->nodep) {
159
    if (idxp->nodep) {
346
        /*
160
        /*
347
         * We are lucky.
161
         * We are lucky.
Line 358... Line 172...
358
     * We must instantiate the node from the file system.
172
     * We must instantiate the node from the file system.
359
     */
173
     */
360
   
174
   
361
    assert(idxp->pfc);
175
    assert(idxp->pfc);
362
 
176
 
363
    futex_down(&ffn_futex);
-
 
364
    if (!list_empty(&ffn_head)) {
-
 
365
        /* Try to use a cached free node structure. */
-
 
366
        fat_idx_t *idxp_tmp;
-
 
367
        nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
-
 
368
        if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
-
 
369
            goto skip_cache;
-
 
370
        idxp_tmp = nodep->idx;
-
 
371
        if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
-
 
372
            futex_up(&nodep->lock);
-
 
373
            goto skip_cache;
-
 
374
        }
-
 
375
        list_remove(&nodep->ffn_link);
-
 
376
        futex_up(&ffn_futex);
-
 
377
        if (nodep->dirty)
-
 
378
            fat_node_sync(nodep);
177
    nodep = fat_node_get_new();
379
        idxp_tmp->nodep = NULL;
-
 
380
        futex_up(&nodep->lock);
-
 
381
        futex_up(&idxp_tmp->lock);
-
 
382
    } else {
-
 
383
skip_cache:
-
 
384
        /* Try to allocate a new node structure. */
-
 
385
        futex_up(&ffn_futex);
-
 
386
        nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
-
 
387
        if (!nodep)
178
    if (!nodep)
388
            return NULL;
179
        return NULL;
389
    }
-
 
390
    fat_node_initialize(nodep);
-
 
391
 
180
 
392
    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;
393
    dps = bps / sizeof(fat_dentry_t);
184
    dps = bps / sizeof(fat_dentry_t);
394
 
185
 
395
    /* Read the block that contains the dentry of interest. */
186
    /* Read the block that contains the dentry of interest. */
396
    b = _fat_block_get(idxp->dev_handle, idxp->pfc,
187
    b = _fat_block_get(bs, idxp->dev_handle, idxp->pfc,
397
        (idxp->pdi * sizeof(fat_dentry_t)) / bps);
188
        (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
398
    assert(b);
189
    assert(b);
399
 
190
 
400
    d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
191
    d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
401
    if (d->attr & FAT_ATTR_SUBDIR) {
192
    if (d->attr & FAT_ATTR_SUBDIR) {
402
        /*
193
        /*
Line 408... Line 199...
408
        /*
199
        /*
409
         * Unfortunately, the 'size' field of the FAT dentry is not
200
         * Unfortunately, the 'size' field of the FAT dentry is not
410
         * defined for the directory entry type. We must determine the
201
         * defined for the directory entry type. We must determine the
411
         * size of the directory by walking the FAT.
202
         * size of the directory by walking the FAT.
412
         */
203
         */
413
        nodep->size = bps * _fat_blcks_get(idxp->dev_handle,
204
        nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
414
            uint16_t_le2host(d->firstc));
205
            uint16_t_le2host(d->firstc));
415
    } else {
206
    } else {
416
        nodep->type = FAT_FILE;
207
        nodep->type = FAT_FILE;
417
        nodep->size = uint32_t_le2host(d->size);
208
        nodep->size = uint32_t_le2host(d->size);
418
    }
209
    }
Line 427... Line 218...
427
    idxp->nodep = nodep;
218
    idxp->nodep = nodep;
428
 
219
 
429
    return nodep;
220
    return nodep;
430
}
221
}
431
 
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
 
432
/** Instantiate a FAT in-core node. */
246
/** Instantiate a FAT in-core node. */
433
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)
434
{
248
{
435
    void *node;
249
    void *node;
436
    fat_idx_t *idxp;
250
    fat_idx_t *idxp;
437
 
251
 
438
    idxp = fat_idx_get_by_index(dev_handle, index);
252
    idxp = fat_idx_get_by_index(dev_handle, index);
Line 442... Line 256...
442
    node = fat_node_get_core(idxp);
256
    node = fat_node_get_core(idxp);
443
    futex_up(&idxp->lock);
257
    futex_up(&idxp->lock);
444
    return node;
258
    return node;
445
}
259
}
446
 
260
 
447
static void fat_node_put(void *node)
261
void fat_node_put(void *node)
448
{
262
{
449
    fat_node_t *nodep = (fat_node_t *)node;
263
    fat_node_t *nodep = (fat_node_t *)node;
-
 
264
    bool destroy = false;
450
 
265
 
451
    futex_down(&nodep->lock);
266
    futex_down(&nodep->lock);
452
    if (!--nodep->refcnt) {
267
    if (!--nodep->refcnt) {
-
 
268
        if (nodep->idx) {
453
        futex_down(&ffn_futex);
269
            futex_down(&ffn_futex);
454
        list_append(&nodep->ffn_link, &ffn_head);
270
            list_append(&nodep->ffn_link, &ffn_head);
455
        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
        }
456
    }
281
    }
457
    futex_up(&nodep->lock);
282
    futex_up(&nodep->lock);
-
 
283
    if (destroy)
-
 
284
        free(node);
458
}
285
}
459
 
286
 
460
static void *fat_create(int flags)
287
void *fat_create_node(dev_handle_t dev_handle, int flags)
461
{
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
    }
462
    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;
463
}
349
}
464
 
350
 
465
static int fat_destroy(void *node)
351
int fat_destroy_node(void *node)
466
{
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);
467
    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;
468
}
379
}
469
 
380
 
470
static bool fat_link(void *prnt, void *chld, const char *name)
381
int fat_link(void *prnt, void *chld, const char *name)
471
{
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
        /*
472
    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;
473
}
528
}
474
 
529
 
475
static int fat_unlink(void *prnt, void *chld)
530
int fat_unlink(void *prnt, void *chld)
476
{
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;
477
    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;
478
}
568
}
479
 
569
 
480
static void *fat_match(void *prnt, const char *component)
570
void *fat_match(void *prnt, const char *component)
481
{
571
{
-
 
572
    fat_bs_t *bs;
482
    fat_node_t *parentp = (fat_node_t *)prnt;
573
    fat_node_t *parentp = (fat_node_t *)prnt;
483
    char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
574
    char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
484
    unsigned i, j;
575
    unsigned i, j;
485
    unsigned bps;       /* bytes per sector */
576
    unsigned bps;       /* bytes per sector */
486
    unsigned dps;       /* dentries per sector */
577
    unsigned dps;       /* dentries per sector */
487
    unsigned blocks;
578
    unsigned blocks;
488
    fat_dentry_t *d;
579
    fat_dentry_t *d;
489
    block_t *b;
580
    block_t *b;
490
 
581
 
491
    futex_down(&parentp->idx->lock);
582
    futex_down(&parentp->idx->lock);
492
    bps = fat_bps_get(parentp->idx->dev_handle);
583
    bs = block_bb_get(parentp->idx->dev_handle);
-
 
584
    bps = uint16_t_le2host(bs->bps);
493
    dps = bps / sizeof(fat_dentry_t);
585
    dps = bps / sizeof(fat_dentry_t);
494
    blocks = parentp->size / bps + (parentp->size % bps != 0);
586
    blocks = parentp->size / bps;
495
    for (i = 0; i < blocks; i++) {
587
    for (i = 0; i < blocks; i++) {
496
        unsigned dentries;
-
 
497
       
-
 
498
        b = fat_block_get(parentp, i);
588
        b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
499
        dentries = (i == blocks - 1) ?
-
 
500
            parentp->size % sizeof(fat_dentry_t) :
-
 
501
            dps;
-
 
502
        for (j = 0; j < dentries; j++) {
589
        for (j = 0; j < dps; j++) {
503
            d = ((fat_dentry_t *)b->data) + j;
590
            d = ((fat_dentry_t *)b->data) + j;
504
            switch (fat_classify_dentry(d)) {
591
            switch (fat_classify_dentry(d)) {
505
            case FAT_DENTRY_SKIP:
592
            case FAT_DENTRY_SKIP:
-
 
593
            case FAT_DENTRY_FREE:
506
                continue;
594
                continue;
507
            case FAT_DENTRY_LAST:
595
            case FAT_DENTRY_LAST:
508
                block_put(b);
596
                block_put(b);
509
                futex_up(&parentp->idx->lock);
597
                futex_up(&parentp->idx->lock);
510
                return NULL;
598
                return NULL;
511
            default:
599
            default:
512
            case FAT_DENTRY_VALID:
600
            case FAT_DENTRY_VALID:
513
                dentry_name_canonify(d, name);
601
                fat_dentry_name_get(d, name);
514
                break;
602
                break;
515
            }
603
            }
516
            if (stricmp(name, component) == 0) {
604
            if (fat_dentry_namecmp(name, component) == 0) {
517
                /* hit */
605
                /* hit */
518
                void *node;
606
                void *node;
519
                /*
607
                /*
520
                 * Assume tree hierarchy for locking.  We
608
                 * Assume tree hierarchy for locking.  We
521
                 * already have the parent and now we are going
609
                 * already have the parent and now we are going
Line 540... Line 628...
540
                return node;
628
                return node;
541
            }
629
            }
542
        }
630
        }
543
        block_put(b);
631
        block_put(b);
544
    }
632
    }
-
 
633
 
545
    futex_up(&parentp->idx->lock);
634
    futex_up(&parentp->idx->lock);
546
    return NULL;
635
    return NULL;
547
}
636
}
548
 
637
 
549
static fs_index_t fat_index_get(void *node)
638
fs_index_t fat_index_get(void *node)
550
{
639
{
551
    fat_node_t *fnodep = (fat_node_t *)node;
640
    fat_node_t *fnodep = (fat_node_t *)node;
552
    if (!fnodep)
641
    if (!fnodep)
553
        return 0;
642
        return 0;
554
    return fnodep->idx->index;
643
    return fnodep->idx->index;
555
}
644
}
556
 
645
 
557
static size_t fat_size_get(void *node)
646
size_t fat_size_get(void *node)
558
{
647
{
559
    return ((fat_node_t *)node)->size;
648
    return ((fat_node_t *)node)->size;
560
}
649
}
561
 
650
 
562
static unsigned fat_lnkcnt_get(void *node)
651
unsigned fat_lnkcnt_get(void *node)
563
{
652
{
564
    return ((fat_node_t *)node)->lnkcnt;
653
    return ((fat_node_t *)node)->lnkcnt;
565
}
654
}
566
 
655
 
567
static bool fat_has_children(void *node)
656
bool fat_has_children(void *node)
568
{
657
{
-
 
658
    fat_bs_t *bs;
569
    fat_node_t *nodep = (fat_node_t *)node;
659
    fat_node_t *nodep = (fat_node_t *)node;
570
    unsigned bps;
660
    unsigned bps;
571
    unsigned dps;
661
    unsigned dps;
572
    unsigned blocks;
662
    unsigned blocks;
573
    block_t *b;
663
    block_t *b;
574
    unsigned i, j;
664
    unsigned i, j;
575
 
665
 
576
    if (nodep->type != FAT_DIRECTORY)
666
    if (nodep->type != FAT_DIRECTORY)
577
        return false;
667
        return false;
578
 
668
   
579
    futex_down(&nodep->idx->lock);
669
    futex_down(&nodep->idx->lock);
580
    bps = fat_bps_get(nodep->idx->dev_handle);
670
    bs = block_bb_get(nodep->idx->dev_handle);
-
 
671
    bps = uint16_t_le2host(bs->bps);
581
    dps = bps / sizeof(fat_dentry_t);
672
    dps = bps / sizeof(fat_dentry_t);
582
 
673
 
583
    blocks = nodep->size / bps + (nodep->size % bps != 0);
674
    blocks = nodep->size / bps;
584
 
675
 
585
    for (i = 0; i < blocks; i++) {
676
    for (i = 0; i < blocks; i++) {
586
        unsigned dentries;
-
 
587
        fat_dentry_t *d;
677
        fat_dentry_t *d;
588
   
678
   
589
        b = fat_block_get(nodep, i);
679
        b = fat_block_get(bs, nodep, i, BLOCK_FLAGS_NONE);
590
        dentries = (i == blocks - 1) ?
-
 
591
            nodep->size % sizeof(fat_dentry_t) :
-
 
592
            dps;
-
 
593
        for (j = 0; j < dentries; j++) {
680
        for (j = 0; j < dps; j++) {
594
            d = ((fat_dentry_t *)b->data) + j;
681
            d = ((fat_dentry_t *)b->data) + j;
595
            switch (fat_classify_dentry(d)) {
682
            switch (fat_classify_dentry(d)) {
596
            case FAT_DENTRY_SKIP:
683
            case FAT_DENTRY_SKIP:
-
 
684
            case FAT_DENTRY_FREE:
597
                continue;
685
                continue;
598
            case FAT_DENTRY_LAST:
686
            case FAT_DENTRY_LAST:
599
                block_put(b);
687
                block_put(b);
600
                futex_up(&nodep->idx->lock);
688
                futex_up(&nodep->idx->lock);
601
                return false;
689
                return false;
Line 614... Line 702...
614
 
702
 
615
    futex_up(&nodep->idx->lock);
703
    futex_up(&nodep->idx->lock);
616
    return false;
704
    return false;
617
}
705
}
618
 
706
 
619
static void *fat_root_get(dev_handle_t dev_handle)
707
void *fat_root_get(dev_handle_t dev_handle)
620
{
708
{
621
    return fat_node_get(dev_handle, 0);
709
    return fat_node_get(dev_handle, 0);
622
}
710
}
623
 
711
 
624
static char fat_plb_get_char(unsigned pos)
712
char fat_plb_get_char(unsigned pos)
625
{
713
{
626
    return fat_reg.plb_ro[pos % PLB_SIZE];
714
    return fat_reg.plb_ro[pos % PLB_SIZE];
627
}
715
}
628
 
716
 
629
static bool fat_is_directory(void *node)
717
bool fat_is_directory(void *node)
630
{
718
{
631
    return ((fat_node_t *)node)->type == FAT_DIRECTORY;
719
    return ((fat_node_t *)node)->type == FAT_DIRECTORY;
632
}
720
}
633
 
721
 
634
static bool fat_is_file(void *node)
722
bool fat_is_file(void *node)
635
{
723
{
636
    return ((fat_node_t *)node)->type == FAT_FILE;
724
    return ((fat_node_t *)node)->type == FAT_FILE;
637
}
725
}
638
 
726
 
639
/** libfs operations */
727
/** libfs operations */
640
libfs_ops_t fat_libfs_ops = {
728
libfs_ops_t fat_libfs_ops = {
641
    .match = fat_match,
729
    .match = fat_match,
642
    .node_get = fat_node_get,
730
    .node_get = fat_node_get,
643
    .node_put = fat_node_put,
731
    .node_put = fat_node_put,
644
    .create = fat_create,
732
    .create = fat_create_node,
645
    .destroy = fat_destroy,
733
    .destroy = fat_destroy_node,
646
    .link = fat_link,
734
    .link = fat_link,
647
    .unlink = fat_unlink,
735
    .unlink = fat_unlink,
648
    .index_get = fat_index_get,
736
    .index_get = fat_index_get,
649
    .size_get = fat_size_get,
737
    .size_get = fat_size_get,
650
    .lnkcnt_get = fat_lnkcnt_get,
738
    .lnkcnt_get = fat_lnkcnt_get,
Line 653... Line 741...
653
    .plb_get_char = fat_plb_get_char,
741
    .plb_get_char = fat_plb_get_char,
654
    .is_directory = fat_is_directory,
742
    .is_directory = fat_is_directory,
655
    .is_file = fat_is_file
743
    .is_file = fat_is_file
656
};
744
};
657
 
745
 
-
 
746
/*
-
 
747
 * VFS operations.
-
 
748
 */
-
 
749
 
658
void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
750
void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
659
{
751
{
660
    dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
752
    dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
661
    block_t *bb;
753
    fat_bs_t *bs;
662
    uint16_t bps;
754
    uint16_t bps;
663
    uint16_t rde;
755
    uint16_t rde;
664
    int rc;
756
    int rc;
665
 
757
 
666
    /*
-
 
667
     * For now, we don't bother to remember dev_handle, dev_phone or
-
 
668
     * dev_buffer in some data structure. We use global variables because we
-
 
669
     * know there will be at most one mount on this file system.
-
 
670
     * Of course, this is a huge TODO item.
758
    /* initialize libblock */
671
     */
-
 
672
    dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
-
 
673
        MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
759
    rc = block_init(dev_handle, BS_SIZE);
674
   
-
 
675
    if (!dev_buffer) {
760
    if (rc != EOK) {
676
        ipc_answer_0(rid, ENOMEM);
761
        ipc_answer_0(rid, rc);
677
        return;
-
 
678
    }
-
 
679
 
-
 
680
    dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
-
 
681
        DEVMAP_CONNECT_TO_DEVICE, dev_handle);
-
 
682
 
-
 
683
    if (dev_phone < 0) {
-
 
684
        munmap(dev_buffer, BS_SIZE);
-
 
685
        ipc_answer_0(rid, dev_phone);
-
 
686
        return;
762
        return;
687
    }
763
    }
688
 
764
 
689
    rc = ipc_share_out_start(dev_phone, dev_buffer,
765
    /* prepare the boot block */
690
        AS_AREA_READ | AS_AREA_WRITE);
766
    rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
691
    if (rc != EOK) {
767
    if (rc != EOK) {
692
            munmap(dev_buffer, BS_SIZE);
768
        block_fini(dev_handle);
693
        ipc_answer_0(rid, rc);
769
        ipc_answer_0(rid, rc);
694
        return;
770
        return;
695
    }
771
    }
696
 
772
 
-
 
773
    /* get the buffer with the boot sector */
-
 
774
    bs = block_bb_get(dev_handle);
-
 
775
   
697
    /* Read the number of root directory entries. */
776
    /* Read the number of root directory entries. */
698
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
699
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
777
    bps = uint16_t_le2host(bs->bps);
700
    rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
778
    rde = uint16_t_le2host(bs->root_ent_max);
701
    block_put(bb);
-
 
702
 
779
 
703
    if (bps != BS_SIZE) {
780
    if (bps != BS_SIZE) {
704
        munmap(dev_buffer, BS_SIZE);
781
        block_fini(dev_handle);
705
        ipc_answer_0(rid, ENOTSUP);
782
        ipc_answer_0(rid, ENOTSUP);
706
        return;
783
        return;
707
    }
784
    }
708
 
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
 
709
    rc = fat_idx_init_by_dev_handle(dev_handle);
794
    rc = fat_idx_init_by_dev_handle(dev_handle);
710
    if (rc != EOK) {
795
    if (rc != EOK) {
711
            munmap(dev_buffer, BS_SIZE);
796
        block_fini(dev_handle);
712
        ipc_answer_0(rid, rc);
797
        ipc_answer_0(rid, rc);
713
        return;
798
        return;
714
    }
799
    }
715
 
800
 
716
    /* Initialize the root node. */
801
    /* Initialize the root node. */
717
    fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
802
    fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
718
    if (!rootp) {
803
    if (!rootp) {
719
            munmap(dev_buffer, BS_SIZE);
804
        block_fini(dev_handle);
720
        fat_idx_fini_by_dev_handle(dev_handle);
805
        fat_idx_fini_by_dev_handle(dev_handle);
721
        ipc_answer_0(rid, ENOMEM);
806
        ipc_answer_0(rid, ENOMEM);
722
        return;
807
        return;
723
    }
808
    }
724
    fat_node_initialize(rootp);
809
    fat_node_initialize(rootp);
725
 
810
 
726
    fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
811
    fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
727
    if (!ridxp) {
812
    if (!ridxp) {
728
            munmap(dev_buffer, BS_SIZE);
813
        block_fini(dev_handle);
729
        free(rootp);
814
        free(rootp);
730
        fat_idx_fini_by_dev_handle(dev_handle);
815
        fat_idx_fini_by_dev_handle(dev_handle);
731
        ipc_answer_0(rid, ENOMEM);
816
        ipc_answer_0(rid, ENOMEM);
732
        return;
817
        return;
733
    }
818
    }
Line 761... Line 846...
761
{
846
{
762
    dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
847
    dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
763
    fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
848
    fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
764
    off_t pos = (off_t)IPC_GET_ARG3(*request);
849
    off_t pos = (off_t)IPC_GET_ARG3(*request);
765
    fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
850
    fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
-
 
851
    fat_bs_t *bs;
766
    uint16_t bps = fat_bps_get(dev_handle);
852
    uint16_t bps;
767
    size_t bytes;
853
    size_t bytes;
768
    block_t *b;
854
    block_t *b;
769
 
855
 
770
    if (!nodep) {
856
    if (!nodep) {
771
        ipc_answer_0(rid, ENOENT);
857
        ipc_answer_0(rid, ENOENT);
Line 779... Line 865...
779
        ipc_answer_0(callid, EINVAL);
865
        ipc_answer_0(callid, EINVAL);
780
        ipc_answer_0(rid, EINVAL);
866
        ipc_answer_0(rid, EINVAL);
781
        return;
867
        return;
782
    }
868
    }
783
 
869
 
-
 
870
    bs = block_bb_get(dev_handle);
-
 
871
    bps = uint16_t_le2host(bs->bps);
-
 
872
 
784
    if (nodep->type == FAT_FILE) {
873
    if (nodep->type == FAT_FILE) {
785
        /*
874
        /*
786
         * Our strategy for regular file reads is to read one block at
875
         * Our strategy for regular file reads is to read one block at
787
         * most and make use of the possibility to return less data than
876
         * most and make use of the possibility to return less data than
788
         * requested. This keeps the code very simple.
877
         * requested. This keeps the code very simple.
789
         */
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 {
790
        bytes = min(len, bps - pos % bps);
884
            bytes = min(len, bps - pos % bps);
-
 
885
            bytes = min(bytes, nodep->size - pos);
791
        b = fat_block_get(nodep, pos / bps);
886
            b = fat_block_get(bs, nodep, pos / bps,
-
 
887
                BLOCK_FLAGS_NONE);
792
        (void) ipc_data_read_finalize(callid, b->data + pos % bps,
888
            (void) ipc_data_read_finalize(callid, b->data + pos % bps,
793
            bytes);
889
                bytes);
794
        block_put(b);
890
            block_put(b);
-
 
891
        }
795
    } else {
892
    } else {
796
        unsigned bnum;
893
        unsigned bnum;
797
        off_t spos = pos;
894
        off_t spos = pos;
798
        char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
895
        char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
799
        fat_dentry_t *d;
896
        fat_dentry_t *d;
Line 810... Line 907...
810
         */
907
         */
811
        bnum = (pos * sizeof(fat_dentry_t)) / bps;
908
        bnum = (pos * sizeof(fat_dentry_t)) / bps;
812
        while (bnum < nodep->size / bps) {
909
        while (bnum < nodep->size / bps) {
813
            off_t o;
910
            off_t o;
814
 
911
 
815
            b = fat_block_get(nodep, bnum);
912
            b = fat_block_get(bs, nodep, bnum, BLOCK_FLAGS_NONE);
816
            for (o = pos % (bps / sizeof(fat_dentry_t));
913
            for (o = pos % (bps / sizeof(fat_dentry_t));
817
                o < bps / sizeof(fat_dentry_t);
914
                o < bps / sizeof(fat_dentry_t);
818
                o++, pos++) {
915
                o++, pos++) {
819
                d = ((fat_dentry_t *)b->data) + o;
916
                d = ((fat_dentry_t *)b->data) + o;
820
                switch (fat_classify_dentry(d)) {
917
                switch (fat_classify_dentry(d)) {
821
                case FAT_DENTRY_SKIP:
918
                case FAT_DENTRY_SKIP:
-
 
919
                case FAT_DENTRY_FREE:
822
                    continue;
920
                    continue;
823
                case FAT_DENTRY_LAST:
921
                case FAT_DENTRY_LAST:
824
                    block_put(b);
922
                    block_put(b);
825
                    goto miss;
923
                    goto miss;
826
                default:
924
                default:
827
                case FAT_DENTRY_VALID:
925
                case FAT_DENTRY_VALID:
828
                    dentry_name_canonify(d, name);
926
                    fat_dentry_name_get(d, name);
829
                    block_put(b);
927
                    block_put(b);
830
                    goto hit;
928
                    goto hit;
831
                }
929
                }
832
            }
930
            }
833
            block_put(b);
931
            block_put(b);
Line 845... Line 943...
845
 
943
 
846
    fat_node_put(nodep);
944
    fat_node_put(nodep);
847
    ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
945
    ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
848
}
946
}
849
 
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
 
850
/**
1128
/**
851
 * @}
1129
 * @}
852
 */
1130
 */