Subversion Repositories HelenOS

Rev

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

Rev 3397 Rev 3593
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);
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;
-
 
309
    }
-
 
310
    if (d->name[0] == FAT_DENTRY_ERASED) {
98
        d->size = host2uint32_t_le(node->size);
311
        /* not-currently-used entry */
99
    /* TODO: update other fields? (e.g time fields, attr field) */
312
        return FAT_DENTRY_SKIP;
-
 
313
    }
100
   
314
    if (d->name[0] == FAT_DENTRY_UNUSED) {
-
 
315
        /* never used entry */
101
    b->dirty = true;        /* need to sync block */
316
        return FAT_DENTRY_LAST;
-
 
317
    }
-
 
318
    if (d->name[0] == FAT_DENTRY_DOT) {
-
 
319
        /*
-
 
320
         * Most likely '.' or '..'.
-
 
321
         * It cannot occur in a regular file name.
-
 
322
         */
-
 
323
        return FAT_DENTRY_SKIP;
-
 
324
    }
-
 
325
    return FAT_DENTRY_VALID;
102
    block_put(b);
326
}
103
}
327
 
104
 
328
static void fat_node_sync(fat_node_t *node)
105
static fat_node_t *fat_node_get_new(void)
329
{
106
{
-
 
107
    fat_node_t *nodep;
-
 
108
 
-
 
109
    futex_down(&ffn_futex);
-
 
110
    if (!list_empty(&ffn_head)) {
-
 
111
        /* Try to use a cached free node structure. */
-
 
112
        fat_idx_t *idxp_tmp;
-
 
113
        nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
-
 
114
        if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
-
 
115
            goto skip_cache;
-
 
116
        idxp_tmp = nodep->idx;
-
 
117
        if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
-
 
118
            futex_up(&nodep->lock);
-
 
119
            goto skip_cache;
-
 
120
        }
-
 
121
        list_remove(&nodep->ffn_link);
-
 
122
        futex_up(&ffn_futex);
-
 
123
        if (nodep->dirty)
-
 
124
            fat_node_sync(nodep);
-
 
125
        idxp_tmp->nodep = NULL;
-
 
126
        futex_up(&nodep->lock);
-
 
127
        futex_up(&idxp_tmp->lock);
330
    /* TODO */
128
    } else {
-
 
129
skip_cache:
-
 
130
        /* Try to allocate a new node structure. */
-
 
131
        futex_up(&ffn_futex);
-
 
132
        nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
-
 
133
        if (!nodep)
-
 
134
            return NULL;
-
 
135
    }
-
 
136
    fat_node_initialize(nodep);
-
 
137
   
-
 
138
    return nodep;
331
}
139
}
332
 
140
 
333
/** Internal version of fat_node_get().
141
/** Internal version of fat_node_get().
334
 *
142
 *
335
 * @param idxp      Locked index structure.
143
 * @param idxp      Locked index structure.
336
 */
144
 */
