source: mainline/uspace/srv/fs/fat/fat_ops.c@ 869e546

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

Introduce the foundation for unique and stable FAT VFS node indices.

The first two reserved FAT entries are physically present in each FAT, so fix
the code to be aware of this.

  • Property mode set to 100644
File size: 9.9 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
115static fat_idx_t *fat_idx_map(fat_cluster_t pfc, unsigned pdi)
116{
117 return NULL; /* TODO */
118}
119
120#define FAT_BS(b) ((fat_bs_t *)((b)->data))
121
122#define FAT_CLST_RES0 0x0000
123#define FAT_CLST_RES1 0x0001 /* internally used to mark root directory */
124#define FAT_CLST_FIRST 0x0002
125#define FAT_CLST_BAD 0xfff7
126#define FAT_CLST_LAST1 0xfff8
127#define FAT_CLST_LAST8 0xffff
128
129static block_t *fat_block_get(fat_node_t *nodep, off_t offset)
130{
131 block_t *bb;
132 block_t *b;
133 unsigned bps;
134 unsigned spc;
135 unsigned rscnt; /* block address of the first FAT */
136 unsigned fatcnt;
137 unsigned rde;
138 unsigned rds; /* root directory size */
139 unsigned sf;
140 unsigned ssa; /* size of the system area */
141 unsigned clusters;
142 fat_cluster_t clst = nodep->firstc;
143 unsigned i;
144
145 bb = block_get(nodep->idx->dev_handle, BS_BLOCK);
146 bps = uint16_t_le2host(FAT_BS(bb)->bps);
147 spc = FAT_BS(bb)->spc;
148 rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
149 fatcnt = FAT_BS(bb)->fatcnt;
150 rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
151 sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
152 block_put(bb);
153
154 rds = (sizeof(fat_dentry_t) * rde) / bps;
155 rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
156 ssa = rscnt + fatcnt * sf + rds;
157
158 if (nodep->idx->index == FAT_CLST_RES1) {
159 /* root directory special case */
160 assert(offset < rds);
161 b = block_get(nodep->idx->dev_handle,
162 rscnt + fatcnt * sf + offset);
163 return b;
164 }
165
166 clusters = offset / spc;
167 for (i = 0; i < clusters; i++) {
168 unsigned fsec; /* sector offset relative to FAT1 */
169 unsigned fidx; /* FAT1 entry index */
170
171 assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
172 fsec = (clst * sizeof(fat_cluster_t)) / bps;
173 fidx = clst % (bps / sizeof(fat_cluster_t));
174 /* read FAT1 */
175 b = block_get(nodep->idx->dev_handle, rscnt + fsec);
176 clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
177 assert(clst != FAT_CLST_BAD);
178 assert(clst < FAT_CLST_LAST1);
179 block_put(b);
180 }
181
182 b = block_get(nodep->idx->dev_handle, ssa +
183 (clst - FAT_CLST_FIRST) * spc + offset % spc);
184
185 return b;
186}
187
188static void fat_node_initialize(fat_node_t *node)
189{
190 node->idx = NULL;
191 node->type = 0;
192 link_initialize(&node->fin_link);
193 link_initialize(&node->ffn_link);
194 node->size = 0;
195 node->lnkcnt = 0;
196 node->refcnt = 0;
197 node->dirty = false;
198}
199
200static uint16_t fat_bps_get(dev_handle_t dev_handle)
201{
202 block_t *bb;
203 uint16_t bps;
204
205 bb = block_get(dev_handle, BS_BLOCK);
206 assert(bb != NULL);
207 bps = uint16_t_le2host(FAT_BS(bb)->bps);
208 block_put(bb);
209
210 return bps;
211}
212
213typedef enum {
214 FAT_DENTRY_SKIP,
215 FAT_DENTRY_LAST,
216 FAT_DENTRY_VALID
217} fat_dentry_clsf_t;
218
219static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
220{
221 if (d->attr & FAT_ATTR_VOLLABEL) {
222 /* volume label entry */
223 return FAT_DENTRY_SKIP;
224 }
225 if (d->name[0] == FAT_DENTRY_ERASED) {
226 /* not-currently-used entry */
227 return FAT_DENTRY_SKIP;
228 }
229 if (d->name[0] == FAT_DENTRY_UNUSED) {
230 /* never used entry */
231 return FAT_DENTRY_LAST;
232 }
233 if (d->name[0] == FAT_DENTRY_DOT) {
234 /*
235 * Most likely '.' or '..'.
236 * It cannot occur in a regular file name.
237 */
238 return FAT_DENTRY_SKIP;
239 }
240 return FAT_DENTRY_VALID;
241}
242
243static void fat_sync_node(fat_node_t *node)
244{
245 /* TODO */
246}
247
248/** Instantiate a FAT in-core node. */
249static void *
250fat_node_get(dev_handle_t dev_handle, fs_index_t index)
251{
252 return NULL; /* TODO */
253}
254
255static void fat_node_put(void *node)
256{
257 /* TODO */
258}
259
260static void *fat_create(int flags)
261{
262 return NULL; /* not supported at the moment */
263}
264
265static int fat_destroy(void *node)
266{
267 return ENOTSUP; /* not supported at the moment */
268}
269
270static bool fat_link(void *prnt, void *chld, const char *name)
271{
272 return false; /* not supported at the moment */
273}
274
275static int fat_unlink(void *prnt, void *chld)
276{
277 return ENOTSUP; /* not supported at the moment */
278}
279
280static void *fat_match(void *prnt, const char *component)
281{
282 fat_node_t *parentp = (fat_node_t *)prnt;
283 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
284 unsigned i, j;
285 unsigned bps; /* bytes per sector */
286 unsigned dps; /* dentries per sector */
287 unsigned blocks;
288 fat_dentry_t *d;
289 block_t *b;
290
291 bps = fat_bps_get(parentp->idx->dev_handle);
292 dps = bps / sizeof(fat_dentry_t);
293 blocks = parentp->size / bps + (parentp->size % bps != 0);
294 for (i = 0; i < blocks; i++) {
295 unsigned dentries;
296
297 b = fat_block_get(parentp, i);
298 dentries = (i == blocks - 1) ?
299 parentp->size % sizeof(fat_dentry_t) :
300 dps;
301 for (j = 0; j < dentries; j++) {
302 d = ((fat_dentry_t *)b->data) + j;
303 switch (fat_classify_dentry(d)) {
304 case FAT_DENTRY_SKIP:
305 continue;
306 case FAT_DENTRY_LAST:
307 block_put(b);
308 return NULL;
309 default:
310 case FAT_DENTRY_VALID:
311 dentry_name_canonify(d, name);
312 break;
313 }
314 if (strcmp(name, component) == 0) {
315 /* hit */
316 fat_idx_t *idx = fat_idx_map(parentp->firstc,
317 i * dps + j);
318 void *node = fat_node_get(idx->dev_handle,
319 idx->index);
320 block_put(b);
321 return node;
322 }
323 }
324 block_put(b);
325 }
326
327 return NULL;
328}
329
330static fs_index_t fat_index_get(void *node)
331{
332 fat_node_t *fnodep = (fat_node_t *)node;
333 if (!fnodep)
334 return 0;
335 return fnodep->idx->index;
336}
337
338static size_t fat_size_get(void *node)
339{
340 return ((fat_node_t *)node)->size;
341}
342
343static unsigned fat_lnkcnt_get(void *node)
344{
345 return ((fat_node_t *)node)->lnkcnt;
346}
347
348static bool fat_has_children(void *node)
349{
350 fat_node_t *nodep = (fat_node_t *)node;
351 unsigned bps;
352 unsigned dps;
353 unsigned blocks;
354 block_t *b;
355 unsigned i, j;
356
357 if (nodep->type != FAT_DIRECTORY)
358 return false;
359
360 bps = fat_bps_get(nodep->idx->dev_handle);
361 dps = bps / sizeof(fat_dentry_t);
362
363 blocks = nodep->size / bps + (nodep->size % bps != 0);
364
365 for (i = 0; i < blocks; i++) {
366 unsigned dentries;
367 fat_dentry_t *d;
368
369 b = fat_block_get(nodep, i);
370 dentries = (i == blocks - 1) ?
371 nodep->size % sizeof(fat_dentry_t) :
372 dps;
373 for (j = 0; j < dentries; j++) {
374 d = ((fat_dentry_t *)b->data) + j;
375 switch (fat_classify_dentry(d)) {
376 case FAT_DENTRY_SKIP:
377 continue;
378 case FAT_DENTRY_LAST:
379 block_put(b);
380 return false;
381 default:
382 case FAT_DENTRY_VALID:
383 block_put(b);
384 return true;
385 }
386 block_put(b);
387 return true;
388 }
389 block_put(b);
390 }
391
392 return false;
393}
394
395static void *fat_root_get(dev_handle_t dev_handle)
396{
397 return fat_node_get(dev_handle, FAT_CLST_RES1);
398}
399
400static char fat_plb_get_char(unsigned pos)
401{
402 return fat_reg.plb_ro[pos % PLB_SIZE];
403}
404
405static bool fat_is_directory(void *node)
406{
407 return ((fat_node_t *)node)->type == FAT_DIRECTORY;
408}
409
410static bool fat_is_file(void *node)
411{
412 return ((fat_node_t *)node)->type == FAT_FILE;
413}
414
415/** libfs operations */
416libfs_ops_t fat_libfs_ops = {
417 .match = fat_match,
418 .node_get = fat_node_get,
419 .node_put = fat_node_put,
420 .create = fat_create,
421 .destroy = fat_destroy,
422 .link = fat_link,
423 .unlink = fat_unlink,
424 .index_get = fat_index_get,
425 .size_get = fat_size_get,
426 .lnkcnt_get = fat_lnkcnt_get,
427 .has_children = fat_has_children,
428 .root_get = fat_root_get,
429 .plb_get_char = fat_plb_get_char,
430 .is_directory = fat_is_directory,
431 .is_file = fat_is_file
432};
433
434void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
435{
436 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
437}
438
439/**
440 * @}
441 */
Note: See TracBrowser for help on using the repository browser.