source: mainline/uspace/srv/fs/fat/fat_ops.c@ 4573a79

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

New first bits of fat_node_get().

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33/**
34 * @file fat_ops.c
35 * @brief Implementation of VFS operations for the FAT file system server.
36 */
37
38#include "fat.h"
39#include "../../vfs/vfs.h"
40#include <libfs.h>
41#include <ipc/ipc.h>
42#include <async.h>
43#include <errno.h>
44#include <string.h>
45#include <byteorder.h>
46#include <libadt/hash_table.h>
47#include <libadt/list.h>
48#include <assert.h>
49#include <futex.h>
50
51#define BS_BLOCK 0
52
53#define FIN_KEY_DEV_HANDLE 0
54#define FIN_KEY_INDEX 1
55
56/** Hash table of FAT in-core nodes. */
57hash_table_t fin_hash;
58
59/** List of free FAT in-core nodes. */
60link_t ffn_head;
61
62#define FAT_NAME_LEN 8
63#define FAT_EXT_LEN 3
64
65#define FAT_PAD ' '
66
67#define FAT_DENTRY_UNUSED 0x00
68#define FAT_DENTRY_E5_ESC 0x05
69#define FAT_DENTRY_DOT 0x2e
70#define FAT_DENTRY_ERASED 0xe5
71
72static void dentry_name_canonify(fat_dentry_t *d, char *buf)
73{
74 int i;
75
76 for (i = 0; i < FAT_NAME_LEN; i++) {
77 if (d->name[i] == FAT_PAD) {
78 buf++;
79 break;
80 }
81 if (d->name[i] == FAT_DENTRY_E5_ESC)
82 *buf++ = 0xe5;
83 else
84 *buf++ = d->name[i];
85 }
86 if (d->ext[0] != FAT_PAD)
87 *buf++ = '.';
88 for (i = 0; i < FAT_EXT_LEN; i++) {
89 if (d->ext[i] == FAT_PAD) {
90 *buf = '\0';
91 return;
92 }
93 if (d->ext[i] == FAT_DENTRY_E5_ESC)
94 *buf++ = 0xe5;
95 else
96 *buf++ = d->ext[i];
97 }
98}
99
100/* TODO and also move somewhere else */
101typedef struct {
102 void *data;
103} block_t;
104
105static block_t *block_get(dev_handle_t dev_handle, off_t offset)
106{
107 return NULL; /* TODO */
108}
109
110static void block_put(block_t *block)
111{
112 /* TODO */
113}
114
115#define FAT_BS(b) ((fat_bs_t *)((b)->data))
116
117#define FAT_CLST_RES0 0x0000
118#define FAT_CLST_RES1 0x0001 /* internally used to mark root directory */
119#define FAT_CLST_FIRST 0x0002
120#define FAT_CLST_BAD 0xfff7
121#define FAT_CLST_LAST1 0xfff8
122#define FAT_CLST_LAST8 0xffff
123
124#define fat_block_get(np, off) \
125 _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
126
127static block_t *
128_fat_block_get(dev_handle_t dev_handle, fat_cluster_t fc, off_t offset)
129{
130 block_t *bb;
131 block_t *b;
132 unsigned bps;
133 unsigned spc;
134 unsigned rscnt; /* block address of the first FAT */
135 unsigned fatcnt;
136 unsigned rde;
137 unsigned rds; /* root directory size */
138 unsigned sf;
139 unsigned ssa; /* size of the system area */
140 unsigned clusters;
141 fat_cluster_t clst = fc;
142 unsigned i;
143
144 bb = block_get(dev_handle, BS_BLOCK);
145 bps = uint16_t_le2host(FAT_BS(bb)->bps);
146 spc = FAT_BS(bb)->spc;
147 rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
148 fatcnt = FAT_BS(bb)->fatcnt;
149 rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
150 sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
151 block_put(bb);
152
153 rds = (sizeof(fat_dentry_t) * rde) / bps;
154 rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
155 ssa = rscnt + fatcnt * sf + rds;
156
157 if (fc == FAT_CLST_RES1) {
158 /* root directory special case */
159 assert(offset < rds);
160 b = block_get(dev_handle, rscnt + fatcnt * sf + offset);
161 return b;
162 }
163
164 clusters = offset / spc;
165 for (i = 0; i < clusters; i++) {
166 unsigned fsec; /* sector offset relative to FAT1 */
167 unsigned fidx; /* FAT1 entry index */
168
169 assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
170 fsec = (clst * sizeof(fat_cluster_t)) / bps;
171 fidx = clst % (bps / sizeof(fat_cluster_t));
172 /* read FAT1 */
173 b = block_get(dev_handle, rscnt + fsec);
174 clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
175 assert(clst != FAT_CLST_BAD);
176 assert(clst < FAT_CLST_LAST1);
177 block_put(b);
178 }
179
180 b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
181 offset % spc);
182
183 return b;
184}
185
186static void fat_node_initialize(fat_node_t *node)
187{
188 node->idx = NULL;
189 node->type = 0;
190 link_initialize(&node->fin_link);
191 link_initialize(&node->ffn_link);
192 node->size = 0;
193 node->lnkcnt = 0;
194 node->refcnt = 0;
195 node->dirty = false;
196}
197
198static uint16_t fat_bps_get(dev_handle_t dev_handle)
199{
200 block_t *bb;
201 uint16_t bps;
202
203 bb = block_get(dev_handle, BS_BLOCK);
204 assert(bb != NULL);
205 bps = uint16_t_le2host(FAT_BS(bb)->bps);
206 block_put(bb);
207
208 return bps;
209}
210
211typedef enum {
212 FAT_DENTRY_SKIP,
213 FAT_DENTRY_LAST,
214 FAT_DENTRY_VALID
215} fat_dentry_clsf_t;
216
217static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
218{
219 if (d->attr & FAT_ATTR_VOLLABEL) {
220 /* volume label entry */
221 return FAT_DENTRY_SKIP;
222 }
223 if (d->name[0] == FAT_DENTRY_ERASED) {
224 /* not-currently-used entry */
225 return FAT_DENTRY_SKIP;
226 }
227 if (d->name[0] == FAT_DENTRY_UNUSED) {
228 /* never used entry */
229 return FAT_DENTRY_LAST;
230 }
231 if (d->name[0] == FAT_DENTRY_DOT) {
232 /*
233 * Most likely '.' or '..'.
234 * It cannot occur in a regular file name.
235 */
236 return FAT_DENTRY_SKIP;
237 }
238 return FAT_DENTRY_VALID;
239}
240
241static void fat_sync_node(fat_node_t *node)
242{
243 /* TODO */
244}
245
246/** Instantiate a FAT in-core node. */
247static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
248{
249 fat_idx_t *idx;
250 block_t *b;
251 fat_dentry_t *d;
252 fat_node_t *nodep;
253 unsigned bps;
254 unsigned dps;
255
256 idx = fat_idx_get_by_index(dev_handle, index);
257 if (!idx)
258 return NULL;
259
260 if (idx->nodep) {
261 /*
262 * We are lucky.
263 * The node is already instantiated in memory.
264 */
265 idx->nodep->refcnt++;
266 return idx->nodep;
267 }
268
269 /*
270 * We must instantiate the node from the file system.
271 */
272
273 assert(idx->pfc);
274
275 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
276 if (!nodep)
277 return NULL;
278 fat_node_initialize(nodep);
279
280 bps = fat_bps_get(dev_handle);
281 dps = bps / sizeof(fat_dentry_t);
282
283 b = _fat_block_get(dev_handle, idx->pfc,
284 (idx->pdi * sizeof(fat_dentry_t)) / bps);
285
286 assert(b);
287
288 d = ((fat_dentry_t *)b->data) + (idx->pdi % dps);
289 /* XXX */
290}
291
292static void fat_node_put(void *node)
293{
294 /* TODO */
295}
296
297static void *fat_create(int flags)
298{
299 return NULL; /* not supported at the moment */
300}
301
302static int fat_destroy(void *node)
303{
304 return ENOTSUP; /* not supported at the moment */
305}
306
307static bool fat_link(void *prnt, void *chld, const char *name)
308{
309 return false; /* not supported at the moment */
310}
311
312static int fat_unlink(void *prnt, void *chld)
313{
314 return ENOTSUP; /* not supported at the moment */
315}
316
317static void *fat_match(void *prnt, const char *component)
318{
319 fat_node_t *parentp = (fat_node_t *)prnt;
320 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
321 unsigned i, j;
322 unsigned bps; /* bytes per sector */
323 unsigned dps; /* dentries per sector */
324 unsigned blocks;
325 fat_dentry_t *d;
326 block_t *b;
327
328 bps = fat_bps_get(parentp->idx->dev_handle);
329 dps = bps / sizeof(fat_dentry_t);
330 blocks = parentp->size / bps + (parentp->size % bps != 0);
331 for (i = 0; i < blocks; i++) {
332 unsigned dentries;
333
334 b = fat_block_get(parentp, i);
335 dentries = (i == blocks - 1) ?
336 parentp->size % sizeof(fat_dentry_t) :
337 dps;
338 for (j = 0; j < dentries; j++) {
339 d = ((fat_dentry_t *)b->data) + j;
340 switch (fat_classify_dentry(d)) {
341 case FAT_DENTRY_SKIP:
342 continue;
343 case FAT_DENTRY_LAST:
344 block_put(b);
345 return NULL;
346 default:
347 case FAT_DENTRY_VALID:
348 dentry_name_canonify(d, name);
349 break;
350 }
351 if (strcmp(name, component) == 0) {
352 /* hit */
353 fat_idx_t *idx = fat_idx_get_by_pos(
354 parentp->idx->dev_handle, parentp->firstc,
355 i * dps + j);
356 if (!idx) {
357 /*
358 * Can happen if memory is low or if we
359 * run out of 32-bit indices.
360 */
361 block_put(b);
362 return NULL;
363 }
364 void *node = fat_node_get(idx->dev_handle,
365 idx->index);
366 block_put(b);
367 return node;
368 }
369 }
370 block_put(b);
371 }
372
373 return NULL;
374}
375
376static fs_index_t fat_index_get(void *node)
377{
378 fat_node_t *fnodep = (fat_node_t *)node;
379 if (!fnodep)
380 return 0;
381 return fnodep->idx->index;
382}
383
384static size_t fat_size_get(void *node)
385{
386 return ((fat_node_t *)node)->size;
387}
388
389static unsigned fat_lnkcnt_get(void *node)
390{
391 return ((fat_node_t *)node)->lnkcnt;
392}
393
394static bool fat_has_children(void *node)
395{
396 fat_node_t *nodep = (fat_node_t *)node;
397 unsigned bps;
398 unsigned dps;
399 unsigned blocks;
400 block_t *b;
401 unsigned i, j;
402
403 if (nodep->type != FAT_DIRECTORY)
404 return false;
405
406 bps = fat_bps_get(nodep->idx->dev_handle);
407 dps = bps / sizeof(fat_dentry_t);
408
409 blocks = nodep->size / bps + (nodep->size % bps != 0);
410
411 for (i = 0; i < blocks; i++) {
412 unsigned dentries;
413 fat_dentry_t *d;
414
415 b = fat_block_get(nodep, i);
416 dentries = (i == blocks - 1) ?
417 nodep->size % sizeof(fat_dentry_t) :
418 dps;
419 for (j = 0; j < dentries; j++) {
420 d = ((fat_dentry_t *)b->data) + j;
421 switch (fat_classify_dentry(d)) {
422 case FAT_DENTRY_SKIP:
423 continue;
424 case FAT_DENTRY_LAST:
425 block_put(b);
426 return false;
427 default:
428 case FAT_DENTRY_VALID:
429 block_put(b);
430 return true;
431 }
432 block_put(b);
433 return true;
434 }
435 block_put(b);
436 }
437
438 return false;
439}
440
441static void *fat_root_get(dev_handle_t dev_handle)
442{
443 return fat_node_get(dev_handle, 0); /* TODO */
444}
445
446static char fat_plb_get_char(unsigned pos)
447{
448 return fat_reg.plb_ro[pos % PLB_SIZE];
449}
450
451static bool fat_is_directory(void *node)
452{
453 return ((fat_node_t *)node)->type == FAT_DIRECTORY;
454}
455
456static bool fat_is_file(void *node)
457{
458 return ((fat_node_t *)node)->type == FAT_FILE;
459}
460
461/** libfs operations */
462libfs_ops_t fat_libfs_ops = {
463 .match = fat_match,
464 .node_get = fat_node_get,
465 .node_put = fat_node_put,
466 .create = fat_create,
467 .destroy = fat_destroy,
468 .link = fat_link,
469 .unlink = fat_unlink,
470 .index_get = fat_index_get,
471 .size_get = fat_size_get,
472 .lnkcnt_get = fat_lnkcnt_get,
473 .has_children = fat_has_children,
474 .root_get = fat_root_get,
475 .plb_get_char = fat_plb_get_char,
476 .is_directory = fat_is_directory,
477 .is_file = fat_is_file
478};
479
480void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
481{
482 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
483}
484
485/**
486 * @}
487 */
Note: See TracBrowser for help on using the repository browser.