337
static void *fat_node_get_core(fat_idx_t *idxp)
145
static void *fat_node_get_core(fat_idx_t *idxp)
338
{
146
{
339
    block_t *b;
147
    block_t *b;
-
 
148
    fat_bs_t *bs;
340
    fat_dentry_t *d;
149
    fat_dentry_t *d;
341
    fat_node_t *nodep = NULL;
150
    fat_node_t *nodep = NULL;
342
    unsigned bps;
151
    unsigned bps;
-
 
152
    unsigned spc;
343
    unsigned dps;
153
    unsigned dps;
344
 
154
 
345
    if (idxp->nodep) {
155
    if (idxp->nodep) {
346
        /*
156
        /*
347
         * We are lucky.
157
         * We are lucky.
Line 358... Line 168...
358
     * We must instantiate the node from the file system.
168
     * We must instantiate the node from the file system.
359
     */
169
     */
360
   
170
   
361
    assert(idxp->pfc);
171
    assert(idxp->pfc);
362
 
172
 
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);
173
    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)
174
    if (!nodep)
388
            return NULL;
175
        return NULL;
389
    }
-
 
390
    fat_node_initialize(nodep);
-
 
391
 
176
 
392
    bps = fat_bps_get(idxp->dev_handle);
177
    bs = block_bb_get(idxp->dev_handle);
-
 
178
    bps = uint16_t_le2host(bs->bps);
-
 
179
    spc = bs->spc;
393
    dps = bps / sizeof(fat_dentry_t);
180
    dps = bps / sizeof(fat_dentry_t);
394
 
181
 
395
    /* Read the block that contains the dentry of interest. */
182
    /* Read the block that contains the dentry of interest. */
396
    b = _fat_block_get(idxp->dev_handle, idxp->pfc,
183
    b = _fat_block_get(bs, idxp->dev_handle, idxp->pfc,
397
        (idxp->pdi * sizeof(fat_dentry_t)) / bps);
184
        (idxp->pdi * sizeof(fat_dentry_t)) / bps);
398
    assert(b);
185
    assert(b);
399
 
186
 
400
    d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
187
    d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
401
    if (d->attr & FAT_ATTR_SUBDIR) {
188
    if (d->attr & FAT_ATTR_SUBDIR) {
Line 408... Line 195...
408
        /*
195
        /*
409
         * Unfortunately, the 'size' field of the FAT dentry is not
196
         * Unfortunately, the 'size' field of the FAT dentry is not
410
         * defined for the directory entry type. We must determine the
197
         * defined for the directory entry type. We must determine the
411
         * size of the directory by walking the FAT.
198
         * size of the directory by walking the FAT.
412
         */
199
         */
413
        nodep->size = bps * _fat_blcks_get(idxp->dev_handle,
200
        nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
414
            uint16_t_le2host(d->firstc));
201
            uint16_t_le2host(d->firstc));
415
    } else {
202
    } else {
416
        nodep->type = FAT_FILE;
203
        nodep->type = FAT_FILE;
417
        nodep->size = uint32_t_le2host(d->size);
204
        nodep->size = uint32_t_le2host(d->size);
418
    }
205
    }
Line 455... Line 242...
455
        futex_up(&ffn_futex);
242
        futex_up(&ffn_futex);
456
    }
243
    }
457
    futex_up(&nodep->lock);
244
    futex_up(&nodep->lock);
458
}
245
}
459
 
246
 
460
static void *fat_create(int flags)
247
static void *fat_create(dev_handle_t dev_handle, int flags)
461
{
248
{
462
    return NULL;    /* not supported at the moment */
249
    return NULL;    /* not supported at the moment */
463
}
250
}
464
 
251
 
465
static int fat_destroy(void *node)
252
static int fat_destroy(void *node)
Line 477... Line 264...
477
    return ENOTSUP; /* not supported at the moment */
264
    return ENOTSUP; /* not supported at the moment */
478
}
265
}
479
 
266
 
