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

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

Skip the first two directories ('.' and '..') in the mfs_read() function

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