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

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

Minixfs file deletion feature is complete but not yet stable.

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