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

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

Coding style and comments

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