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

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

Implementation of fat_append_clusters().

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