source: mainline/uspace/srv/fs/exfat/exfat_ops.c@ 5f0e16e4

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

exFAT: implement bitmap_alloc_clusters

  • Property mode set to 100644
File size: 34.5 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * Copyright (c) 2011 Oleg Romanenko
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup fs
31 * @{
32 */
33
34/**
35 * @file exfat_ops.c
36 * @brief Implementation of VFS operations for the exFAT file system server.
37 */
38
39#include "exfat.h"
40#include "exfat_fat.h"
41#include "exfat_dentry.h"
42#include "exfat_directory.h"
43#include "../../vfs/vfs.h"
44#include <libfs.h>
45#include <libblock.h>
46#include <ipc/services.h>
47#include <ipc/devmap.h>
48#include <macros.h>
49#include <async.h>
50#include <errno.h>
51#include <str.h>
52#include <byteorder.h>
53#include <adt/hash_table.h>
54#include <adt/list.h>
55#include <assert.h>
56#include <fibril_synch.h>
57#include <sys/mman.h>
58#include <align.h>
59#include <malloc.h>
60#include <stdio.h>
61
62#define EXFAT_NODE(node) ((node) ? (exfat_node_t *) (node)->data : NULL)
63#define FS_NODE(node) ((node) ? (node)->bp : NULL)
64#define DPS(bs) (BPS((bs)) / sizeof(exfat_dentry_t))
65
66/** Mutex protecting the list of cached free FAT nodes. */
67static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
68
69/** List of cached free FAT nodes. */
70static LIST_INITIALIZE(ffn_list);
71
72/*
73 * Forward declarations of FAT libfs operations.
74 */
75/*
76static int exfat_bitmap_get(fs_node_t **, devmap_handle_t);
77static int exfat_uctable_get(fs_node_t **, devmap_handle_t);
78*/
79static int exfat_root_get(fs_node_t **, devmap_handle_t);
80static int exfat_match(fs_node_t **, fs_node_t *, const char *);
81static int exfat_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
82static int exfat_node_open(fs_node_t *);
83static int exfat_node_put(fs_node_t *);
84static int exfat_create_node(fs_node_t **, devmap_handle_t, int);
85static int exfat_destroy_node(fs_node_t *);
86static int exfat_link(fs_node_t *, fs_node_t *, const char *);
87static int exfat_unlink(fs_node_t *, fs_node_t *, const char *);
88static int exfat_has_children(bool *, fs_node_t *);
89static fs_index_t exfat_index_get(fs_node_t *);
90static aoff64_t exfat_size_get(fs_node_t *);
91static unsigned exfat_lnkcnt_get(fs_node_t *);
92static bool exfat_is_directory(fs_node_t *);
93static bool exfat_is_file(fs_node_t *node);
94static devmap_handle_t exfat_device_get(fs_node_t *node);
95
96/*
97 * Helper functions.
98 */
99static void exfat_node_initialize(exfat_node_t *node)
100{
101 fibril_mutex_initialize(&node->lock);
102 node->bp = NULL;
103 node->idx = NULL;
104 node->type = EXFAT_UNKNOW;
105 link_initialize(&node->ffn_link);
106 node->size = 0;
107 node->lnkcnt = 0;
108 node->refcnt = 0;
109 node->dirty = false;
110 node->fragmented = false;
111 node->lastc_cached_valid = false;
112 node->lastc_cached_value = 0;
113 node->currc_cached_valid = false;
114 node->currc_cached_bn = 0;
115 node->currc_cached_value = 0;
116}
117
118static int exfat_node_sync(exfat_node_t *node)
119{
120 /* TODO */
121 return EOK;
122}
123
124static int exfat_node_fini_by_devmap_handle(devmap_handle_t devmap_handle)
125{
126 exfat_node_t *nodep;
127 int rc;
128
129 /*
130 * We are called from fat_unmounted() and assume that there are already
131 * no nodes belonging to this instance with non-zero refcount. Therefore
132 * it is sufficient to clean up only the FAT free node list.
133 */
134
135restart:
136 fibril_mutex_lock(&ffn_mutex);
137 list_foreach(ffn_list, lnk) {
138 nodep = list_get_instance(lnk, exfat_node_t, ffn_link);
139 if (!fibril_mutex_trylock(&nodep->lock)) {
140 fibril_mutex_unlock(&ffn_mutex);
141 goto restart;
142 }
143 if (!fibril_mutex_trylock(&nodep->idx->lock)) {
144 fibril_mutex_unlock(&nodep->lock);
145 fibril_mutex_unlock(&ffn_mutex);
146 goto restart;
147 }
148 if (nodep->idx->devmap_handle != devmap_handle) {
149 fibril_mutex_unlock(&nodep->idx->lock);
150 fibril_mutex_unlock(&nodep->lock);
151 continue;
152 }
153
154 list_remove(&nodep->ffn_link);
155 fibril_mutex_unlock(&ffn_mutex);
156
157 /*
158 * We can unlock the node and its index structure because we are
159 * the last player on this playground and VFS is preventing new
160 * players from entering.
161 */
162 fibril_mutex_unlock(&nodep->idx->lock);
163 fibril_mutex_unlock(&nodep->lock);
164
165 if (nodep->dirty) {
166 rc = exfat_node_sync(nodep);
167 if (rc != EOK)
168 return rc;
169 }
170 nodep->idx->nodep = NULL;
171 free(nodep->bp);
172 free(nodep);
173
174 /* Need to restart because we changed the ffn_list. */
175 goto restart;
176 }
177 fibril_mutex_unlock(&ffn_mutex);
178
179 return EOK;
180}
181
182static int exfat_node_get_new(exfat_node_t **nodepp)
183{
184 fs_node_t *fn;
185 exfat_node_t *nodep;
186 int rc;
187
188 fibril_mutex_lock(&ffn_mutex);
189 if (!list_empty(&ffn_list)) {
190 /* Try to use a cached free node structure. */
191 exfat_idx_t *idxp_tmp;
192 nodep = list_get_instance(list_first(&ffn_list), exfat_node_t,
193 ffn_link);
194 if (!fibril_mutex_trylock(&nodep->lock))
195 goto skip_cache;
196 idxp_tmp = nodep->idx;
197 if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
198 fibril_mutex_unlock(&nodep->lock);
199 goto skip_cache;
200 }
201 list_remove(&nodep->ffn_link);
202 fibril_mutex_unlock(&ffn_mutex);
203 if (nodep->dirty) {
204 rc = exfat_node_sync(nodep);
205 if (rc != EOK) {
206 idxp_tmp->nodep = NULL;
207 fibril_mutex_unlock(&nodep->lock);
208 fibril_mutex_unlock(&idxp_tmp->lock);
209 free(nodep->bp);
210 free(nodep);
211 return rc;
212 }
213 }
214 idxp_tmp->nodep = NULL;
215 fibril_mutex_unlock(&nodep->lock);
216 fibril_mutex_unlock(&idxp_tmp->lock);
217 fn = FS_NODE(nodep);
218 } else {
219skip_cache:
220 /* Try to allocate a new node structure. */
221 fibril_mutex_unlock(&ffn_mutex);
222 fn = (fs_node_t *)malloc(sizeof(fs_node_t));
223 if (!fn)
224 return ENOMEM;
225 nodep = (exfat_node_t *)malloc(sizeof(exfat_node_t));
226 if (!nodep) {
227 free(fn);
228 return ENOMEM;
229 }
230 }
231 exfat_node_initialize(nodep);
232 fs_node_initialize(fn);
233 fn->data = nodep;
234 nodep->bp = fn;
235
236 *nodepp = nodep;
237 return EOK;
238}
239
240static int exfat_node_get_new_by_pos(exfat_node_t **nodepp,
241 devmap_handle_t devmap_handle, exfat_cluster_t pfc, unsigned pdi)
242{
243 exfat_idx_t *idxp = exfat_idx_get_by_pos(devmap_handle, pfc, pdi);
244 if (!idxp)
245 return ENOMEM;
246 if (exfat_node_get_new(nodepp) != EOK)
247 return ENOMEM;
248 (*nodepp)->idx = idxp;
249 idxp->nodep = *nodepp;
250 return EOK;
251}
252
253
254/** Internal version of exfat_node_get().
255 *
256 * @param idxp Locked index structure.
257 */
258static int exfat_node_get_core(exfat_node_t **nodepp, exfat_idx_t *idxp)
259{
260 block_t *b=NULL;
261 exfat_bs_t *bs;
262 exfat_dentry_t *d;
263 exfat_node_t *nodep = NULL;
264 int rc;
265
266 if (idxp->nodep) {
267 /*
268 * We are lucky.
269 * The node is already instantiated in memory.
270 */
271 fibril_mutex_lock(&idxp->nodep->lock);
272 if (!idxp->nodep->refcnt++) {
273 fibril_mutex_lock(&ffn_mutex);
274 list_remove(&idxp->nodep->ffn_link);
275 fibril_mutex_unlock(&ffn_mutex);
276 }
277 fibril_mutex_unlock(&idxp->nodep->lock);
278 *nodepp = idxp->nodep;
279 return EOK;
280 }
281
282 /*
283 * We must instantiate the node from the file system.
284 */
285
286 assert(idxp->pfc);
287
288 rc = exfat_node_get_new(&nodep);
289 if (rc != EOK)
290 return rc;
291
292 bs = block_bb_get(idxp->devmap_handle);
293
294 rc = exfat_block_get_by_clst(&b, bs, idxp->devmap_handle,
295 idxp->parent_fragmented, idxp->pfc, NULL,
296 (idxp->pdi * sizeof(exfat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
297 if (rc != EOK) {
298 (void) exfat_node_put(FS_NODE(nodep));
299 return rc;
300 }
301
302 d = ((exfat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
303 switch (exfat_classify_dentry(d)) {
304 case EXFAT_DENTRY_FILE:
305 nodep->type = (d->file.attr & EXFAT_ATTR_SUBDIR)?
306 EXFAT_DIRECTORY : EXFAT_FILE;
307 rc = block_put(b);
308 if (rc != EOK) {
309 (void) exfat_node_put(FS_NODE(nodep));
310 return rc;
311 }
312 rc = exfat_block_get_by_clst(&b, bs, idxp->devmap_handle,
313 idxp->parent_fragmented, idxp->pfc, NULL,
314 ((idxp->pdi+1) * sizeof(exfat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
315 if (rc != EOK) {
316 (void) exfat_node_put(FS_NODE(nodep));
317 return rc;
318 }
319 d = ((exfat_dentry_t *)b->data) + ((idxp->pdi+1) % DPS(bs));
320
321 nodep->firstc = d->stream.firstc;
322 nodep->size = d->stream.data_size;
323 nodep->fragmented = (d->stream.flags & 0x02) == 0;
324 break;
325 case EXFAT_DENTRY_BITMAP:
326 nodep->type = EXFAT_BITMAP;
327 nodep->firstc = d->bitmap.firstc;
328 nodep->size = d->bitmap.size;
329 nodep->fragmented = true;
330 break;
331 case EXFAT_DENTRY_UCTABLE:
332 nodep->type = EXFAT_UCTABLE;
333 nodep->firstc = d->uctable.firstc;
334 nodep->size = d->uctable.size;
335 nodep->fragmented = true;
336 break;
337 default:
338 case EXFAT_DENTRY_SKIP:
339 case EXFAT_DENTRY_LAST:
340 case EXFAT_DENTRY_FREE:
341 case EXFAT_DENTRY_VOLLABEL:
342 case EXFAT_DENTRY_GUID:
343 case EXFAT_DENTRY_STREAM:
344 case EXFAT_DENTRY_NAME:
345 (void) block_put(b);
346 (void) exfat_node_put(FS_NODE(nodep));
347 return ENOENT;
348 }
349
350 nodep->lnkcnt = 1;
351 nodep->refcnt = 1;
352
353 rc = block_put(b);
354 if (rc != EOK) {
355 (void) exfat_node_put(FS_NODE(nodep));
356 return rc;
357 }
358
359 /* Link the idx structure with the node structure. */
360 nodep->idx = idxp;
361 idxp->nodep = nodep;
362
363 *nodepp = nodep;
364 return EOK;
365}
366
367static int exfat_node_expand(devmap_handle_t devmap_handle, exfat_node_t *nodep, exfat_cluster_t clusters)
368{
369 exfat_bs_t *bs;
370 int rc;
371 bs = block_bb_get(devmap_handle);
372
373 if (nodep->fragmented) {
374 /* TODO */
375 rc = bitmap_append_clusters(bs, nodep, clusters);
376 if (rc != ENOSPC)
377 return rc;
378 if (rc == ENOSPC) {
379 nodep->fragmented = true;
380 nodep->dirty = true; /* need to sync node */
381 rc = bitmap_replicate_clusters(bs, nodep);
382 if (rc != EOK)
383 return rc;
384 }
385 }
386
387 /* If we cant linear expand the node, we should use FAT instead */
388 exfat_cluster_t mcl, lcl;
389
390 /* create an independent chain of nclsts clusters in all FATs */
391 rc = exfat_alloc_clusters(bs, devmap_handle, clusters, &mcl, &lcl);
392 if (rc != EOK)
393 return rc;
394 /*
395 * Append the cluster chain starting in mcl to the end of the
396 * node's cluster chain.
397 */
398 rc = exfat_append_clusters(bs, nodep, mcl, lcl);
399 if (rc != EOK) {
400 (void) exfat_free_clusters(bs, devmap_handle, mcl);
401 return rc;
402 }
403
404 return EOK;
405}
406
407static int exfat_node_shrink(devmap_handle_t devmap_handle, exfat_node_t *nodep, aoff64_t size)
408{
409 exfat_bs_t *bs;
410 int rc;
411 bs = block_bb_get(devmap_handle);
412
413 if (nodep->fragmented) {
414 /* TODO */
415 exfat_cluster_t clsts, prev_clsts, new_clsts;
416 prev_clsts = ROUND_UP(nodep->size, BPC(bs)) / BPC(bs);
417 new_clsts = ROUND_UP(size, BPC(bs)) / BPC(bs);
418
419 assert(new_clsts < prev_clsts);
420
421 clsts = prev_clsts - new_clsts;
422
423 rc = bitmap_free_clusters(bs, nodep, clsts);
424 if (rc != EOK)
425 return rc;
426 } else {
427 /*
428 * The node will be shrunk, clusters will be deallocated.
429 */
430 if (size == 0) {
431 rc = exfat_chop_clusters(bs, nodep, 0);
432 if (rc != EOK)
433 return rc;
434 } else {
435 exfat_cluster_t lastc;
436 rc = exfat_cluster_walk(bs, devmap_handle, nodep->firstc,
437 &lastc, NULL, (size - 1) / BPC(bs));
438 if (rc != EOK)
439 return rc;
440 rc = exfat_chop_clusters(bs, nodep, lastc);
441 if (rc != EOK)
442 return rc;
443 }
444 }
445
446 nodep->size = size;
447 nodep->dirty = true; /* need to sync node */
448 return EOK;
449}
450
451
452/*
453 * EXFAT libfs operations.
454 */
455
456int exfat_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
457{
458 return exfat_node_get(rfn, devmap_handle, EXFAT_ROOT_IDX);
459}
460
461/*
462int exfat_bitmap_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
463{
464 return exfat_node_get(rfn, devmap_handle, EXFAT_BITMAP_IDX);
465}
466*/
467/*
468int exfat_uctable_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
469{
470 return exfat_node_get(rfn, devmap_handle, EXFAT_UCTABLE_IDX);
471}
472*/
473
474int exfat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
475{
476 exfat_node_t *parentp = EXFAT_NODE(pfn);
477 char name[EXFAT_FILENAME_LEN+1];
478 exfat_file_dentry_t df;
479 exfat_stream_dentry_t ds;
480 devmap_handle_t devmap_handle;
481 int rc;
482
483 fibril_mutex_lock(&parentp->idx->lock);
484 devmap_handle = parentp->idx->devmap_handle;
485 fibril_mutex_unlock(&parentp->idx->lock);
486
487 exfat_directory_t di;
488 rc = exfat_directory_open(parentp, &di);
489 if (rc != EOK)
490 return rc;
491
492 while (exfat_directory_read_file(&di, name, EXFAT_FILENAME_LEN,
493 &df, &ds) == EOK) {
494 if (stricmp(name, component) == 0) {
495 /* hit */
496 exfat_node_t *nodep;
497 aoff64_t o = di.pos % (BPS(di.bs) / sizeof(exfat_dentry_t));
498 exfat_idx_t *idx = exfat_idx_get_by_pos(devmap_handle,
499 parentp->firstc, di.bnum * DPS(di.bs) + o);
500 if (!idx) {
501 /*
502 * Can happen if memory is low or if we
503 * run out of 32-bit indices.
504 */
505 rc = exfat_directory_close(&di);
506 return (rc == EOK) ? ENOMEM : rc;
507 }
508 rc = exfat_node_get_core(&nodep, idx);
509 fibril_mutex_unlock(&idx->lock);
510 if (rc != EOK) {
511 (void) exfat_directory_close(&di);
512 return rc;
513 }
514 *rfn = FS_NODE(nodep);
515 rc = exfat_directory_close(&di);
516 if (rc != EOK)
517 (void) exfat_node_put(*rfn);
518 return rc;
519 } else {
520 rc = exfat_directory_next(&di);
521 if (rc != EOK)
522 break;
523 }
524 }
525 (void) exfat_directory_close(&di);
526 *rfn = NULL;
527 return EOK;
528}
529
530/** Instantiate a exFAT in-core node. */
531int exfat_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
532{
533 exfat_node_t *nodep;
534 exfat_idx_t *idxp;
535 int rc;
536
537 idxp = exfat_idx_get_by_index(devmap_handle, index);
538 if (!idxp) {
539 *rfn = NULL;
540 return EOK;
541 }
542 /* idxp->lock held */
543 rc = exfat_node_get_core(&nodep, idxp);
544 fibril_mutex_unlock(&idxp->lock);
545 if (rc == EOK)
546 *rfn = FS_NODE(nodep);
547 return rc;
548}
549
550int exfat_node_open(fs_node_t *fn)
551{
552 /*
553 * Opening a file is stateless, nothing
554 * to be done here.
555 */
556 return EOK;
557}
558
559int exfat_node_put(fs_node_t *fn)
560{
561 exfat_node_t *nodep = EXFAT_NODE(fn);
562 bool destroy = false;
563
564 fibril_mutex_lock(&nodep->lock);
565 if (!--nodep->refcnt) {
566 if (nodep->idx) {
567 fibril_mutex_lock(&ffn_mutex);
568 list_append(&nodep->ffn_link, &ffn_list);
569 fibril_mutex_unlock(&ffn_mutex);
570 } else {
571 /*
572 * The node does not have any index structure associated
573 * with itself. This can only mean that we are releasing
574 * the node after a failed attempt to allocate the index
575 * structure for it.
576 */
577 destroy = true;
578 }
579 }
580 fibril_mutex_unlock(&nodep->lock);
581 if (destroy) {
582 free(nodep->bp);
583 free(nodep);
584 }
585 return EOK;
586}
587
588int exfat_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
589{
590 exfat_idx_t *idxp;
591 exfat_node_t *nodep;
592 int rc;
593
594 rc = exfat_node_get_new(&nodep);
595 if (rc != EOK)
596 return rc;
597
598 rc = exfat_idx_get_new(&idxp, devmap_handle);
599 if (rc != EOK) {
600 (void) exfat_node_put(FS_NODE(nodep));
601 return rc;
602 }
603
604 if (flags & L_DIRECTORY)
605 nodep->type = EXFAT_DIRECTORY;
606 else
607 nodep->type = EXFAT_FILE;
608
609 nodep->firstc = 0;
610 nodep->size = 0;
611 nodep->fragmented = false;
612 nodep->lnkcnt = 0; /* not linked anywhere */
613 nodep->refcnt = 1;
614 nodep->dirty = true;
615
616 nodep->idx = idxp;
617 idxp->nodep = nodep;
618
619 fibril_mutex_unlock(&idxp->lock);
620 *rfn = FS_NODE(nodep);
621 return EOK;
622}
623
624int exfat_destroy_node(fs_node_t *fn)
625{
626 exfat_node_t *nodep = EXFAT_NODE(fn);
627 exfat_bs_t *bs;
628 bool has_children;
629 int rc;
630
631 /*
632 * The node is not reachable from the file system. This means that the
633 * link count should be zero and that the index structure cannot be
634 * found in the position hash. Obviously, we don't need to lock the node
635 * nor its index structure.
636 */
637 assert(nodep->lnkcnt == 0);
638
639 /*
640 * The node may not have any children.
641 */
642 rc = exfat_has_children(&has_children, fn);
643 if (rc != EOK)
644 return rc;
645 assert(!has_children);
646
647 bs = block_bb_get(nodep->idx->devmap_handle);
648 if (nodep->firstc != 0) {
649 assert(nodep->size);
650 /* Free all clusters allocated to the node. */
651 if (nodep->fragmented)
652 rc = exfat_free_clusters(bs, nodep->idx->devmap_handle,
653 nodep->firstc);
654 else
655 rc = bitmap_free_clusters(bs, nodep,
656 ROUND_UP(nodep->size, BPC(bs)) / BPC(bs));
657 }
658
659 exfat_idx_destroy(nodep->idx);
660 free(nodep->bp);
661 free(nodep);
662 return rc;
663}
664
665int exfat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
666{
667 exfat_node_t *parentp = EXFAT_NODE(pfn);
668 exfat_node_t *childp = EXFAT_NODE(cfn);
669 exfat_directory_t di;
670 int rc;
671
672 fibril_mutex_lock(&childp->lock);
673 if (childp->lnkcnt == 1) {
674 /*
675 * We don't support multiple hard links.
676 */
677 fibril_mutex_unlock(&childp->lock);
678 return EMLINK;
679 }
680 assert(childp->lnkcnt == 0);
681 fibril_mutex_unlock(&childp->lock);
682
683 if (!exfat_valid_name(name))
684 return ENOTSUP;
685
686 fibril_mutex_lock(&parentp->idx->lock);
687 rc = exfat_directory_open(parentp, &di);
688 if (rc != EOK)
689 return rc;
690
691 /*
692 * At this point we only establish the link between the parent and the
693 * child. The dentry, except of the name and the extension, will remain
694 * uninitialized until the corresponding node is synced. Thus the valid
695 * dentry data is kept in the child node structure.
696 */
697
698 /* TODO */
699 rc = exfat_directory_write_file(&di, name);
700 if (rc!=EOK)
701 return rc;
702 rc = exfat_directory_close(&di);
703 if (rc!=EOK)
704 return rc;
705
706 fibril_mutex_unlock(&parentp->idx->lock);
707 if (rc != EOK)
708 return rc;
709
710 fibril_mutex_lock(&childp->idx->lock);
711
712
713 childp->idx->pfc = parentp->firstc;
714 childp->idx->parent_fragmented = parentp->fragmented;
715 childp->idx->pdi = di.pos; /* di.pos holds absolute position of SFN entry */
716 fibril_mutex_unlock(&childp->idx->lock);
717
718 fibril_mutex_lock(&childp->lock);
719 childp->lnkcnt = 1;
720 childp->dirty = true; /* need to sync node */
721 fibril_mutex_unlock(&childp->lock);
722
723 /*
724 * Hash in the index structure into the position hash.
725 */
726 exfat_idx_hashin(childp->idx);
727
728 return EOK;
729
730}
731
732int exfat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
733{
734 exfat_node_t *parentp = EXFAT_NODE(pfn);
735 exfat_node_t *childp = EXFAT_NODE(cfn);
736 bool has_children;
737 int rc;
738
739 if (!parentp)
740 return EBUSY;
741
742 rc = exfat_has_children(&has_children, cfn);
743 if (rc != EOK)
744 return rc;
745 if (has_children)
746 return ENOTEMPTY;
747
748 fibril_mutex_lock(&parentp->lock);
749 fibril_mutex_lock(&childp->lock);
750 assert(childp->lnkcnt == 1);
751 fibril_mutex_lock(&childp->idx->lock);
752
753 exfat_directory_t di;
754 rc = exfat_directory_open(parentp,&di);
755 if (rc != EOK)
756 goto error;
757 rc = exfat_directory_erase_file(&di, childp->idx->pdi);
758 if (rc != EOK)
759 goto error;
760 rc = exfat_directory_close(&di);
761 if (rc != EOK)
762 goto error;
763
764 /* remove the index structure from the position hash */
765 exfat_idx_hashout(childp->idx);
766 /* clear position information */
767 childp->idx->pfc = 0;
768 childp->idx->pdi = 0;
769 fibril_mutex_unlock(&childp->idx->lock);
770 childp->lnkcnt = 0;
771 childp->refcnt++; /* keep the node in memory until destroyed */
772 childp->dirty = true;
773 fibril_mutex_unlock(&childp->lock);
774 fibril_mutex_unlock(&parentp->lock);
775
776 return EOK;
777
778error:
779 (void) exfat_directory_close(&di);
780 fibril_mutex_unlock(&childp->idx->lock);
781 fibril_mutex_unlock(&childp->lock);
782 fibril_mutex_unlock(&parentp->lock);
783 return rc;
784
785}
786
787int exfat_has_children(bool *has_children, fs_node_t *fn)
788{
789 exfat_directory_t di;
790 exfat_dentry_t *d;
791 exfat_node_t *nodep = EXFAT_NODE(fn);
792 int rc;
793
794 *has_children = false;
795
796 if (nodep->type != EXFAT_DIRECTORY)
797 return EOK;
798
799 fibril_mutex_lock(&nodep->idx->lock);
800
801 rc = exfat_directory_open(nodep, &di);
802 if (rc != EOK) {
803 fibril_mutex_unlock(&nodep->idx->lock);
804 return rc;
805 }
806
807 do {
808 rc = exfat_directory_get(&di, &d);
809 if (rc != EOK) {
810 (void) exfat_directory_close(&di);
811 fibril_mutex_unlock(&nodep->idx->lock);
812 return rc;
813 }
814 switch (exfat_classify_dentry(d)) {
815 case EXFAT_DENTRY_SKIP:
816 case EXFAT_DENTRY_FREE:
817 continue;
818 case EXFAT_DENTRY_LAST:
819 *has_children = false;
820 goto exit;
821 default:
822 *has_children = true;
823 goto exit;
824 }
825 } while (exfat_directory_next(&di) == EOK);
826
827exit:
828 rc = exfat_directory_close(&di);
829 fibril_mutex_unlock(&nodep->idx->lock);
830 return rc;
831}
832
833
834fs_index_t exfat_index_get(fs_node_t *fn)
835{
836 return EXFAT_NODE(fn)->idx->index;
837}
838
839aoff64_t exfat_size_get(fs_node_t *fn)
840{
841 return EXFAT_NODE(fn)->size;
842}
843
844unsigned exfat_lnkcnt_get(fs_node_t *fn)
845{
846 return EXFAT_NODE(fn)->lnkcnt;
847}
848
849bool exfat_is_directory(fs_node_t *fn)
850{
851 return EXFAT_NODE(fn)->type == EXFAT_DIRECTORY;
852}
853
854bool exfat_is_file(fs_node_t *fn)
855{
856 return EXFAT_NODE(fn)->type == EXFAT_FILE;
857}
858
859devmap_handle_t exfat_device_get(fs_node_t *node)
860{
861 return 0;
862}
863
864
865/** libfs operations */
866libfs_ops_t exfat_libfs_ops = {
867 .root_get = exfat_root_get,
868 .match = exfat_match,
869 .node_get = exfat_node_get,
870 .node_open = exfat_node_open,
871 .node_put = exfat_node_put,
872 .create = exfat_create_node,
873 .destroy = exfat_destroy_node,
874 .link = exfat_link,
875 .unlink = exfat_unlink,
876 .has_children = exfat_has_children,
877 .index_get = exfat_index_get,
878 .size_get = exfat_size_get,
879 .lnkcnt_get = exfat_lnkcnt_get,
880 .is_directory = exfat_is_directory,
881 .is_file = exfat_is_file,
882 .device_get = exfat_device_get
883};
884
885
886/*
887 * VFS_OUT operations.
888 */
889
890/* Print debug info */
891static void exfat_fsinfo(exfat_bs_t *bs, devmap_handle_t devmap_handle)
892{
893 printf("exFAT file system mounted\n");
894 printf("Version: %d.%d\n", bs->version.major, bs->version.minor);
895 printf("Volume serial: %d\n", uint32_t_le2host(bs->volume_serial));
896 printf("Volume first sector: %lld\n", VOL_FS(bs));
897 printf("Volume sectors: %lld\n", VOL_CNT(bs));
898 printf("FAT first sector: %d\n", FAT_FS(bs));
899 printf("FAT sectors: %d\n", FAT_CNT(bs));
900 printf("Data first sector: %d\n", DATA_FS(bs));
901 printf("Data sectors: %d\n", DATA_CNT(bs));
902 printf("Root dir first cluster: %d\n", ROOT_FC(bs));
903 printf("Bytes per sector: %d\n", BPS(bs));
904 printf("Sectors per cluster: %d\n", SPC(bs));
905 printf("KBytes per cluster: %d\n", SPC(bs)*BPS(bs)/1024);
906
907 int i, rc;
908 exfat_cluster_t clst;
909 for (i=0; i<6; i++) {
910 rc = exfat_get_cluster(bs, devmap_handle, i, &clst);
911 if (rc != EOK)
912 return;
913 printf("Clst %d: %x\n", i, clst);
914 }
915}
916
917static int
918exfat_mounted(devmap_handle_t devmap_handle, const char *opts, fs_index_t *index,
919 aoff64_t *size, unsigned *linkcnt)
920{
921 int rc;
922 exfat_node_t *rootp=NULL, *bitmapp=NULL, *uctablep=NULL;
923 enum cache_mode cmode;
924 exfat_bs_t *bs;
925
926 /* Check for option enabling write through. */
927 if (str_cmp(opts, "wtcache") == 0)
928 cmode = CACHE_MODE_WT;
929 else
930 cmode = CACHE_MODE_WB;
931
932 /* initialize libblock */
933 rc = block_init(EXCHANGE_SERIALIZE, devmap_handle, BS_SIZE);
934 if (rc != EOK)
935 return rc;
936
937 /* prepare the boot block */
938 rc = block_bb_read(devmap_handle, BS_BLOCK);
939 if (rc != EOK) {
940 block_fini(devmap_handle);
941 return rc;
942 }
943
944 /* get the buffer with the boot sector */
945 bs = block_bb_get(devmap_handle);
946
947 /* Initialize the block cache */
948 rc = block_cache_init(devmap_handle, BPS(bs), 0 /* XXX */, cmode);
949 if (rc != EOK) {
950 block_fini(devmap_handle);
951 return rc;
952 }
953
954 /* Do some simple sanity checks on the file system. */
955 rc = exfat_sanity_check(bs, devmap_handle);
956 if (rc != EOK) {
957 (void) block_cache_fini(devmap_handle);
958 block_fini(devmap_handle);
959 return rc;
960 }
961
962 rc = exfat_idx_init_by_devmap_handle(devmap_handle);
963 if (rc != EOK) {
964 (void) block_cache_fini(devmap_handle);
965 block_fini(devmap_handle);
966 return rc;
967 }
968
969 /* Initialize the root node. */
970 rc = exfat_node_get_new_by_pos(&rootp, devmap_handle, EXFAT_ROOT_PAR,
971 EXFAT_ROOT_POS);
972 if (rc!=EOK) {
973 (void) block_cache_fini(devmap_handle);
974 block_fini(devmap_handle);
975 exfat_idx_fini_by_devmap_handle(devmap_handle);
976 return ENOMEM;
977 }
978 assert(rootp->idx->index == EXFAT_ROOT_IDX);
979
980 rootp->type = EXFAT_DIRECTORY;
981 rootp->firstc = ROOT_FC(bs);
982 rootp->fragmented = true;
983 rootp->refcnt = 1;
984 rootp->lnkcnt = 0; /* FS root is not linked */
985
986 uint32_t clusters;
987 rc = exfat_clusters_get(&clusters, bs, devmap_handle, rootp->firstc);
988 if (rc != EOK) {
989 free(rootp);
990 (void) block_cache_fini(devmap_handle);
991 block_fini(devmap_handle);
992 exfat_idx_fini_by_devmap_handle(devmap_handle);
993 return ENOTSUP;
994 }
995 rootp->size = BPS(bs) * SPC(bs) * clusters;
996 fibril_mutex_unlock(&rootp->idx->lock);
997
998 /* Open root directory and looking for Bitmap and UC-Table */
999 exfat_directory_t di;
1000 exfat_dentry_t *de;
1001 rc = exfat_directory_open(rootp, &di);
1002 if (rc != EOK) {
1003 free(rootp);
1004 (void) block_cache_fini(devmap_handle);
1005 block_fini(devmap_handle);
1006 exfat_idx_fini_by_devmap_handle(devmap_handle);
1007 return ENOTSUP;
1008 }
1009
1010 /* Initialize the bitmap node. */
1011 rc = exfat_directory_find(&di, EXFAT_DENTRY_BITMAP, &de);
1012 if (rc != EOK) {
1013 free(rootp);
1014 (void) block_cache_fini(devmap_handle);
1015 block_fini(devmap_handle);
1016 exfat_idx_fini_by_devmap_handle(devmap_handle);
1017 return ENOTSUP;
1018 }
1019
1020 rc = exfat_node_get_new_by_pos(&bitmapp, devmap_handle, rootp->firstc,
1021 di.pos);
1022 if (rc!=EOK) {
1023 free(rootp);
1024 (void) block_cache_fini(devmap_handle);
1025 block_fini(devmap_handle);
1026 exfat_idx_fini_by_devmap_handle(devmap_handle);
1027 return ENOMEM;
1028 }
1029 assert(bitmapp->idx->index == EXFAT_BITMAP_IDX);
1030 fibril_mutex_unlock(&bitmapp->idx->lock);
1031
1032 bitmapp->type = EXFAT_BITMAP;
1033 bitmapp->firstc = de->bitmap.firstc;
1034 bitmapp->fragmented = true;
1035 bitmapp->idx->parent_fragmented = true;
1036 bitmapp->refcnt = 1;
1037 bitmapp->lnkcnt = 0;
1038 bitmapp->size = de->bitmap.size;
1039
1040 /* Initialize the uctable node. */
1041 rc = exfat_directory_seek(&di, 0);
1042 if (rc != EOK) {
1043 free(rootp);
1044 free(bitmapp);
1045 (void) block_cache_fini(devmap_handle);
1046 block_fini(devmap_handle);
1047 exfat_idx_fini_by_devmap_handle(devmap_handle);
1048 return ENOTSUP;
1049 }
1050
1051 rc = exfat_directory_find(&di, EXFAT_DENTRY_UCTABLE, &de);
1052 if (rc != EOK) {
1053 free(rootp);
1054 free(bitmapp);
1055 (void) block_cache_fini(devmap_handle);
1056 block_fini(devmap_handle);
1057 exfat_idx_fini_by_devmap_handle(devmap_handle);
1058 return ENOTSUP;
1059 }
1060
1061 rc = exfat_node_get_new_by_pos(&uctablep, devmap_handle, rootp->firstc,
1062 di.pos);
1063 if (rc!=EOK) {
1064 free(rootp);
1065 free(bitmapp);
1066 (void) block_cache_fini(devmap_handle);
1067 block_fini(devmap_handle);
1068 exfat_idx_fini_by_devmap_handle(devmap_handle);
1069 return ENOMEM;
1070 }
1071 assert(uctablep->idx->index == EXFAT_UCTABLE_IDX);
1072 fibril_mutex_unlock(&uctablep->idx->lock);
1073
1074 uctablep->type = EXFAT_UCTABLE;
1075 uctablep->firstc = de->uctable.firstc;
1076 uctablep->fragmented = true;
1077 uctablep->idx->parent_fragmented = true;
1078 uctablep->refcnt = 1;
1079 uctablep->lnkcnt = 0;
1080 uctablep->size = de->uctable.size;
1081
1082 rc = exfat_directory_close(&di);
1083 if (rc!=EOK) {
1084 free(rootp);
1085 free(bitmapp);
1086 free(uctablep);
1087 (void) block_cache_fini(devmap_handle);
1088 block_fini(devmap_handle);
1089 exfat_idx_fini_by_devmap_handle(devmap_handle);
1090 return ENOMEM;
1091 }
1092
1093 exfat_fsinfo(bs, devmap_handle);
1094 printf("Root dir size: %lld\n", rootp->size);
1095
1096 *index = rootp->idx->index;
1097 *size = rootp->size;
1098 *linkcnt = rootp->lnkcnt;
1099
1100 return EOK;
1101}
1102
1103static int exfat_unmounted(devmap_handle_t devmap_handle)
1104{
1105 fs_node_t *fn;
1106 exfat_node_t *nodep;
1107 int rc;
1108
1109 rc = exfat_root_get(&fn, devmap_handle);
1110 if (rc != EOK)
1111 return rc;
1112 nodep = EXFAT_NODE(fn);
1113
1114 /*
1115 * We expect exactly two references on the root node. One for the
1116 * fat_root_get() above and one created in fat_mounted().
1117 */
1118 if (nodep->refcnt != 2) {
1119 (void) exfat_node_put(fn);
1120 return EBUSY;
1121 }
1122
1123 /*
1124 * Put the root node and force it to the FAT free node list.
1125 */
1126 (void) exfat_node_put(fn);
1127 (void) exfat_node_put(fn);
1128
1129 /*
1130 * Perform cleanup of the node structures, index structures and
1131 * associated data. Write back this file system's dirty blocks and
1132 * stop using libblock for this instance.
1133 */
1134 (void) exfat_node_fini_by_devmap_handle(devmap_handle);
1135 exfat_idx_fini_by_devmap_handle(devmap_handle);
1136 (void) block_cache_fini(devmap_handle);
1137 block_fini(devmap_handle);
1138
1139 return EOK;
1140}
1141
1142/*
1143int bitmap_is_allocated(exfat_bs_t *bs, devmap_handle_t devmap_handle,
1144 exfat_cluster_t clst, bool *status)
1145{
1146 fs_node_t *fn;
1147 exfat_node_t *bitmap;
1148 int rc;
1149
1150 rc = exfat_bitmap_get(&fn, devmap_handle);
1151 if (rc != EOK)
1152 return rc;
1153
1154 nbitmap = EXFAT_NODE(fn);
1155
1156
1157 return EOK;
1158}
1159*/
1160
1161static int
1162exfat_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
1163 size_t *rbytes)
1164{
1165 fs_node_t *fn;
1166 exfat_node_t *nodep;
1167 exfat_bs_t *bs;
1168 size_t bytes=0;
1169 block_t *b;
1170 int rc;
1171
1172 rc = exfat_node_get(&fn, devmap_handle, index);
1173 if (rc != EOK)
1174 return rc;
1175 if (!fn)
1176 return ENOENT;
1177 nodep = EXFAT_NODE(fn);
1178
1179 ipc_callid_t callid;
1180 size_t len;
1181 if (!async_data_read_receive(&callid, &len)) {
1182 exfat_node_put(fn);
1183 async_answer_0(callid, EINVAL);
1184 return EINVAL;
1185 }
1186
1187 bs = block_bb_get(devmap_handle);
1188
1189 if (nodep->type == EXFAT_FILE) {
1190 /*
1191 * Our strategy for regular file reads is to read one block at
1192 * most and make use of the possibility to return less data than
1193 * requested. This keeps the code very simple.
1194 */
1195 if (pos >= nodep->size) {
1196 /* reading beyond the EOF */
1197 bytes = 0;
1198 (void) async_data_read_finalize(callid, NULL, 0);
1199 } else {
1200 bytes = min(len, BPS(bs) - pos % BPS(bs));
1201 bytes = min(bytes, nodep->size - pos);
1202 rc = exfat_block_get(&b, bs, nodep, pos / BPS(bs),
1203 BLOCK_FLAGS_NONE);
1204 if (rc != EOK) {
1205 exfat_node_put(fn);
1206 async_answer_0(callid, rc);
1207 return rc;
1208 }
1209 (void) async_data_read_finalize(callid,
1210 b->data + pos % BPS(bs), bytes);
1211 rc = block_put(b);
1212 if (rc != EOK) {
1213 exfat_node_put(fn);
1214 return rc;
1215 }
1216 }
1217 } else {
1218 if (nodep->type != EXFAT_DIRECTORY) {
1219 async_answer_0(callid, ENOTSUP);
1220 return ENOTSUP;
1221 }
1222
1223 aoff64_t spos = pos;
1224 char name[EXFAT_FILENAME_LEN+1];
1225 exfat_file_dentry_t df;
1226 exfat_stream_dentry_t ds;
1227
1228 assert(nodep->size % BPS(bs) == 0);
1229 assert(BPS(bs) % sizeof(exfat_dentry_t) == 0);
1230
1231 exfat_directory_t di;
1232 rc = exfat_directory_open(nodep, &di);
1233 if (rc != EOK) goto err;
1234 rc = exfat_directory_seek(&di, pos);
1235 if (rc != EOK) {
1236 (void) exfat_directory_close(&di);
1237 goto err;
1238 }
1239
1240 rc = exfat_directory_read_file(&di, name, EXFAT_FILENAME_LEN, &df, &ds);
1241 if (rc == EOK) goto hit;
1242 if (rc == ENOENT) goto miss;
1243
1244err:
1245 (void) exfat_node_put(fn);
1246 async_answer_0(callid, rc);
1247 return rc;
1248
1249miss:
1250 rc = exfat_directory_close(&di);
1251 if (rc!=EOK)
1252 goto err;
1253 rc = exfat_node_put(fn);
1254 async_answer_0(callid, rc != EOK ? rc : ENOENT);
1255 *rbytes = 0;
1256 return rc != EOK ? rc : ENOENT;
1257
1258hit:
1259 pos = di.pos;
1260 rc = exfat_directory_close(&di);
1261 if (rc!=EOK)
1262 goto err;
1263 (void) async_data_read_finalize(callid, name, str_size(name) + 1);
1264 bytes = (pos - spos)+1;
1265 }
1266
1267 rc = exfat_node_put(fn);
1268 *rbytes = bytes;
1269 return rc;
1270}
1271
1272static int exfat_close(devmap_handle_t devmap_handle, fs_index_t index)
1273{
1274 return EOK;
1275}
1276
1277static int exfat_sync(devmap_handle_t devmap_handle, fs_index_t index)
1278{
1279 fs_node_t *fn;
1280 int rc = exfat_node_get(&fn, devmap_handle, index);
1281 if (rc != EOK)
1282 return rc;
1283 if (!fn)
1284 return ENOENT;
1285
1286 exfat_node_t *nodep = EXFAT_NODE(fn);
1287
1288 nodep->dirty = true;
1289 rc = exfat_node_sync(nodep);
1290
1291 exfat_node_put(fn);
1292 return rc;
1293}
1294
1295static int
1296exfat_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
1297 size_t *wbytes, aoff64_t *nsize)
1298{
1299 fs_node_t *fn;
1300 exfat_node_t *nodep;
1301 exfat_bs_t *bs;
1302 size_t bytes;
1303 block_t *b;
1304 aoff64_t boundary;
1305 int flags = BLOCK_FLAGS_NONE;
1306 int rc;
1307
1308 rc = exfat_node_get(&fn, devmap_handle, index);
1309 if (rc != EOK)
1310 return rc;
1311 if (!fn)
1312 return ENOENT;
1313 nodep = EXFAT_NODE(fn);
1314
1315 ipc_callid_t callid;
1316 size_t len;
1317 if (!async_data_write_receive(&callid, &len)) {
1318 (void) exfat_node_put(fn);
1319 async_answer_0(callid, EINVAL);
1320 return EINVAL;
1321 }
1322
1323 bs = block_bb_get(devmap_handle);
1324
1325 /*
1326 * In all scenarios, we will attempt to write out only one block worth
1327 * of data at maximum. There might be some more efficient approaches,
1328 * but this one greatly simplifies fat_write(). Note that we can afford
1329 * to do this because the client must be ready to handle the return
1330 * value signalizing a smaller number of bytes written.
1331 */
1332 bytes = min(len, BPS(bs) - pos % BPS(bs));
1333 if (bytes == BPS(bs))
1334 flags |= BLOCK_FLAGS_NOREAD;
1335
1336 boundary = ROUND_UP(nodep->size, BPC(bs));
1337
1338 if (pos >= boundary) {
1339 unsigned nclsts;
1340 nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
1341 rc = exfat_node_expand(devmap_handle, nodep, nclsts);
1342 if (rc != EOK) {
1343 /* could not expand node */
1344 (void) exfat_node_put(fn);
1345 async_answer_0(callid, rc);
1346 return rc;
1347 }
1348 }
1349
1350 if (pos + bytes > nodep->size) {
1351 nodep->size = pos + bytes;
1352 nodep->dirty = true; /* need to sync node */
1353 }
1354
1355 /*
1356 * This is the easier case - we are either overwriting already
1357 * existing contents or writing behind the EOF, but still within
1358 * the limits of the last cluster. The node size may grow to the
1359 * next block size boundary.
1360 */
1361 rc = exfat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
1362 if (rc != EOK) {
1363 (void) exfat_node_put(fn);
1364 async_answer_0(callid, rc);
1365 return rc;
1366 }
1367
1368 (void) async_data_write_finalize(callid,
1369 b->data + pos % BPS(bs), bytes);
1370 b->dirty = true; /* need to sync block */
1371 rc = block_put(b);
1372 if (rc != EOK) {
1373 (void) exfat_node_put(fn);
1374 return rc;
1375 }
1376
1377
1378 *wbytes = bytes;
1379 *nsize = nodep->size;
1380 rc = exfat_node_put(fn);
1381 return rc;
1382}
1383
1384static int
1385exfat_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
1386{
1387 fs_node_t *fn;
1388 exfat_node_t *nodep;
1389 exfat_bs_t *bs;
1390 int rc;
1391
1392 rc = exfat_node_get(&fn, devmap_handle, index);
1393 if (rc != EOK)
1394 return rc;
1395 if (!fn)
1396 return ENOENT;
1397 nodep = EXFAT_NODE(fn);
1398
1399 bs = block_bb_get(devmap_handle);
1400
1401 if (nodep->size == size) {
1402 rc = EOK;
1403 } else if (nodep->size < size) {
1404 /*
1405 * The standard says we have the freedom to grow the node.
1406 * For now, we simply return an error.
1407 */
1408 rc = EINVAL;
1409 } else if (ROUND_UP(nodep->size, BPC(bs)) == ROUND_UP(size, BPC(bs))) {
1410 /*
1411 * The node will be shrunk, but no clusters will be deallocated.
1412 */
1413 nodep->size = size;
1414 nodep->dirty = true; /* need to sync node */
1415 rc = EOK;
1416 } else {
1417 rc = exfat_node_shrink(devmap_handle, nodep, size);
1418 }
1419
1420 (void) exfat_node_put(fn);
1421 return rc;
1422}
1423
1424static int exfat_destroy(devmap_handle_t devmap_handle, fs_index_t index)
1425{
1426 fs_node_t *fn;
1427 exfat_node_t *nodep;
1428 int rc;
1429
1430 rc = exfat_node_get(&fn, devmap_handle, index);
1431 if (rc != EOK)
1432 return rc;
1433 if (!fn)
1434 return ENOENT;
1435
1436 nodep = EXFAT_NODE(fn);
1437 /*
1438 * We should have exactly two references. One for the above
1439 * call to fat_node_get() and one from fat_unlink().
1440 */
1441 assert(nodep->refcnt == 2);
1442
1443 rc = exfat_destroy_node(fn);
1444 return rc;
1445}
1446
1447vfs_out_ops_t exfat_ops = {
1448 .mounted = exfat_mounted,
1449 .unmounted = exfat_unmounted,
1450 .read = exfat_read,
1451 .write = exfat_write,
1452 .truncate = exfat_truncate,
1453 .close = exfat_close,
1454 .destroy = exfat_destroy,
1455 .sync = exfat_sync,
1456};
1457
1458
1459/**
1460 * @}
1461 */
Note: See TracBrowser for help on using the repository browser.