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

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

When removing a FAT node from the ffn list, use the correct pointer instead of
an uninitialized one.

  • Property mode set to 100644
File size: 17.3 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 <ipc/services.h>
43#include <ipc/devmap.h>
44#include <async.h>
45#include <errno.h>
46#include <string.h>
47#include <byteorder.h>
48#include <libadt/hash_table.h>
49#include <libadt/list.h>
50#include <assert.h>
51#include <futex.h>
52#include <sys/mman.h>
53
54#define BS_BLOCK 0
55#define BS_SIZE 512
56
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);
62
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
75static 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
102static int dev_phone = -1; /* FIXME */
103static void *dev_buffer = NULL; /* FIXME */
104
105/* TODO move somewhere else */
106typedef struct {
107 void *data;
108 size_t size;
109} block_t;
110
111static 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
143static 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
167static 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
226static void fat_node_initialize(fat_node_t *node)
227{
228 futex_initialize(&node->lock, 1);
229 node->idx = NULL;
230 node->type = 0;
231 link_initialize(&node->ffn_link);
232 node->size = 0;
233 node->lnkcnt = 0;
234 node->refcnt = 0;
235 node->dirty = false;
236}
237
238static uint16_t fat_bps_get(dev_handle_t dev_handle)
239{
240 block_t *bb;
241 uint16_t bps;
242
243 bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
244 assert(bb != NULL);
245 bps = uint16_t_le2host(FAT_BS(bb)->bps);
246 block_put(bb);
247
248 return bps;
249}
250
251typedef enum {
252 FAT_DENTRY_SKIP,
253 FAT_DENTRY_LAST,
254 FAT_DENTRY_VALID
255} fat_dentry_clsf_t;
256
257static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
258{
259 if (d->attr & FAT_ATTR_VOLLABEL) {
260 /* volume label entry */
261 return FAT_DENTRY_SKIP;
262 }
263 if (d->name[0] == FAT_DENTRY_ERASED) {
264 /* not-currently-used entry */
265 return FAT_DENTRY_SKIP;
266 }
267 if (d->name[0] == FAT_DENTRY_UNUSED) {
268 /* never used entry */
269 return FAT_DENTRY_LAST;
270 }
271 if (d->name[0] == FAT_DENTRY_DOT) {
272 /*
273 * Most likely '.' or '..'.
274 * It cannot occur in a regular file name.
275 */
276 return FAT_DENTRY_SKIP;
277 }
278 return FAT_DENTRY_VALID;
279}
280
281static void fat_node_sync(fat_node_t *node)
282{
283 /* TODO */
284}
285
286/** Internal version of fat_node_get().
287 *
288 * @param idxp Locked index structure.
289 */
290static void *fat_node_get_core(fat_idx_t *idxp)
291{
292 block_t *b;
293 fat_dentry_t *d;
294 fat_node_t *nodep = NULL;
295 unsigned bps;
296 unsigned dps;
297
298 if (idxp->nodep) {
299 /*
300 * We are lucky.
301 * The node is already instantiated in memory.
302 */
303 futex_down(&idxp->nodep->lock);
304 if (!idxp->nodep->refcnt++)
305 list_remove(&idxp->nodep->ffn_link);
306 futex_up(&idxp->nodep->lock);
307 return idxp->nodep;
308 }
309
310 /*
311 * We must instantiate the node from the file system.
312 */
313
314 assert(idxp->pfc);
315
316 futex_down(&ffn_futex);
317 if (!list_empty(&ffn_head)) {
318 /* Try to use a cached free node structure. */
319 fat_idx_t *idxp_tmp;
320 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
321 if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
322 goto skip_cache;
323 idxp_tmp = nodep->idx;
324 if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
325 futex_up(&nodep->lock);
326 goto skip_cache;
327 }
328 list_remove(&nodep->ffn_link);
329 futex_up(&ffn_futex);
330 if (nodep->dirty)
331 fat_node_sync(nodep);
332 idxp_tmp->nodep = NULL;
333 futex_up(&nodep->lock);
334 futex_up(&idxp_tmp->lock);
335 } else {
336skip_cache:
337 /* Try to allocate a new node structure. */
338 futex_up(&ffn_futex);
339 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
340 if (!nodep)
341 return NULL;
342 }
343 fat_node_initialize(nodep);
344
345 bps = fat_bps_get(idxp->dev_handle);
346 dps = bps / sizeof(fat_dentry_t);
347
348 /* Read the block that contains the dentry of interest. */
349 b = _fat_block_get(idxp->dev_handle, idxp->pfc,
350 (idxp->pdi * sizeof(fat_dentry_t)) / bps);
351 assert(b);
352
353 d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
354 if (d->attr & FAT_ATTR_SUBDIR) {
355 /*
356 * The only directory which does not have this bit set is the
357 * root directory itself. The root directory node is handled
358 * and initialized elsewhere.
359 */
360 nodep->type = FAT_DIRECTORY;
361 /*
362 * TODO: determine the size by walking FAT. Surprisingly, the
363 * 'size' filed of the FAT dentry is not defined for the
364 * directory entry type.
365 */
366 nodep->size = 64 * sizeof(fat_dentry_t);
367 } else {
368 nodep->type = FAT_FILE;
369 nodep->size = uint32_t_le2host(d->size);
370 }
371 nodep->firstc = uint16_t_le2host(d->firstc);
372 nodep->lnkcnt = 1;
373 nodep->refcnt = 1;
374
375 block_put(b);
376
377 /* Link the idx structure with the node structure. */
378 nodep->idx = idxp;
379 idxp->nodep = nodep;
380
381 return nodep;
382}
383
384/** Instantiate a FAT in-core node. */
385static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
386{
387 void *node;
388 fat_idx_t *idxp;
389
390 idxp = fat_idx_get_by_index(dev_handle, index);
391 if (!idxp)
392 return NULL;
393 /* idxp->lock held */
394 node = fat_node_get_core(idxp);
395 futex_up(&idxp->lock);
396 return node;
397}
398
399static void fat_node_put(void *node)
400{
401 fat_node_t *nodep = (fat_node_t *)node;
402
403 futex_down(&nodep->lock);
404 if (!--nodep->refcnt) {
405 futex_down(&ffn_futex);
406 list_append(&nodep->ffn_link, &ffn_head);
407 futex_up(&ffn_futex);
408 }
409 futex_up(&nodep->lock);
410}
411
412static void *fat_create(int flags)
413{
414 return NULL; /* not supported at the moment */
415}
416
417static int fat_destroy(void *node)
418{
419 return ENOTSUP; /* not supported at the moment */
420}
421
422static bool fat_link(void *prnt, void *chld, const char *name)
423{
424 return false; /* not supported at the moment */
425}
426
427static int fat_unlink(void *prnt, void *chld)
428{
429 return ENOTSUP; /* not supported at the moment */
430}
431
432static void *fat_match(void *prnt, const char *component)
433{
434 fat_node_t *parentp = (fat_node_t *)prnt;
435 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
436 unsigned i, j;
437 unsigned bps; /* bytes per sector */
438 unsigned dps; /* dentries per sector */
439 unsigned blocks;
440 fat_dentry_t *d;
441 block_t *b;
442
443 futex_down(&parentp->idx->lock);
444 bps = fat_bps_get(parentp->idx->dev_handle);
445 dps = bps / sizeof(fat_dentry_t);
446 blocks = parentp->size / bps + (parentp->size % bps != 0);
447 for (i = 0; i < blocks; i++) {
448 unsigned dentries;
449
450 b = fat_block_get(parentp, i);
451 dentries = (i == blocks - 1) ?
452 parentp->size % sizeof(fat_dentry_t) :
453 dps;
454 for (j = 0; j < dentries; j++) {
455 d = ((fat_dentry_t *)b->data) + j;
456 switch (fat_classify_dentry(d)) {
457 case FAT_DENTRY_SKIP:
458 continue;
459 case FAT_DENTRY_LAST:
460 block_put(b);
461 futex_up(&parentp->idx->lock);
462 return NULL;
463 default:
464 case FAT_DENTRY_VALID:
465 dentry_name_canonify(d, name);
466 break;
467 }
468 if (stricmp(name, component) == 0) {
469 /* hit */
470 void *node;
471 /*
472 * Assume tree hierarchy for locking. We
473 * already have the parent and now we are going
474 * to lock the child. Never lock in the oposite
475 * order.
476 */
477 fat_idx_t *idx = fat_idx_get_by_pos(
478 parentp->idx->dev_handle, parentp->firstc,
479 i * dps + j);
480 futex_up(&parentp->idx->lock);
481 if (!idx) {
482 /*
483 * Can happen if memory is low or if we
484 * run out of 32-bit indices.
485 */
486 block_put(b);
487 return NULL;
488 }
489 node = fat_node_get_core(idx);
490 futex_up(&idx->lock);
491 block_put(b);
492 return node;
493 }
494 }
495 block_put(b);
496 }
497 futex_up(&parentp->idx->lock);
498 return NULL;
499}
500
501static fs_index_t fat_index_get(void *node)
502{
503 fat_node_t *fnodep = (fat_node_t *)node;
504 if (!fnodep)
505 return 0;
506 return fnodep->idx->index;
507}
508
509static size_t fat_size_get(void *node)
510{
511 return ((fat_node_t *)node)->size;
512}
513
514static unsigned fat_lnkcnt_get(void *node)
515{
516 return ((fat_node_t *)node)->lnkcnt;
517}
518
519static bool fat_has_children(void *node)
520{
521 fat_node_t *nodep = (fat_node_t *)node;
522 unsigned bps;
523 unsigned dps;
524 unsigned blocks;
525 block_t *b;
526 unsigned i, j;
527
528 if (nodep->type != FAT_DIRECTORY)
529 return false;
530
531 futex_down(&nodep->idx->lock);
532 bps = fat_bps_get(nodep->idx->dev_handle);
533 dps = bps / sizeof(fat_dentry_t);
534
535 blocks = nodep->size / bps + (nodep->size % bps != 0);
536
537 for (i = 0; i < blocks; i++) {
538 unsigned dentries;
539 fat_dentry_t *d;
540
541 b = fat_block_get(nodep, i);
542 dentries = (i == blocks - 1) ?
543 nodep->size % sizeof(fat_dentry_t) :
544 dps;
545 for (j = 0; j < dentries; j++) {
546 d = ((fat_dentry_t *)b->data) + j;
547 switch (fat_classify_dentry(d)) {
548 case FAT_DENTRY_SKIP:
549 continue;
550 case FAT_DENTRY_LAST:
551 block_put(b);
552 futex_up(&nodep->idx->lock);
553 return false;
554 default:
555 case FAT_DENTRY_VALID:
556 block_put(b);
557 futex_up(&nodep->idx->lock);
558 return true;
559 }
560 block_put(b);
561 futex_up(&nodep->idx->lock);
562 return true;
563 }
564 block_put(b);
565 }
566
567 futex_up(&nodep->idx->lock);
568 return false;
569}
570
571static void *fat_root_get(dev_handle_t dev_handle)
572{
573 return fat_node_get(dev_handle, 0);
574}
575
576static char fat_plb_get_char(unsigned pos)
577{
578 return fat_reg.plb_ro[pos % PLB_SIZE];
579}
580
581static bool fat_is_directory(void *node)
582{
583 return ((fat_node_t *)node)->type == FAT_DIRECTORY;
584}
585
586static bool fat_is_file(void *node)
587{
588 return ((fat_node_t *)node)->type == FAT_FILE;
589}
590
591/** libfs operations */
592libfs_ops_t fat_libfs_ops = {
593 .match = fat_match,
594 .node_get = fat_node_get,
595 .node_put = fat_node_put,
596 .create = fat_create,
597 .destroy = fat_destroy,
598 .link = fat_link,
599 .unlink = fat_unlink,
600 .index_get = fat_index_get,
601 .size_get = fat_size_get,
602 .lnkcnt_get = fat_lnkcnt_get,
603 .has_children = fat_has_children,
604 .root_get = fat_root_get,
605 .plb_get_char = fat_plb_get_char,
606 .is_directory = fat_is_directory,
607 .is_file = fat_is_file
608};
609
610void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
611{
612 dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
613 block_t *bb;
614 uint16_t bps;
615 uint16_t rde;
616 int rc;
617
618 /*
619 * For now, we don't bother to remember dev_handle, dev_phone or
620 * dev_buffer in some data structure. We use global variables because we
621 * know there will be at most one mount on this file system.
622 * Of course, this is a huge TODO item.
623 */
624 dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
625 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
626
627 if (!dev_buffer) {
628 ipc_answer_0(rid, ENOMEM);
629 return;
630 }
631
632 dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
633 DEVMAP_CONNECT_TO_DEVICE, dev_handle);
634
635 if (dev_phone < 0) {
636 munmap(dev_buffer, BS_SIZE);
637 ipc_answer_0(rid, dev_phone);
638 return;
639 }
640
641 rc = ipc_share_out_start(dev_phone, dev_buffer,
642 AS_AREA_READ | AS_AREA_WRITE);
643 if (rc != EOK) {
644 munmap(dev_buffer, BS_SIZE);
645 ipc_answer_0(rid, rc);
646 return;
647 }
648
649 /* Read the number of root directory entries. */
650 bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
651 bps = uint16_t_le2host(FAT_BS(bb)->bps);
652 rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
653 block_put(bb);
654
655 if (bps != BS_SIZE) {
656 munmap(dev_buffer, BS_SIZE);
657 ipc_answer_0(rid, ENOTSUP);
658 return;
659 }
660
661 rc = fat_idx_init_by_dev_handle(dev_handle);
662 if (rc != EOK) {
663 munmap(dev_buffer, BS_SIZE);
664 ipc_answer_0(rid, rc);
665 return;
666 }
667
668 /* Initialize the root node. */
669 fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
670 if (!rootp) {
671 munmap(dev_buffer, BS_SIZE);
672 fat_idx_fini_by_dev_handle(dev_handle);
673 ipc_answer_0(rid, ENOMEM);
674 return;
675 }
676 fat_node_initialize(rootp);
677
678 fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
679 if (!ridxp) {
680 munmap(dev_buffer, BS_SIZE);
681 free(rootp);
682 fat_idx_fini_by_dev_handle(dev_handle);
683 ipc_answer_0(rid, ENOMEM);
684 return;
685 }
686 assert(ridxp->index == 0);
687 /* ridxp->lock held */
688
689 rootp->type = FAT_DIRECTORY;
690 rootp->firstc = FAT_CLST_ROOT;
691 rootp->refcnt = 1;
692 rootp->size = rde * sizeof(fat_dentry_t);
693 rootp->idx = ridxp;
694 ridxp->nodep = rootp;
695
696 futex_up(&ridxp->lock);
697
698 ipc_answer_0(rid, EOK);
699}
700
701void fat_mount(ipc_callid_t rid, ipc_call_t *request)
702{
703 ipc_answer_0(rid, ENOTSUP);
704}
705
706void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
707{
708 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
709}
710
711void fat_read(ipc_callid_t rid, ipc_call_t *request)
712{
713 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
714 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
715 off_t pos = (off_t)IPC_GET_ARG3(*request);
716 fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
717 uint16_t bps = fat_bps_get(dev_handle);
718 size_t bytes;
719
720 if (!nodep) {
721 ipc_answer_0(rid, ENOENT);
722 return;
723 }
724
725 ipc_callid_t callid;
726 size_t len;
727 if (!ipc_data_write_receive(&callid, &len)) {
728 fat_node_put(nodep);
729 ipc_answer_0(callid, EINVAL);
730 ipc_answer_0(rid, EINVAL);
731 return;
732 }
733
734 if (nodep->type == FAT_FILE) {
735 block_t *b;
736
737 bytes = min(len, bps - pos % bps);
738 b = fat_block_get(nodep, pos / bps);
739 (void) ipc_data_read_finalize(callid, b->data + pos % bps,
740 bytes);
741 block_put(b);
742 } else {
743 assert(nodep->type == FAT_DIRECTORY);
744 /* TODO */
745 fat_node_put(nodep);
746 ipc_answer_0(callid, ENOTSUP);
747 ipc_answer_0(rid, ENOTSUP);
748 return;
749 }
750
751 fat_node_put(nodep);
752 ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
753}
754
755/**
756 * @}
757 */
Note: See TracBrowser for help on using the repository browser.