source: mainline/uspace/srv/fs/ext2fs/ext2fs_ops.c@ d1ac0d7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d1ac0d7 was d1ac0d7, checked in by Martin Sucha <sucha14@…>, 15 years ago

Fixed bugs with mounting

  • Property mode set to 100644
File size: 24.7 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * Copyright (c) 2011 Martin Sucha
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup fs
31 * @{
32 */
33
34/**
35 * @file ext2fs_ops.c
36 * @brief Implementation of VFS operations for the EXT2 file system server.
37 */
38
39#include "ext2fs.h"
40#include "../../vfs/vfs.h"
41#include <libfs.h>
42#include <libblock.h>
43#include <libext2.h>
44#include <ipc/services.h>
45#include <ipc/devmap.h>
46#include <macros.h>
47#include <async.h>
48#include <errno.h>
49#include <str.h>
50#include <byteorder.h>
51#include <adt/hash_table.h>
52#include <adt/list.h>
53#include <assert.h>
54#include <fibril_synch.h>
55#include <sys/mman.h>
56#include <align.h>
57#include <adt/hash_table.h>
58#include <sys/typefmt.h>
59#include <malloc.h>
60#include <stdio.h>
61
62#define EXT2FS_NODE(node) ((node) ? (ext2fs_node_t *) (node)->data : NULL)
63#define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
64#define OPEN_NODES_KEYS 2
65#define OPEN_NODES_DEV_HANDLE_KEY 0
66#define OPEN_NODES_INODE_KEY 1
67#define OPEN_NODES_BUCKETS 256
68
69typedef struct ext2fs_instance {
70 link_t link;
71 devmap_handle_t devmap_handle;
72 ext2_filesystem_t *filesystem;
73 unsigned int open_nodes_count;
74} ext2fs_instance_t;
75
76typedef struct ext2fs_node {
77 ext2fs_instance_t *instance;
78 ext2_inode_ref_t *inode_ref;
79 fs_node_t *fs_node;
80 link_t link;
81 unsigned int references;
82} ext2fs_node_t;
83
84/*
85 * Forward declarations of auxiliary functions
86 */
87static int ext2fs_instance_get(devmap_handle_t, ext2fs_instance_t **);
88static void ext2fs_read_directory(ipc_callid_t, ipc_callid_t, aoff64_t,
89 size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
90static void ext2fs_read_file(ipc_callid_t, ipc_callid_t, aoff64_t,
91 size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
92static bool ext2fs_is_dots(const uint8_t *, size_t);
93static int ext2fs_node_get_core(fs_node_t **, ext2fs_instance_t *, fs_index_t);
94static int ext2fs_node_put_core(ext2fs_node_t *);
95
96/*
97 * Forward declarations of EXT2 libfs operations.
98 */
99static int ext2fs_root_get(fs_node_t **, devmap_handle_t);
100static int ext2fs_match(fs_node_t **, fs_node_t *, const char *);
101static int ext2fs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
102static int ext2fs_node_open(fs_node_t *);
103static int ext2fs_node_put(fs_node_t *);
104static int ext2fs_create_node(fs_node_t **, devmap_handle_t, int);
105static int ext2fs_destroy_node(fs_node_t *);
106static int ext2fs_link(fs_node_t *, fs_node_t *, const char *);
107static int ext2fs_unlink(fs_node_t *, fs_node_t *, const char *);
108static int ext2fs_has_children(bool *, fs_node_t *);
109static fs_index_t ext2fs_index_get(fs_node_t *);
110static aoff64_t ext2fs_size_get(fs_node_t *);
111static unsigned ext2fs_lnkcnt_get(fs_node_t *);
112static char ext2fs_plb_get_char(unsigned);
113static bool ext2fs_is_directory(fs_node_t *);
114static bool ext2fs_is_file(fs_node_t *node);
115static devmap_handle_t ext2fs_device_get(fs_node_t *node);
116
117/*
118 * Static variables
119 */
120static LIST_INITIALIZE(instance_list);
121static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
122static hash_table_t open_nodes;
123static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
124
125/* Hash table interface for open nodes hash table */
126static hash_index_t open_nodes_hash(unsigned long key[])
127{
128 /* TODO: This is very simple and probably can be improved */
129 return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
130}
131
132static int open_nodes_compare(unsigned long key[], hash_count_t keys,
133 link_t *item)
134{
135 ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
136 assert(keys > 0);
137 if (enode->instance->devmap_handle !=
138 ((devmap_handle_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
139 return false;
140 }
141 if (keys == 1) {
142 return true;
143 }
144 assert(keys == 2);
145 return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
146}
147
148static void open_nodes_remove_cb(link_t *link)
149{
150 /* We don't use remove callback for this hash table */
151}
152
153static hash_table_operations_t open_nodes_ops = {
154 .hash = open_nodes_hash,
155 .compare = open_nodes_compare,
156 .remove_callback = open_nodes_remove_cb,
157};
158
159/**
160 *
161 */
162int ext2fs_global_init(void)
163{
164 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
165 OPEN_NODES_KEYS, &open_nodes_ops)) {
166 return ENOMEM;
167 }
168 return EOK;
169}
170
171int ext2fs_global_fini(void)
172{
173 hash_table_destroy(&open_nodes);
174 return EOK;
175}
176
177
178/*
179 * EXT2 libfs operations.
180 */
181
182/**
183 * Find an instance of filesystem for the given devmap_handle
184 */
185int ext2fs_instance_get(devmap_handle_t devmap_handle, ext2fs_instance_t **inst)
186{
187 EXT2FS_DBG("(%u, -)", devmap_handle);
188 link_t *link;
189 ext2fs_instance_t *tmp;
190
191 fibril_mutex_lock(&instance_list_mutex);
192
193 if (list_empty(&instance_list)) {
194 EXT2FS_DBG("list empty");
195 fibril_mutex_unlock(&instance_list_mutex);
196 return EINVAL;
197 }
198
199 for (link = instance_list.next; link != &instance_list; link = link->next) {
200 tmp = list_get_instance(link, ext2fs_instance_t, link);
201
202 if (tmp->devmap_handle == devmap_handle) {
203 *inst = tmp;
204 fibril_mutex_unlock(&instance_list_mutex);
205 return EOK;
206 }
207 }
208
209 EXT2FS_DBG("not found");
210
211 fibril_mutex_unlock(&instance_list_mutex);
212 return EINVAL;
213}
214
215
216
217int ext2fs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
218{
219 EXT2FS_DBG("(-, %u)", devmap_handle);
220 return ext2fs_node_get(rfn, devmap_handle, EXT2_INODE_ROOT_INDEX);
221}
222
223int ext2fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
224{
225 EXT2FS_DBG("(-,-,%s)", component);
226 ext2fs_node_t *eparent = EXT2FS_NODE(pfn);
227 ext2_filesystem_t *fs;
228 ext2_directory_iterator_t it;
229 int rc;
230 size_t name_size;
231 size_t component_size;
232 bool found = false;
233
234 fs = eparent->instance->filesystem;
235
236 if (!ext2_inode_is_type(fs->superblock, eparent->inode_ref->inode,
237 EXT2_INODE_MODE_DIRECTORY)) {
238 return ENOTDIR;
239 }
240
241 rc = ext2_directory_iterator_init(&it, fs, eparent->inode_ref);
242 if (rc != EOK) {
243 return rc;
244 }
245
246 // Find length of component in bytes
247 // TODO: check for library function call that does this
248 component_size = 0;
249 while (*(component+component_size) != 0) {
250 component_size++;
251 }
252
253 while (it.current != NULL) {
254 // ignore empty directory entries
255 if (it.current->inode != 0) {
256 name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
257 it.current);
258
259 if (name_size == component_size && bcmp(component, &it.current->name,
260 name_size) == 0) {
261 rc = ext2fs_node_get_core(rfn, eparent->instance,
262 it.current->inode);
263 if (rc != EOK) {
264 ext2_directory_iterator_fini(&it);
265 return rc;
266 }
267 found = true;
268 break;
269 }
270 }
271
272 rc = ext2_directory_iterator_next(&it);
273 if (rc != EOK) {
274 ext2_directory_iterator_fini(&it);
275 return rc;
276 }
277 }
278
279 ext2_directory_iterator_fini(&it);
280
281 if (!found) {
282 return ENOENT;
283 }
284
285 return EOK;
286}
287
288/** Instantiate a EXT2 in-core node. */
289int ext2fs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
290{
291 EXT2FS_DBG("(-,%u,%u)", devmap_handle, index);
292
293 ext2fs_instance_t *inst = NULL;
294 int rc;
295
296 rc = ext2fs_instance_get(devmap_handle, &inst);
297 if (rc != EOK) {
298 return rc;
299 }
300
301 return ext2fs_node_get_core(rfn, inst, index);
302}
303
304int ext2fs_node_get_core(fs_node_t **rfn, ext2fs_instance_t *inst,
305 fs_index_t index)
306{
307 int rc;
308 fs_node_t *node = NULL;
309 ext2fs_node_t *enode = NULL;
310
311 ext2_inode_ref_t *inode_ref = NULL;
312
313 fibril_mutex_lock(&open_nodes_lock);
314
315 /* Check if the node is not already open */
316 unsigned long key[] = {
317 [OPEN_NODES_DEV_HANDLE_KEY] = inst->devmap_handle,
318 [OPEN_NODES_INODE_KEY] = index,
319 };
320 link_t *already_open = hash_table_find(&open_nodes, key);
321
322 if (already_open) {
323 enode = hash_table_get_instance(already_open, ext2fs_node_t, link);
324 *rfn = enode->fs_node;
325 enode->references++;
326
327 fibril_mutex_unlock(&open_nodes_lock);
328 return EOK;
329 }
330
331 enode = malloc(sizeof(ext2fs_node_t));
332 if (enode == NULL) {
333 fibril_mutex_unlock(&open_nodes_lock);
334 return ENOMEM;
335 }
336
337 node = malloc(sizeof(fs_node_t));
338 if (node == NULL) {
339 free(enode);
340 fibril_mutex_unlock(&open_nodes_lock);
341 return ENOMEM;
342 }
343 fs_node_initialize(node);
344
345 rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
346 if (rc != EOK) {
347 free(enode);
348 free(node);
349 fibril_mutex_unlock(&open_nodes_lock);
350 return rc;
351 }
352
353 enode->inode_ref = inode_ref;
354 enode->instance = inst;
355 enode->references = 1;
356 enode->fs_node = node;
357 link_initialize(&enode->link);
358
359 node->data = enode;
360 *rfn = node;
361
362 hash_table_insert(&open_nodes, key, &enode->link);
363 inst->open_nodes_count++;
364
365 EXT2FS_DBG("inode: %u", inode_ref->index);
366
367 EXT2FS_DBG("EOK");
368
369 fibril_mutex_unlock(&open_nodes_lock);
370 return EOK;
371}
372
373int ext2fs_node_open(fs_node_t *fn)
374{
375 EXT2FS_DBG("");
376 /*
377 * Opening a file is stateless, nothing
378 * to be done here.
379 */
380 return EOK;
381}
382
383int ext2fs_node_put(fs_node_t *fn)
384{
385 EXT2FS_DBG("");
386 int rc;
387 ext2fs_node_t *enode = EXT2FS_NODE(fn);
388
389 fibril_mutex_lock(&open_nodes_lock);
390
391 assert(enode->references > 0);
392 enode->references--;
393 if (enode->references == 0) {
394 rc = ext2fs_node_put_core(enode);
395 if (rc != EOK) {
396 fibril_mutex_unlock(&open_nodes_lock);
397 return rc;
398 }
399 }
400
401 fibril_mutex_unlock(&open_nodes_lock);
402
403 return EOK;
404}
405
406int ext2fs_node_put_core(ext2fs_node_t *enode)
407{
408 int rc;
409
410 unsigned long key[] = {
411 [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->devmap_handle,
412 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
413 };
414 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
415 assert(enode->instance->open_nodes_count > 0);
416 enode->instance->open_nodes_count--;
417
418 rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
419 if (rc != EOK) {
420 EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
421 return rc;
422 }
423
424 free(enode->fs_node);
425 free(enode);
426 return EOK;
427}
428
429int ext2fs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
430{
431 EXT2FS_DBG("");
432 // TODO
433 return ENOTSUP;
434}
435
436int ext2fs_destroy_node(fs_node_t *fn)
437{
438 EXT2FS_DBG("");
439 // TODO
440 return ENOTSUP;
441}
442
443int ext2fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
444{
445 EXT2FS_DBG("");
446 // TODO
447 return ENOTSUP;
448}
449
450int ext2fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
451{
452 EXT2FS_DBG("");
453 // TODO
454 return ENOTSUP;
455}
456
457int ext2fs_has_children(bool *has_children, fs_node_t *fn)
458{
459 EXT2FS_DBG("");
460 ext2fs_node_t *enode = EXT2FS_NODE(fn);
461 ext2_directory_iterator_t it;
462 ext2_filesystem_t *fs;
463 int rc;
464 bool found = false;
465 size_t name_size;
466
467 fs = enode->instance->filesystem;
468
469 if (!ext2_inode_is_type(fs->superblock, enode->inode_ref->inode,
470 EXT2_INODE_MODE_DIRECTORY)) {
471 *has_children = false;
472 EXT2FS_DBG("EOK - false");
473 return EOK;
474 }
475
476 rc = ext2_directory_iterator_init(&it, fs, enode->inode_ref);
477 if (rc != EOK) {
478 EXT2FS_DBG("error %u", rc);
479 return rc;
480 }
481
482 // Find a non-empty directory entry
483 while (it.current != NULL) {
484 if (it.current->inode != 0) {
485 name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
486 it.current);
487 if (!ext2fs_is_dots(&it.current->name, name_size)) {
488 found = true;
489 break;
490 }
491 }
492
493 rc = ext2_directory_iterator_next(&it);
494 if (rc != EOK) {
495 ext2_directory_iterator_fini(&it);
496 EXT2FS_DBG("error %u", rc);
497 return rc;
498 }
499 }
500
501 rc = ext2_directory_iterator_fini(&it);
502 if (rc != EOK) {
503 EXT2FS_DBG("error %u", rc);
504 return rc;
505 }
506
507 *has_children = found;
508 EXT2FS_DBG("EOK");
509
510 return EOK;
511}
512
513
514fs_index_t ext2fs_index_get(fs_node_t *fn)
515{
516 ext2fs_node_t *enode = EXT2FS_NODE(fn);
517 EXT2FS_DBG("%u", enode->inode_ref->index);
518 return enode->inode_ref->index;
519}
520
521aoff64_t ext2fs_size_get(fs_node_t *fn)
522{
523 ext2fs_node_t *enode = EXT2FS_NODE(fn);
524 aoff64_t size = ext2_inode_get_size(enode->instance->filesystem->superblock,
525 enode->inode_ref->inode);
526 EXT2FS_DBG("%" PRIu64, size);
527 return size;
528}
529
530unsigned ext2fs_lnkcnt_get(fs_node_t *fn)
531{
532 ext2fs_node_t *enode = EXT2FS_NODE(fn);
533 unsigned count = ext2_inode_get_usage_count(enode->inode_ref->inode);
534 EXT2FS_DBG("%u", count);
535 return count;
536}
537
538char ext2fs_plb_get_char(unsigned pos)
539{
540 return ext2fs_reg.plb_ro[pos % PLB_SIZE];
541}
542
543bool ext2fs_is_directory(fs_node_t *fn)
544{
545 ext2fs_node_t *enode = EXT2FS_NODE(fn);
546 bool is_dir = ext2_inode_is_type(enode->instance->filesystem->superblock,
547 enode->inode_ref->inode, EXT2_INODE_MODE_DIRECTORY);
548 EXT2FS_DBG("%s", is_dir ? "true" : "false");
549 EXT2FS_DBG("%u", enode->inode_ref->index);
550 return is_dir;
551}
552
553bool ext2fs_is_file(fs_node_t *fn)
554{
555 ext2fs_node_t *enode = EXT2FS_NODE(fn);
556 bool is_file = ext2_inode_is_type(enode->instance->filesystem->superblock,
557 enode->inode_ref->inode, EXT2_INODE_MODE_FILE);
558 EXT2FS_DBG("%s", is_file ? "true" : "false");
559 return is_file;
560}
561
562devmap_handle_t ext2fs_device_get(fs_node_t *fn)
563{
564 EXT2FS_DBG("");
565 ext2fs_node_t *enode = EXT2FS_NODE(fn);
566 return enode->instance->devmap_handle;
567}
568
569/** libfs operations */
570libfs_ops_t ext2fs_libfs_ops = {
571 .root_get = ext2fs_root_get,
572 .match = ext2fs_match,
573 .node_get = ext2fs_node_get,
574 .node_open = ext2fs_node_open,
575 .node_put = ext2fs_node_put,
576 .create = ext2fs_create_node,
577 .destroy = ext2fs_destroy_node,
578 .link = ext2fs_link,
579 .unlink = ext2fs_unlink,
580 .has_children = ext2fs_has_children,
581 .index_get = ext2fs_index_get,
582 .size_get = ext2fs_size_get,
583 .lnkcnt_get = ext2fs_lnkcnt_get,
584 .plb_get_char = ext2fs_plb_get_char,
585 .is_directory = ext2fs_is_directory,
586 .is_file = ext2fs_is_file,
587 .device_get = ext2fs_device_get
588};
589
590/*
591 * VFS operations.
592 */
593
594void ext2fs_mounted(ipc_callid_t rid, ipc_call_t *request)
595{
596 EXT2FS_DBG("");
597 int rc;
598 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
599 ext2_filesystem_t *fs;
600 ext2fs_instance_t *inst;
601 bool read_only;
602
603 /* Accept the mount options */
604 char *opts;
605 rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
606
607 if (rc != EOK) {
608 async_answer_0(rid, rc);
609 return;
610 }
611
612 free(opts);
613
614 /* Allocate libext2 filesystem structure */
615 fs = (ext2_filesystem_t *) malloc(sizeof(ext2_filesystem_t));
616 if (fs == NULL) {
617 async_answer_0(rid, ENOMEM);
618 return;
619 }
620
621 /* Allocate instance structure */
622 inst = (ext2fs_instance_t *) malloc(sizeof(ext2fs_instance_t));
623 if (inst == NULL) {
624 free(fs);
625 async_answer_0(rid, ENOMEM);
626 return;
627 }
628
629 /* Initialize the filesystem */
630 rc = ext2_filesystem_init(fs, devmap_handle);
631 if (rc != EOK) {
632 free(fs);
633 free(inst);
634 async_answer_0(rid, rc);
635 return;
636 }
637
638 /* Do some sanity checking */
639 rc = ext2_filesystem_check_sanity(fs);
640 if (rc != EOK) {
641 ext2_filesystem_fini(fs);
642 free(fs);
643 free(inst);
644 async_answer_0(rid, rc);
645 return;
646 }
647
648 /* Check flags */
649 rc = ext2_filesystem_check_flags(fs, &read_only);
650 if (rc != EOK) {
651 ext2_filesystem_fini(fs);
652 free(fs);
653 free(inst);
654 async_answer_0(rid, rc);
655 return;
656 }
657
658 /* Initialize instance */
659 link_initialize(&inst->link);
660 inst->devmap_handle = devmap_handle;
661 inst->filesystem = fs;
662 inst->open_nodes_count = 0;
663
664 /* Read root node */
665 fs_node_t *root_node;
666 rc = ext2fs_node_get_core(&root_node, inst, EXT2_INODE_ROOT_INDEX);
667 if (rc != EOK) {
668 ext2_filesystem_fini(fs);
669 free(fs);
670 free(inst);
671 async_answer_0(rid, rc);
672 return;
673 }
674 ext2fs_node_t *enode = EXT2FS_NODE(root_node);
675
676 /* Add instance to the list */
677 fibril_mutex_lock(&instance_list_mutex);
678 list_append(&inst->link, &instance_list);
679 fibril_mutex_unlock(&instance_list_mutex);
680
681 async_answer_3(rid, EOK,
682 EXT2_INODE_ROOT_INDEX,
683 0,
684 ext2_inode_get_usage_count(enode->inode_ref->inode));
685
686 ext2fs_node_put(root_node);
687}
688
689void ext2fs_mount(ipc_callid_t rid, ipc_call_t *request)
690{
691 EXT2FS_DBG("");
692 libfs_mount(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
693}
694
695void ext2fs_unmounted(ipc_callid_t rid, ipc_call_t *request)
696{
697 EXT2FS_DBG("");
698 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
699 ext2fs_instance_t *inst;
700 int rc;
701
702 rc = ext2fs_instance_get(devmap_handle, &inst);
703
704 if (rc != EOK) {
705 async_answer_0(rid, rc);
706 return;
707 }
708
709 fibril_mutex_lock(&open_nodes_lock);
710
711 EXT2FS_DBG("open_nodes_count = %d", inst->open_nodes_count)
712 if (inst->open_nodes_count != 0) {
713 fibril_mutex_unlock(&open_nodes_lock);
714 async_answer_0(rid, EBUSY);
715 return;
716 }
717
718 // Remove the instance from list
719 fibril_mutex_lock(&instance_list_mutex);
720 list_remove(&inst->link);
721 fibril_mutex_unlock(&instance_list_mutex);
722
723 fibril_mutex_unlock(&open_nodes_lock);
724
725 ext2_filesystem_fini(inst->filesystem);
726
727 async_answer_0(rid, EOK);
728}
729
730void ext2fs_unmount(ipc_callid_t rid, ipc_call_t *request)
731{
732 EXT2FS_DBG("");
733 libfs_unmount(&ext2fs_libfs_ops, rid, request);
734}
735
736void ext2fs_lookup(ipc_callid_t rid, ipc_call_t *request)
737{
738 EXT2FS_DBG("");
739 libfs_lookup(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
740}
741
742void ext2fs_read(ipc_callid_t rid, ipc_call_t *request)
743{
744 EXT2FS_DBG("");
745 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
746 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
747 aoff64_t pos =
748 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
749
750 ext2fs_instance_t *inst;
751 ext2_inode_ref_t *inode_ref;
752 int rc;
753
754 /*
755 * Receive the read request.
756 */
757 ipc_callid_t callid;
758 size_t size;
759 if (!async_data_read_receive(&callid, &size)) {
760 async_answer_0(callid, EINVAL);
761 async_answer_0(rid, EINVAL);
762 return;
763 }
764
765 rc = ext2fs_instance_get(devmap_handle, &inst);
766 if (rc != EOK) {
767 async_answer_0(callid, rc);
768 async_answer_0(rid, rc);
769 return;
770 }
771
772 rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
773 if (rc != EOK) {
774 async_answer_0(callid, rc);
775 async_answer_0(rid, rc);
776 return;
777 }
778
779 if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
780 EXT2_INODE_MODE_FILE)) {
781 ext2fs_read_file(rid, callid, pos, size, inst, inode_ref);
782 }
783 else if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
784 EXT2_INODE_MODE_DIRECTORY)) {
785 ext2fs_read_directory(rid, callid, pos, size, inst, inode_ref);
786 }
787 else {
788 // Other inode types not supported
789 async_answer_0(callid, ENOTSUP);
790 async_answer_0(rid, ENOTSUP);
791 }
792
793 ext2_filesystem_put_inode_ref(inode_ref);
794
795}
796
797/**
798 * Determine whether given directory entry name is . or ..
799 */
800bool ext2fs_is_dots(const uint8_t *name, size_t name_size) {
801 if (name_size == 1 && name[0] == '.') {
802 return true;
803 }
804
805 if (name_size == 2 && name[0] == '.' && name[1] == '.') {
806 return true;
807 }
808
809 return false;
810}
811
812void ext2fs_read_directory(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
813 size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
814{
815 ext2_directory_iterator_t it;
816 aoff64_t cur;
817 uint8_t *buf;
818 size_t name_size;
819 int rc;
820 bool found = false;
821
822 rc = ext2_directory_iterator_init(&it, inst->filesystem, inode_ref);
823 if (rc != EOK) {
824 async_answer_0(callid, rc);
825 async_answer_0(rid, rc);
826 return;
827 }
828
829 // Find the index we want to read
830 // Note that we need to iterate and count as
831 // the underlying structure is a linked list
832 // Moreover, we want to skip . and .. entries
833 // as these are not used in HelenOS
834 cur = 0;
835 while (it.current != NULL) {
836 if (it.current->inode == 0) {
837 goto skip;
838 }
839
840 name_size = ext2_directory_entry_ll_get_name_length(
841 inst->filesystem->superblock, it.current);
842
843 // skip . and ..
844 if (ext2fs_is_dots(&it.current->name, name_size)) {
845 goto skip;
846 }
847
848 // Is this the dir entry we want to read?
849 if (cur == pos) {
850 // The on-disk entry does not contain \0 at the end
851 // end of entry name, so we copy it to new buffer
852 // and add the \0 at the end
853 buf = malloc(name_size+1);
854 if (buf == NULL) {
855 ext2_directory_iterator_fini(&it);
856 async_answer_0(callid, ENOMEM);
857 async_answer_0(rid, ENOMEM);
858 return;
859 }
860 memcpy(buf, &it.current->name, name_size);
861 *(buf+name_size) = 0;
862 found = true;
863 (void) async_data_read_finalize(callid, buf, name_size+1);
864 free(buf);
865 break;
866 }
867 cur++;
868
869skip:
870 rc = ext2_directory_iterator_next(&it);
871 if (rc != EOK) {
872 ext2_directory_iterator_fini(&it);
873 async_answer_0(callid, rc);
874 async_answer_0(rid, rc);
875 return;
876 }
877 }
878
879 rc = ext2_directory_iterator_fini(&it);
880 if (rc != EOK) {
881 async_answer_0(rid, rc);
882 return;
883 }
884
885 if (found) {
886 async_answer_1(rid, EOK, 1);
887 }
888 else {
889 async_answer_0(callid, ENOENT);
890 async_answer_0(rid, ENOENT);
891 }
892}
893
894void ext2fs_read_file(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
895 size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
896{
897 int rc;
898 uint32_t block_size;
899 aoff64_t file_block;
900 uint64_t file_size;
901 uint32_t fs_block;
902 size_t offset_in_block;
903 size_t bytes;
904 block_t *block;
905 uint8_t *buffer;
906
907 file_size = ext2_inode_get_size(inst->filesystem->superblock,
908 inode_ref->inode);
909
910 if (pos >= file_size) {
911 // Read 0 bytes successfully
912 async_data_read_finalize(callid, NULL, 0);
913 async_answer_1(rid, EOK, 0);
914 return;
915 }
916
917 // For now, we only read data from one block at a time
918 block_size = ext2_superblock_get_block_size(inst->filesystem->superblock);
919 file_block = pos / block_size;
920 offset_in_block = pos % block_size;
921 bytes = min(block_size - offset_in_block, size);
922
923 // Handle end of file
924 if (pos + bytes > file_size) {
925 bytes = file_size - pos;
926 }
927
928 rc = ext2_filesystem_get_inode_data_block_index(inst->filesystem,
929 inode_ref->inode, file_block, &fs_block);
930 if (rc != EOK) {
931 async_answer_0(callid, rc);
932 async_answer_0(rid, rc);
933 return;
934 }
935
936 // Check for sparse file
937 // If ext2_filesystem_get_inode_data_block_index returned
938 // fs_block == 0, it means that the given block is not allocated for the
939 // file and we need to return a buffer of zeros
940 if (fs_block == 0) {
941 buffer = malloc(bytes);
942 if (buffer == NULL) {
943 async_answer_0(callid, ENOMEM);
944 async_answer_0(rid, ENOMEM);
945 return;
946 }
947
948 memset(buffer, 0, bytes);
949
950 async_data_read_finalize(callid, buffer, bytes);
951 async_answer_1(rid, EOK, bytes);
952
953 free(buffer);
954
955 return;
956 }
957
958 // Usual case - we need to read a block from device
959 rc = block_get(&block, inst->devmap_handle, fs_block, BLOCK_FLAGS_NONE);
960 if (rc != EOK) {
961 async_answer_0(callid, rc);
962 async_answer_0(rid, rc);
963 return;
964 }
965
966 assert(offset_in_block + bytes <= block_size);
967 async_data_read_finalize(callid, block->data + offset_in_block, bytes);
968
969 rc = block_put(block);
970 if (rc != EOK) {
971 async_answer_0(rid, rc);
972 return;
973 }
974
975 async_answer_1(rid, EOK, bytes);
976}
977
978void ext2fs_write(ipc_callid_t rid, ipc_call_t *request)
979{
980 EXT2FS_DBG("");
981// devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
982// fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
983// aoff64_t pos =
984// (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
985
986 // TODO
987 async_answer_0(rid, ENOTSUP);
988}
989
990void ext2fs_truncate(ipc_callid_t rid, ipc_call_t *request)
991{
992 EXT2FS_DBG("");
993// devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
994// fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
995// aoff64_t size =
996// (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
997
998 // TODO
999 async_answer_0(rid, ENOTSUP);
1000}
1001
1002void ext2fs_close(ipc_callid_t rid, ipc_call_t *request)
1003{
1004 EXT2FS_DBG("");
1005 async_answer_0(rid, EOK);
1006}
1007
1008void ext2fs_destroy(ipc_callid_t rid, ipc_call_t *request)
1009{
1010 EXT2FS_DBG("");
1011// devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
1012// fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
1013
1014 // TODO
1015 async_answer_0(rid, ENOTSUP);
1016}
1017
1018void ext2fs_open_node(ipc_callid_t rid, ipc_call_t *request)
1019{
1020 EXT2FS_DBG("");
1021 libfs_open_node(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
1022}
1023
1024void ext2fs_stat(ipc_callid_t rid, ipc_call_t *request)
1025{
1026 EXT2FS_DBG("");
1027 libfs_stat(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
1028}
1029
1030void ext2fs_sync(ipc_callid_t rid, ipc_call_t *request)
1031{
1032 EXT2FS_DBG("");
1033// devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
1034// fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
1035
1036 // TODO
1037 async_answer_0(rid, ENOTSUP);
1038}
1039
1040/**
1041 * @}
1042 */
Note: See TracBrowser for help on using the repository browser.