480
static void *fat_match(void *prnt, const char *component)
267
static void *fat_match(void *prnt, const char *component)
481
{
268
{
-
 
269
    fat_bs_t *bs;
482
    fat_node_t *parentp = (fat_node_t *)prnt;
270
    fat_node_t *parentp = (fat_node_t *)prnt;
483
    char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
271
    char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
484
    unsigned i, j;
272
    unsigned i, j;
485
    unsigned bps;       /* bytes per sector */
273
    unsigned bps;       /* bytes per sector */
486
    unsigned dps;       /* dentries per sector */
274
    unsigned dps;       /* dentries per sector */
487
    unsigned blocks;
275
    unsigned blocks;
488
    fat_dentry_t *d;
276
    fat_dentry_t *d;
489
    block_t *b;
277
    block_t *b;
490
 
278
 
491
    futex_down(&parentp->idx->lock);
279
    futex_down(&parentp->idx->lock);
492
    bps = fat_bps_get(parentp->idx->dev_handle);
280
    bs = block_bb_get(parentp->idx->dev_handle);
-
 
281
    bps = uint16_t_le2host(bs->bps);
493
    dps = bps / sizeof(fat_dentry_t);
282
    dps = bps / sizeof(fat_dentry_t);
494
    blocks = parentp->size / bps + (parentp->size % bps != 0);
283
    blocks = parentp->size / bps;
495
    for (i = 0; i < blocks; i++) {
284
    for (i = 0; i < blocks; i++) {
496
        unsigned dentries;
-
 
497
       
-
 
498
        b = fat_block_get(parentp, i);
285
        b = fat_block_get(bs, parentp, i);
499
        dentries = (i == blocks - 1) ?
-
 
500
            parentp->size % sizeof(fat_dentry_t) :
-
 
501
            dps;
-
 
502
        for (j = 0; j < dentries; j++) {
286
        for (j = 0; j < dps; j++) {
503
            d = ((fat_dentry_t *)b->data) + j;
287
            d = ((fat_dentry_t *)b->data) + j;
504
            switch (fat_classify_dentry(d)) {
288
            switch (fat_classify_dentry(d)) {
505
            case FAT_DENTRY_SKIP:
289
            case FAT_DENTRY_SKIP:
506
                continue;
290
                continue;
507
            case FAT_DENTRY_LAST:
291
            case FAT_DENTRY_LAST:
Line 540... Line 324...
540
                return node;
324
                return node;
541
            }
325
            }
542
        }
326
        }
543
        block_put(b);
327
        block_put(b);
544
    }
328
    }
-
 
329
 
545
    futex_up(&parentp->idx->lock);
330
    futex_up(&parentp->idx->lock);
546
    return NULL;
331
    return NULL;
547
}
332
}
548
 
333
 
549
static fs_index_t fat_index_get(void *node)
334
static fs_index_t fat_index_get(void *node)
Line 564... Line 349...
564
    return ((fat_node_t *)node)->lnkcnt;
349
    return ((fat_node_t *)node)->lnkcnt;
565
}
350
}
566
 
351
 
