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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9f4067b6 was 4e00f87, checked in by Jakub Jermar <jakub@…>, 13 years ago

Use NULL instead of 0 as a hash_table_ops_t member initializer.

  • Property mode set to 100644
File size: 22.2 KB
RevLine 
[796c276]1/*
2 * Copyright (c) 2011 Martin Sucha
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33/**
34 * @file ext2fs_ops.c
35 * @brief Implementation of VFS operations for the EXT2 file system server.
36 */
37
38#include "ext2fs.h"
39#include "../../vfs/vfs.h"
40#include <libfs.h>
[f73b291]41#include <block.h>
[796c276]42#include <libext2.h>
43#include <ipc/services.h>
[15f3c3f]44#include <ipc/loc.h>
[796c276]45#include <macros.h>
46#include <async.h>
47#include <errno.h>
48#include <str.h>
49#include <byteorder.h>
50#include <adt/hash_table.h>
[062d900]51#include <adt/hash.h>
[796c276]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__);}
[796c276]65
[4dc6a32]66typedef struct ext2fs_instance {
67 link_t link;
[15f3c3f]68 service_id_t service_id;
[4dc6a32]69 ext2_filesystem_t *filesystem;
[d1ac0d7]70 unsigned int open_nodes_count;
[4dc6a32]71} ext2fs_instance_t;
72
73typedef struct ext2fs_node {
74 ext2fs_instance_t *instance;
75 ext2_inode_ref_t *inode_ref;
[d1ac0d7]76 fs_node_t *fs_node;
[062d900]77 ht_link_t link;
[d1ac0d7]78 unsigned int references;
[4dc6a32]79} ext2fs_node_t;
80
[e2abab03]81/*
82 * Forward declarations of auxiliary functions
83 */
[15f3c3f]84static int ext2fs_instance_get(service_id_t, ext2fs_instance_t **);
[efcebe1]85static int ext2fs_read_directory(ipc_callid_t, aoff64_t, size_t,
86 ext2fs_instance_t *, ext2_inode_ref_t *, size_t *);
87static int ext2fs_read_file(ipc_callid_t, aoff64_t, size_t, ext2fs_instance_t *,
88 ext2_inode_ref_t *, size_t *);
[84226f0]89static bool ext2fs_is_dots(const uint8_t *, size_t);
[e2abab03]90static int ext2fs_node_get_core(fs_node_t **, ext2fs_instance_t *, fs_index_t);
[d1ac0d7]91static int ext2fs_node_put_core(ext2fs_node_t *);
[796c276]92
93/*
94 * Forward declarations of EXT2 libfs operations.
95 */
[15f3c3f]96static int ext2fs_root_get(fs_node_t **, service_id_t);
[796c276]97static int ext2fs_match(fs_node_t **, fs_node_t *, const char *);
[15f3c3f]98static int ext2fs_node_get(fs_node_t **, service_id_t, fs_index_t);
[796c276]99static int ext2fs_node_open(fs_node_t *);
100static int ext2fs_node_put(fs_node_t *);
[15f3c3f]101static int ext2fs_create_node(fs_node_t **, service_id_t, int);
[796c276]102static int ext2fs_destroy_node(fs_node_t *);
103static int ext2fs_link(fs_node_t *, fs_node_t *, const char *);
104static int ext2fs_unlink(fs_node_t *, fs_node_t *, const char *);
105static int ext2fs_has_children(bool *, fs_node_t *);
106static fs_index_t ext2fs_index_get(fs_node_t *);
107static aoff64_t ext2fs_size_get(fs_node_t *);
108static unsigned ext2fs_lnkcnt_get(fs_node_t *);
109static bool ext2fs_is_directory(fs_node_t *);
110static bool ext2fs_is_file(fs_node_t *node);
[b33870b]111static service_id_t ext2fs_service_get(fs_node_t *node);
[796c276]112
113/*
114 * Static variables
115 */
[4dc6a32]116static LIST_INITIALIZE(instance_list);
[a210bc7]117static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
[d1ac0d7]118static hash_table_t open_nodes;
119static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
120
[062d900]121/*
122 * Hash table interface for open nodes hash table
123 */
124
125typedef struct {
126 service_id_t service_id;
127 fs_index_t index;
128} node_key_t;
129
130static size_t open_nodes_key_hash(void *key)
[d1ac0d7]131{
[062d900]132 node_key_t *node_key = (node_key_t*)key;
133 return hash_combine(node_key->service_id, node_key->index);
[d1ac0d7]134}
135
[062d900]136static size_t open_nodes_hash(const ht_link_t *item)
[d1ac0d7]137{
[062d900]138 ext2fs_node_t *enode = hash_table_get_inst(item, ext2fs_node_t, link);
139
140 assert(enode->instance);
141 assert(enode->inode_ref);
142
143 return hash_combine(enode->instance->service_id, enode->inode_ref->index);
[d1ac0d7]144}
145
[062d900]146static bool open_nodes_key_equal(void *key, const ht_link_t *item)
[d1ac0d7]147{
[062d900]148 node_key_t *node_key = (node_key_t*)key;
149 ext2fs_node_t *enode = hash_table_get_inst(item, ext2fs_node_t, link);
150
151 return node_key->service_id == enode->instance->service_id
152 && node_key->index == enode->inode_ref->index;
[d1ac0d7]153}
154
[062d900]155static hash_table_ops_t open_nodes_ops = {
[d1ac0d7]156 .hash = open_nodes_hash,
[062d900]157 .key_hash = open_nodes_key_hash,
158 .key_equal = open_nodes_key_equal,
[4e00f87]159 .equal = NULL,
160 .remove_callback = NULL,
[d1ac0d7]161};
[796c276]162
163/**
164 *
165 */
166int ext2fs_global_init(void)
167{
[062d900]168 if (!hash_table_create(&open_nodes, 0, 0, &open_nodes_ops)) {
[d1ac0d7]169 return ENOMEM;
170 }
[4dc6a32]171 return EOK;
172}
173
174int ext2fs_global_fini(void)
175{
[d1ac0d7]176 hash_table_destroy(&open_nodes);
[796c276]177 return EOK;
178}
179
180
181/*
182 * EXT2 libfs operations.
183 */
184
[4dc6a32]185/**
[15f3c3f]186 * Find an instance of filesystem for the given service_id
[4dc6a32]187 */
[15f3c3f]188int ext2fs_instance_get(service_id_t service_id, ext2fs_instance_t **inst)
[4dc6a32]189{
[15f3c3f]190 EXT2FS_DBG("(%" PRIun ", -)", service_id);
[4dc6a32]191 ext2fs_instance_t *tmp;
[a210bc7]192
193 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]194
195 if (list_empty(&instance_list)) {
196 EXT2FS_DBG("list empty");
[a210bc7]197 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]198 return EINVAL;
199 }
200
[b72efe8]201 list_foreach(instance_list, link) {
[4dc6a32]202 tmp = list_get_instance(link, ext2fs_instance_t, link);
203
[15f3c3f]204 if (tmp->service_id == service_id) {
[4dc6a32]205 *inst = tmp;
[a210bc7]206 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]207 return EOK;
208 }
209 }
210
211 EXT2FS_DBG("not found");
[a210bc7]212
213 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]214 return EINVAL;
215}
216
217
218
[15f3c3f]219int ext2fs_root_get(fs_node_t **rfn, service_id_t service_id)
[796c276]220{
[15f3c3f]221 EXT2FS_DBG("(-, %" PRIun ")", service_id);
222 return ext2fs_node_get(rfn, service_id, EXT2_INODE_ROOT_INDEX);
[796c276]223}
224
225int ext2fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
226{
[4dc6a32]227 EXT2FS_DBG("(-,-,%s)", component);
228 ext2fs_node_t *eparent = EXT2FS_NODE(pfn);
229 ext2_filesystem_t *fs;
230 ext2_directory_iterator_t it;
231 int rc;
232 size_t name_size;
233 size_t component_size;
234 bool found = false;
[82a3b31f]235 uint32_t inode;
[4dc6a32]236
237 fs = eparent->instance->filesystem;
238
239 if (!ext2_inode_is_type(fs->superblock, eparent->inode_ref->inode,
240 EXT2_INODE_MODE_DIRECTORY)) {
241 return ENOTDIR;
242 }
243
[4e36219]244 rc = ext2_directory_iterator_init(&it, fs, eparent->inode_ref, 0);
[4dc6a32]245 if (rc != EOK) {
246 return rc;
247 }
248
[1a86c50]249 /* Find length of component in bytes
250 * TODO: check for library function call that does this
251 */
[4dc6a32]252 component_size = 0;
253 while (*(component+component_size) != 0) {
254 component_size++;
255 }
256
257 while (it.current != NULL) {
[82a3b31f]258 inode = ext2_directory_entry_ll_get_inode(it.current);
259
[1a86c50]260 /* ignore empty directory entries */
[82a3b31f]261 if (inode != 0) {
[4dc6a32]262 name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
263 it.current);
264
265 if (name_size == component_size && bcmp(component, &it.current->name,
266 name_size) == 0) {
[e2abab03]267 rc = ext2fs_node_get_core(rfn, eparent->instance,
[82a3b31f]268 inode);
[4dc6a32]269 if (rc != EOK) {
270 ext2_directory_iterator_fini(&it);
271 return rc;
272 }
273 found = true;
274 break;
275 }
276 }
277
278 rc = ext2_directory_iterator_next(&it);
279 if (rc != EOK) {
280 ext2_directory_iterator_fini(&it);
281 return rc;
282 }
283 }
284
285 ext2_directory_iterator_fini(&it);
286
287 if (!found) {
288 return ENOENT;
289 }
290
291 return EOK;
[796c276]292}
293
294/** Instantiate a EXT2 in-core node. */
[15f3c3f]295int ext2fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
[796c276]296{
[15f3c3f]297 EXT2FS_DBG("(-,%" PRIun ",%u)", service_id, index);
[e2abab03]298
299 ext2fs_instance_t *inst = NULL;
300 int rc;
301
[15f3c3f]302 rc = ext2fs_instance_get(service_id, &inst);
[e2abab03]303 if (rc != EOK) {
304 return rc;
305 }
306
307 return ext2fs_node_get_core(rfn, inst, index);
308}
309
310int ext2fs_node_get_core(fs_node_t **rfn, ext2fs_instance_t *inst,
311 fs_index_t index)
312{
[4dc6a32]313 int rc;
314 fs_node_t *node = NULL;
315 ext2fs_node_t *enode = NULL;
[e2abab03]316
[4dc6a32]317 ext2_inode_ref_t *inode_ref = NULL;
318
[d1ac0d7]319 fibril_mutex_lock(&open_nodes_lock);
320
321 /* Check if the node is not already open */
[062d900]322 node_key_t key = {
323 .service_id = inst->service_id,
324 .index = index
[d1ac0d7]325 };
[062d900]326 ht_link_t *already_open = hash_table_find(&open_nodes, &key);
[d1ac0d7]327
328 if (already_open) {
[062d900]329 enode = hash_table_get_inst(already_open, ext2fs_node_t, link);
[d1ac0d7]330 *rfn = enode->fs_node;
331 enode->references++;
332
333 fibril_mutex_unlock(&open_nodes_lock);
334 return EOK;
335 }
336
[4dc6a32]337 enode = malloc(sizeof(ext2fs_node_t));
338 if (enode == NULL) {
[d1ac0d7]339 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]340 return ENOMEM;
341 }
342
343 node = malloc(sizeof(fs_node_t));
344 if (node == NULL) {
345 free(enode);
[d1ac0d7]346 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]347 return ENOMEM;
[e2abab03]348 }
[4dc6a32]349 fs_node_initialize(node);
350
351 rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
352 if (rc != EOK) {
353 free(enode);
354 free(node);
[d1ac0d7]355 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]356 return rc;
357 }
358
359 enode->inode_ref = inode_ref;
360 enode->instance = inst;
[d1ac0d7]361 enode->references = 1;
362 enode->fs_node = node;
363
[4dc6a32]364 node->data = enode;
365 *rfn = node;
366
[062d900]367 hash_table_insert(&open_nodes, &enode->link);
[d1ac0d7]368 inst->open_nodes_count++;
369
[4dc6a32]370 EXT2FS_DBG("inode: %u", inode_ref->index);
371
372 EXT2FS_DBG("EOK");
373
[d1ac0d7]374 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]375 return EOK;
[796c276]376}
377
378int ext2fs_node_open(fs_node_t *fn)
379{
[4dc6a32]380 EXT2FS_DBG("");
[796c276]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{
[4dc6a32]390 EXT2FS_DBG("");
391 int rc;
392 ext2fs_node_t *enode = EXT2FS_NODE(fn);
[d1ac0d7]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{
[062d900]413 node_key_t key = {
414 .service_id = enode->instance->service_id,
415 .index = enode->inode_ref->index
[d1ac0d7]416 };
[062d900]417
418 hash_table_remove(&open_nodes, &key);
419
[d1ac0d7]420 assert(enode->instance->open_nodes_count > 0);
421 enode->instance->open_nodes_count--;
422
[062d900]423 int rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
[4dc6a32]424 if (rc != EOK) {
425 EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
[d1ac0d7]426 return rc;
[4dc6a32]427 }
[d1ac0d7]428
429 free(enode->fs_node);
430 free(enode);
431 return EOK;
[796c276]432}
433
[15f3c3f]434int ext2fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[796c276]435{
[4dc6a32]436 EXT2FS_DBG("");
[796c276]437 // TODO
438 return ENOTSUP;
439}
440
441int ext2fs_destroy_node(fs_node_t *fn)
442{
[4dc6a32]443 EXT2FS_DBG("");
[796c276]444 // TODO
445 return ENOTSUP;
446}
447
448int ext2fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
449{
[4dc6a32]450 EXT2FS_DBG("");
[796c276]451 // TODO
452 return ENOTSUP;
453}
454
455int ext2fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
456{
[4dc6a32]457 EXT2FS_DBG("");
[796c276]458 // TODO
459 return ENOTSUP;
460}
461
462int ext2fs_has_children(bool *has_children, fs_node_t *fn)
463{
[4dc6a32]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;
[84226f0]470 size_t name_size;
[4dc6a32]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
[4e36219]481 rc = ext2_directory_iterator_init(&it, fs, enode->inode_ref, 0);
[4dc6a32]482 if (rc != EOK) {
483 EXT2FS_DBG("error %u", rc);
484 return rc;
485 }
486
[1a86c50]487 /* Find a non-empty directory entry */
[4dc6a32]488 while (it.current != NULL) {
489 if (it.current->inode != 0) {
[84226f0]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 }
[4dc6a32]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;
[796c276]516}
517
518
519fs_index_t ext2fs_index_get(fs_node_t *fn)
520{
[4dc6a32]521 ext2fs_node_t *enode = EXT2FS_NODE(fn);
522 EXT2FS_DBG("%u", enode->inode_ref->index);
523 return enode->inode_ref->index;
[796c276]524}
525
526aoff64_t ext2fs_size_get(fs_node_t *fn)
527{
[4dc6a32]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;
[796c276]533}
534
535unsigned ext2fs_lnkcnt_get(fs_node_t *fn)
536{
[4dc6a32]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;
[796c276]541}
542
543bool ext2fs_is_directory(fs_node_t *fn)
544{
[4dc6a32]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;
[796c276]551}
552
553bool ext2fs_is_file(fs_node_t *fn)
554{
[4dc6a32]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;
[796c276]560}
561
[b33870b]562service_id_t ext2fs_service_get(fs_node_t *fn)
[796c276]563{
[4dc6a32]564 EXT2FS_DBG("");
565 ext2fs_node_t *enode = EXT2FS_NODE(fn);
[15f3c3f]566 return enode->instance->service_id;
[796c276]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 .is_directory = ext2fs_is_directory,
585 .is_file = ext2fs_is_file,
[b33870b]586 .service_get = ext2fs_service_get
[796c276]587};
588
589/*
590 * VFS operations.
591 */
592
[86ffa27f]593static int ext2fs_mounted(service_id_t service_id, const char *opts,
[efcebe1]594 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
[796c276]595{
[4dc6a32]596 EXT2FS_DBG("");
[796c276]597 int rc;
598 ext2_filesystem_t *fs;
[4dc6a32]599 ext2fs_instance_t *inst;
[eef306c]600 bool read_only;
[4dc6a32]601
[796c276]602 /* Allocate libext2 filesystem structure */
603 fs = (ext2_filesystem_t *) malloc(sizeof(ext2_filesystem_t));
[efcebe1]604 if (fs == NULL)
605 return ENOMEM;
[796c276]606
[4dc6a32]607 /* Allocate instance structure */
608 inst = (ext2fs_instance_t *) malloc(sizeof(ext2fs_instance_t));
609 if (inst == NULL) {
610 free(fs);
[efcebe1]611 return ENOMEM;
[4dc6a32]612 }
613
[796c276]614 /* Initialize the filesystem */
[15f3c3f]615 rc = ext2_filesystem_init(fs, service_id);
[796c276]616 if (rc != EOK) {
[4dc6a32]617 free(fs);
618 free(inst);
[efcebe1]619 return rc;
[796c276]620 }
621
622 /* Do some sanity checking */
623 rc = ext2_filesystem_check_sanity(fs);
624 if (rc != EOK) {
625 ext2_filesystem_fini(fs);
[4dc6a32]626 free(fs);
627 free(inst);
[efcebe1]628 return rc;
[796c276]629 }
630
[eef306c]631 /* Check flags */
632 rc = ext2_filesystem_check_flags(fs, &read_only);
633 if (rc != EOK) {
634 ext2_filesystem_fini(fs);
635 free(fs);
636 free(inst);
[efcebe1]637 return rc;
[eef306c]638 }
639
[d1ac0d7]640 /* Initialize instance */
[4dc6a32]641 link_initialize(&inst->link);
[15f3c3f]642 inst->service_id = service_id;
[4dc6a32]643 inst->filesystem = fs;
[d1ac0d7]644 inst->open_nodes_count = 0;
[a210bc7]645
[d1ac0d7]646 /* Read root node */
647 fs_node_t *root_node;
648 rc = ext2fs_node_get_core(&root_node, inst, EXT2_INODE_ROOT_INDEX);
649 if (rc != EOK) {
650 ext2_filesystem_fini(fs);
651 free(fs);
652 free(inst);
[efcebe1]653 return rc;
[d1ac0d7]654 }
655 ext2fs_node_t *enode = EXT2FS_NODE(root_node);
656
657 /* Add instance to the list */
[a210bc7]658 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]659 list_append(&inst->link, &instance_list);
[a210bc7]660 fibril_mutex_unlock(&instance_list_mutex);
[796c276]661
[efcebe1]662 *index = EXT2_INODE_ROOT_INDEX;
663 *size = 0;
664 *lnkcnt = ext2_inode_get_usage_count(enode->inode_ref->inode);
[d1ac0d7]665
666 ext2fs_node_put(root_node);
[796c276]667
[efcebe1]668 return EOK;
[796c276]669}
670
[86ffa27f]671static int ext2fs_unmounted(service_id_t service_id)
[796c276]672{
[4dc6a32]673 EXT2FS_DBG("");
674 ext2fs_instance_t *inst;
675 int rc;
676
[15f3c3f]677 rc = ext2fs_instance_get(service_id, &inst);
[4dc6a32]678
[efcebe1]679 if (rc != EOK)
680 return rc;
[4dc6a32]681
[d1ac0d7]682 fibril_mutex_lock(&open_nodes_lock);
683
684 EXT2FS_DBG("open_nodes_count = %d", inst->open_nodes_count)
685 if (inst->open_nodes_count != 0) {
686 fibril_mutex_unlock(&open_nodes_lock);
[efcebe1]687 return EBUSY;
[d1ac0d7]688 }
[4dc6a32]689
[1a86c50]690 /* Remove the instance from the list */
[a210bc7]691 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]692 list_remove(&inst->link);
[a210bc7]693 fibril_mutex_unlock(&instance_list_mutex);
[d1ac0d7]694
695 fibril_mutex_unlock(&open_nodes_lock);
[a210bc7]696
[4dc6a32]697 ext2_filesystem_fini(inst->filesystem);
698
[efcebe1]699 return EOK;
[796c276]700}
701
[efcebe1]702static int
[86ffa27f]703ext2fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]704 size_t *rbytes)
[796c276]705{
[4dc6a32]706 EXT2FS_DBG("");
[796c276]707
[4dc6a32]708 ext2fs_instance_t *inst;
709 ext2_inode_ref_t *inode_ref;
710 int rc;
[b83e16ff]711
[4dc6a32]712 /*
713 * Receive the read request.
714 */
715 ipc_callid_t callid;
716 size_t size;
717 if (!async_data_read_receive(&callid, &size)) {
718 async_answer_0(callid, EINVAL);
[efcebe1]719 return EINVAL;
[4dc6a32]720 }
721
[15f3c3f]722 rc = ext2fs_instance_get(service_id, &inst);
[4dc6a32]723 if (rc != EOK) {
724 async_answer_0(callid, rc);
[efcebe1]725 return rc;
[4dc6a32]726 }
727
728 rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
729 if (rc != EOK) {
730 async_answer_0(callid, rc);
[efcebe1]731 return rc;
[4dc6a32]732 }
733
734 if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
[efcebe1]735 EXT2_INODE_MODE_FILE)) {
736 rc = ext2fs_read_file(callid, pos, size, inst, inode_ref,
737 rbytes);
738 } else if (ext2_inode_is_type(inst->filesystem->superblock,
739 inode_ref->inode, EXT2_INODE_MODE_DIRECTORY)) {
740 rc = ext2fs_read_directory(callid, pos, size, inst, inode_ref,
741 rbytes);
742 } else {
[1a86c50]743 /* Other inode types not supported */
[df38657]744 async_answer_0(callid, ENOTSUP);
[efcebe1]745 rc = ENOTSUP;
[df38657]746 }
747
748 ext2_filesystem_put_inode_ref(inode_ref);
[b83e16ff]749
[efcebe1]750 return rc;
[b83e16ff]751}
752
[84226f0]753/**
754 * Determine whether given directory entry name is . or ..
755 */
756bool ext2fs_is_dots(const uint8_t *name, size_t name_size) {
757 if (name_size == 1 && name[0] == '.') {
758 return true;
759 }
760
761 if (name_size == 2 && name[0] == '.' && name[1] == '.') {
762 return true;
763 }
764
765 return false;
766}
767
[efcebe1]768int ext2fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size,
769 ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
[b83e16ff]770{
771 ext2_directory_iterator_t it;
[4e36219]772 aoff64_t next;
[b83e16ff]773 uint8_t *buf;
774 size_t name_size;
775 int rc;
[df38657]776 bool found = false;
[b83e16ff]777
[4e36219]778 rc = ext2_directory_iterator_init(&it, inst->filesystem, inode_ref, pos);
[b83e16ff]779 if (rc != EOK) {
780 async_answer_0(callid, rc);
[efcebe1]781 return rc;
[b83e16ff]782 }
783
[4e36219]784 /* Find next interesting directory entry.
785 * We want to skip . and .. entries
[1a86c50]786 * as these are not used in HelenOS
787 */
[b83e16ff]788 while (it.current != NULL) {
[df38657]789 if (it.current->inode == 0) {
790 goto skip;
791 }
792
793 name_size = ext2_directory_entry_ll_get_name_length(
[efcebe1]794 inst->filesystem->superblock, it.current);
[df38657]795
[1a86c50]796 /* skip . and .. */
[84226f0]797 if (ext2fs_is_dots(&it.current->name, name_size)) {
798 goto skip;
[4dc6a32]799 }
800
[4e36219]801 /* The on-disk entry does not contain \0 at the end
[efcebe1]802 * end of entry name, so we copy it to new buffer
803 * and add the \0 at the end
804 */
[4e36219]805 buf = malloc(name_size+1);
806 if (buf == NULL) {
807 ext2_directory_iterator_fini(&it);
808 async_answer_0(callid, ENOMEM);
[efcebe1]809 return ENOMEM;
[df38657]810 }
[4e36219]811 memcpy(buf, &it.current->name, name_size);
[efcebe1]812 *(buf + name_size) = 0;
[4e36219]813 found = true;
[efcebe1]814 (void) async_data_read_finalize(callid, buf, name_size + 1);
[4e36219]815 free(buf);
816 break;
[df38657]817
818skip:
[b83e16ff]819 rc = ext2_directory_iterator_next(&it);
[4dc6a32]820 if (rc != EOK) {
[b83e16ff]821 ext2_directory_iterator_fini(&it);
822 async_answer_0(callid, rc);
[efcebe1]823 return rc;
[4dc6a32]824 }
825 }
826
[4e36219]827 if (found) {
828 rc = ext2_directory_iterator_next(&it);
[efcebe1]829 if (rc != EOK)
830 return rc;
[4e36219]831 next = it.current_offset;
[b83e16ff]832 }
833
834 rc = ext2_directory_iterator_fini(&it);
[efcebe1]835 if (rc != EOK)
836 return rc;
[b83e16ff]837
[df38657]838 if (found) {
[efcebe1]839 *rbytes = next - pos;
840 return EOK;
841 } else {
[df38657]842 async_answer_0(callid, ENOENT);
[efcebe1]843 return ENOENT;
[df38657]844 }
[796c276]845}
846
[efcebe1]847int ext2fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size,
848 ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
[529edc66]849{
850 int rc;
851 uint32_t block_size;
852 aoff64_t file_block;
853 uint64_t file_size;
854 uint32_t fs_block;
855 size_t offset_in_block;
856 size_t bytes;
857 block_t *block;
[7ea69a6]858 uint8_t *buffer;
[529edc66]859
860 file_size = ext2_inode_get_size(inst->filesystem->superblock,
861 inode_ref->inode);
862
863 if (pos >= file_size) {
[1a86c50]864 /* Read 0 bytes successfully */
[529edc66]865 async_data_read_finalize(callid, NULL, 0);
[efcebe1]866 *rbytes = 0;
867 return EOK;
[529edc66]868 }
869
[1a86c50]870 /* For now, we only read data from one block at a time */
[529edc66]871 block_size = ext2_superblock_get_block_size(inst->filesystem->superblock);
872 file_block = pos / block_size;
873 offset_in_block = pos % block_size;
874 bytes = min(block_size - offset_in_block, size);
875
[1a86c50]876 /* Handle end of file */
[7ea69a6]877 if (pos + bytes > file_size) {
878 bytes = file_size - pos;
879 }
880
[1a86c50]881 /* Get the real block number */
[529edc66]882 rc = ext2_filesystem_get_inode_data_block_index(inst->filesystem,
883 inode_ref->inode, file_block, &fs_block);
884 if (rc != EOK) {
885 async_answer_0(callid, rc);
[efcebe1]886 return rc;
[529edc66]887 }
888
[1a86c50]889 /* Check for sparse file
890 * If ext2_filesystem_get_inode_data_block_index returned
891 * fs_block == 0, it means that the given block is not allocated for the
892 * file and we need to return a buffer of zeros
893 */
[7ea69a6]894 if (fs_block == 0) {
895 buffer = malloc(bytes);
896 if (buffer == NULL) {
897 async_answer_0(callid, ENOMEM);
[efcebe1]898 return ENOMEM;
[7ea69a6]899 }
900
901 memset(buffer, 0, bytes);
902
903 async_data_read_finalize(callid, buffer, bytes);
[efcebe1]904 *rbytes = bytes;
[7ea69a6]905
906 free(buffer);
907
[efcebe1]908 return EOK;
[7ea69a6]909 }
910
[1a86c50]911 /* Usual case - we need to read a block from device */
[15f3c3f]912 rc = block_get(&block, inst->service_id, fs_block, BLOCK_FLAGS_NONE);
[529edc66]913 if (rc != EOK) {
914 async_answer_0(callid, rc);
[efcebe1]915 return rc;
[529edc66]916 }
917
[7ea69a6]918 assert(offset_in_block + bytes <= block_size);
919 async_data_read_finalize(callid, block->data + offset_in_block, bytes);
[529edc66]920
921 rc = block_put(block);
[efcebe1]922 if (rc != EOK)
923 return rc;
[796c276]924
[efcebe1]925 *rbytes = bytes;
926 return EOK;
[796c276]927}
928
[efcebe1]929static int
[86ffa27f]930ext2fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]931 size_t *wbytes, aoff64_t *nsize)
[796c276]932{
[4dc6a32]933 EXT2FS_DBG("");
[efcebe1]934 return ENOTSUP;
[796c276]935}
936
[efcebe1]937static int
[86ffa27f]938ext2fs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
[796c276]939{
[4dc6a32]940 EXT2FS_DBG("");
[efcebe1]941 return ENOTSUP;
[796c276]942}
943
[86ffa27f]944static int ext2fs_close(service_id_t service_id, fs_index_t index)
[796c276]945{
[4dc6a32]946 EXT2FS_DBG("");
[efcebe1]947 return EOK;
[796c276]948}
949
[86ffa27f]950static int ext2fs_destroy(service_id_t service_id, fs_index_t index)
[796c276]951{
[4dc6a32]952 EXT2FS_DBG("");
[efcebe1]953 return ENOTSUP;
[796c276]954}
955
[86ffa27f]956static int ext2fs_sync(service_id_t service_id, fs_index_t index)
[796c276]957{
[4dc6a32]958 EXT2FS_DBG("");
[efcebe1]959 return ENOTSUP;
[796c276]960}
961
[efcebe1]962vfs_out_ops_t ext2fs_ops = {
963 .mounted = ext2fs_mounted,
964 .unmounted = ext2fs_unmounted,
965 .read = ext2fs_read,
966 .write = ext2fs_write,
967 .truncate = ext2fs_truncate,
968 .close = ext2fs_close,
969 .destroy = ext2fs_destroy,
970 .sync = ext2fs_sync,
971};
[796c276]972
973/**
974 * @}
975 */
[efcebe1]976
Note: See TracBrowser for help on using the repository browser.