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

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

Fix ext2 on big-endian machines

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