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

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

Pass the buffer holding the boot sector to the internal functions so that it
doesn't have to be block_get()'ed in each function. The idea is that the boot
block should be read by the top-level functions in fat_ops.c and passed down the
call chain.

  • Property mode set to 100644
File size: 18.6 KB
RevLine 
[be815bc]1/*
[a2aa1dec]2 * Copyright (c) 2008 Jakub Jermar
[be815bc]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"
[033ef7d3]39#include "fat_dentry.h"
40#include "fat_fat.h"
[6364d3c]41#include "../../vfs/vfs.h"
[a2aa1dec]42#include <libfs.h>
[be815bc]43#include <ipc/ipc.h>
[7a35204a]44#include <ipc/services.h>
45#include <ipc/devmap.h>
[be815bc]46#include <async.h>
47#include <errno.h>
[a2aa1dec]48#include <string.h>
[776f2e6]49#include <byteorder.h>
[e1e3b26]50#include <libadt/hash_table.h>
51#include <libadt/list.h>
52#include <assert.h>
[d9e9caf]53#include <futex.h>
[7a35204a]54#include <sys/mman.h>
[8d32152]55#include <align.h>
[e1e3b26]56
[add5835]57/** Futex protecting the list of cached free FAT nodes. */
58static futex_t ffn_futex = FUTEX_INITIALIZER;
59
60/** List of cached free FAT nodes. */
61static LIST_INITIALIZE(ffn_head);
[6364d3c]62
[7a35204a]63static int dev_phone = -1; /* FIXME */
64static void *dev_buffer = NULL; /* FIXME */
65
[0f57d0e]66block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
[a2aa1dec]67{
[7a35204a]68 /* FIXME */
69 block_t *b;
70 off_t bufpos = 0;
71 size_t buflen = 0;
[d2e9c47]72 off_t pos = offset * bs;
[7a35204a]73
74 assert(dev_phone != -1);
75 assert(dev_buffer);
76
77 b = malloc(sizeof(block_t));
78 if (!b)
79 return NULL;
80
81 b->data = malloc(bs);
82 if (!b->data) {
83 free(b);
84 return NULL;
85 }
86 b->size = bs;
87
[d2e9c47]88 if (!libfs_blockread(dev_phone, dev_buffer, &bufpos, &buflen, &pos,
[7a35204a]89 b->data, bs, bs)) {
90 free(b->data);
91 free(b);
92 return NULL;
93 }
94
95 return b;
[a2aa1dec]96}
97
[0f57d0e]98void block_put(block_t *block)
[6364d3c]99{
[7a35204a]100 /* FIXME */
101 free(block->data);
102 free(block);
[a2aa1dec]103}
104
[e1e3b26]105static void fat_node_initialize(fat_node_t *node)
[a2aa1dec]106{
[add5835]107 futex_initialize(&node->lock, 1);
[869e546]108 node->idx = NULL;
[e1e3b26]109 node->type = 0;
110 link_initialize(&node->ffn_link);
111 node->size = 0;
112 node->lnkcnt = 0;
113 node->refcnt = 0;
114 node->dirty = false;
115}
116
[2c4bbcde]117static void fat_node_sync(fat_node_t *node)
[e1e3b26]118{
119 /* TODO */
120}
121
[add5835]122/** Internal version of fat_node_get().
123 *
124 * @param idxp Locked index structure.
125 */
126static void *fat_node_get_core(fat_idx_t *idxp)
[e1e3b26]127{
[cb682eb]128 block_t *bb, *b;
[4573a79]129 fat_dentry_t *d;
[c06dbf9]130 fat_node_t *nodep = NULL;
[4573a79]131 unsigned bps;
132 unsigned dps;
133
[add5835]134 if (idxp->nodep) {
[4573a79]135 /*
136 * We are lucky.
137 * The node is already instantiated in memory.
138 */
[add5835]139 futex_down(&idxp->nodep->lock);
140 if (!idxp->nodep->refcnt++)
[c06dbf9]141 list_remove(&idxp->nodep->ffn_link);
[add5835]142 futex_up(&idxp->nodep->lock);
143 return idxp->nodep;
[4573a79]144 }
145
146 /*
147 * We must instantiate the node from the file system.
148 */
149
[add5835]150 assert(idxp->pfc);
[4573a79]151
[add5835]152 futex_down(&ffn_futex);
[2c4bbcde]153 if (!list_empty(&ffn_head)) {
[add5835]154 /* Try to use a cached free node structure. */
155 fat_idx_t *idxp_tmp;
[2c4bbcde]156 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
[add5835]157 if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
158 goto skip_cache;
159 idxp_tmp = nodep->idx;
160 if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
161 futex_up(&nodep->lock);
162 goto skip_cache;
163 }
164 list_remove(&nodep->ffn_link);
165 futex_up(&ffn_futex);
[2c4bbcde]166 if (nodep->dirty)
167 fat_node_sync(nodep);
[add5835]168 idxp_tmp->nodep = NULL;
169 futex_up(&nodep->lock);
170 futex_up(&idxp_tmp->lock);
[2c4bbcde]171 } else {
[add5835]172skip_cache:
[2c4bbcde]173 /* Try to allocate a new node structure. */
[add5835]174 futex_up(&ffn_futex);
[2c4bbcde]175 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
176 if (!nodep)
177 return NULL;
178 }
[4573a79]179 fat_node_initialize(nodep);
180
[cb682eb]181 bb = block_get(idxp->dev_handle, BS_BLOCK, BS_SIZE);
182 bps = uint16_t_le2host(FAT_BS(bb)->bps);
[4573a79]183 dps = bps / sizeof(fat_dentry_t);
184
[2c4bbcde]185 /* Read the block that contains the dentry of interest. */
[cb682eb]186 b = _fat_block_get(bb->data, idxp->dev_handle, idxp->pfc,
[add5835]187 (idxp->pdi * sizeof(fat_dentry_t)) / bps);
[4573a79]188 assert(b);
189
[add5835]190 d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
[2c4bbcde]191 if (d->attr & FAT_ATTR_SUBDIR) {
192 /*
193 * The only directory which does not have this bit set is the
194 * root directory itself. The root directory node is handled
195 * and initialized elsewhere.
196 */
197 nodep->type = FAT_DIRECTORY;
[2ab1023]198 /*
[e2115311]199 * Unfortunately, the 'size' field of the FAT dentry is not
200 * defined for the directory entry type. We must determine the
201 * size of the directory by walking the FAT.
[2ab1023]202 */
[cb682eb]203 nodep->size = bps * _fat_blcks_get(bb->data, idxp->dev_handle,
[e17d986]204 uint16_t_le2host(d->firstc), NULL);
[2c4bbcde]205 } else {
206 nodep->type = FAT_FILE;
[2ab1023]207 nodep->size = uint32_t_le2host(d->size);
[2c4bbcde]208 }
209 nodep->firstc = uint16_t_le2host(d->firstc);
210 nodep->lnkcnt = 1;
211 nodep->refcnt = 1;
212
213 block_put(b);
[cb682eb]214 block_put(bb);
[2c4bbcde]215
216 /* Link the idx structure with the node structure. */
[add5835]217 nodep->idx = idxp;
218 idxp->nodep = nodep;
[2c4bbcde]219
220 return nodep;
[a2aa1dec]221}
222
[add5835]223/** Instantiate a FAT in-core node. */
224static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
225{
226 void *node;
227 fat_idx_t *idxp;
228
229 idxp = fat_idx_get_by_index(dev_handle, index);
230 if (!idxp)
231 return NULL;
232 /* idxp->lock held */
233 node = fat_node_get_core(idxp);
234 futex_up(&idxp->lock);
235 return node;
236}
237
[06901c6b]238static void fat_node_put(void *node)
239{
[34b3ce3]240 fat_node_t *nodep = (fat_node_t *)node;
241
[add5835]242 futex_down(&nodep->lock);
[34b3ce3]243 if (!--nodep->refcnt) {
[add5835]244 futex_down(&ffn_futex);
[34b3ce3]245 list_append(&nodep->ffn_link, &ffn_head);
[add5835]246 futex_up(&ffn_futex);
[34b3ce3]247 }
[add5835]248 futex_up(&nodep->lock);
[06901c6b]249}
250
[80e8482]251static void *fat_create(int flags)
252{
253 return NULL; /* not supported at the moment */
254}
255
[45f244b]256static int fat_destroy(void *node)
[80e8482]257{
[45f244b]258 return ENOTSUP; /* not supported at the moment */
[80e8482]259}
260
261static bool fat_link(void *prnt, void *chld, const char *name)
262{
263 return false; /* not supported at the moment */
264}
265
266static int fat_unlink(void *prnt, void *chld)
267{
268 return ENOTSUP; /* not supported at the moment */
269}
270
[a2aa1dec]271static void *fat_match(void *prnt, const char *component)
272{
273 fat_node_t *parentp = (fat_node_t *)prnt;
274 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
[79dbc3e]275 unsigned i, j;
[5446bee0]276 unsigned bps; /* bytes per sector */
[79dbc3e]277 unsigned dps; /* dentries per sector */
278 unsigned blocks;
[a2aa1dec]279 fat_dentry_t *d;
[cb682eb]280 block_t *bb, *b;
[79dbc3e]281
[e811bde]282 futex_down(&parentp->idx->lock);
[cb682eb]283 bb = block_get(parentp->idx->dev_handle, BS_BLOCK, BS_SIZE);
284 bps = uint16_t_le2host(FAT_BS(bb)->bps);
[5446bee0]285 dps = bps / sizeof(fat_dentry_t);
286 blocks = parentp->size / bps + (parentp->size % bps != 0);
[79dbc3e]287 for (i = 0; i < blocks; i++) {
288 unsigned dentries;
289
[cb682eb]290 b = fat_block_get(bb->data, parentp, i);
[79dbc3e]291 dentries = (i == blocks - 1) ?
292 parentp->size % sizeof(fat_dentry_t) :
293 dps;
294 for (j = 0; j < dentries; j++) {
295 d = ((fat_dentry_t *)b->data) + j;
[32fb10ed]296 switch (fat_classify_dentry(d)) {
297 case FAT_DENTRY_SKIP:
[79dbc3e]298 continue;
[32fb10ed]299 case FAT_DENTRY_LAST:
[79dbc3e]300 block_put(b);
[cb682eb]301 block_put(bb);
[e811bde]302 futex_up(&parentp->idx->lock);
[79dbc3e]303 return NULL;
[32fb10ed]304 default:
305 case FAT_DENTRY_VALID:
306 dentry_name_canonify(d, name);
307 break;
[79dbc3e]308 }
[d2e9c47]309 if (stricmp(name, component) == 0) {
[79dbc3e]310 /* hit */
[add5835]311 void *node;
[e811bde]312 /*
313 * Assume tree hierarchy for locking. We
314 * already have the parent and now we are going
315 * to lock the child. Never lock in the oposite
316 * order.
317 */
[4797132]318 fat_idx_t *idx = fat_idx_get_by_pos(
[5a324099]319 parentp->idx->dev_handle, parentp->firstc,
[869e546]320 i * dps + j);
[e811bde]321 futex_up(&parentp->idx->lock);
[4797132]322 if (!idx) {
323 /*
324 * Can happen if memory is low or if we
325 * run out of 32-bit indices.
326 */
327 block_put(b);
[cb682eb]328 block_put(bb);
[4797132]329 return NULL;
330 }
[add5835]331 node = fat_node_get_core(idx);
332 futex_up(&idx->lock);
[79dbc3e]333 block_put(b);
[cb682eb]334 block_put(bb);
[79dbc3e]335 return node;
336 }
[9119d25]337 }
[79dbc3e]338 block_put(b);
[9119d25]339 }
[cb682eb]340 block_put(bb);
341
[e811bde]342 futex_up(&parentp->idx->lock);
[a2aa1dec]343 return NULL;
[6364d3c]344}
345
[e1e3b26]346static fs_index_t fat_index_get(void *node)
347{
348 fat_node_t *fnodep = (fat_node_t *)node;
349 if (!fnodep)
350 return 0;
[869e546]351 return fnodep->idx->index;
[e1e3b26]352}
353
354static size_t fat_size_get(void *node)
355{
356 return ((fat_node_t *)node)->size;
357}
358
359static unsigned fat_lnkcnt_get(void *node)
360{
361 return ((fat_node_t *)node)->lnkcnt;
362}
363
[32fb10ed]364static bool fat_has_children(void *node)
365{
366 fat_node_t *nodep = (fat_node_t *)node;
367 unsigned bps;
368 unsigned dps;
369 unsigned blocks;
[cb682eb]370 block_t *bb, *b;
[32fb10ed]371 unsigned i, j;
372
373 if (nodep->type != FAT_DIRECTORY)
374 return false;
375
[add5835]376 futex_down(&nodep->idx->lock);
[cb682eb]377 bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE);
378 bps = uint16_t_le2host(FAT_BS(bb)->bps);
[32fb10ed]379 dps = bps / sizeof(fat_dentry_t);
380
381 blocks = nodep->size / bps + (nodep->size % bps != 0);
382
383 for (i = 0; i < blocks; i++) {
384 unsigned dentries;
385 fat_dentry_t *d;
386
[cb682eb]387 b = fat_block_get(bb->data, nodep, i);
[32fb10ed]388 dentries = (i == blocks - 1) ?
389 nodep->size % sizeof(fat_dentry_t) :
390 dps;
391 for (j = 0; j < dentries; j++) {
392 d = ((fat_dentry_t *)b->data) + j;
393 switch (fat_classify_dentry(d)) {
394 case FAT_DENTRY_SKIP:
395 continue;
396 case FAT_DENTRY_LAST:
397 block_put(b);
[cb682eb]398 block_put(bb);
[add5835]399 futex_up(&nodep->idx->lock);
[32fb10ed]400 return false;
401 default:
402 case FAT_DENTRY_VALID:
403 block_put(b);
[cb682eb]404 block_put(bb);
[add5835]405 futex_up(&nodep->idx->lock);
[32fb10ed]406 return true;
407 }
408 block_put(b);
[cb682eb]409 block_put(bb);
[add5835]410 futex_up(&nodep->idx->lock);
[32fb10ed]411 return true;
412 }
413 block_put(b);
414 }
[cb682eb]415 block_put(bb);
[32fb10ed]416
[add5835]417 futex_up(&nodep->idx->lock);
[32fb10ed]418 return false;
419}
420
[74ea3c6]421static void *fat_root_get(dev_handle_t dev_handle)
422{
[689f036]423 return fat_node_get(dev_handle, 0);
[74ea3c6]424}
425
426static char fat_plb_get_char(unsigned pos)
427{
428 return fat_reg.plb_ro[pos % PLB_SIZE];
429}
430
[e1e3b26]431static bool fat_is_directory(void *node)
432{
433 return ((fat_node_t *)node)->type == FAT_DIRECTORY;
434}
435
436static bool fat_is_file(void *node)
437{
438 return ((fat_node_t *)node)->type == FAT_FILE;
439}
440
[a2aa1dec]441/** libfs operations */
442libfs_ops_t fat_libfs_ops = {
443 .match = fat_match,
444 .node_get = fat_node_get,
[06901c6b]445 .node_put = fat_node_put,
[80e8482]446 .create = fat_create,
447 .destroy = fat_destroy,
448 .link = fat_link,
449 .unlink = fat_unlink,
[e1e3b26]450 .index_get = fat_index_get,
451 .size_get = fat_size_get,
452 .lnkcnt_get = fat_lnkcnt_get,
[32fb10ed]453 .has_children = fat_has_children,
[74ea3c6]454 .root_get = fat_root_get,
455 .plb_get_char = fat_plb_get_char,
[e1e3b26]456 .is_directory = fat_is_directory,
457 .is_file = fat_is_file
[a2aa1dec]458};
459
[cde485d]460void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
461{
462 dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
[689f036]463 block_t *bb;
[7a35204a]464 uint16_t bps;
[689f036]465 uint16_t rde;
[cde485d]466 int rc;
467
[7a35204a]468 /*
469 * For now, we don't bother to remember dev_handle, dev_phone or
470 * dev_buffer in some data structure. We use global variables because we
471 * know there will be at most one mount on this file system.
472 * Of course, this is a huge TODO item.
473 */
474 dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
475 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
476
477 if (!dev_buffer) {
478 ipc_answer_0(rid, ENOMEM);
479 return;
480 }
481
482 dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
483 DEVMAP_CONNECT_TO_DEVICE, dev_handle);
484
485 if (dev_phone < 0) {
486 munmap(dev_buffer, BS_SIZE);
487 ipc_answer_0(rid, dev_phone);
488 return;
489 }
490
491 rc = ipc_share_out_start(dev_phone, dev_buffer,
492 AS_AREA_READ | AS_AREA_WRITE);
493 if (rc != EOK) {
494 munmap(dev_buffer, BS_SIZE);
495 ipc_answer_0(rid, rc);
496 return;
497 }
498
[689f036]499 /* Read the number of root directory entries. */
[a61d1fc3]500 bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
[7a35204a]501 bps = uint16_t_le2host(FAT_BS(bb)->bps);
[689f036]502 rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
503 block_put(bb);
504
[7a35204a]505 if (bps != BS_SIZE) {
506 munmap(dev_buffer, BS_SIZE);
507 ipc_answer_0(rid, ENOTSUP);
508 return;
509 }
510
[cde485d]511 rc = fat_idx_init_by_dev_handle(dev_handle);
512 if (rc != EOK) {
[7a35204a]513 munmap(dev_buffer, BS_SIZE);
[cde485d]514 ipc_answer_0(rid, rc);
515 return;
516 }
517
[689f036]518 /* Initialize the root node. */
519 fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
520 if (!rootp) {
[7a35204a]521 munmap(dev_buffer, BS_SIZE);
[689f036]522 fat_idx_fini_by_dev_handle(dev_handle);
523 ipc_answer_0(rid, ENOMEM);
524 return;
525 }
526 fat_node_initialize(rootp);
527
528 fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
529 if (!ridxp) {
[7a35204a]530 munmap(dev_buffer, BS_SIZE);
[689f036]531 free(rootp);
532 fat_idx_fini_by_dev_handle(dev_handle);
533 ipc_answer_0(rid, ENOMEM);
534 return;
535 }
536 assert(ridxp->index == 0);
537 /* ridxp->lock held */
538
539 rootp->type = FAT_DIRECTORY;
540 rootp->firstc = FAT_CLST_ROOT;
541 rootp->refcnt = 1;
[5ab597d]542 rootp->lnkcnt = 0; /* FS root is not linked */
[689f036]543 rootp->size = rde * sizeof(fat_dentry_t);
544 rootp->idx = ridxp;
545 ridxp->nodep = rootp;
546
547 futex_up(&ridxp->lock);
548
[5ab597d]549 ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
[cde485d]550}
551
552void fat_mount(ipc_callid_t rid, ipc_call_t *request)
553{
554 ipc_answer_0(rid, ENOTSUP);
555}
556
[be815bc]557void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
558{
[a2aa1dec]559 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
[be815bc]560}
561
[4bf40f6]562void fat_read(ipc_callid_t rid, ipc_call_t *request)
563{
564 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
565 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
566 off_t pos = (off_t)IPC_GET_ARG3(*request);
567 fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
[cb682eb]568 uint16_t bps;
[79d031b]569 size_t bytes;
[cb682eb]570 block_t *bb, *b;
[79d031b]571
[4bf40f6]572 if (!nodep) {
573 ipc_answer_0(rid, ENOENT);
574 return;
575 }
576
577 ipc_callid_t callid;
578 size_t len;
[6808614]579 if (!ipc_data_read_receive(&callid, &len)) {
[4bf40f6]580 fat_node_put(nodep);
581 ipc_answer_0(callid, EINVAL);
582 ipc_answer_0(rid, EINVAL);
583 return;
584 }
585
[cb682eb]586 bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
587 bps = uint16_t_le2host(FAT_BS(bb)->bps);
588
[4bf40f6]589 if (nodep->type == FAT_FILE) {
[ddd1219]590 /*
591 * Our strategy for regular file reads is to read one block at
592 * most and make use of the possibility to return less data than
593 * requested. This keeps the code very simple.
594 */
[79d031b]595 bytes = min(len, bps - pos % bps);
[cb682eb]596 b = fat_block_get(bb->data, nodep, pos / bps);
[79d031b]597 (void) ipc_data_read_finalize(callid, b->data + pos % bps,
598 bytes);
599 block_put(b);
[4bf40f6]600 } else {
[ddd1219]601 unsigned bnum;
602 off_t spos = pos;
603 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
604 fat_dentry_t *d;
605
[4bf40f6]606 assert(nodep->type == FAT_DIRECTORY);
[ddd1219]607 assert(nodep->size % bps == 0);
608 assert(bps % sizeof(fat_dentry_t) == 0);
609
610 /*
611 * Our strategy for readdir() is to use the position pointer as
612 * an index into the array of all dentries. On entry, it points
613 * to the first unread dentry. If we skip any dentries, we bump
614 * the position pointer accordingly.
615 */
616 bnum = (pos * sizeof(fat_dentry_t)) / bps;
617 while (bnum < nodep->size / bps) {
618 off_t o;
619
[cb682eb]620 b = fat_block_get(bb->data, nodep, bnum);
[ddd1219]621 for (o = pos % (bps / sizeof(fat_dentry_t));
622 o < bps / sizeof(fat_dentry_t);
623 o++, pos++) {
624 d = ((fat_dentry_t *)b->data) + o;
625 switch (fat_classify_dentry(d)) {
626 case FAT_DENTRY_SKIP:
627 continue;
628 case FAT_DENTRY_LAST:
629 block_put(b);
630 goto miss;
631 default:
632 case FAT_DENTRY_VALID:
633 dentry_name_canonify(d, name);
634 block_put(b);
635 goto hit;
636 }
637 }
638 block_put(b);
639 bnum++;
640 }
641miss:
[4bf40f6]642 fat_node_put(nodep);
[cb682eb]643 block_put(bb);
[ddd1219]644 ipc_answer_0(callid, ENOENT);
645 ipc_answer_1(rid, ENOENT, 0);
[4bf40f6]646 return;
[ddd1219]647hit:
648 (void) ipc_data_read_finalize(callid, name, strlen(name) + 1);
649 bytes = (pos - spos) + 1;
[4bf40f6]650 }
651
652 fat_node_put(nodep);
[cb682eb]653 block_put(bb);
[79d031b]654 ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
[4bf40f6]655}
656
[c947dda]657void fat_write(ipc_callid_t rid, ipc_call_t *request)
658{
[8d32152]659 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
660 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
661 off_t pos = (off_t)IPC_GET_ARG3(*request);
662 fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
663 size_t bytes;
664 block_t *b, *bb;
665 uint16_t bps;
666 unsigned spc;
[b4b7187]667 off_t boundary;
[8d32152]668
669 if (!nodep) {
670 ipc_answer_0(rid, ENOENT);
671 return;
672 }
673
674 /* XXX remove me when you are ready */
675 {
676 ipc_answer_0(rid, ENOTSUP);
677 fat_node_put(nodep);
678 return;
679 }
680
681 ipc_callid_t callid;
682 size_t len;
683 if (!ipc_data_write_receive(&callid, &len)) {
684 fat_node_put(nodep);
685 ipc_answer_0(callid, EINVAL);
686 ipc_answer_0(rid, EINVAL);
687 return;
688 }
689
690 /*
691 * In all scenarios, we will attempt to write out only one block worth
692 * of data at maximum. There might be some more efficient approaches,
693 * but this one greatly simplifies fat_write(). Note that we can afford
694 * to do this because the client must be ready to handle the return
695 * value signalizing a smaller number of bytes written.
696 */
697 bytes = min(len, bps - pos % bps);
698
699 bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
700 bps = uint16_t_le2host(FAT_BS(bb)->bps);
701 spc = FAT_BS(bb)->spc;
702
[b4b7187]703 boundary = ROUND_UP(nodep->size, bps * spc);
704 if (pos < boundary) {
[8d32152]705 /*
706 * This is the easier case - we are either overwriting already
707 * existing contents or writing behind the EOF, but still within
708 * the limits of the last cluster. The node size may grow to the
709 * next block size boundary.
710 */
[cb682eb]711 fat_fill_gap(bb->data, nodep, FAT_CLST_RES0, pos);
712 b = fat_block_get(bb->data, nodep, pos / bps);
[8d32152]713 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
714 bytes);
715 b->dirty = true; /* need to sync block */
[6f2dfd1]716 block_put(b);
[8d32152]717 if (pos + bytes > nodep->size) {
718 nodep->size = pos + bytes;
719 nodep->dirty = true; /* need to sync node */
720 }
721 fat_node_put(nodep);
[cb682eb]722 block_put(bb);
[8d32152]723 ipc_answer_1(rid, EOK, bytes);
724 return;
725 } else {
726 /*
727 * This is the more difficult case. We must allocate new
728 * clusters for the node and zero them out.
729 */
[6f2dfd1]730 int status;
[8d32152]731 unsigned nclsts;
[6f2dfd1]732 fat_cluster_t mcl, lcl;
733
[b4b7187]734 nclsts = (ROUND_UP(pos + bytes, bps * spc) - boundary) /
[6f2dfd1]735 bps * spc;
736 /* create an independent chain of nclsts clusters in all FATs */
[cb682eb]737 status = fat_alloc_clusters(bb->data, dev_handle, nclsts, &mcl,
738 &lcl);
[6f2dfd1]739 if (status != EOK) {
740 /* could not allocate a chain of nclsts clusters */
741 fat_node_put(nodep);
[cb682eb]742 block_put(bb);
[6f2dfd1]743 ipc_answer_0(callid, status);
744 ipc_answer_0(rid, status);
745 return;
746 }
747 /* zero fill any gaps */
[cb682eb]748 fat_fill_gap(bb->data, nodep, mcl, pos);
749 b = _fat_block_get(bb->data, dev_handle, lcl,
750 (pos / bps) % spc);
[6f2dfd1]751 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
752 bytes);
[b4b7187]753 b->dirty = true; /* need to sync block */
[6f2dfd1]754 block_put(b);
755 /*
756 * Append the cluster chain starting in mcl to the end of the
757 * node's cluster chain.
758 */
[cb682eb]759 fat_append_clusters(bb->data, nodep, mcl);
[6f2dfd1]760 nodep->size = pos + bytes;
[b4b7187]761 nodep->dirty = true; /* need to sync node */
[6f2dfd1]762 fat_node_put(nodep);
[cb682eb]763 block_put(bb);
[6f2dfd1]764 ipc_answer_1(rid, EOK, bytes);
765 return;
[8d32152]766 }
[c947dda]767}
768
[be815bc]769/**
770 * @}
771 */
Note: See TracBrowser for help on using the repository browser.