567
static bool fat_has_children(void *node)
352
static bool fat_has_children(void *node)
568
{
353
{
-
 
354
    fat_bs_t *bs;
569
    fat_node_t *nodep = (fat_node_t *)node;
355
    fat_node_t *nodep = (fat_node_t *)node;
570
    unsigned bps;
356
    unsigned bps;
571
    unsigned dps;
357
    unsigned dps;
572
    unsigned blocks;
358
    unsigned blocks;
573
    block_t *b;
359
    block_t *b;
574
    unsigned i, j;
360
    unsigned i, j;
575
 
361
 
576
    if (nodep->type != FAT_DIRECTORY)
362
    if (nodep->type != FAT_DIRECTORY)
577
        return false;
363
        return false;
578
 
364
   
579
    futex_down(&nodep->idx->lock);
365
    futex_down(&nodep->idx->lock);
580
    bps = fat_bps_get(nodep->idx->dev_handle);
366
    bs = block_bb_get(nodep->idx->dev_handle);
-
 
367
    bps = uint16_t_le2host(bs->bps);
581
    dps = bps / sizeof(fat_dentry_t);
368
    dps = bps / sizeof(fat_dentry_t);
582
 
369
 
583
    blocks = nodep->size / bps + (nodep->size % bps != 0);
370
    blocks = nodep->size / bps;
584
 
371
 
585
    for (i = 0; i < blocks; i++) {
372
    for (i = 0; i < blocks; i++) {
586
        unsigned dentries;
-
 
587
        fat_dentry_t *d;
373
        fat_dentry_t *d;
588
   
374
   
589
        b = fat_block_get(nodep, i);
375
        b = fat_block_get(bs, nodep, i);
590
        dentries = (i == blocks - 1) ?
-
 
591
            nodep->size % sizeof(fat_dentry_t) :
-
 
592
            dps;
-
 
593
        for (j = 0; j < dentries; j++) {
376
        for (j = 0; j < dps; j++) {
594
            d = ((fat_dentry_t *)b->data) + j;
377
            d = ((fat_dentry_t *)b->data) + j;
595
            switch (fat_classify_dentry(d)) {
378
            switch (fat_classify_dentry(d)) {
596
            case FAT_DENTRY_SKIP:
379
            case FAT_DENTRY_SKIP:
597
                continue;
380
                continue;
598
            case FAT_DENTRY_LAST:
381
            case FAT_DENTRY_LAST:
Line 656... Line 439...
656
};
439
};
657
 
440
 
658
void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
441
void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
659
{
442
{
660
    dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
443
    dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
661
    block_t *bb;
444
    fat_bs_t *bs;
662
    uint16_t bps;
445
    uint16_t bps;
663
    uint16_t rde;
446
    uint16_t rde;
664
    int rc;
447
    int rc;
665
 
448
 
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.
449
    /* initialize libblock */
671
     */
-
 
672
    dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
-
 
673
        MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
450
    rc = block_init(dev_handle, BS_SIZE);
674
   
-
 
675
    if (!dev_buffer) {
451
    if (rc != EOK) {
676
        ipc_answer_0(rid, ENOMEM);
452
        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;
453
        return;
687
    }
454
    }
688
 
455
 
689
    rc = ipc_share_out_start(dev_phone, dev_buffer,
456
    /* prepare the boot block */
690
        AS_AREA_READ | AS_AREA_WRITE);
457
    rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
691
    if (rc != EOK) {
458
    if (rc != EOK) {
692
            munmap(dev_buffer, BS_SIZE);
459
        block_fini(dev_handle);
693
        ipc_answer_0(rid, rc);
460
        ipc_answer_0(rid, rc);
694
        return;
461
        return;
695
    }
462
    }
696
 
463
 
-
 
464
    /* get the buffer with the boot sector */
-
 
465
    bs = block_bb_get(dev_handle);
-
 
466
   
697
    /* Read the number of root directory entries. */
467
    /* 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);
468
    bps = uint16_t_le2host(bs->bps);
700
    rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
469
    rde = uint16_t_le2host(bs->root_ent_max);
701
    block_put(bb);
-
 
702
 
470
 
703
    if (bps != BS_SIZE) {
471
    if (bps != BS_SIZE) {
704
        munmap(dev_buffer, BS_SIZE);
472
        block_fini(dev_handle);
705
        ipc_answer_0(rid, ENOTSUP);
473
        ipc_answer_0(rid, ENOTSUP);
706
        return;
474
        return;
707
    }
475
    }
708
 
476
 
-
 
477
    /* Initialize the block cache */
-
 
478
    rc = block_cache_init(dev_handle, bps, 0 /* XXX */);
-
 
479
    if (rc != EOK) {
-
 
480
        block_fini(dev_handle);
-
 
481
        ipc_answer_0(rid, rc);
-
 
482
        return;
-
 
483
    }
-
 
484
 
709
    rc = fat_idx_init_by_dev_handle(dev_handle);
485
    rc = fat_idx_init_by_dev_handle(dev_handle);
710
    if (rc != EOK) {
486
    if (rc != EOK) {
711
            munmap(dev_buffer, BS_SIZE);
487
        block_fini(dev_handle);
712
        ipc_answer_0(rid, rc);
488
        ipc_answer_0(rid, rc);
713
        return;
489
        return;
714
    }
490
    }
715
 
491
 
716
    /* Initialize the root node. */
492
    /* Initialize the root node. */
717
    fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
493
    fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
718
    if (!rootp) {
494
    if (!rootp) {
719
            munmap(dev_buffer, BS_SIZE);
495
        block_fini(dev_handle);
720
        fat_idx_fini_by_dev_handle(dev_handle);
496
        fat_idx_fini_by_dev_handle(dev_handle);
721
        ipc_answer_0(rid, ENOMEM);
497
        ipc_answer_0(rid, ENOMEM);
722
        return;
498
        return;
723
    }
499
    }
724
    fat_node_initialize(rootp);
500
    fat_node_initialize(rootp);
725
 
501
 
726
    fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
502
    fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
727
    if (!ridxp) {
503
    if (!ridxp) {
728
            munmap(dev_buffer, BS_SIZE);
504
        block_fini(dev_handle);
729
        free(rootp);
505
        free(rootp);
730
        fat_idx_fini_by_dev_handle(dev_handle);
506
        fat_idx_fini_by_dev_handle(dev_handle);
731
        ipc_answer_0(rid, ENOMEM);
507
        ipc_answer_0(rid, ENOMEM);
732
        return;
508
        return;
733
    }
509
    }
Line 761... Line 537...
761
{
537
{
762
    dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
538
    dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
763
    fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
539
    fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
764
    off_t pos = (off_t)IPC_GET_ARG3(*request);
540
    off_t pos = (off_t)IPC_GET_ARG3(*request);
765
    fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
541
    fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
-
 
542
    fat_bs_t *bs;
766
    uint16_t bps = fat_bps_get(dev_handle);
543
    uint16_t bps;
767
    size_t bytes;
544
    size_t bytes;
768
    block_t *b;
545
    block_t *b;
769
 
546
 
770
    if (!nodep) {
547
    if (!nodep) {
771
        ipc_answer_0(rid, ENOENT);
548
        ipc_answer_0(rid, ENOENT);
Line 779... Line 556...
779
        ipc_answer_0(callid, EINVAL);
556
        ipc_answer_0(callid, EINVAL);
780
        ipc_answer_0(rid, EINVAL);
557
        ipc_answer_0(rid, EINVAL);
781
        return;
558
        return;
782
    }
559
    }
783
 
560
 
-
 
561
    bs = block_bb_get(dev_handle);
-
 
562
    bps = uint16_t_le2host(bs->bps);
-
 
563
 
784
    if (nodep->type == FAT_FILE) {
564
    if (nodep->type == FAT_FILE) {
785
        /*
565
        /*
786
         * Our strategy for regular file reads is to read one block at
566
         * 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
567
         * most and make use of the possibility to return less data than
788
         * requested. This keeps the code very simple.
568
         * requested. This keeps the code very simple.
789
         */
569
         */
-
 
570
        if (pos >= nodep->size) {
-
 
571
            /* reading beyond the EOF */
-
 
572
            bytes = 0;
-
 
573
            (void) ipc_data_read_finalize(callid, NULL, 0);
-
 
574
        } else {
790
        bytes = min(len, bps - pos % bps);
575
            bytes = min(len, bps - pos % bps);
-
 
576
            bytes = min(bytes, nodep->size - pos);
791
        b = fat_block_get(nodep, pos / bps);
577
            b = fat_block_get(bs, nodep, pos / bps);
792
        (void) ipc_data_read_finalize(callid, b->data + pos % bps,
578
            (void) ipc_data_read_finalize(callid, b->data + pos % bps,
793
            bytes);
579
                bytes);
794
        block_put(b);
580
            block_put(b);
-
 
581
        }
795
    } else {
582
    } else {
796
        unsigned bnum;
583
        unsigned bnum;
797
        off_t spos = pos;
584
        off_t spos = pos;
798
        char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
585
        char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
799
        fat_dentry_t *d;
586
        fat_dentry_t *d;
Line 810... Line 597...
810
         */
597
         */
811
        bnum = (pos * sizeof(fat_dentry_t)) / bps;
598
        bnum = (pos * sizeof(fat_dentry_t)) / bps;
812
        while (bnum < nodep->size / bps) {
599
        while (bnum < nodep->size / bps) {
813
            off_t o;
600
            off_t o;
814
 
601
 
815
            b = fat_block_get(nodep, bnum);
602
            b = fat_block_get(bs, nodep, bnum);
816
            for (o = pos % (bps / sizeof(fat_dentry_t));
603
            for (o = pos % (bps / sizeof(fat_dentry_t));
817
                o < bps / sizeof(fat_dentry_t);
604
                o < bps / sizeof(fat_dentry_t);
818
                o++, pos++) {
605
                o++, pos++) {
819
                d = ((fat_dentry_t *)b->data) + o;
606
                d = ((fat_dentry_t *)b->data) + o;
820
                switch (fat_classify_dentry(d)) {
607
                switch (fat_classify_dentry(d)) {
Line 845... Line 632...
845
 
632
 
846
    fat_node_put(nodep);
633
    fat_node_put(nodep);
847
    ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
634
    ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
848
}
635
}
849
 
636
 
-
 
637
void fat_write(ipc_callid_t rid, ipc_call_t *request)
-
 
638
{
-
 
639
    dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
-
 
640
    fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
-
 
641
    off_t pos = (off_t)IPC_GET_ARG3(*request);
-
 
642
    fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
-
 
643
    fat_bs_t *bs;
-
 
644
    size_t bytes;
-
 
645
    block_t *b;
-
 
646
    uint16_t bps;
-
 
647
    unsigned spc;
-
 
648
    unsigned bpc;       /* bytes per cluster */
-
 
649
    off_t boundary;
-
 
650
   
-
 
651
    if (!nodep) {
-
 
652
        ipc_answer_0(rid, ENOENT);
-
 
653
        return;
-
 
654
    }
-
 
655
   
-
 
656
    ipc_callid_t callid;
-
 
657
    size_t len;
-
 
658
    if (!ipc_data_write_receive(&callid, &len)) {
-
 
659
        fat_node_put(nodep);
-
 
660
        ipc_answer_0(callid, EINVAL);
-
 
661
        ipc_answer_0(rid, EINVAL);
-
 
662
        return;
-
 
663
    }
-
 
664
 
-
 
665
    bs = block_bb_get(dev_handle);
-
 
666
    bps = uint16_t_le2host(bs->bps);
-
 
667
    spc = bs->spc;
-
 
668
    bpc = bps * spc;
-
 
669
 
-
 
670
    /*
-
 
671
     * In all scenarios, we will attempt to write out only one block worth
-
 
672
     * of data at maximum. There might be some more efficient approaches,
-
 
673
     * but this one greatly simplifies fat_write(). Note that we can afford
-
 
674
     * to do this because the client must be ready to handle the return
-
 
675
     * value signalizing a smaller number of bytes written.
-
 
676
     */
-
 
677
    bytes = min(len, bps - pos % bps);
-
 
678
   
-
 
679
    boundary = ROUND_UP(nodep->size, bpc);
-
 
680
    if (pos < boundary) {
-
 
681
        /*
-
 
682
         * This is the easier case - we are either overwriting already
-
 
683
         * existing contents or writing behind the EOF, but still within
-
 
684
         * the limits of the last cluster. The node size may grow to the
-
 
685
         * next block size boundary.
-
 
686
         */
-
 
687
        fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
-
 
688
        b = fat_block_get(bs, nodep, pos / bps);
-
 
689
        (void) ipc_data_write_finalize(callid, b->data + pos % bps,
-
 
690
            bytes);
-
 
691
        b->dirty = true;        /* need to sync block */
-
 
692
        block_put(b);
-
 
693
        if (pos + bytes > nodep->size) {
-
 
694
            nodep->size = pos + bytes;
-
 
695
            nodep->dirty = true;    /* need to sync node */
-
 
696
        }
-
 
697
        ipc_answer_2(rid, EOK, bytes, nodep->size);
-
 
698
        fat_node_put(nodep);
-
 
699
        return;
-
 
700
    } else {
-
 
701
        /*
-
 
702
         * This is the more difficult case. We must allocate new
-
 
703
         * clusters for the node and zero them out.
-
 
704
         */
-
 
705
        int status;
-
 
706
        unsigned nclsts;
-
 
707
        fat_cluster_t mcl, lcl;
-
 
708
 
-
 
709
        nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
-
 
710
        /* create an independent chain of nclsts clusters in all FATs */
-
 
711
        status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
-
 
712
        if (status != EOK) {
-
 
713
            /* could not allocate a chain of nclsts clusters */
-
 
714
            fat_node_put(nodep);
-
 
715
            ipc_answer_0(callid, status);
-
 
716
            ipc_answer_0(rid, status);
-
 
717
            return;
-
 
718
        }
-
 
719
        /* zero fill any gaps */
-
 
720
        fat_fill_gap(bs, nodep, mcl, pos);
-
 
721
        b = _fat_block_get(bs, dev_handle, lcl, (pos / bps) % spc);
-
 
722
        (void) ipc_data_write_finalize(callid, b->data + pos % bps,
-
 
723
            bytes);
-
 
724
        b->dirty = true;        /* need to sync block */
-
 
725
        block_put(b);
-
 
726
        /*
-
 
727
         * Append the cluster chain starting in mcl to the end of the
-
 
728
         * node's cluster chain.
-
 
729
         */
-
 
730
        fat_append_clusters(bs, nodep, mcl);
-
 
731
        nodep->size = pos + bytes;
-
 
732
        nodep->dirty = true;        /* need to sync node */
-
 
733
        ipc_answer_2(rid, EOK, bytes, nodep->size);
-
 
734
        fat_node_put(nodep);
-
 
735
        return;
-
 
736
    }
-
 
737
}
-
 
738
 
-
 
739
void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
-
 
740
{
-
 
741
    dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
-
 
742
    fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
-
 
743
    size_t size = (off_t)IPC_GET_ARG3(*request);
-
 
744
    fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
-
 
745
    fat_bs_t *bs;
-
 
746
    uint16_t bps;
-
 
747
    uint8_t spc;
-
 
748
    unsigned bpc;   /* bytes per cluster */
-
 
749
    int rc;
-
 
750
 
-
 
751
    if (!nodep) {
-
 
752
        ipc_answer_0(rid, ENOENT);
-
 
753
        return;
-
 
754
    }
-
 
755
 
-
 
756
    bs = block_bb_get(dev_handle);
-
 
757
    bps = uint16_t_le2host(bs->bps);
-
 
758
    spc = bs->spc;
-
 
759
    bpc = bps * spc;
-
 
760
 
-
 
761
    if (nodep->size == size) {
-
 
762
        rc = EOK;
-
 
763
    } else if (nodep->size < size) {
-
 
764
        /*
-
 
765
         * The standard says we have the freedom to grow the node.
-
 
766
         * For now, we simply return an error.
-
 
767
         */
-
 
768
        rc = EINVAL;
-
 
769
    } else if (ROUND_UP(nodep->size, bpc) == ROUND_UP(size, bpc)) {
-
 
770
        /*
-
 
771
         * The node will be shrunk, but no clusters will be deallocated.
-
 
772
         */
-
 
773
        nodep->size = size;
-
 
774
        nodep->dirty = true;        /* need to sync node */
-
 
775
        rc = EOK;  
-
 
776
    } else {
-
 
777
        /*
-
 
778
         * The node will be shrunk, clusters will be deallocated.
-
 
779
         */
-
 
780
        if (size == 0) {
-
 
781
            fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
-
 
782
        } else {
-
 
783
            fat_cluster_t lastc;
-
 
784
            (void) fat_cluster_walk(bs, dev_handle, nodep->firstc,
-
 
785
                &lastc, (size - 1) / bpc);
-
 
786
            fat_chop_clusters(bs, nodep, lastc);
-
 
787
        }
-
 
788
        nodep->size = size;
-
 
789
        nodep->dirty = true;        /* need to sync node */
-
 
790
        rc = EOK;  
-
 
791
    }
-
 
792
    fat_node_put(nodep);
-
 
793
    ipc_answer_0(rid, rc);
-
 
794
    return;
-
 
795
}
-
 
796
 
850
/**
797
/**
851
 * @}
798
 * @}
852
 */
799
 */