source: mainline/uspace/srv/fs/mfs/mfs_ops.c@ bf08ff0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bf08ff0 was bf08ff0, checked in by Maurizio Lombardi <m.lombardi85@…>, 14 years ago

Cleaning error code path in mfs_mounted()

  • Property mode set to 100644
File size: 24.2 KB
Line 
1/*
2 * Copyright (c) 2011 Maurizio Lombardi
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#include <stdlib.h>
34#include <fibril_synch.h>
35#include <align.h>
36#include <adt/hash_table.h>
37#include "mfs.h"
38
39#define OPEN_NODES_KEYS 2
40#define OPEN_NODES_SERVICE_KEY 0
41#define OPEN_NODES_INODE_KEY 1
42#define OPEN_NODES_BUCKETS 256
43
44static bool check_magic_number(uint16_t magic, bool *native,
45 mfs_version_t *version, bool *longfilenames);
46static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
47 fs_index_t index);
48
49static int mfs_node_put(fs_node_t *fsnode);
50static int mfs_node_open(fs_node_t *fsnode);
51static fs_index_t mfs_index_get(fs_node_t *fsnode);
52static unsigned mfs_lnkcnt_get(fs_node_t *fsnode);
53static bool mfs_is_directory(fs_node_t *fsnode);
54static bool mfs_is_file(fs_node_t *fsnode);
55static int mfs_has_children(bool *has_children, fs_node_t *fsnode);
56static int mfs_root_get(fs_node_t **rfn, service_id_t service_id);
57static service_id_t mfs_service_get(fs_node_t *fsnode);
58static aoff64_t mfs_size_get(fs_node_t *node);
59static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
60static int mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags);
61static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name);
62static int mfs_unlink(fs_node_t *, fs_node_t *, const char *name);
63static int mfs_destroy_node(fs_node_t *fn);
64static hash_index_t open_nodes_hash(unsigned long key[]);
65static int open_nodes_compare(unsigned long key[], hash_count_t keys,
66 link_t *item);
67static void open_nodes_remove_cb(link_t *link);
68
69static int mfs_node_get(fs_node_t **rfn, service_id_t service_id,
70 fs_index_t index);
71static int
72mfs_instance_get(service_id_t service_id, struct mfs_instance **instance);
73
74
75static hash_table_t open_nodes;
76static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
77
78libfs_ops_t mfs_libfs_ops = {
79 .size_get = mfs_size_get,
80 .root_get = mfs_root_get,
81 .service_get = mfs_service_get,
82 .is_directory = mfs_is_directory,
83 .is_file = mfs_is_file,
84 .node_get = mfs_node_get,
85 .node_put = mfs_node_put,
86 .node_open = mfs_node_open,
87 .index_get = mfs_index_get,
88 .match = mfs_match,
89 .create = mfs_create_node,
90 .link = mfs_link,
91 .unlink = mfs_unlink,
92 .destroy = mfs_destroy_node,
93 .has_children = mfs_has_children,
94 .lnkcnt_get = mfs_lnkcnt_get
95};
96
97/* Hash table interface for open nodes hash table */
98static hash_index_t open_nodes_hash(unsigned long key[])
99{
100 /* TODO: This is very simple and probably can be improved */
101 return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
102}
103
104static int open_nodes_compare(unsigned long key[], hash_count_t keys,
105 link_t *item)
106{
107 struct mfs_node *mnode = hash_table_get_instance(item, struct mfs_node, link);
108 assert(keys > 0);
109 if (mnode->instance->service_id !=
110 ((service_id_t) key[OPEN_NODES_SERVICE_KEY])) {
111 return false;
112 }
113 if (keys == 1) {
114 return true;
115 }
116 assert(keys == 2);
117 return (mnode->ino_i->index == key[OPEN_NODES_INODE_KEY]);
118}
119
120static void open_nodes_remove_cb(link_t *link)
121{
122 /* We don't use remove callback for this hash table */
123}
124
125static hash_table_operations_t open_nodes_ops = {
126 .hash = open_nodes_hash,
127 .compare = open_nodes_compare,
128 .remove_callback = open_nodes_remove_cb,
129};
130
131int mfs_global_init(void)
132{
133 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
134 OPEN_NODES_KEYS, &open_nodes_ops)) {
135 return ENOMEM;
136 }
137 return EOK;
138}
139
140static int
141mfs_mounted(service_id_t service_id, const char *opts, fs_index_t *index,
142 aoff64_t *size, unsigned *linkcnt)
143{
144 enum cache_mode cmode;
145 struct mfs_superblock *sb = NULL;
146 struct mfs3_superblock *sb3 = NULL;
147 struct mfs_sb_info *sbi = NULL;
148 struct mfs_instance *instance = NULL;
149 bool native, longnames;
150 mfs_version_t version;
151 uint16_t magic;
152 int rc;
153
154 /* Check for option enabling write through. */
155 if (str_cmp(opts, "wtcache") == 0)
156 cmode = CACHE_MODE_WT;
157 else
158 cmode = CACHE_MODE_WB;
159
160 /* initialize libblock */
161 rc = block_init(EXCHANGE_SERIALIZE, service_id, 4096);
162 if (rc != EOK)
163 return rc;
164
165 /*Allocate space for generic MFS superblock*/
166 sbi = malloc(sizeof(*sbi));
167 if (!sbi) {
168 rc = ENOMEM;
169 goto out_error;
170 }
171
172 /*Allocate space for filesystem instance*/
173 instance = malloc(sizeof(*instance));
174 if (!instance) {
175 rc = ENOMEM;
176 goto out_error;
177 }
178
179 sb = malloc(MFS_SUPERBLOCK_SIZE);
180 if (!sb) {
181 rc = ENOMEM;
182 goto out_error;
183 }
184
185 /* Read the superblock */
186 rc = block_read_direct(service_id, MFS_SUPERBLOCK << 1, 2, sb);
187 if (rc != EOK)
188 goto out_error;
189
190 sb3 = (struct mfs3_superblock *) sb;
191
192 if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
193 /*This is a V1 or V2 Minix filesystem*/
194 magic = sb->s_magic;
195 } else if (check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
196 /*This is a V3 Minix filesystem*/
197 magic = sb3->s_magic;
198 } else {
199 /*Not recognized*/
200 mfsdebug("magic number not recognized\n");
201 rc = ENOTSUP;
202 goto out_error;
203 }
204
205 mfsdebug("magic number recognized = %04x\n", magic);
206
207 /*Fill superblock info structure*/
208
209 sbi->fs_version = version;
210 sbi->long_names = longnames;
211 sbi->native = native;
212 sbi->magic = magic;
213 sbi->isearch = 0;
214 sbi->zsearch = 0;
215
216 if (version == MFS_VERSION_V3) {
217 sbi->ninodes = conv32(native, sb3->s_ninodes);
218 sbi->ibmap_blocks = conv16(native, sb3->s_ibmap_blocks);
219 sbi->zbmap_blocks = conv16(native, sb3->s_zbmap_blocks);
220 sbi->firstdatazone = conv16(native, sb3->s_first_data_zone);
221 sbi->log2_zone_size = conv16(native, sb3->s_log2_zone_size);
222 sbi->max_file_size = conv32(native, sb3->s_max_file_size);
223 sbi->nzones = conv32(native, sb3->s_nzones);
224 sbi->block_size = conv16(native, sb3->s_block_size);
225 sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
226 sbi->dirsize = MFS3_DIRSIZE;
227 sbi->max_name_len = MFS3_MAX_NAME_LEN;
228 } else {
229 sbi->ninodes = conv16(native, sb->s_ninodes);
230 sbi->ibmap_blocks = conv16(native, sb->s_ibmap_blocks);
231 sbi->zbmap_blocks = conv16(native, sb->s_zbmap_blocks);
232 sbi->firstdatazone = conv16(native, sb->s_first_data_zone);
233 sbi->log2_zone_size = conv16(native, sb->s_log2_zone_size);
234 sbi->max_file_size = conv32(native, sb->s_max_file_size);
235 sbi->block_size = MFS_BLOCKSIZE;
236 if (version == MFS_VERSION_V2) {
237 sbi->nzones = conv32(native, sb->s_nzones2);
238 sbi->ino_per_block = V2_INODES_PER_BLOCK;
239 } else {
240 sbi->nzones = conv16(native, sb->s_nzones);
241 sbi->ino_per_block = V1_INODES_PER_BLOCK;
242 }
243 sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
244 sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
245 MFS_MAX_NAME_LEN;
246 }
247
248 if (sbi->log2_zone_size != 0) {
249 /* In MFS, file space is allocated per zones.
250 * Zones are a collection of consecutive blocks on disk.
251 *
252 * The current MFS implementation supports only filesystems
253 * where the size of a zone is equal to the
254 * size of a block.
255 */
256 rc = ENOTSUP;
257 goto out_error;
258 }
259
260 sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
261
262 rc = block_cache_init(service_id, sbi->block_size, 0, cmode);
263 if (rc != EOK) {
264 mfsdebug("block cache initialization failed\n");
265 rc = EINVAL;
266 goto out_error;
267 }
268
269 /*Initialize the instance structure and remember it*/
270 instance->service_id = service_id;
271 instance->sbi = sbi;
272 instance->open_nodes_cnt = 0;
273 rc = fs_instance_create(service_id, instance);
274 if (rc != EOK) {
275 block_cache_fini(service_id);
276 mfsdebug("fs instance creation failed\n");
277 goto out_error;
278 }
279
280 mfsdebug("mount successful\n");
281
282 fs_node_t *fn;
283 mfs_node_get(&fn, service_id, MFS_ROOT_INO);
284
285 struct mfs_node *mroot = fn->data;
286
287 *index = mroot->ino_i->index;
288 *size = mroot->ino_i->i_size;
289 *linkcnt = 1;
290
291 free(sb);
292
293 return mfs_node_put(fn);
294
295out_error:
296 block_fini(service_id);
297 if (sb)
298 free(sb);
299 if (sbi)
300 free(sbi);
301 if(instance)
302 free(instance);
303 return rc;
304}
305
306static int
307mfs_unmounted(service_id_t service_id)
308{
309 struct mfs_instance *inst;
310
311 mfsdebug("%s()\n", __FUNCTION__);
312
313 int r = mfs_instance_get(service_id, &inst);
314 if (r != EOK)
315 return r;
316
317 if (inst->open_nodes_cnt != 0)
318 return EBUSY;
319
320 (void) block_cache_fini(service_id);
321 block_fini(service_id);
322
323 /* Remove and destroy the instance */
324 (void) fs_instance_destroy(service_id);
325 free(inst->sbi);
326 free(inst);
327 return EOK;
328}
329
330service_id_t mfs_service_get(fs_node_t *fsnode)
331{
332 struct mfs_node *node = fsnode->data;
333 return node->instance->service_id;
334}
335
336static int mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
337{
338 int r;
339 struct mfs_instance *inst;
340 struct mfs_node *mnode;
341 fs_node_t *fsnode;
342 uint32_t inum;
343
344 mfsdebug("%s()\n", __FUNCTION__);
345
346 r = mfs_instance_get(service_id, &inst);
347 if (r != EOK)
348 return r;
349
350 /*Alloc a new inode*/
351 r = mfs_alloc_inode(inst, &inum);
352 if (r != EOK)
353 return r;
354
355 struct mfs_ino_info *ino_i;
356
357 ino_i = malloc(sizeof(*ino_i));
358 if (!ino_i) {
359 r = ENOMEM;
360 goto out_err;
361 }
362
363 mnode = malloc(sizeof(*mnode));
364 if (!mnode) {
365 r = ENOMEM;
366 goto out_err_1;
367 }
368
369 fsnode = malloc(sizeof(fs_node_t));
370 if (!fsnode) {
371 r = ENOMEM;
372 goto out_err_2;
373 }
374
375 if (flags & L_DIRECTORY) {
376 ino_i->i_mode = S_IFDIR;
377 ino_i->i_nlinks = 2; /*This accounts for the '.' dentry*/
378 } else {
379 ino_i->i_mode = S_IFREG;
380 ino_i->i_nlinks = 1;
381 }
382
383 ino_i->i_uid = 0;
384 ino_i->i_gid = 0;
385 ino_i->i_size = 0;
386 ino_i->i_atime = 0;
387 ino_i->i_mtime = 0;
388 ino_i->i_ctime = 0;
389
390 memset(ino_i->i_dzone, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES);
391 memset(ino_i->i_izone, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES);
392
393 mfsdebug("new node idx = %d\n", (int) inum);
394
395 ino_i->index = inum;
396 ino_i->dirty = true;
397 mnode->ino_i = ino_i;
398 mnode->instance = inst;
399 mnode->refcnt = 1;
400
401 link_initialize(&mnode->link);
402
403 unsigned long key[] = {
404 [OPEN_NODES_SERVICE_KEY] = inst->service_id,
405 [OPEN_NODES_INODE_KEY] = inum,
406 };
407
408 fibril_mutex_lock(&open_nodes_lock);
409 hash_table_insert(&open_nodes, key, &mnode->link);
410 fibril_mutex_unlock(&open_nodes_lock);
411 inst->open_nodes_cnt++;
412
413 mnode->ino_i->dirty = true;
414
415 fs_node_initialize(fsnode);
416 fsnode->data = mnode;
417 mnode->fsnode = fsnode;
418 *rfn = fsnode;
419
420 return EOK;
421
422out_err_2:
423 free(mnode);
424out_err_1:
425 free(ino_i);
426out_err:
427 return r;
428}
429
430static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
431{
432 struct mfs_node *mnode = pfn->data;
433 struct mfs_ino_info *ino_i = mnode->ino_i;
434 struct mfs_dentry_info d_info;
435 int r;
436
437 mfsdebug("%s()\n", __FUNCTION__);
438
439 if (!S_ISDIR(ino_i->i_mode))
440 return ENOTDIR;
441
442 struct mfs_sb_info *sbi = mnode->instance->sbi;
443 const size_t comp_size = str_size(component);
444
445 unsigned i;
446 for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
447 r = mfs_read_dentry(mnode, &d_info, i);
448 if (r != EOK)
449 return r;
450
451 if (!d_info.d_inum) {
452 /*This entry is not used*/
453 continue;
454 }
455
456 const size_t dentry_name_size = str_size(d_info.d_name);
457
458 if (comp_size == dentry_name_size &&
459 !bcmp(component, d_info.d_name, dentry_name_size)) {
460 /*Hit!*/
461 mfs_node_core_get(rfn, mnode->instance,
462 d_info.d_inum);
463 goto found;
464 }
465 }
466 *rfn = NULL;
467found:
468 return EOK;
469}
470
471static aoff64_t mfs_size_get(fs_node_t *node)
472{
473 const struct mfs_node *mnode = node->data;
474 return mnode->ino_i->i_size;
475}
476
477static int
478mfs_node_get(fs_node_t **rfn, service_id_t service_id,
479 fs_index_t index)
480{
481 int rc;
482 struct mfs_instance *instance;
483
484 mfsdebug("%s()\n", __FUNCTION__);
485
486 rc = mfs_instance_get(service_id, &instance);
487 if (rc != EOK)
488 return rc;
489
490 return mfs_node_core_get(rfn, instance, index);
491}
492
493static int
494mfs_node_put(fs_node_t *fsnode)
495{
496 int rc = EOK;
497 struct mfs_node *mnode = fsnode->data;
498
499 mfsdebug("%s()\n", __FUNCTION__);
500
501 fibril_mutex_lock(&open_nodes_lock);
502
503 assert(mnode->refcnt > 0);
504 mnode->refcnt--;
505 if (mnode->refcnt == 0) {
506 unsigned long key[] = {
507 [OPEN_NODES_SERVICE_KEY] = mnode->instance->service_id,
508 [OPEN_NODES_INODE_KEY] = mnode->ino_i->index
509 };
510 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
511 assert(mnode->instance->open_nodes_cnt > 0);
512 mnode->instance->open_nodes_cnt--;
513 rc = mfs_put_inode(mnode);
514 free(mnode->ino_i);
515 free(mnode);
516 free(fsnode);
517 }
518
519 fibril_mutex_unlock(&open_nodes_lock);
520 return rc;
521}
522
523static int mfs_node_open(fs_node_t *fsnode)
524{
525 /*
526 * Opening a file is stateless, nothing
527 * to be done here.
528 */
529 return EOK;
530}
531
532static fs_index_t mfs_index_get(fs_node_t *fsnode)
533{
534 struct mfs_node *mnode = fsnode->data;
535 return mnode->ino_i->index;
536}
537
538static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
539{
540 struct mfs_node *mnode = fsnode->data;
541
542 mfsdebug("%s() %d\n", __FUNCTION__, mnode->ino_i->i_nlinks);
543
544 if (S_ISDIR(mnode->ino_i->i_mode)) {
545 if (mnode->ino_i->i_nlinks > 1)
546 return 1;
547 else
548 return 0;
549 } else
550 return mnode->ino_i->i_nlinks;
551}
552
553static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
554 fs_index_t index)
555{
556 fs_node_t *node = NULL;
557 struct mfs_node *mnode = NULL;
558 int rc;
559
560 mfsdebug("%s()\n", __FUNCTION__);
561
562 fibril_mutex_lock(&open_nodes_lock);
563
564 /* Check if the node is not already open */
565 unsigned long key[] = {
566 [OPEN_NODES_SERVICE_KEY] = inst->service_id,
567 [OPEN_NODES_INODE_KEY] = index,
568 };
569 link_t *already_open = hash_table_find(&open_nodes, key);
570
571 if (already_open) {
572 mnode = hash_table_get_instance(already_open, struct mfs_node, link);
573 *rfn = mnode->fsnode;
574 mnode->refcnt++;
575
576 fibril_mutex_unlock(&open_nodes_lock);
577 return EOK;
578 }
579
580 node = malloc(sizeof(fs_node_t));
581 if (!node) {
582 rc = ENOMEM;
583 goto out_err;
584 }
585
586 fs_node_initialize(node);
587
588 mnode = malloc(sizeof(*mnode));
589 if (!mnode) {
590 rc = ENOMEM;
591 goto out_err;
592 }
593
594 struct mfs_ino_info *ino_i;
595
596 rc = mfs_get_inode(inst, &ino_i, index);
597 if (rc != EOK)
598 goto out_err;
599
600 ino_i->index = index;
601 mnode->ino_i = ino_i;
602 mnode->refcnt = 1;
603 link_initialize(&mnode->link);
604
605 mnode->instance = inst;
606 node->data = mnode;
607 mnode->fsnode = node;
608 *rfn = node;
609
610 hash_table_insert(&open_nodes, key, &mnode->link);
611 inst->open_nodes_cnt++;
612
613 fibril_mutex_unlock(&open_nodes_lock);
614
615 return EOK;
616
617out_err:
618 if (node)
619 free(node);
620 if (mnode)
621 free(mnode);
622 fibril_mutex_unlock(&open_nodes_lock);
623 return rc;
624}
625
626static bool mfs_is_directory(fs_node_t *fsnode)
627{
628 const struct mfs_node *node = fsnode->data;
629 return S_ISDIR(node->ino_i->i_mode);
630}
631
632static bool mfs_is_file(fs_node_t *fsnode)
633{
634 struct mfs_node *node = fsnode->data;
635 return S_ISREG(node->ino_i->i_mode);
636}
637
638static int mfs_root_get(fs_node_t **rfn, service_id_t service_id)
639{
640 int rc = mfs_node_get(rfn, service_id, MFS_ROOT_INO);
641 return rc;
642}
643
644static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
645{
646 struct mfs_node *parent = pfn->data;
647 struct mfs_node *child = cfn->data;
648 struct mfs_sb_info *sbi = parent->instance->sbi;
649
650 mfsdebug("%s()\n", __FUNCTION__);
651
652 if (str_size(name) > sbi->max_name_len)
653 return ENAMETOOLONG;
654
655 int r = mfs_insert_dentry(parent, name, child->ino_i->index);
656 if (r != EOK)
657 goto exit_error;
658
659 if (S_ISDIR(child->ino_i->i_mode)) {
660 r = mfs_insert_dentry(child, ".", child->ino_i->index);
661 if (r != EOK)
662 goto exit_error;
663
664 r = mfs_insert_dentry(child, "..", parent->ino_i->index);
665 if (r != EOK)
666 goto exit_error;
667
668 parent->ino_i->i_nlinks++;
669 parent->ino_i->dirty = true;
670 }
671
672exit_error:
673 return r;
674}
675
676static int
677mfs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name)
678{
679 struct mfs_node *parent = pfn->data;
680 struct mfs_node *child = cfn->data;
681 bool has_children;
682 int r;
683
684 mfsdebug("%s()\n", __FUNCTION__);
685
686 if (!parent)
687 return EBUSY;
688
689 r = mfs_has_children(&has_children, cfn);
690 if (r != EOK)
691 return r;
692
693 if (has_children)
694 return ENOTEMPTY;
695
696 r = mfs_remove_dentry(parent, name);
697 if (r != EOK)
698 return r;
699
700 struct mfs_ino_info *chino = child->ino_i;
701
702 assert(chino->i_nlinks >= 1);
703 chino->i_nlinks--;
704 mfsdebug("Links: %d\n", chino->i_nlinks);
705
706 if (chino->i_nlinks <= 1 && S_ISDIR(chino->i_mode)) {
707 /* The child directory will be destroyed, decrease the
708 * parent hard links counter.
709 */
710 parent->ino_i->i_nlinks--;
711 parent->ino_i->dirty = true;
712 }
713
714 chino->dirty = true;
715
716 return r;
717}
718
719static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
720{
721 struct mfs_node *mnode = fsnode->data;
722 struct mfs_sb_info *sbi = mnode->instance->sbi;
723 int r;
724
725 *has_children = false;
726
727 if (!S_ISDIR(mnode->ino_i->i_mode))
728 goto out;
729
730 struct mfs_dentry_info d_info;
731
732 /* The first two dentries are always . and .. */
733 unsigned i;
734 for (i = 2; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
735 r = mfs_read_dentry(mnode, &d_info, i);
736 if (r != EOK)
737 return r;
738
739 if (d_info.d_inum) {
740 /*A valid entry has been found*/
741 *has_children = true;
742 break;
743 }
744 }
745out:
746
747 return EOK;
748}
749
750static int
751mfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
752 size_t *rbytes)
753{
754 int rc;
755 fs_node_t *fn;
756
757 rc = mfs_node_get(&fn, service_id, index);
758 if (rc != EOK)
759 return rc;
760 if (!fn)
761 return ENOENT;
762
763 struct mfs_node *mnode;
764 struct mfs_ino_info *ino_i;
765 size_t len, bytes = 0;
766 ipc_callid_t callid;
767
768 mnode = fn->data;
769 ino_i = mnode->ino_i;
770
771 if (!async_data_read_receive(&callid, &len)) {
772 rc = EINVAL;
773 goto out_error;
774 }
775
776 if (S_ISDIR(ino_i->i_mode)) {
777 aoff64_t spos = pos;
778 struct mfs_dentry_info d_info;
779 struct mfs_sb_info *sbi = mnode->instance->sbi;
780
781 if (pos < 2) {
782 /*Skip the first two dentries ('.' and '..')*/
783 pos = 2;
784 }
785
786 for (; pos < mnode->ino_i->i_size / sbi->dirsize; ++pos) {
787 rc = mfs_read_dentry(mnode, &d_info, pos);
788 if (rc != EOK)
789 goto out_error;
790
791 if (d_info.d_inum) {
792 /*Dentry found!*/
793 goto found;
794 }
795 }
796
797 rc = mfs_node_put(fn);
798 async_answer_0(callid, rc != EOK ? rc : ENOENT);
799 return rc;
800found:
801 async_data_read_finalize(callid, d_info.d_name,
802 str_size(d_info.d_name) + 1);
803 bytes = ((pos - spos) + 1);
804 } else {
805 struct mfs_sb_info *sbi = mnode->instance->sbi;
806
807 if (pos >= (size_t) ino_i->i_size) {
808 /*Trying to read beyond the end of file*/
809 bytes = 0;
810 (void) async_data_read_finalize(callid, NULL, 0);
811 goto out_success;
812 }
813
814 bytes = min(len, sbi->block_size - pos % sbi->block_size);
815 bytes = min(bytes, ino_i->i_size - pos);
816
817 uint32_t zone;
818 block_t *b;
819
820 rc = mfs_read_map(&zone, mnode, pos);
821 if (rc != EOK)
822 goto out_error;
823
824 if (zone == 0) {
825 /*sparse file*/
826 uint8_t *buf = malloc(sbi->block_size);
827 if (!buf) {
828 rc = ENOMEM;
829 goto out_error;
830 }
831 memset(buf, 0, sizeof(sbi->block_size));
832 async_data_read_finalize(callid,
833 buf + pos % sbi->block_size, bytes);
834 free(buf);
835 goto out_success;
836 }
837
838 rc = block_get(&b, service_id, zone, BLOCK_FLAGS_NONE);
839 if (rc != EOK)
840 goto out_error;
841
842 async_data_read_finalize(callid, b->data +
843 pos % sbi->block_size, bytes);
844
845 rc = block_put(b);
846 if (rc != EOK) {
847 mfs_node_put(fn);
848 return rc;
849 }
850 }
851out_success:
852 rc = mfs_node_put(fn);
853 *rbytes = bytes;
854 return rc;
855out_error:
856 ;
857 int tmp = mfs_node_put(fn);
858 async_answer_0(callid, tmp != EOK ? tmp : rc);
859 return tmp != EOK ? tmp : rc;
860}
861
862static int
863mfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
864 size_t *wbytes, aoff64_t *nsize)
865{
866 fs_node_t *fn;
867 int r;
868 int flags = BLOCK_FLAGS_NONE;
869
870 r = mfs_node_get(&fn, service_id, index);
871 if (r != EOK)
872 return r;
873 if (!fn)
874 return ENOENT;
875
876 ipc_callid_t callid;
877 size_t len;
878
879 if (!async_data_write_receive(&callid, &len)) {
880 r = EINVAL;
881 goto out_err;
882 }
883
884 struct mfs_node *mnode = fn->data;
885 struct mfs_sb_info *sbi = mnode->instance->sbi;
886 struct mfs_ino_info *ino_i = mnode->ino_i;
887 const size_t bs = sbi->block_size;
888 size_t bytes = min(len, bs - (pos % bs));
889 uint32_t block;
890
891 if (bytes == bs)
892 flags = BLOCK_FLAGS_NOREAD;
893
894 r = mfs_read_map(&block, mnode, pos);
895 if (r != EOK)
896 goto out_err;
897
898 if (block == 0) {
899 /*Writing in a sparse block*/
900 uint32_t dummy;
901
902 r = mfs_alloc_zone(mnode->instance, &block);
903 if (r != EOK)
904 goto out_err;
905
906 r = mfs_write_map(mnode, pos, block, &dummy);
907 if (r != EOK)
908 goto out_err;
909
910 flags = BLOCK_FLAGS_NOREAD;
911 }
912
913 block_t *b;
914 r = block_get(&b, service_id, block, flags);
915 if (r != EOK)
916 goto out_err;
917
918 if (flags == BLOCK_FLAGS_NOREAD)
919 memset(b->data, 0, sbi->block_size);
920
921 async_data_write_finalize(callid, b->data + (pos % bs), bytes);
922 b->dirty = true;
923
924 r = block_put(b);
925 if (r != EOK) {
926 mfs_node_put(fn);
927 return r;
928 }
929
930 if (pos + bytes > ino_i->i_size) {
931 ino_i->i_size = pos + bytes;
932 ino_i->dirty = true;
933 }
934 r = mfs_node_put(fn);
935 *nsize = ino_i->i_size;
936 *wbytes = bytes;
937 return r;
938
939out_err:
940 mfs_node_put(fn);
941 async_answer_0(callid, r);
942 return r;
943}
944
945static int
946mfs_destroy(service_id_t service_id, fs_index_t index)
947{
948 fs_node_t *fn;
949 int r;
950
951 r = mfs_node_get(&fn, service_id, index);
952 if (r != EOK)
953 return r;
954 if (!fn)
955 return ENOENT;
956
957 /*Destroy the inode*/
958 return mfs_destroy_node(fn);
959}
960
961static int
962mfs_destroy_node(fs_node_t *fn)
963{
964 struct mfs_node *mnode = fn->data;
965 bool has_children;
966 int r;
967
968 mfsdebug("mfs_destroy_node %d\n", mnode->ino_i->index);
969
970 r = mfs_has_children(&has_children, fn);
971 if (r != EOK)
972 goto out;
973
974 assert(!has_children);
975
976 /*Free the entire inode content*/
977 r = mfs_inode_shrink(mnode, mnode->ino_i->i_size);
978 if (r != EOK)
979 goto out;
980
981 /*Mark the inode as free in the bitmap*/
982 r = mfs_free_inode(mnode->instance, mnode->ino_i->index);
983
984out:
985 mfs_node_put(fn);
986 return r;
987}
988
989static int
990mfs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
991{
992 fs_node_t *fn;
993 int r;
994
995 r = mfs_node_get(&fn, service_id, index);
996 if (r != EOK)
997 return r;
998 if (!fn)
999 return r;
1000
1001 struct mfs_node *mnode = fn->data;
1002 struct mfs_ino_info *ino_i = mnode->ino_i;
1003
1004 if (ino_i->i_size == size)
1005 r = EOK;
1006 else
1007 r = mfs_inode_shrink(mnode, ino_i->i_size - size);
1008
1009 mfs_node_put(fn);
1010 return r;
1011}
1012
1013static int
1014mfs_instance_get(service_id_t service_id, struct mfs_instance **instance)
1015{
1016 void *data;
1017 int rc;
1018
1019 rc = fs_instance_get(service_id, &data);
1020 if (rc == EOK) {
1021 *instance = (struct mfs_instance *) data;
1022 } else {
1023 mfsdebug("instance not found\n");
1024 }
1025
1026 return rc;
1027}
1028
1029static bool check_magic_number(uint16_t magic, bool *native,
1030 mfs_version_t *version, bool *longfilenames)
1031{
1032 bool rc = true;
1033 *longfilenames = false;
1034
1035 if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
1036 *native = magic == MFS_MAGIC_V1;
1037 *version = MFS_VERSION_V1;
1038 } else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
1039 *native = magic == MFS_MAGIC_V1L;
1040 *version = MFS_VERSION_V1;
1041 *longfilenames = true;
1042 } else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
1043 *native = magic == MFS_MAGIC_V2;
1044 *version = MFS_VERSION_V2;
1045 } else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
1046 *native = magic == MFS_MAGIC_V2L;
1047 *version = MFS_VERSION_V2;
1048 *longfilenames = true;
1049 } else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
1050 *native = magic == MFS_MAGIC_V3;
1051 *version = MFS_VERSION_V3;
1052 } else
1053 rc = false;
1054
1055 return rc;
1056}
1057
1058static int
1059mfs_close(service_id_t service_id, fs_index_t index)
1060{
1061 return 0;
1062}
1063
1064static int
1065mfs_sync(service_id_t service_id, fs_index_t index)
1066{
1067 fs_node_t *fn;
1068 int rc = mfs_node_get(&fn, service_id, index);
1069 if (rc != EOK)
1070 return rc;
1071 if (!fn)
1072 return ENOENT;
1073
1074 struct mfs_node *mnode = fn->data;
1075 mnode->ino_i->dirty = true;
1076
1077 return mfs_node_put(fn);
1078}
1079
1080vfs_out_ops_t mfs_ops = {
1081 .mounted = mfs_mounted,
1082 .unmounted = mfs_unmounted,
1083 .read = mfs_read,
1084 .write = mfs_write,
1085 .truncate = mfs_truncate,
1086 .close = mfs_close,
1087 .destroy = mfs_destroy,
1088 .sync = mfs_sync,
1089};
1090
1091/**
1092 * @}
1093 */
1094
Note: See TracBrowser for help on using the repository browser.