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

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

Implementation of fat_node_sync().

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