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

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

Move libfs_blockread(), block_get() and block_put() to libblock.

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