source: mainline/uspace/srv/fs/minixfs/mfs_ops.c@ d2c67e7

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

remove useless goto

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