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

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

Improve mfs_read(), now it can read files (not tested with very large files yet)

  • Property mode set to 100644
File size: 16.8 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 <stdio.h>
34#include <stdlib.h>
35#include <assert.h>
36#include <fibril_synch.h>
37#include <errno.h>
38#include "mfs.h"
39#include "mfs_utils.h"
40
41static bool check_magic_number(uint16_t magic, bool *native,
42 mfs_version_t *version, bool *longfilenames);
43static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
44 fs_index_t index);
45
46static int mfs_node_put(fs_node_t *fsnode);
47static int mfs_node_open(fs_node_t *fsnode);
48static fs_index_t mfs_index_get(fs_node_t *fsnode);
49static unsigned mfs_lnkcnt_get(fs_node_t *fsnode);
50static char mfs_plb_get_char(unsigned pos);
51static bool mfs_is_directory(fs_node_t *fsnode);
52static bool mfs_is_file(fs_node_t *fsnode);
53static int mfs_has_children(bool *has_children, fs_node_t *fsnode);
54static int mfs_root_get(fs_node_t **rfn, devmap_handle_t handle);
55static devmap_handle_t mfs_device_get(fs_node_t *fsnode);
56static aoff64_t mfs_size_get(fs_node_t *node);
57static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
58static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags);
59static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name);
60
61static int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
62 fs_index_t index);
63
64
65static LIST_INITIALIZE(inst_list);
66static FIBRIL_MUTEX_INITIALIZE(inst_list_mutex);
67
68libfs_ops_t mfs_libfs_ops = {
69 .size_get = mfs_size_get,
70 .root_get = mfs_root_get,
71 .device_get = mfs_device_get,
72 .is_directory = mfs_is_directory,
73 .is_file = mfs_is_file,
74 .node_get = mfs_node_get,
75 .node_put = mfs_node_put,
76 .node_open = mfs_node_open,
77 .index_get = mfs_index_get,
78 .match = mfs_match,
79 .create = mfs_create_node,
80 .link = mfs_link,
81 .plb_get_char = mfs_plb_get_char,
82 .has_children = mfs_has_children,
83 .lnkcnt_get = mfs_lnkcnt_get
84};
85
86void mfs_mounted(ipc_callid_t rid, ipc_call_t *request)
87{
88 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
89 enum cache_mode cmode;
90 struct mfs_superblock *sb;
91 struct mfs3_superblock *sb3;
92 struct mfs_sb_info *sbi;
93 struct mfs_instance *instance;
94 bool native, longnames;
95 mfs_version_t version;
96 uint16_t magic;
97
98 /* Accept the mount options */
99 char *opts;
100 int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
101
102 if (rc != EOK) {
103 mfsdebug("Can't accept async data write\n");
104 async_answer_0(rid, rc);
105 return;
106 }
107
108 /* Check for option enabling write through. */
109 if (str_cmp(opts, "wtcache") == 0)
110 cmode = CACHE_MODE_WT;
111 else
112 cmode = CACHE_MODE_WB;
113
114 free(opts);
115
116 /* initialize libblock */
117 rc = block_init(devmap_handle, 1024);
118 if (rc != EOK) {
119 mfsdebug("libblock initialization failed\n");
120 async_answer_0(rid, rc);
121 return;
122 }
123
124 /*Allocate space for generic MFS superblock*/
125 sbi = malloc(sizeof(*sbi));
126
127 if (!sbi) {
128 async_answer_0(rid, ENOMEM);
129 return;
130 }
131
132 /*Allocate space for filesystem instance*/
133 instance = malloc(sizeof(*instance));
134
135 if (!instance) {
136 async_answer_0(rid, ENOMEM);
137 return;
138 }
139
140 sb = malloc(MFS_SUPERBLOCK_SIZE);
141
142 if (!sb) {
143 async_answer_0(rid, ENOMEM);
144 return;
145 }
146
147 /* Read the superblock */
148 rc = block_read_direct(devmap_handle, MFS_SUPERBLOCK << 1, 1, sb);
149 if (rc != EOK) {
150 block_fini(devmap_handle);
151 async_answer_0(rid, rc);
152 return;
153 }
154
155 sb3 = (struct mfs3_superblock *) sb;
156
157 if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
158 /*This is a V1 or V2 Minix filesystem*/
159 magic = sb->s_magic;
160 goto recognized;
161 }
162
163 if (!check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
164 mfsdebug("magic number not recognized\n");
165 block_fini(devmap_handle);
166 async_answer_0(rid, ENOTSUP);
167 return;
168 }
169
170 /*This is a V3 Minix filesystem*/
171
172 magic = sb3->s_magic;
173
174recognized:
175
176 mfsdebug("magic number recognized = %04x\n", magic);
177
178 /*Fill superblock info structure*/
179
180 sbi->fs_version = version;
181 sbi->long_names = longnames;
182 sbi->native = native;
183 sbi->magic = magic;
184 sbi->isearch = 0;
185 sbi->zsearch = 0;
186
187 if (version == MFS_VERSION_V3) {
188 sbi->ninodes = conv32(native, sb3->s_ninodes);
189 sbi->ibmap_blocks = conv16(native, sb3->s_ibmap_blocks);
190 sbi->zbmap_blocks = conv16(native, sb3->s_zbmap_blocks);
191 sbi->firstdatazone = conv16(native, sb3->s_first_data_zone);
192 sbi->log2_zone_size = conv16(native, sb3->s_log2_zone_size);
193 sbi->max_file_size = conv32(native, sb3->s_max_file_size);
194 sbi->nzones = conv32(native, sb3->s_nzones);
195 sbi->block_size = conv16(native, sb3->s_block_size);
196 sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
197 sbi->dirsize = MFS3_DIRSIZE;
198 sbi->max_name_len = MFS3_MAX_NAME_LEN;
199 } else {
200 sbi->ninodes = conv16(native, sb->s_ninodes);
201 sbi->ibmap_blocks = conv16(native, sb->s_ibmap_blocks);
202 sbi->zbmap_blocks = conv16(native, sb->s_zbmap_blocks);
203 sbi->firstdatazone = conv16(native, sb->s_first_data_zone);
204 sbi->log2_zone_size = conv16(native, sb->s_log2_zone_size);
205 sbi->max_file_size = conv32(native, sb->s_max_file_size);
206 sbi->nzones = conv16(native, sb->s_nzones);
207 sbi->block_size = MFS_BLOCKSIZE;
208 sbi->ino_per_block = V1_INODES_PER_BLOCK;
209 if (version == MFS_VERSION_V2)
210 sbi->nzones = conv32(native, sb->s_nzones2);
211 sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
212 sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
213 MFS_MAX_NAME_LEN;
214 }
215 sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
216
217 free(sb);
218
219 rc = block_cache_init(devmap_handle, sbi->block_size, 0, cmode);
220
221 if (rc != EOK) {
222 block_fini(devmap_handle);
223 async_answer_0(rid, EINVAL);
224 mfsdebug("block cache initialization failed\n");
225 return;
226 }
227
228 /*Initialize the instance structure and add it to the list*/
229 link_initialize(&instance->link);
230 instance->handle = devmap_handle;
231 instance->sbi = sbi;
232
233 fibril_mutex_lock(&inst_list_mutex);
234 list_append(&instance->link, &inst_list);
235 fibril_mutex_unlock(&inst_list_mutex);
236
237 mfsdebug("mount successful\n");
238
239 async_answer_0(rid, EOK);
240}
241
242void mfs_mount(ipc_callid_t rid, ipc_call_t *request)
243{
244 libfs_mount(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
245}
246
247devmap_handle_t mfs_device_get(fs_node_t *fsnode)
248{
249 struct mfs_node *node = fsnode->data;
250 return node->instance->handle;
251}
252
253static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags)
254{
255 int r;
256 struct mfs_instance *inst;
257 struct mfs_node *mnode;
258 fs_node_t *fsnode;
259 uint32_t inum;
260
261 mfsdebug("create_node()\n");
262
263 r = mfs_instance_get(handle, &inst);
264 if (r != EOK)
265 return r;
266
267 if (flags & L_DIRECTORY) {
268 /*Not yet supported*/
269 return ENOTSUP;
270 }
271
272 /*Alloc a new inode*/
273 r = mfs_alloc_bit(inst, &inum, BMAP_INODE);
274 if (r != EOK)
275 return r;
276
277 struct mfs_ino_info *ino_i;
278
279 ino_i = malloc(sizeof(*ino_i));
280 if (!ino_i) {
281 r = ENOMEM;
282 goto out_err;
283 }
284
285 mnode = malloc(sizeof(*mnode));
286 if (!mnode) {
287 r = ENOMEM;
288 goto out_err_1;
289 }
290
291 fsnode = malloc(sizeof(fs_node_t));
292 if (!fsnode) {
293 r = ENOMEM;
294 goto out_err_2;
295 }
296
297 ino_i->i_mode = S_IFREG;
298 ino_i->i_nlinks = 1;
299 ino_i->i_uid = 0;
300 ino_i->i_gid = 0;
301 ino_i->i_size = 0;
302 ino_i->i_atime = 0;
303 ino_i->i_mtime = 0;
304 ino_i->i_ctime = 0;
305
306 memset(ino_i->i_dzone, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES);
307 memset(ino_i->i_izone, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES);
308
309 ino_i->index = inum;
310 ino_i->dirty = true;
311 mnode->ino_i = ino_i;
312 mnode->instance = inst;
313
314 put_inode(mnode);
315
316 fs_node_initialize(fsnode);
317 fsnode->data = mnode;
318 *rfn = fsnode;
319
320 return EOK;
321
322out_err_2:
323 free(mnode);
324out_err_1:
325 free(ino_i);
326out_err:
327 return r;
328}
329
330static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
331{
332 struct mfs_node *mnode = pfn->data;
333 struct mfs_ino_info *ino_i = mnode->ino_i;
334 struct mfs_dentry_info *d_info;
335
336 mfsdebug("mfs_match()\n");
337
338 if (!S_ISDIR(ino_i->i_mode))
339 return ENOTDIR;
340
341 struct mfs_sb_info *sbi = mnode->instance->sbi;
342 const size_t comp_size = str_size(component);
343
344 int i = 2;
345 while (1) {
346 d_info = read_directory_entry(mnode, i++);
347 if (!d_info) {
348 /*Reached the end of the directory entry list*/
349 break;
350 }
351
352 if (!d_info->d_inum) {
353 /*This entry is not used*/
354 free(d_info);
355 continue;
356 }
357
358 if (!bcmp(component, d_info->d_name, min(sbi->max_name_len,
359 comp_size))) {
360 /*Hit!*/
361 mfs_node_core_get(rfn, mnode->instance,
362 d_info->d_inum);
363 free(d_info);
364 goto found;
365 }
366 free(d_info);
367 }
368 *rfn = NULL;
369 return ENOENT;
370found:
371 return EOK;
372}
373
374static aoff64_t mfs_size_get(fs_node_t *node)
375{
376 assert(node);
377
378 const struct mfs_node *mnode = node->data;
379 assert(mnode);
380 assert(mnode->ino_i);
381
382 return mnode->ino_i->i_size;
383}
384
385void mfs_stat(ipc_callid_t rid, ipc_call_t *request)
386{
387 mfsdebug("mfs_stat()\n");
388 libfs_stat(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
389}
390
391static int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
392 fs_index_t index)
393{
394 int rc;
395 struct mfs_instance *instance;
396
397 rc = mfs_instance_get(devmap_handle, &instance);
398
399 if (rc != EOK)
400 return rc;
401
402 return mfs_node_core_get(rfn, instance, index);
403}
404
405static int mfs_node_put(fs_node_t *fsnode)
406{
407 struct mfs_node *mnode = fsnode->data;
408
409 put_inode(mnode);
410 free(mnode->ino_i);
411 free(mnode);
412
413 return EOK;
414}
415
416static int mfs_node_open(fs_node_t *fsnode)
417{
418 /*
419 * Opening a file is stateless, nothing
420 * to be done here.
421 */
422 return EOK;
423}
424
425static fs_index_t mfs_index_get(fs_node_t *fsnode)
426{
427 struct mfs_node *mnode = fsnode->data;
428
429 assert(mnode->ino_i);
430 return mnode->ino_i->index;
431}
432
433static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
434{
435 unsigned rc;
436 struct mfs_node *mnode = fsnode->data;
437
438 assert(mnode);
439 assert(mnode->ino_i);
440
441 rc = mnode->ino_i->i_nlinks;
442 return rc;
443}
444
445static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
446 fs_index_t index)
447{
448 fs_node_t *node = NULL;
449 struct mfs_node *mnode = NULL;
450 int rc;
451
452 node = malloc(sizeof(fs_node_t));
453 if (!node) {
454 rc = ENOMEM;
455 goto out_err;
456 }
457
458 fs_node_initialize(node);
459
460 mnode = malloc(sizeof(*mnode));
461 if (!mnode) {
462 rc = ENOMEM;
463 goto out_err;
464 }
465
466 struct mfs_ino_info *ino_i;
467
468 rc = get_inode(inst, &ino_i, index);
469 if (rc != EOK)
470 goto out_err;
471
472 ino_i->index = index;
473 mnode->ino_i = ino_i;
474
475 mnode->instance = inst;
476 node->data = mnode;
477 *rfn = node;
478
479 mfsdebug("node_get_core(%d) OK\n", (int) index);
480
481 return EOK;
482
483out_err:
484 if (node)
485 free(node);
486 if (mnode)
487 free(mnode);
488 return rc;
489}
490
491static bool mfs_is_directory(fs_node_t *fsnode)
492{
493 const struct mfs_node *node = fsnode->data;
494 return S_ISDIR(node->ino_i->i_mode);
495}
496
497static bool mfs_is_file(fs_node_t *fsnode)
498{
499 struct mfs_node *node = fsnode->data;
500 return S_ISREG(node->ino_i->i_mode);
501}
502
503static int mfs_root_get(fs_node_t **rfn, devmap_handle_t handle)
504{
505 int rc = mfs_node_get(rfn, handle, MFS_ROOT_INO);
506 return rc;
507}
508
509void mfs_lookup(ipc_callid_t rid, ipc_call_t *request)
510{
511 libfs_lookup(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
512}
513
514static char mfs_plb_get_char(unsigned pos)
515{
516 return mfs_reg.plb_ro[pos % PLB_SIZE];
517}
518
519static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
520{
521 mfsdebug("mfs_link()\n");
522 return ENOTSUP;
523}
524
525static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
526{
527 struct mfs_node *mnode = fsnode->data;
528
529 *has_children = false;
530
531 if (!S_ISDIR(mnode->ino_i->i_mode))
532 goto out;
533
534 struct mfs_dentry_info *d_info;
535
536 /* The first two dentries are always . and .. */
537 int i = 2;
538 while (1) {
539 d_info = read_directory_entry(mnode, i++);
540
541 if (!d_info) {
542 /*Reached the end of the dentries list*/
543 break;
544 }
545
546 if (d_info->d_inum) {
547 /*A valid entry has been found*/
548 *has_children = true;
549 free(d_info);
550 break;
551 }
552
553 free(d_info);
554 }
555
556out:
557
558 if (*has_children)
559 mfsdebug("Has children\n");
560 else
561 mfsdebug("Has not children\n");
562
563 return EOK;
564}
565
566void
567mfs_read(ipc_callid_t rid, ipc_call_t *request)
568{
569 int rc;
570 devmap_handle_t handle = (devmap_handle_t) IPC_GET_ARG1(*request);
571 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
572 aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request),
573 IPC_GET_ARG4(*request));
574 fs_node_t *fn;
575
576 rc = mfs_node_get(&fn, handle, index);
577 if (rc != EOK) {
578 async_answer_0(rid, rc);
579 return;
580 }
581 if (!fn) {
582 async_answer_0(rid, ENOENT);
583 return;
584 }
585
586 struct mfs_node *mnode;
587 struct mfs_ino_info *ino_i;
588 size_t len, bytes = 0;
589 ipc_callid_t callid;
590
591 mnode = fn->data;
592 ino_i = mnode->ino_i;
593
594 if (!async_data_read_receive(&callid, &len)) {
595 rc = EINVAL;
596 goto out_error;
597 }
598
599 if (S_ISDIR(ino_i->i_mode)) {
600 aoff64_t spos = pos;
601 struct mfs_dentry_info *d_info;
602
603 while (1) {
604 d_info = read_directory_entry(mnode, pos);
605 if (!d_info) {
606 /*Reached the end of the dentries list*/
607 break;
608 }
609
610 if (d_info->d_inum) {
611 /*Dentry found!*/
612 mfsdebug("DENTRY FOUND %s!!\n", d_info->d_name);
613 goto found;
614 }
615
616 free(d_info);
617 pos++;
618 }
619
620 rc = mfs_node_put(fn);
621 async_answer_0(callid, rc != EOK ? rc : ENOENT);
622 async_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
623 return;
624found:
625 async_data_read_finalize(callid, d_info->d_name,
626 str_size(d_info->d_name) + 1);
627 bytes = ((pos - spos) + 1);
628 } else {
629 struct mfs_sb_info *sbi = mnode->instance->sbi;
630
631 if (pos >= (size_t) ino_i->i_size) {
632 /*Trying to read beyond the end of file*/
633 bytes = 0;
634 (void) async_data_read_finalize(callid, NULL, 0);
635 goto out_success;
636 }
637
638 bytes = min(len, sbi->block_size - pos % sbi->block_size);
639 bytes = min(bytes, ino_i->i_size - pos);
640
641 uint32_t zone;
642 block_t *b;
643
644 rc = read_map(&zone, mnode, pos);
645 if (rc != EOK)
646 goto out_error;
647
648 if (zone == 0) {
649 /*sparse file*/
650 uint8_t *buf = malloc(sbi->block_size);
651 if (!buf) {
652 rc = ENOMEM;
653 goto out_error;
654 }
655 async_data_read_finalize(callid,
656 buf + pos % sbi->block_size, bytes);
657 free(buf);
658 goto out_success;
659 }
660
661 rc = block_get(&b, handle, zone, BLOCK_FLAGS_NONE);
662 if (rc != EOK)
663 goto out_error;
664
665 async_data_read_finalize(callid, b->data +
666 pos % sbi->block_size, bytes);
667
668 rc = block_put(b);
669 if (rc != EOK) {
670 mfs_node_put(fn);
671 async_answer_0(rid, rc);
672 return;
673 }
674 }
675out_success:
676 rc = mfs_node_put(fn);
677 async_answer_1(rid, rc, (sysarg_t)bytes);
678 return;
679out_error: ;
680 int tmp = mfs_node_put(fn);
681 async_answer_0(callid, tmp != EOK ? tmp : rc);
682 async_answer_0(rid, tmp != EOK ? tmp : rc);
683}
684
685int mfs_instance_get(devmap_handle_t handle, struct mfs_instance **instance)
686{
687 link_t *link;
688 struct mfs_instance *instance_ptr;
689
690 fibril_mutex_lock(&inst_list_mutex);
691
692 for (link = inst_list.next; link != &inst_list; link = link->next) {
693 instance_ptr = list_get_instance(link, struct mfs_instance,
694 link);
695
696 if (instance_ptr->handle == handle) {
697 *instance = instance_ptr;
698 fibril_mutex_unlock(&inst_list_mutex);
699 return EOK;
700 }
701 }
702
703 mfsdebug("Instance not found\n");
704
705 fibril_mutex_unlock(&inst_list_mutex);
706 return EINVAL;
707}
708
709static bool check_magic_number(uint16_t magic, bool *native,
710 mfs_version_t *version, bool *longfilenames)
711{
712 bool rc = false;
713 *longfilenames = false;
714
715 if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
716 *native = magic == MFS_MAGIC_V1;
717 *version = MFS_VERSION_V1;
718 rc = true;
719 } else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
720 *native = magic == MFS_MAGIC_V1L;
721 *version = MFS_VERSION_V1;
722 *longfilenames = true;
723 rc = true;
724 } else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
725 *native = magic == MFS_MAGIC_V2;
726 *version = MFS_VERSION_V2;
727 rc = true;
728 } else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
729 *native = magic == MFS_MAGIC_V2L;
730 *version = MFS_VERSION_V2;
731 *longfilenames = true;
732 rc = true;
733 } else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
734 *native = magic == MFS_MAGIC_V3;
735 *version = MFS_VERSION_V3;
736 rc = true;
737 }
738
739 return rc;
740}
741
742/**
743 * @}
744 */
745
Note: See TracBrowser for help on using the repository browser.