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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 15f3c3f was 15f3c3f, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Rename devmap to loc, devfs to locfs.

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