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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 97bc3ee was 97bc3ee, checked in by Oleg Romanenko <romanenko.oleg@…>, 15 years ago

Full support for FAT12 file system. Correct creating directories and files. Fixing addressing issue.
Type of FAT (12,16,32) is determined only on the basis of the count of clusters(according to Microsoft FAT specification). I.e. FAT
with 4085 clusters or less will be determined as FAT12. FAT16 must contain more than 4085 clusters but less then 65525.

  • Property mode set to 100644
File size: 38.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 <libblock.h>
44#include <ipc/services.h>
45#include <ipc/devmap.h>
46#include <macros.h>
47#include <async.h>
48#include <errno.h>
49#include <str.h>
50#include <byteorder.h>
51#include <adt/hash_table.h>
52#include <adt/list.h>
53#include <assert.h>
54#include <fibril_synch.h>
55#include <sys/mman.h>
56#include <align.h>
57
58#define FAT_NODE(node) ((node) ? (fat_node_t *) (node)->data : NULL)
59#define FS_NODE(node) ((node) ? (node)->bp : NULL)
60
61#define DPS(bs) (BPS((bs)) / sizeof(fat_dentry_t))
62#define BPC(bs) (BPS((bs)) * SPC((bs)))
63
64/** Mutex protecting the list of cached free FAT nodes. */
65static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
66
67/** List of cached free FAT nodes. */
68static LIST_INITIALIZE(ffn_head);
69
70/*
71 * Forward declarations of FAT libfs operations.
72 */
73static int fat_root_get(fs_node_t **, devmap_handle_t);
74static int fat_match(fs_node_t **, fs_node_t *, const char *);
75static int fat_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
76static int fat_node_open(fs_node_t *);
77static int fat_node_put(fs_node_t *);
78static int fat_create_node(fs_node_t **, devmap_handle_t, int);
79static int fat_destroy_node(fs_node_t *);
80static int fat_link(fs_node_t *, fs_node_t *, const char *);
81static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
82static int fat_has_children(bool *, fs_node_t *);
83static fs_index_t fat_index_get(fs_node_t *);
84static aoff64_t fat_size_get(fs_node_t *);
85static unsigned fat_lnkcnt_get(fs_node_t *);
86static char fat_plb_get_char(unsigned);
87static bool fat_is_directory(fs_node_t *);
88static bool fat_is_file(fs_node_t *node);
89static devmap_handle_t fat_device_get(fs_node_t *node);
90
91/*
92 * Helper functions.
93 */
94static void fat_node_initialize(fat_node_t *node)
95{
96 fibril_mutex_initialize(&node->lock);
97 node->bp = NULL;
98 node->idx = NULL;
99 node->type = 0;
100 link_initialize(&node->ffn_link);
101 node->size = 0;
102 node->lnkcnt = 0;
103 node->refcnt = 0;
104 node->dirty = false;
105 node->lastc_cached_valid = false;
106 node->lastc_cached_value = FAT16_CLST_LAST1;
107 node->currc_cached_valid = false;
108 node->currc_cached_bn = 0;
109 node->currc_cached_value = FAT16_CLST_LAST1;
110}
111
112static int fat_node_sync(fat_node_t *node)
113{
114 block_t *b;
115 fat_bs_t *bs;
116 fat_dentry_t *d;
117 int rc;
118
119 assert(node->dirty);
120
121 bs = block_bb_get(node->idx->devmap_handle);
122
123 /* Read the block that contains the dentry of interest. */
124 rc = _fat_block_get(&b, bs, node->idx->devmap_handle, node->idx->pfc,
125 NULL, (node->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
126 BLOCK_FLAGS_NONE);
127 if (rc != EOK)
128 return rc;
129
130 d = ((fat_dentry_t *)b->data) + (node->idx->pdi % DPS(bs));
131
132 d->firstc = host2uint16_t_le(node->firstc);
133 if (node->type == FAT_FILE) {
134 d->size = host2uint32_t_le(node->size);
135 } else if (node->type == FAT_DIRECTORY) {
136 d->attr = FAT_ATTR_SUBDIR;
137 }
138
139 /* TODO: update other fields? (e.g time fields) */
140
141 b->dirty = true; /* need to sync block */
142 rc = block_put(b);
143 return rc;
144}
145
146static int fat_node_fini_by_devmap_handle(devmap_handle_t devmap_handle)
147{
148 link_t *lnk;
149 fat_node_t *nodep;
150 int rc;
151
152 /*
153 * We are called from fat_unmounted() and assume that there are already
154 * no nodes belonging to this instance with non-zero refcount. Therefore
155 * it is sufficient to clean up only the FAT free node list.
156 */
157
158restart:
159 fibril_mutex_lock(&ffn_mutex);
160 for (lnk = ffn_head.next; lnk != &ffn_head; lnk = lnk->next) {
161 nodep = list_get_instance(lnk, fat_node_t, ffn_link);
162 if (!fibril_mutex_trylock(&nodep->lock)) {
163 fibril_mutex_unlock(&ffn_mutex);
164 goto restart;
165 }
166 if (!fibril_mutex_trylock(&nodep->idx->lock)) {
167 fibril_mutex_unlock(&nodep->lock);
168 fibril_mutex_unlock(&ffn_mutex);
169 goto restart;
170 }
171 if (nodep->idx->devmap_handle != devmap_handle) {
172 fibril_mutex_unlock(&nodep->idx->lock);
173 fibril_mutex_unlock(&nodep->lock);
174 continue;
175 }
176
177 list_remove(&nodep->ffn_link);
178 fibril_mutex_unlock(&ffn_mutex);
179
180 /*
181 * We can unlock the node and its index structure because we are
182 * the last player on this playground and VFS is preventing new
183 * players from entering.
184 */
185 fibril_mutex_unlock(&nodep->idx->lock);
186 fibril_mutex_unlock(&nodep->lock);
187
188 if (nodep->dirty) {
189 rc = fat_node_sync(nodep);
190 if (rc != EOK)
191 return rc;
192 }
193 nodep->idx->nodep = NULL;
194 free(nodep->bp);
195 free(nodep);
196
197 /* Need to restart because we changed the ffn_head list. */
198 goto restart;
199 }
200 fibril_mutex_unlock(&ffn_mutex);
201
202 return EOK;
203}
204
205static int fat_node_get_new(fat_node_t **nodepp)
206{
207 fs_node_t *fn;
208 fat_node_t *nodep;
209 int rc;
210
211 fibril_mutex_lock(&ffn_mutex);
212 if (!list_empty(&ffn_head)) {
213 /* Try to use a cached free node structure. */
214 fat_idx_t *idxp_tmp;
215 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
216 if (!fibril_mutex_trylock(&nodep->lock))
217 goto skip_cache;
218 idxp_tmp = nodep->idx;
219 if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
220 fibril_mutex_unlock(&nodep->lock);
221 goto skip_cache;
222 }
223 list_remove(&nodep->ffn_link);
224 fibril_mutex_unlock(&ffn_mutex);
225 if (nodep->dirty) {
226 rc = fat_node_sync(nodep);
227 if (rc != EOK) {
228 idxp_tmp->nodep = NULL;
229 fibril_mutex_unlock(&nodep->lock);
230 fibril_mutex_unlock(&idxp_tmp->lock);
231 free(nodep->bp);
232 free(nodep);
233 return rc;
234 }
235 }
236 idxp_tmp->nodep = NULL;
237 fibril_mutex_unlock(&nodep->lock);
238 fibril_mutex_unlock(&idxp_tmp->lock);
239 fn = FS_NODE(nodep);
240 } else {
241skip_cache:
242 /* Try to allocate a new node structure. */
243 fibril_mutex_unlock(&ffn_mutex);
244 fn = (fs_node_t *)malloc(sizeof(fs_node_t));
245 if (!fn)
246 return ENOMEM;
247 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
248 if (!nodep) {
249 free(fn);
250 return ENOMEM;
251 }
252 }
253 fat_node_initialize(nodep);
254 fs_node_initialize(fn);
255 fn->data = nodep;
256 nodep->bp = fn;
257
258 *nodepp = nodep;
259 return EOK;
260}
261
262/** Internal version of fat_node_get().
263 *
264 * @param idxp Locked index structure.
265 */
266static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
267{
268 block_t *b;
269 fat_bs_t *bs;
270 fat_dentry_t *d;
271 fat_node_t *nodep = NULL;
272 int rc;
273
274 if (idxp->nodep) {
275 /*
276 * We are lucky.
277 * The node is already instantiated in memory.
278 */
279 fibril_mutex_lock(&idxp->nodep->lock);
280 if (!idxp->nodep->refcnt++) {
281 fibril_mutex_lock(&ffn_mutex);
282 list_remove(&idxp->nodep->ffn_link);
283 fibril_mutex_unlock(&ffn_mutex);
284 }
285 fibril_mutex_unlock(&idxp->nodep->lock);
286 *nodepp = idxp->nodep;
287 return EOK;
288 }
289
290 /*
291 * We must instantiate the node from the file system.
292 */
293
294 assert(idxp->pfc);
295
296 rc = fat_node_get_new(&nodep);
297 if (rc != EOK)
298 return rc;
299
300 bs = block_bb_get(idxp->devmap_handle);
301
302 /* Read the block that contains the dentry of interest. */
303 rc = _fat_block_get(&b, bs, idxp->devmap_handle, idxp->pfc, NULL,
304 (idxp->pdi * sizeof(fat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
305 if (rc != EOK) {
306 (void) fat_node_put(FS_NODE(nodep));
307 return rc;
308 }
309
310 d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
311 if (d->attr & FAT_ATTR_SUBDIR) {
312 /*
313 * The only directory which does not have this bit set is the
314 * root directory itself. The root directory node is handled
315 * and initialized elsewhere.
316 */
317 nodep->type = FAT_DIRECTORY;
318
319 /*
320 * Unfortunately, the 'size' field of the FAT dentry is not
321 * defined for the directory entry type. We must determine the
322 * size of the directory by walking the FAT.
323 */
324 uint16_t clusters;
325 rc = fat_clusters_get(&clusters, bs, idxp->devmap_handle,
326 uint16_t_le2host(d->firstc));
327 if (rc != EOK) {
328 (void) block_put(b);
329 (void) fat_node_put(FS_NODE(nodep));
330 return rc;
331 }
332 nodep->size = BPS(bs) * SPC(bs) * clusters;
333 } else {
334 nodep->type = FAT_FILE;
335 nodep->size = uint32_t_le2host(d->size);
336 }
337
338 nodep->firstc = uint16_t_le2host(d->firstc);
339 nodep->lnkcnt = 1;
340 nodep->refcnt = 1;
341
342 rc = block_put(b);
343 if (rc != EOK) {
344 (void) fat_node_put(FS_NODE(nodep));
345 return rc;
346 }
347
348 /* Link the idx structure with the node structure. */
349 nodep->idx = idxp;
350 idxp->nodep = nodep;
351
352 *nodepp = nodep;
353 return EOK;
354}
355
356/*
357 * FAT libfs operations.
358 */
359
360int fat_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
361{
362 return fat_node_get(rfn, devmap_handle, 0);
363}
364
365int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
366{
367 fat_bs_t *bs;
368 fat_node_t *parentp = FAT_NODE(pfn);
369 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
370 unsigned i, j;
371 unsigned blocks;
372 fat_dentry_t *d;
373 devmap_handle_t devmap_handle;
374 block_t *b;
375 int rc;
376
377 fibril_mutex_lock(&parentp->idx->lock);
378 devmap_handle = parentp->idx->devmap_handle;
379 fibril_mutex_unlock(&parentp->idx->lock);
380
381 bs = block_bb_get(devmap_handle);
382 blocks = parentp->size / BPS(bs);
383 for (i = 0; i < blocks; i++) {
384 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
385 if (rc != EOK)
386 return rc;
387 for (j = 0; j < DPS(bs); j++) {
388 d = ((fat_dentry_t *)b->data) + j;
389 switch (fat_classify_dentry(d)) {
390 case FAT_DENTRY_SKIP:
391 case FAT_DENTRY_FREE:
392 continue;
393 case FAT_DENTRY_LAST:
394 /* miss */
395 rc = block_put(b);
396 *rfn = NULL;
397 return rc;
398 default:
399 case FAT_DENTRY_VALID:
400 fat_dentry_name_get(d, name);
401 break;
402 }
403 if (fat_dentry_namecmp(name, component) == 0) {
404 /* hit */
405 fat_node_t *nodep;
406 fat_idx_t *idx = fat_idx_get_by_pos(devmap_handle,
407 parentp->firstc, i * DPS(bs) + j);
408 if (!idx) {
409 /*
410 * Can happen if memory is low or if we
411 * run out of 32-bit indices.
412 */
413 rc = block_put(b);
414 return (rc == EOK) ? ENOMEM : rc;
415 }
416 rc = fat_node_get_core(&nodep, idx);
417 fibril_mutex_unlock(&idx->lock);
418 if (rc != EOK) {
419 (void) block_put(b);
420 return rc;
421 }
422 *rfn = FS_NODE(nodep);
423 rc = block_put(b);
424 if (rc != EOK)
425 (void) fat_node_put(*rfn);
426 return rc;
427 }
428 }
429 rc = block_put(b);
430 if (rc != EOK)
431 return rc;
432 }
433
434 *rfn = NULL;
435 return EOK;
436}
437
438/** Instantiate a FAT in-core node. */
439int fat_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
440{
441 fat_node_t *nodep;
442 fat_idx_t *idxp;
443 int rc;
444
445 idxp = fat_idx_get_by_index(devmap_handle, index);
446 if (!idxp) {
447 *rfn = NULL;
448 return EOK;
449 }
450 /* idxp->lock held */
451 rc = fat_node_get_core(&nodep, idxp);
452 fibril_mutex_unlock(&idxp->lock);
453 if (rc == EOK)
454 *rfn = FS_NODE(nodep);
455 return rc;
456}
457
458int fat_node_open(fs_node_t *fn)
459{
460 /*
461 * Opening a file is stateless, nothing
462 * to be done here.
463 */
464 return EOK;
465}
466
467int fat_node_put(fs_node_t *fn)
468{
469 fat_node_t *nodep = FAT_NODE(fn);
470 bool destroy = false;
471
472 fibril_mutex_lock(&nodep->lock);
473 if (!--nodep->refcnt) {
474 if (nodep->idx) {
475 fibril_mutex_lock(&ffn_mutex);
476 list_append(&nodep->ffn_link, &ffn_head);
477 fibril_mutex_unlock(&ffn_mutex);
478 } else {
479 /*
480 * The node does not have any index structure associated
481 * with itself. This can only mean that we are releasing
482 * the node after a failed attempt to allocate the index
483 * structure for it.
484 */
485 destroy = true;
486 }
487 }
488 fibril_mutex_unlock(&nodep->lock);
489 if (destroy) {
490 free(nodep->bp);
491 free(nodep);
492 }
493 return EOK;
494}
495
496int fat_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
497{
498 fat_idx_t *idxp;
499 fat_node_t *nodep;
500 fat_bs_t *bs;
501 fat_cluster_t mcl, lcl;
502 int rc;
503
504 bs = block_bb_get(devmap_handle);
505 if (flags & L_DIRECTORY) {
506 /* allocate a cluster */
507 rc = fat_alloc_clusters(bs, devmap_handle, 1, &mcl, &lcl);
508 if (rc != EOK)
509 return rc;
510 /* populate the new cluster with unused dentries */
511 rc = fat_zero_cluster(bs, devmap_handle, mcl);
512 if (rc != EOK) {
513 (void) fat_free_clusters(bs, devmap_handle, mcl);
514 return rc;
515 }
516 }
517
518 rc = fat_node_get_new(&nodep);
519 if (rc != EOK) {
520 (void) fat_free_clusters(bs, devmap_handle, mcl);
521 return rc;
522 }
523 rc = fat_idx_get_new(&idxp, devmap_handle);
524 if (rc != EOK) {
525 (void) fat_free_clusters(bs, devmap_handle, mcl);
526 (void) fat_node_put(FS_NODE(nodep));
527 return rc;
528 }
529 /* idxp->lock held */
530 if (flags & L_DIRECTORY) {
531 nodep->type = FAT_DIRECTORY;
532 nodep->firstc = mcl;
533 nodep->size = BPS(bs) * SPC(bs);
534 } else {
535 nodep->type = FAT_FILE;
536 nodep->firstc = FAT_CLST_RES0;
537 nodep->size = 0;
538 }
539 nodep->lnkcnt = 0; /* not linked anywhere */
540 nodep->refcnt = 1;
541 nodep->dirty = true;
542
543 nodep->idx = idxp;
544 idxp->nodep = nodep;
545
546 fibril_mutex_unlock(&idxp->lock);
547 *rfn = FS_NODE(nodep);
548 return EOK;
549}
550
551int fat_destroy_node(fs_node_t *fn)
552{
553 fat_node_t *nodep = FAT_NODE(fn);
554 fat_bs_t *bs;
555 bool has_children;
556 int rc;
557
558 /*
559 * The node is not reachable from the file system. This means that the
560 * link count should be zero and that the index structure cannot be
561 * found in the position hash. Obviously, we don't need to lock the node
562 * nor its index structure.
563 */
564 assert(nodep->lnkcnt == 0);
565
566 /*
567 * The node may not have any children.
568 */
569 rc = fat_has_children(&has_children, fn);
570 if (rc != EOK)
571 return rc;
572 assert(!has_children);
573
574 bs = block_bb_get(nodep->idx->devmap_handle);
575 if (nodep->firstc != FAT_CLST_RES0) {
576 assert(nodep->size);
577 /* Free all clusters allocated to the node. */
578 rc = fat_free_clusters(bs, nodep->idx->devmap_handle,
579 nodep->firstc);
580 }
581
582 fat_idx_destroy(nodep->idx);
583 free(nodep->bp);
584 free(nodep);
585 return rc;
586}
587
588int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
589{
590 fat_node_t *parentp = FAT_NODE(pfn);
591 fat_node_t *childp = FAT_NODE(cfn);
592 fat_dentry_t *d;
593 fat_bs_t *bs;
594 block_t *b;
595 unsigned i, j;
596 unsigned blocks;
597 fat_cluster_t mcl, lcl;
598 int rc;
599
600 fibril_mutex_lock(&childp->lock);
601 if (childp->lnkcnt == 1) {
602 /*
603 * On FAT, we don't support multiple hard links.
604 */
605 fibril_mutex_unlock(&childp->lock);
606 return EMLINK;
607 }
608 assert(childp->lnkcnt == 0);
609 fibril_mutex_unlock(&childp->lock);
610
611 if (!fat_dentry_name_verify(name)) {
612 /*
613 * Attempt to create unsupported name.
614 */
615 return ENOTSUP;
616 }
617
618 /*
619 * Get us an unused parent node's dentry or grow the parent and allocate
620 * a new one.
621 */
622
623 fibril_mutex_lock(&parentp->idx->lock);
624 bs = block_bb_get(parentp->idx->devmap_handle);
625
626 blocks = parentp->size / BPS(bs);
627
628 for (i = 0; i < blocks; i++) {
629 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
630 if (rc != EOK) {
631 fibril_mutex_unlock(&parentp->idx->lock);
632 return rc;
633 }
634 for (j = 0; j < DPS(bs); j++) {
635 d = ((fat_dentry_t *)b->data) + j;
636 switch (fat_classify_dentry(d)) {
637 case FAT_DENTRY_SKIP:
638 case FAT_DENTRY_VALID:
639 /* skipping used and meta entries */
640 continue;
641 case FAT_DENTRY_FREE:
642 case FAT_DENTRY_LAST:
643 /* found an empty slot */
644 goto hit;
645 }
646 }
647 rc = block_put(b);
648 if (rc != EOK) {
649 fibril_mutex_unlock(&parentp->idx->lock);
650 return rc;
651 }
652 }
653 j = 0;
654
655 /*
656 * We need to grow the parent in order to create a new unused dentry.
657 */
658 if (parentp->firstc == FAT_CLST_ROOT) {
659 /* Can't grow the root directory. */
660 fibril_mutex_unlock(&parentp->idx->lock);
661 return ENOSPC;
662 }
663 rc = fat_alloc_clusters(bs, parentp->idx->devmap_handle, 1, &mcl, &lcl);
664 if (rc != EOK) {
665 fibril_mutex_unlock(&parentp->idx->lock);
666 return rc;
667 }
668 rc = fat_zero_cluster(bs, parentp->idx->devmap_handle, mcl);
669 if (rc != EOK) {
670 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
671 fibril_mutex_unlock(&parentp->idx->lock);
672 return rc;
673 }
674 rc = fat_append_clusters(bs, parentp, mcl, lcl);
675 if (rc != EOK) {
676 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
677 fibril_mutex_unlock(&parentp->idx->lock);
678 return rc;
679 }
680 parentp->size += BPS(bs) * SPC(bs);
681 parentp->dirty = true; /* need to sync node */
682 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
683 if (rc != EOK) {
684 fibril_mutex_unlock(&parentp->idx->lock);
685 return rc;
686 }
687 d = (fat_dentry_t *)b->data;
688
689hit:
690 /*
691 * At this point we only establish the link between the parent and the
692 * child. The dentry, except of the name and the extension, will remain
693 * uninitialized until the corresponding node is synced. Thus the valid
694 * dentry data is kept in the child node structure.
695 */
696 memset(d, 0, sizeof(fat_dentry_t));
697 fat_dentry_name_set(d, name);
698 b->dirty = true; /* need to sync block */
699 rc = block_put(b);
700 fibril_mutex_unlock(&parentp->idx->lock);
701 if (rc != EOK)
702 return rc;
703
704 fibril_mutex_lock(&childp->idx->lock);
705
706 if (childp->type == FAT_DIRECTORY) {
707 /*
708 * If possible, create the Sub-directory Identifier Entry and
709 * the Sub-directory Parent Pointer Entry (i.e. "." and "..").
710 * These entries are not mandatory according to Standard
711 * ECMA-107 and HelenOS VFS does not use them anyway, so this is
712 * rather a sign of our good will.
713 */
714 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
715 if (rc != EOK) {
716 /*
717 * Rather than returning an error, simply skip the
718 * creation of these two entries.
719 */
720 goto skip_dots;
721 }
722 d = (fat_dentry_t *) b->data;
723 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
724 (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) {
725 memset(d, 0, sizeof(fat_dentry_t));
726 str_cpy((char *) d->name, 8, FAT_NAME_DOT);
727 str_cpy((char *) d->ext, 3, FAT_EXT_PAD);
728 d->attr = FAT_ATTR_SUBDIR;
729 d->firstc = host2uint16_t_le(childp->firstc);
730 /* TODO: initialize also the date/time members. */
731 }
732 d++;
733 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
734 (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) {
735 memset(d, 0, sizeof(fat_dentry_t));
736 str_cpy((char *) d->name, 8, FAT_NAME_DOT_DOT);
737 str_cpy((char *) d->ext, 3, FAT_EXT_PAD);
738 d->attr = FAT_ATTR_SUBDIR;
739 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
740 host2uint16_t_le(FAT_CLST_RES0) :
741 host2uint16_t_le(parentp->firstc);
742 /* TODO: initialize also the date/time members. */
743 }
744 b->dirty = true; /* need to sync block */
745 /*
746 * Ignore the return value as we would have fallen through on error
747 * anyway.
748 */
749 (void) block_put(b);
750 }
751skip_dots:
752
753 childp->idx->pfc = parentp->firstc;
754 childp->idx->pdi = i * DPS(bs) + j;
755 fibril_mutex_unlock(&childp->idx->lock);
756
757 fibril_mutex_lock(&childp->lock);
758 childp->lnkcnt = 1;
759 childp->dirty = true; /* need to sync node */
760 fibril_mutex_unlock(&childp->lock);
761
762 /*
763 * Hash in the index structure into the position hash.
764 */
765 fat_idx_hashin(childp->idx);
766
767 return EOK;
768}
769
770int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
771{
772 fat_node_t *parentp = FAT_NODE(pfn);
773 fat_node_t *childp = FAT_NODE(cfn);
774 fat_bs_t *bs;
775 fat_dentry_t *d;
776 block_t *b;
777 bool has_children;
778 int rc;
779
780 if (!parentp)
781 return EBUSY;
782
783 rc = fat_has_children(&has_children, cfn);
784 if (rc != EOK)
785 return rc;
786 if (has_children)
787 return ENOTEMPTY;
788
789 fibril_mutex_lock(&parentp->lock);
790 fibril_mutex_lock(&childp->lock);
791 assert(childp->lnkcnt == 1);
792 fibril_mutex_lock(&childp->idx->lock);
793 bs = block_bb_get(childp->idx->devmap_handle);
794
795 rc = _fat_block_get(&b, bs, childp->idx->devmap_handle, childp->idx->pfc,
796 NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
797 BLOCK_FLAGS_NONE);
798 if (rc != EOK)
799 goto error;
800 d = (fat_dentry_t *)b->data +
801 (childp->idx->pdi % (BPS(bs) / sizeof(fat_dentry_t)));
802 /* mark the dentry as not-currently-used */
803 d->name[0] = FAT_DENTRY_ERASED;
804 b->dirty = true; /* need to sync block */
805 rc = block_put(b);
806 if (rc != EOK)
807 goto error;
808
809 /* remove the index structure from the position hash */
810 fat_idx_hashout(childp->idx);
811 /* clear position information */
812 childp->idx->pfc = FAT_CLST_RES0;
813 childp->idx->pdi = 0;
814 fibril_mutex_unlock(&childp->idx->lock);
815 childp->lnkcnt = 0;
816 childp->refcnt++; /* keep the node in memory until destroyed */
817 childp->dirty = true;
818 fibril_mutex_unlock(&childp->lock);
819 fibril_mutex_unlock(&parentp->lock);
820
821 return EOK;
822
823error:
824 fibril_mutex_unlock(&parentp->idx->lock);
825 fibril_mutex_unlock(&childp->lock);
826 fibril_mutex_unlock(&childp->idx->lock);
827 return rc;
828}
829
830int fat_has_children(bool *has_children, fs_node_t *fn)
831{
832 fat_bs_t *bs;
833 fat_node_t *nodep = FAT_NODE(fn);
834 unsigned blocks;
835 block_t *b;
836 unsigned i, j;
837 int rc;
838
839 if (nodep->type != FAT_DIRECTORY) {
840 *has_children = false;
841 return EOK;
842 }
843
844 fibril_mutex_lock(&nodep->idx->lock);
845 bs = block_bb_get(nodep->idx->devmap_handle);
846
847 blocks = nodep->size / BPS(bs);
848
849 for (i = 0; i < blocks; i++) {
850 fat_dentry_t *d;
851
852 rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
853 if (rc != EOK) {
854 fibril_mutex_unlock(&nodep->idx->lock);
855 return rc;
856 }
857 for (j = 0; j < DPS(bs); j++) {
858 d = ((fat_dentry_t *)b->data) + j;
859 switch (fat_classify_dentry(d)) {
860 case FAT_DENTRY_SKIP:
861 case FAT_DENTRY_FREE:
862 continue;
863 case FAT_DENTRY_LAST:
864 rc = block_put(b);
865 fibril_mutex_unlock(&nodep->idx->lock);
866 *has_children = false;
867 return rc;
868 default:
869 case FAT_DENTRY_VALID:
870 rc = block_put(b);
871 fibril_mutex_unlock(&nodep->idx->lock);
872 *has_children = true;
873 return rc;
874 }
875 }
876 rc = block_put(b);
877 if (rc != EOK) {
878 fibril_mutex_unlock(&nodep->idx->lock);
879 return rc;
880 }
881 }
882
883 fibril_mutex_unlock(&nodep->idx->lock);
884 *has_children = false;
885 return EOK;
886}
887
888
889fs_index_t fat_index_get(fs_node_t *fn)
890{
891 return FAT_NODE(fn)->idx->index;
892}
893
894aoff64_t fat_size_get(fs_node_t *fn)
895{
896 return FAT_NODE(fn)->size;
897}
898
899unsigned fat_lnkcnt_get(fs_node_t *fn)
900{
901 return FAT_NODE(fn)->lnkcnt;
902}
903
904char fat_plb_get_char(unsigned pos)
905{
906 return fat_reg.plb_ro[pos % PLB_SIZE];
907}
908
909bool fat_is_directory(fs_node_t *fn)
910{
911 return FAT_NODE(fn)->type == FAT_DIRECTORY;
912}
913
914bool fat_is_file(fs_node_t *fn)
915{
916 return FAT_NODE(fn)->type == FAT_FILE;
917}
918
919devmap_handle_t fat_device_get(fs_node_t *node)
920{
921 return 0;
922}
923
924/** libfs operations */
925libfs_ops_t fat_libfs_ops = {
926 .root_get = fat_root_get,
927 .match = fat_match,
928 .node_get = fat_node_get,
929 .node_open = fat_node_open,
930 .node_put = fat_node_put,
931 .create = fat_create_node,
932 .destroy = fat_destroy_node,
933 .link = fat_link,
934 .unlink = fat_unlink,
935 .has_children = fat_has_children,
936 .index_get = fat_index_get,
937 .size_get = fat_size_get,
938 .lnkcnt_get = fat_lnkcnt_get,
939 .plb_get_char = fat_plb_get_char,
940 .is_directory = fat_is_directory,
941 .is_file = fat_is_file,
942 .device_get = fat_device_get
943};
944
945/*
946 * VFS operations.
947 */
948
949void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
950{
951 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
952 enum cache_mode cmode;
953 fat_bs_t *bs;
954
955 /* Accept the mount options */
956 char *opts;
957 int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
958
959 if (rc != EOK) {
960 async_answer_0(rid, rc);
961 return;
962 }
963
964 /* Check for option enabling write through. */
965 if (str_cmp(opts, "wtcache") == 0)
966 cmode = CACHE_MODE_WT;
967 else
968 cmode = CACHE_MODE_WB;
969
970 free(opts);
971
972 /* initialize libblock */
973 rc = block_init(devmap_handle, BS_SIZE);
974 if (rc != EOK) {
975 async_answer_0(rid, rc);
976 return;
977 }
978
979 /* prepare the boot block */
980 rc = block_bb_read(devmap_handle, BS_BLOCK);
981 if (rc != EOK) {
982 block_fini(devmap_handle);
983 async_answer_0(rid, rc);
984 return;
985 }
986
987 /* get the buffer with the boot sector */
988 bs = block_bb_get(devmap_handle);
989
990 if (BPS(bs) != BS_SIZE) {
991 block_fini(devmap_handle);
992 async_answer_0(rid, ENOTSUP);
993 return;
994 }
995
996 /* Initialize the block cache */
997 rc = block_cache_init(devmap_handle, BPS(bs), 0 /* XXX */, cmode);
998 if (rc != EOK) {
999 block_fini(devmap_handle);
1000 async_answer_0(rid, rc);
1001 return;
1002 }
1003
1004 /* Storing FAT type (12, 16, 32) in reserved field (bs->reserved) */
1005 if (CC(bs) < 4085) {
1006 /* Volume is FAT12 */
1007 printf("Found FAT12 filesystem\n");
1008 (bs)->reserved = 12;
1009 } else if (CC(bs) < 65525) {
1010 /* Volume is FAT16 */
1011 printf("Found FAT16 filesystem\n");
1012 (bs)->reserved = 16;
1013 } else {
1014 /* Volume is FAT32 */
1015 printf("FAT32 filesystem is not supported by FAT server. Sorry.\n");
1016 block_fini(devmap_handle);
1017 async_answer_0(rid, ENOTSUP);
1018 return;
1019
1020 }
1021
1022 /* Do some simple sanity checks on the file system. */
1023 rc = fat_sanity_check(bs, devmap_handle);
1024 if (rc != EOK) {
1025 printf("Sanity check failed\n");
1026 (void) block_cache_fini(devmap_handle);
1027 block_fini(devmap_handle);
1028 async_answer_0(rid, rc);
1029 return;
1030 }
1031
1032 rc = fat_idx_init_by_devmap_handle(devmap_handle);
1033 if (rc != EOK) {
1034 (void) block_cache_fini(devmap_handle);
1035 block_fini(devmap_handle);
1036 async_answer_0(rid, rc);
1037 return;
1038 }
1039
1040 /* Initialize the root node. */
1041 fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
1042 if (!rfn) {
1043 (void) block_cache_fini(devmap_handle);
1044 block_fini(devmap_handle);
1045 fat_idx_fini_by_devmap_handle(devmap_handle);
1046 async_answer_0(rid, ENOMEM);
1047 return;
1048 }
1049 fs_node_initialize(rfn);
1050 fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
1051 if (!rootp) {
1052 free(rfn);
1053 (void) block_cache_fini(devmap_handle);
1054 block_fini(devmap_handle);
1055 fat_idx_fini_by_devmap_handle(devmap_handle);
1056 async_answer_0(rid, ENOMEM);
1057 return;
1058 }
1059 fat_node_initialize(rootp);
1060
1061 fat_idx_t *ridxp = fat_idx_get_by_pos(devmap_handle, FAT_CLST_ROOTPAR, 0);
1062 if (!ridxp) {
1063 free(rfn);
1064 free(rootp);
1065 (void) block_cache_fini(devmap_handle);
1066 block_fini(devmap_handle);
1067 fat_idx_fini_by_devmap_handle(devmap_handle);
1068 async_answer_0(rid, ENOMEM);
1069 return;
1070 }
1071 assert(ridxp->index == 0);
1072 /* ridxp->lock held */
1073
1074 rootp->type = FAT_DIRECTORY;
1075 rootp->firstc = FAT_CLST_ROOT;
1076 rootp->refcnt = 1;
1077 rootp->lnkcnt = 0; /* FS root is not linked */
1078 rootp->size = RDE(bs) * sizeof(fat_dentry_t);
1079 rootp->idx = ridxp;
1080 ridxp->nodep = rootp;
1081 rootp->bp = rfn;
1082 rfn->data = rootp;
1083
1084 fibril_mutex_unlock(&ridxp->lock);
1085
1086 async_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
1087}
1088
1089void fat_mount(ipc_callid_t rid, ipc_call_t *request)
1090{
1091 libfs_mount(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
1092}
1093
1094void fat_unmounted(ipc_callid_t rid, ipc_call_t *request)
1095{
1096 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
1097 fs_node_t *fn;
1098 fat_node_t *nodep;
1099 int rc;
1100
1101 rc = fat_root_get(&fn, devmap_handle);
1102 if (rc != EOK) {
1103 async_answer_0(rid, rc);
1104 return;
1105 }
1106 nodep = FAT_NODE(fn);
1107
1108 /*
1109 * We expect exactly two references on the root node. One for the
1110 * fat_root_get() above and one created in fat_mounted().
1111 */
1112 if (nodep->refcnt != 2) {
1113 (void) fat_node_put(fn);
1114 async_answer_0(rid, EBUSY);
1115 return;
1116 }
1117
1118 /*
1119 * Put the root node and force it to the FAT free node list.
1120 */
1121 (void) fat_node_put(fn);
1122 (void) fat_node_put(fn);
1123
1124 /*
1125 * Perform cleanup of the node structures, index structures and
1126 * associated data. Write back this file system's dirty blocks and
1127 * stop using libblock for this instance.
1128 */
1129 (void) fat_node_fini_by_devmap_handle(devmap_handle);
1130 fat_idx_fini_by_devmap_handle(devmap_handle);
1131 (void) block_cache_fini(devmap_handle);
1132 block_fini(devmap_handle);
1133
1134 async_answer_0(rid, EOK);
1135}
1136
1137void fat_unmount(ipc_callid_t rid, ipc_call_t *request)
1138{
1139 libfs_unmount(&fat_libfs_ops, rid, request);
1140}
1141
1142void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
1143{
1144 libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
1145}
1146
1147void fat_read(ipc_callid_t rid, ipc_call_t *request)
1148{
1149 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
1150 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
1151 aoff64_t pos =
1152 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
1153 fs_node_t *fn;
1154 fat_node_t *nodep;
1155 fat_bs_t *bs;
1156 size_t bytes;
1157 block_t *b;
1158 int rc;
1159
1160 rc = fat_node_get(&fn, devmap_handle, index);
1161 if (rc != EOK) {
1162 async_answer_0(rid, rc);
1163 return;
1164 }
1165 if (!fn) {
1166 async_answer_0(rid, ENOENT);
1167 return;
1168 }
1169 nodep = FAT_NODE(fn);
1170
1171 ipc_callid_t callid;
1172 size_t len;
1173 if (!async_data_read_receive(&callid, &len)) {
1174 fat_node_put(fn);
1175 async_answer_0(callid, EINVAL);
1176 async_answer_0(rid, EINVAL);
1177 return;
1178 }
1179
1180 bs = block_bb_get(devmap_handle);
1181
1182 if (nodep->type == FAT_FILE) {
1183 /*
1184 * Our strategy for regular file reads is to read one block at
1185 * most and make use of the possibility to return less data than
1186 * requested. This keeps the code very simple.
1187 */
1188 if (pos >= nodep->size) {
1189 /* reading beyond the EOF */
1190 bytes = 0;
1191 (void) async_data_read_finalize(callid, NULL, 0);
1192 } else {
1193 bytes = min(len, BPS(bs) - pos % BPS(bs));
1194 bytes = min(bytes, nodep->size - pos);
1195 rc = fat_block_get(&b, bs, nodep, pos / BPS(bs),
1196 BLOCK_FLAGS_NONE);
1197 if (rc != EOK) {
1198 fat_node_put(fn);
1199 async_answer_0(callid, rc);
1200 async_answer_0(rid, rc);
1201 return;
1202 }
1203 (void) async_data_read_finalize(callid,
1204 b->data + pos % BPS(bs), bytes);
1205 rc = block_put(b);
1206 if (rc != EOK) {
1207 fat_node_put(fn);
1208 async_answer_0(rid, rc);
1209 return;
1210 }
1211 }
1212 } else {
1213 unsigned bnum;
1214 aoff64_t spos = pos;
1215 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
1216 fat_dentry_t *d;
1217
1218 assert(nodep->type == FAT_DIRECTORY);
1219 assert(nodep->size % BPS(bs) == 0);
1220 assert(BPS(bs) % sizeof(fat_dentry_t) == 0);
1221
1222 /*
1223 * Our strategy for readdir() is to use the position pointer as
1224 * an index into the array of all dentries. On entry, it points
1225 * to the first unread dentry. If we skip any dentries, we bump
1226 * the position pointer accordingly.
1227 */
1228 bnum = (pos * sizeof(fat_dentry_t)) / BPS(bs);
1229 while (bnum < nodep->size / BPS(bs)) {
1230 aoff64_t o;
1231
1232 rc = fat_block_get(&b, bs, nodep, bnum,
1233 BLOCK_FLAGS_NONE);
1234 if (rc != EOK)
1235 goto err;
1236 for (o = pos % (BPS(bs) / sizeof(fat_dentry_t));
1237 o < BPS(bs) / sizeof(fat_dentry_t);
1238 o++, pos++) {
1239 d = ((fat_dentry_t *)b->data) + o;
1240 switch (fat_classify_dentry(d)) {
1241 case FAT_DENTRY_SKIP:
1242 case FAT_DENTRY_FREE:
1243 continue;
1244 case FAT_DENTRY_LAST:
1245 rc = block_put(b);
1246 if (rc != EOK)
1247 goto err;
1248 goto miss;
1249 default:
1250 case FAT_DENTRY_VALID:
1251 fat_dentry_name_get(d, name);
1252 rc = block_put(b);
1253 if (rc != EOK)
1254 goto err;
1255 goto hit;
1256 }
1257 }
1258 rc = block_put(b);
1259 if (rc != EOK)
1260 goto err;
1261 bnum++;
1262 }
1263miss:
1264 rc = fat_node_put(fn);
1265 async_answer_0(callid, rc != EOK ? rc : ENOENT);
1266 async_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
1267 return;
1268
1269err:
1270 (void) fat_node_put(fn);
1271 async_answer_0(callid, rc);
1272 async_answer_0(rid, rc);
1273 return;
1274
1275hit:
1276 (void) async_data_read_finalize(callid, name, str_size(name) + 1);
1277 bytes = (pos - spos) + 1;
1278 }
1279
1280 rc = fat_node_put(fn);
1281 async_answer_1(rid, rc, (sysarg_t)bytes);
1282}
1283
1284void fat_write(ipc_callid_t rid, ipc_call_t *request)
1285{
1286 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
1287 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
1288 aoff64_t pos =
1289 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
1290 fs_node_t *fn;
1291 fat_node_t *nodep;
1292 fat_bs_t *bs;
1293 size_t bytes, size;
1294 block_t *b;
1295 aoff64_t boundary;
1296 int flags = BLOCK_FLAGS_NONE;
1297 int rc;
1298
1299 rc = fat_node_get(&fn, devmap_handle, index);
1300 if (rc != EOK) {
1301 async_answer_0(rid, rc);
1302 return;
1303 }
1304 if (!fn) {
1305 async_answer_0(rid, ENOENT);
1306 return;
1307 }
1308 nodep = FAT_NODE(fn);
1309
1310 ipc_callid_t callid;
1311 size_t len;
1312 if (!async_data_write_receive(&callid, &len)) {
1313 (void) fat_node_put(fn);
1314 async_answer_0(callid, EINVAL);
1315 async_answer_0(rid, EINVAL);
1316 return;
1317 }
1318
1319 bs = block_bb_get(devmap_handle);
1320
1321 /*
1322 * In all scenarios, we will attempt to write out only one block worth
1323 * of data at maximum. There might be some more efficient approaches,
1324 * but this one greatly simplifies fat_write(). Note that we can afford
1325 * to do this because the client must be ready to handle the return
1326 * value signalizing a smaller number of bytes written.
1327 */
1328 bytes = min(len, BPS(bs) - pos % BPS(bs));
1329 if (bytes == BPS(bs))
1330 flags |= BLOCK_FLAGS_NOREAD;
1331
1332 boundary = ROUND_UP(nodep->size, BPC(bs));
1333 if (pos < boundary) {
1334 /*
1335 * This is the easier case - we are either overwriting already
1336 * existing contents or writing behind the EOF, but still within
1337 * the limits of the last cluster. The node size may grow to the
1338 * next block size boundary.
1339 */
1340 rc = fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
1341 if (rc != EOK) {
1342 (void) fat_node_put(fn);
1343 async_answer_0(callid, rc);
1344 async_answer_0(rid, rc);
1345 return;
1346 }
1347 rc = fat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
1348 if (rc != EOK) {
1349 (void) fat_node_put(fn);
1350 async_answer_0(callid, rc);
1351 async_answer_0(rid, rc);
1352 return;
1353 }
1354 (void) async_data_write_finalize(callid,
1355 b->data + pos % BPS(bs), bytes);
1356 b->dirty = true; /* need to sync block */
1357 rc = block_put(b);
1358 if (rc != EOK) {
1359 (void) fat_node_put(fn);
1360 async_answer_0(rid, rc);
1361 return;
1362 }
1363 if (pos + bytes > nodep->size) {
1364 nodep->size = pos + bytes;
1365 nodep->dirty = true; /* need to sync node */
1366 }
1367 size = nodep->size;
1368 rc = fat_node_put(fn);
1369 async_answer_2(rid, rc, bytes, nodep->size);
1370 return;
1371 } else {
1372 /*
1373 * This is the more difficult case. We must allocate new
1374 * clusters for the node and zero them out.
1375 */
1376 unsigned nclsts;
1377 fat_cluster_t mcl, lcl;
1378
1379 nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
1380 /* create an independent chain of nclsts clusters in all FATs */
1381 rc = fat_alloc_clusters(bs, devmap_handle, nclsts, &mcl, &lcl);
1382 if (rc != EOK) {
1383 /* could not allocate a chain of nclsts clusters */
1384 (void) fat_node_put(fn);
1385 async_answer_0(callid, rc);
1386 async_answer_0(rid, rc);
1387 return;
1388 }
1389 /* zero fill any gaps */
1390 rc = fat_fill_gap(bs, nodep, mcl, pos);
1391 if (rc != EOK) {
1392 (void) fat_free_clusters(bs, devmap_handle, mcl);
1393 (void) fat_node_put(fn);
1394 async_answer_0(callid, rc);
1395 async_answer_0(rid, rc);
1396 return;
1397 }
1398 rc = _fat_block_get(&b, bs, devmap_handle, lcl, NULL,
1399 (pos / BPS(bs)) % SPC(bs), flags);
1400 if (rc != EOK) {
1401 (void) fat_free_clusters(bs, devmap_handle, mcl);
1402 (void) fat_node_put(fn);
1403 async_answer_0(callid, rc);
1404 async_answer_0(rid, rc);
1405 return;
1406 }
1407 (void) async_data_write_finalize(callid,
1408 b->data + pos % BPS(bs), bytes);
1409 b->dirty = true; /* need to sync block */
1410 rc = block_put(b);
1411 if (rc != EOK) {
1412 (void) fat_free_clusters(bs, devmap_handle, mcl);
1413 (void) fat_node_put(fn);
1414 async_answer_0(rid, rc);
1415 return;
1416 }
1417 /*
1418 * Append the cluster chain starting in mcl to the end of the
1419 * node's cluster chain.
1420 */
1421 rc = fat_append_clusters(bs, nodep, mcl, lcl);
1422 if (rc != EOK) {
1423 (void) fat_free_clusters(bs, devmap_handle, mcl);
1424 (void) fat_node_put(fn);
1425 async_answer_0(rid, rc);
1426 return;
1427 }
1428 nodep->size = size = pos + bytes;
1429 nodep->dirty = true; /* need to sync node */
1430 rc = fat_node_put(fn);
1431 async_answer_2(rid, rc, bytes, size);
1432 return;
1433 }
1434}
1435
1436void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
1437{
1438 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
1439 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
1440 aoff64_t size =
1441 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
1442 fs_node_t *fn;
1443 fat_node_t *nodep;
1444 fat_bs_t *bs;
1445 int rc;
1446
1447 rc = fat_node_get(&fn, devmap_handle, index);
1448 if (rc != EOK) {
1449 async_answer_0(rid, rc);
1450 return;
1451 }
1452 if (!fn) {
1453 async_answer_0(rid, ENOENT);
1454 return;
1455 }
1456 nodep = FAT_NODE(fn);
1457
1458 bs = block_bb_get(devmap_handle);
1459
1460 if (nodep->size == size) {
1461 rc = EOK;
1462 } else if (nodep->size < size) {
1463 /*
1464 * The standard says we have the freedom to grow the node.
1465 * For now, we simply return an error.
1466 */
1467 rc = EINVAL;
1468 } else if (ROUND_UP(nodep->size, BPC(bs)) == ROUND_UP(size, BPC(bs))) {
1469 /*
1470 * The node will be shrunk, but no clusters will be deallocated.
1471 */
1472 nodep->size = size;
1473 nodep->dirty = true; /* need to sync node */
1474 rc = EOK;
1475 } else {
1476 /*
1477 * The node will be shrunk, clusters will be deallocated.
1478 */
1479 if (size == 0) {
1480 rc = fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
1481 if (rc != EOK)
1482 goto out;
1483 } else {
1484 fat_cluster_t lastc;
1485 rc = fat_cluster_walk(bs, devmap_handle, nodep->firstc,
1486 &lastc, NULL, (size - 1) / BPC(bs));
1487 if (rc != EOK)
1488 goto out;
1489 rc = fat_chop_clusters(bs, nodep, lastc);
1490 if (rc != EOK)
1491 goto out;
1492 }
1493 nodep->size = size;
1494 nodep->dirty = true; /* need to sync node */
1495 rc = EOK;
1496 }
1497out:
1498 fat_node_put(fn);
1499 async_answer_0(rid, rc);
1500 return;
1501}
1502
1503void fat_close(ipc_callid_t rid, ipc_call_t *request)
1504{
1505 async_answer_0(rid, EOK);
1506}
1507
1508void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
1509{
1510 devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
1511 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
1512 fs_node_t *fn;
1513 fat_node_t *nodep;
1514 int rc;
1515
1516 rc = fat_node_get(&fn, devmap_handle, index);
1517 if (rc != EOK) {
1518 async_answer_0(rid, rc);
1519 return;
1520 }
1521 if (!fn) {
1522 async_answer_0(rid, ENOENT);
1523 return;
1524 }
1525
1526 nodep = FAT_NODE(fn);
1527 /*
1528 * We should have exactly two references. One for the above
1529 * call to fat_node_get() and one from fat_unlink().
1530 */
1531 assert(nodep->refcnt == 2);
1532
1533 rc = fat_destroy_node(fn);
1534 async_answer_0(rid, rc);
1535}
1536
1537void fat_open_node(ipc_callid_t rid, ipc_call_t *request)
1538{
1539 libfs_open_node(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
1540}
1541
1542void fat_stat(ipc_callid_t rid, ipc_call_t *request)
1543{
1544 libfs_stat(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
1545}
1546
1547void fat_sync(ipc_callid_t rid, ipc_call_t *request)
1548{
1549 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
1550 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
1551
1552 fs_node_t *fn;
1553 int rc = fat_node_get(&fn, devmap_handle, index);
1554 if (rc != EOK) {
1555 async_answer_0(rid, rc);
1556 return;
1557 }
1558 if (!fn) {
1559 async_answer_0(rid, ENOENT);
1560 return;
1561 }
1562
1563 fat_node_t *nodep = FAT_NODE(fn);
1564
1565 nodep->dirty = true;
1566 rc = fat_node_sync(nodep);
1567
1568 fat_node_put(fn);
1569 async_answer_0(rid, rc);
1570}
1571
1572/**
1573 * @}
1574 */
Note: See TracBrowser for help on using the repository browser.