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
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 *bb, *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 bb = block_get(idxp->dev_handle, BS_BLOCK, BS_SIZE);
182 bps = uint16_t_le2host(FAT_BS(bb)->bps);
183 dps = bps / sizeof(fat_dentry_t);
184
185 /* Read the block that contains the dentry of interest. */
186 b = _fat_block_get(bb->data, idxp->dev_handle, idxp->pfc,
187 (idxp->pdi * sizeof(fat_dentry_t)) / bps);
188 assert(b);
189
190 d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
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;
198 /*
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.
202 */
203 nodep->size = bps * _fat_blcks_get(bb->data, idxp->dev_handle,
204 uint16_t_le2host(d->firstc), NULL);
205 } else {
206 nodep->type = FAT_FILE;
207 nodep->size = uint32_t_le2host(d->size);
208 }
209 nodep->firstc = uint16_t_le2host(d->firstc);
210 nodep->lnkcnt = 1;
211 nodep->refcnt = 1;
212
213 block_put(b);
214 block_put(bb);
215
216 /* Link the idx structure with the node structure. */
217 nodep->idx = idxp;
218 idxp->nodep = nodep;
219
220 return nodep;
221}
222
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
238static void fat_node_put(void *node)
239{
240 fat_node_t *nodep = (fat_node_t *)node;
241
242 futex_down(&nodep->lock);
243 if (!--nodep->refcnt) {
244 futex_down(&ffn_futex);
245 list_append(&nodep->ffn_link, &ffn_head);
246 futex_up(&ffn_futex);
247 }
248 futex_up(&nodep->lock);
249}
250
251static void *fat_create(int flags)
252{
253 return NULL; /* not supported at the moment */
254}
255
256static int fat_destroy(void *node)
257{
258 return ENOTSUP; /* not supported at the moment */
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
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];
275 unsigned i, j;
276 unsigned bps; /* bytes per sector */
277 unsigned dps; /* dentries per sector */
278 unsigned blocks;
279 fat_dentry_t *d;
280 block_t *bb, *b;
281
282 futex_down(&parentp->idx->lock);
283 bb = block_get(parentp->idx->dev_handle, BS_BLOCK, BS_SIZE);
284 bps = uint16_t_le2host(FAT_BS(bb)->bps);
285 dps = bps / sizeof(fat_dentry_t);
286 blocks = parentp->size / bps + (parentp->size % bps != 0);
287 for (i = 0; i < blocks; i++) {
288 unsigned dentries;
289
290 b = fat_block_get(bb->data, parentp, i);
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;
296 switch (fat_classify_dentry(d)) {
297 case FAT_DENTRY_SKIP:
298 continue;
299 case FAT_DENTRY_LAST:
300 block_put(b);
301 block_put(bb);
302 futex_up(&parentp->idx->lock);
303 return NULL;
304 default:
305 case FAT_DENTRY_VALID:
306 dentry_name_canonify(d, name);
307 break;
308 }
309 if (stricmp(name, component) == 0) {
310 /* hit */
311 void *node;
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 */
318 fat_idx_t *idx = fat_idx_get_by_pos(
319 parentp->idx->dev_handle, parentp->firstc,
320 i * dps + j);
321 futex_up(&parentp->idx->lock);
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);
328 block_put(bb);
329 return NULL;
330 }
331 node = fat_node_get_core(idx);
332 futex_up(&idx->lock);
333 block_put(b);
334 block_put(bb);
335 return node;
336 }
337 }
338 block_put(b);
339 }
340 block_put(bb);
341
342 futex_up(&parentp->idx->lock);
343 return NULL;
344}
345
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;
351 return fnodep->idx->index;
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
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;
370 block_t *bb, *b;
371 unsigned i, j;
372
373 if (nodep->type != FAT_DIRECTORY)
374 return false;
375
376 futex_down(&nodep->idx->lock);
377 bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE);
378 bps = uint16_t_le2host(FAT_BS(bb)->bps);
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
387 b = fat_block_get(bb->data, nodep, i);
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);
398 block_put(bb);
399 futex_up(&nodep->idx->lock);
400 return false;
401 default:
402 case FAT_DENTRY_VALID:
403 block_put(b);
404 block_put(bb);
405 futex_up(&nodep->idx->lock);
406 return true;
407 }
408 block_put(b);
409 block_put(bb);
410 futex_up(&nodep->idx->lock);
411 return true;
412 }
413 block_put(b);
414 }
415 block_put(bb);
416
417 futex_up(&nodep->idx->lock);
418 return false;
419}
420
421static void *fat_root_get(dev_handle_t dev_handle)
422{
423 return fat_node_get(dev_handle, 0);
424}
425
426static char fat_plb_get_char(unsigned pos)
427{
428 return fat_reg.plb_ro[pos % PLB_SIZE];
429}
430
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
441/** libfs operations */
442libfs_ops_t fat_libfs_ops = {
443 .match = fat_match,
444 .node_get = fat_node_get,
445 .node_put = fat_node_put,
446 .create = fat_create,
447 .destroy = fat_destroy,
448 .link = fat_link,
449 .unlink = fat_unlink,
450 .index_get = fat_index_get,
451 .size_get = fat_size_get,
452 .lnkcnt_get = fat_lnkcnt_get,
453 .has_children = fat_has_children,
454 .root_get = fat_root_get,
455 .plb_get_char = fat_plb_get_char,
456 .is_directory = fat_is_directory,
457 .is_file = fat_is_file
458};
459
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);
463 block_t *bb;
464 uint16_t bps;
465 uint16_t rde;
466 int rc;
467
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
499 /* Read the number of root directory entries. */
500 bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
501 bps = uint16_t_le2host(FAT_BS(bb)->bps);
502 rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
503 block_put(bb);
504
505 if (bps != BS_SIZE) {
506 munmap(dev_buffer, BS_SIZE);
507 ipc_answer_0(rid, ENOTSUP);
508 return;
509 }
510
511 rc = fat_idx_init_by_dev_handle(dev_handle);
512 if (rc != EOK) {
513 munmap(dev_buffer, BS_SIZE);
514 ipc_answer_0(rid, rc);
515 return;
516 }
517
518 /* Initialize the root node. */
519 fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
520 if (!rootp) {
521 munmap(dev_buffer, BS_SIZE);
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) {
530 munmap(dev_buffer, BS_SIZE);
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;
542 rootp->lnkcnt = 0; /* FS root is not linked */
543 rootp->size = rde * sizeof(fat_dentry_t);
544 rootp->idx = ridxp;
545 ridxp->nodep = rootp;
546
547 futex_up(&ridxp->lock);
548
549 ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
550}
551
552void fat_mount(ipc_callid_t rid, ipc_call_t *request)
553{
554 ipc_answer_0(rid, ENOTSUP);
555}
556
557void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
558{
559 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
560}
561
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);
568 uint16_t bps;
569 size_t bytes;
570 block_t *bb, *b;
571
572 if (!nodep) {
573 ipc_answer_0(rid, ENOENT);
574 return;
575 }
576
577 ipc_callid_t callid;
578 size_t len;
579 if (!ipc_data_read_receive(&callid, &len)) {
580 fat_node_put(nodep);
581 ipc_answer_0(callid, EINVAL);
582 ipc_answer_0(rid, EINVAL);
583 return;
584 }
585
586 bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
587 bps = uint16_t_le2host(FAT_BS(bb)->bps);
588
589 if (nodep->type == FAT_FILE) {
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 */
595 bytes = min(len, bps - pos % bps);
596 b = fat_block_get(bb->data, nodep, pos / bps);
597 (void) ipc_data_read_finalize(callid, b->data + pos % bps,
598 bytes);
599 block_put(b);
600 } else {
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
606 assert(nodep->type == FAT_DIRECTORY);
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
620 b = fat_block_get(bb->data, nodep, bnum);
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:
642 fat_node_put(nodep);
643 block_put(bb);
644 ipc_answer_0(callid, ENOENT);
645 ipc_answer_1(rid, ENOENT, 0);
646 return;
647hit:
648 (void) ipc_data_read_finalize(callid, name, strlen(name) + 1);
649 bytes = (pos - spos) + 1;
650 }
651
652 fat_node_put(nodep);
653 block_put(bb);
654 ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
655}
656
657void fat_write(ipc_callid_t rid, ipc_call_t *request)
658{
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;
667 off_t boundary;
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
703 boundary = ROUND_UP(nodep->size, bps * spc);
704 if (pos < boundary) {
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 */
711 fat_fill_gap(bb->data, nodep, FAT_CLST_RES0, pos);
712 b = fat_block_get(bb->data, nodep, pos / bps);
713 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
714 bytes);
715 b->dirty = true; /* need to sync block */
716 block_put(b);
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);
722 block_put(bb);
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 */
730 int status;
731 unsigned nclsts;
732 fat_cluster_t mcl, lcl;
733
734 nclsts = (ROUND_UP(pos + bytes, bps * spc) - boundary) /
735 bps * spc;
736 /* create an independent chain of nclsts clusters in all FATs */
737 status = fat_alloc_clusters(bb->data, dev_handle, nclsts, &mcl,
738 &lcl);
739 if (status != EOK) {
740 /* could not allocate a chain of nclsts clusters */
741 fat_node_put(nodep);
742 block_put(bb);
743 ipc_answer_0(callid, status);
744 ipc_answer_0(rid, status);
745 return;
746 }
747 /* zero fill any gaps */
748 fat_fill_gap(bb->data, nodep, mcl, pos);
749 b = _fat_block_get(bb->data, dev_handle, lcl,
750 (pos / bps) % spc);
751 (void) ipc_data_write_finalize(callid, b->data + pos % bps,
752 bytes);
753 b->dirty = true; /* need to sync block */
754 block_put(b);
755 /*
756 * Append the cluster chain starting in mcl to the end of the
757 * node's cluster chain.
758 */
759 fat_append_clusters(bb->data, nodep, mcl);
760 nodep->size = pos + bytes;
761 nodep->dirty = true; /* need to sync node */
762 fat_node_put(nodep);
763 block_put(bb);
764 ipc_answer_1(rid, EOK, bytes);
765 return;
766 }
767}
768
769/**
770 * @}
771 */
Note: See TracBrowser for help on using the repository browser.