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

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

rename device_get() method to service_get() to better reflect changes in the location service

  • Property mode set to 100644
File size: 22.3 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>
41#include <libblock.h>
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>
51#include <adt/list.h>
52#include <assert.h>
53#include <fibril_synch.h>
54#include <sys/mman.h>
55#include <align.h>
56#include <adt/hash_table.h>
[7ea69a6]57#include <sys/typefmt.h>
[0e26444]58#include <malloc.h>
59#include <stdio.h>
[f6fece9]60#include <inttypes.h>
[796c276]61
[4dc6a32]62#define EXT2FS_NODE(node) ((node) ? (ext2fs_node_t *) (node)->data : NULL)
63#define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
[d1ac0d7]64#define OPEN_NODES_KEYS 2
65#define OPEN_NODES_DEV_HANDLE_KEY 0
66#define OPEN_NODES_INODE_KEY 1
67#define OPEN_NODES_BUCKETS 256
[796c276]68
[4dc6a32]69typedef struct ext2fs_instance {
70 link_t link;
[15f3c3f]71 service_id_t service_id;
[4dc6a32]72 ext2_filesystem_t *filesystem;
[d1ac0d7]73 unsigned int open_nodes_count;
[4dc6a32]74} ext2fs_instance_t;
75
76typedef struct ext2fs_node {
77 ext2fs_instance_t *instance;
78 ext2_inode_ref_t *inode_ref;
[d1ac0d7]79 fs_node_t *fs_node;
80 link_t link;
81 unsigned int references;
[4dc6a32]82} ext2fs_node_t;
83
[e2abab03]84/*
85 * Forward declarations of auxiliary functions
86 */
[15f3c3f]87static int ext2fs_instance_get(service_id_t, ext2fs_instance_t **);
[efcebe1]88static int ext2fs_read_directory(ipc_callid_t, aoff64_t, size_t,
89 ext2fs_instance_t *, ext2_inode_ref_t *, size_t *);
90static int ext2fs_read_file(ipc_callid_t, aoff64_t, size_t, ext2fs_instance_t *,
91 ext2_inode_ref_t *, size_t *);
[84226f0]92static bool ext2fs_is_dots(const uint8_t *, size_t);
[e2abab03]93static int ext2fs_node_get_core(fs_node_t **, ext2fs_instance_t *, fs_index_t);
[d1ac0d7]94static int ext2fs_node_put_core(ext2fs_node_t *);
[796c276]95
96/*
97 * Forward declarations of EXT2 libfs operations.
98 */
[15f3c3f]99static int ext2fs_root_get(fs_node_t **, service_id_t);
[796c276]100static int ext2fs_match(fs_node_t **, fs_node_t *, const char *);
[15f3c3f]101static int ext2fs_node_get(fs_node_t **, service_id_t, fs_index_t);
[796c276]102static int ext2fs_node_open(fs_node_t *);
103static int ext2fs_node_put(fs_node_t *);
[15f3c3f]104static int ext2fs_create_node(fs_node_t **, service_id_t, int);
[796c276]105static int ext2fs_destroy_node(fs_node_t *);
106static int ext2fs_link(fs_node_t *, fs_node_t *, const char *);
107static int ext2fs_unlink(fs_node_t *, fs_node_t *, const char *);
108static int ext2fs_has_children(bool *, fs_node_t *);
109static fs_index_t ext2fs_index_get(fs_node_t *);
110static aoff64_t ext2fs_size_get(fs_node_t *);
111static unsigned ext2fs_lnkcnt_get(fs_node_t *);
112static bool ext2fs_is_directory(fs_node_t *);
113static bool ext2fs_is_file(fs_node_t *node);
[b33870b]114static service_id_t ext2fs_service_get(fs_node_t *node);
[796c276]115
116/*
117 * Static variables
118 */
[4dc6a32]119static LIST_INITIALIZE(instance_list);
[a210bc7]120static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
[d1ac0d7]121static hash_table_t open_nodes;
122static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
123
124/* Hash table interface for open nodes hash table */
125static hash_index_t open_nodes_hash(unsigned long key[])
126{
127 /* TODO: This is very simple and probably can be improved */
128 return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
129}
130
131static int open_nodes_compare(unsigned long key[], hash_count_t keys,
132 link_t *item)
133{
134 ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
135 assert(keys > 0);
[15f3c3f]136 if (enode->instance->service_id !=
137 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
[d1ac0d7]138 return false;
139 }
140 if (keys == 1) {
141 return true;
142 }
143 assert(keys == 2);
144 return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
145}
146
147static void open_nodes_remove_cb(link_t *link)
148{
149 /* We don't use remove callback for this hash table */
150}
151
152static hash_table_operations_t open_nodes_ops = {
153 .hash = open_nodes_hash,
154 .compare = open_nodes_compare,
155 .remove_callback = open_nodes_remove_cb,
156};
[796c276]157
158/**
159 *
160 */
161int ext2fs_global_init(void)
162{
[d1ac0d7]163 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
164 OPEN_NODES_KEYS, &open_nodes_ops)) {
165 return ENOMEM;
166 }
[4dc6a32]167 return EOK;
168}
169
170int ext2fs_global_fini(void)
171{
[d1ac0d7]172 hash_table_destroy(&open_nodes);
[796c276]173 return EOK;
174}
175
176
177/*
178 * EXT2 libfs operations.
179 */
180
[4dc6a32]181/**
[15f3c3f]182 * Find an instance of filesystem for the given service_id
[4dc6a32]183 */
[15f3c3f]184int ext2fs_instance_get(service_id_t service_id, ext2fs_instance_t **inst)
[4dc6a32]185{
[15f3c3f]186 EXT2FS_DBG("(%" PRIun ", -)", service_id);
[4dc6a32]187 ext2fs_instance_t *tmp;
[a210bc7]188
189 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]190
191 if (list_empty(&instance_list)) {
192 EXT2FS_DBG("list empty");
[a210bc7]193 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]194 return EINVAL;
195 }
196
[b72efe8]197 list_foreach(instance_list, link) {
[4dc6a32]198 tmp = list_get_instance(link, ext2fs_instance_t, link);
199
[15f3c3f]200 if (tmp->service_id == service_id) {
[4dc6a32]201 *inst = tmp;
[a210bc7]202 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]203 return EOK;
204 }
205 }
206
207 EXT2FS_DBG("not found");
[a210bc7]208
209 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]210 return EINVAL;
211}
212
213
214
[15f3c3f]215int ext2fs_root_get(fs_node_t **rfn, service_id_t service_id)
[796c276]216{
[15f3c3f]217 EXT2FS_DBG("(-, %" PRIun ")", service_id);
218 return ext2fs_node_get(rfn, service_id, EXT2_INODE_ROOT_INDEX);
[796c276]219}
220
221int ext2fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
222{
[4dc6a32]223 EXT2FS_DBG("(-,-,%s)", component);
224 ext2fs_node_t *eparent = EXT2FS_NODE(pfn);
225 ext2_filesystem_t *fs;
226 ext2_directory_iterator_t it;
227 int rc;
228 size_t name_size;
229 size_t component_size;
230 bool found = false;
[82a3b31f]231 uint32_t inode;
[4dc6a32]232
233 fs = eparent->instance->filesystem;
234
235 if (!ext2_inode_is_type(fs->superblock, eparent->inode_ref->inode,
236 EXT2_INODE_MODE_DIRECTORY)) {
237 return ENOTDIR;
238 }
239
[4e36219]240 rc = ext2_directory_iterator_init(&it, fs, eparent->inode_ref, 0);
[4dc6a32]241 if (rc != EOK) {
242 return rc;
243 }
244
[1a86c50]245 /* Find length of component in bytes
246 * TODO: check for library function call that does this
247 */
[4dc6a32]248 component_size = 0;
249 while (*(component+component_size) != 0) {
250 component_size++;
251 }
252
253 while (it.current != NULL) {
[82a3b31f]254 inode = ext2_directory_entry_ll_get_inode(it.current);
255
[1a86c50]256 /* ignore empty directory entries */
[82a3b31f]257 if (inode != 0) {
[4dc6a32]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,
[82a3b31f]264 inode);
[4dc6a32]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. */
[15f3c3f]291int ext2fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
[796c276]292{
[15f3c3f]293 EXT2FS_DBG("(-,%" PRIun ",%u)", service_id, index);
[e2abab03]294
295 ext2fs_instance_t *inst = NULL;
296 int rc;
297
[15f3c3f]298 rc = ext2fs_instance_get(service_id, &inst);
[e2abab03]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[] = {
[15f3c3f]319 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
[d1ac0d7]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[] = {
[15f3c3f]413 [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
[d1ac0d7]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
[15f3c3f]431int ext2fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[796c276]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
[4e36219]478 rc = ext2_directory_iterator_init(&it, fs, enode->inode_ref, 0);
[4dc6a32]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
540bool ext2fs_is_directory(fs_node_t *fn)
541{
[4dc6a32]542 ext2fs_node_t *enode = EXT2FS_NODE(fn);
543 bool is_dir = ext2_inode_is_type(enode->instance->filesystem->superblock,
544 enode->inode_ref->inode, EXT2_INODE_MODE_DIRECTORY);
545 EXT2FS_DBG("%s", is_dir ? "true" : "false");
546 EXT2FS_DBG("%u", enode->inode_ref->index);
547 return is_dir;
[796c276]548}
549
550bool ext2fs_is_file(fs_node_t *fn)
551{
[4dc6a32]552 ext2fs_node_t *enode = EXT2FS_NODE(fn);
553 bool is_file = ext2_inode_is_type(enode->instance->filesystem->superblock,
554 enode->inode_ref->inode, EXT2_INODE_MODE_FILE);
555 EXT2FS_DBG("%s", is_file ? "true" : "false");
556 return is_file;
[796c276]557}
558
[b33870b]559service_id_t ext2fs_service_get(fs_node_t *fn)
[796c276]560{
[4dc6a32]561 EXT2FS_DBG("");
562 ext2fs_node_t *enode = EXT2FS_NODE(fn);
[15f3c3f]563 return enode->instance->service_id;
[796c276]564}
565
566/** libfs operations */
567libfs_ops_t ext2fs_libfs_ops = {
568 .root_get = ext2fs_root_get,
569 .match = ext2fs_match,
570 .node_get = ext2fs_node_get,
571 .node_open = ext2fs_node_open,
572 .node_put = ext2fs_node_put,
573 .create = ext2fs_create_node,
574 .destroy = ext2fs_destroy_node,
575 .link = ext2fs_link,
576 .unlink = ext2fs_unlink,
577 .has_children = ext2fs_has_children,
578 .index_get = ext2fs_index_get,
579 .size_get = ext2fs_size_get,
580 .lnkcnt_get = ext2fs_lnkcnt_get,
581 .is_directory = ext2fs_is_directory,
582 .is_file = ext2fs_is_file,
[b33870b]583 .service_get = ext2fs_service_get
[796c276]584};
585
586/*
587 * VFS operations.
588 */
589
[86ffa27f]590static int ext2fs_mounted(service_id_t service_id, const char *opts,
[efcebe1]591 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
[796c276]592{
[4dc6a32]593 EXT2FS_DBG("");
[796c276]594 int rc;
595 ext2_filesystem_t *fs;
[4dc6a32]596 ext2fs_instance_t *inst;
[eef306c]597 bool read_only;
[4dc6a32]598
[796c276]599 /* Allocate libext2 filesystem structure */
600 fs = (ext2_filesystem_t *) malloc(sizeof(ext2_filesystem_t));
[efcebe1]601 if (fs == NULL)
602 return ENOMEM;
[796c276]603
[4dc6a32]604 /* Allocate instance structure */
605 inst = (ext2fs_instance_t *) malloc(sizeof(ext2fs_instance_t));
606 if (inst == NULL) {
607 free(fs);
[efcebe1]608 return ENOMEM;
[4dc6a32]609 }
610
[796c276]611 /* Initialize the filesystem */
[15f3c3f]612 rc = ext2_filesystem_init(fs, service_id);
[796c276]613 if (rc != EOK) {
[4dc6a32]614 free(fs);
615 free(inst);
[efcebe1]616 return rc;
[796c276]617 }
618
619 /* Do some sanity checking */
620 rc = ext2_filesystem_check_sanity(fs);
621 if (rc != EOK) {
622 ext2_filesystem_fini(fs);
[4dc6a32]623 free(fs);
624 free(inst);
[efcebe1]625 return rc;
[796c276]626 }
627
[eef306c]628 /* Check flags */
629 rc = ext2_filesystem_check_flags(fs, &read_only);
630 if (rc != EOK) {
631 ext2_filesystem_fini(fs);
632 free(fs);
633 free(inst);
[efcebe1]634 return rc;
[eef306c]635 }
636
[d1ac0d7]637 /* Initialize instance */
[4dc6a32]638 link_initialize(&inst->link);
[15f3c3f]639 inst->service_id = service_id;
[4dc6a32]640 inst->filesystem = fs;
[d1ac0d7]641 inst->open_nodes_count = 0;
[a210bc7]642
[d1ac0d7]643 /* Read root node */
644 fs_node_t *root_node;
645 rc = ext2fs_node_get_core(&root_node, inst, EXT2_INODE_ROOT_INDEX);
646 if (rc != EOK) {
647 ext2_filesystem_fini(fs);
648 free(fs);
649 free(inst);
[efcebe1]650 return rc;
[d1ac0d7]651 }
652 ext2fs_node_t *enode = EXT2FS_NODE(root_node);
653
654 /* Add instance to the list */
[a210bc7]655 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]656 list_append(&inst->link, &instance_list);
[a210bc7]657 fibril_mutex_unlock(&instance_list_mutex);
[796c276]658
[efcebe1]659 *index = EXT2_INODE_ROOT_INDEX;
660 *size = 0;
661 *lnkcnt = ext2_inode_get_usage_count(enode->inode_ref->inode);
[d1ac0d7]662
663 ext2fs_node_put(root_node);
[796c276]664
[efcebe1]665 return EOK;
[796c276]666}
667
[86ffa27f]668static int ext2fs_unmounted(service_id_t service_id)
[796c276]669{
[4dc6a32]670 EXT2FS_DBG("");
671 ext2fs_instance_t *inst;
672 int rc;
673
[15f3c3f]674 rc = ext2fs_instance_get(service_id, &inst);
[4dc6a32]675
[efcebe1]676 if (rc != EOK)
677 return rc;
[4dc6a32]678
[d1ac0d7]679 fibril_mutex_lock(&open_nodes_lock);
680
681 EXT2FS_DBG("open_nodes_count = %d", inst->open_nodes_count)
682 if (inst->open_nodes_count != 0) {
683 fibril_mutex_unlock(&open_nodes_lock);
[efcebe1]684 return EBUSY;
[d1ac0d7]685 }
[4dc6a32]686
[1a86c50]687 /* Remove the instance from the list */
[a210bc7]688 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]689 list_remove(&inst->link);
[a210bc7]690 fibril_mutex_unlock(&instance_list_mutex);
[d1ac0d7]691
692 fibril_mutex_unlock(&open_nodes_lock);
[a210bc7]693
[4dc6a32]694 ext2_filesystem_fini(inst->filesystem);
695
[efcebe1]696 return EOK;
[796c276]697}
698
[efcebe1]699static int
[86ffa27f]700ext2fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]701 size_t *rbytes)
[796c276]702{
[4dc6a32]703 EXT2FS_DBG("");
[796c276]704
[4dc6a32]705 ext2fs_instance_t *inst;
706 ext2_inode_ref_t *inode_ref;
707 int rc;
[b83e16ff]708
[4dc6a32]709 /*
710 * Receive the read request.
711 */
712 ipc_callid_t callid;
713 size_t size;
714 if (!async_data_read_receive(&callid, &size)) {
715 async_answer_0(callid, EINVAL);
[efcebe1]716 return EINVAL;
[4dc6a32]717 }
718
[15f3c3f]719 rc = ext2fs_instance_get(service_id, &inst);
[4dc6a32]720 if (rc != EOK) {
721 async_answer_0(callid, rc);
[efcebe1]722 return rc;
[4dc6a32]723 }
724
725 rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
726 if (rc != EOK) {
727 async_answer_0(callid, rc);
[efcebe1]728 return rc;
[4dc6a32]729 }
730
731 if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
[efcebe1]732 EXT2_INODE_MODE_FILE)) {
733 rc = ext2fs_read_file(callid, pos, size, inst, inode_ref,
734 rbytes);
735 } else if (ext2_inode_is_type(inst->filesystem->superblock,
736 inode_ref->inode, EXT2_INODE_MODE_DIRECTORY)) {
737 rc = ext2fs_read_directory(callid, pos, size, inst, inode_ref,
738 rbytes);
739 } else {
[1a86c50]740 /* Other inode types not supported */
[df38657]741 async_answer_0(callid, ENOTSUP);
[efcebe1]742 rc = ENOTSUP;
[df38657]743 }
744
745 ext2_filesystem_put_inode_ref(inode_ref);
[b83e16ff]746
[efcebe1]747 return rc;
[b83e16ff]748}
749
[84226f0]750/**
751 * Determine whether given directory entry name is . or ..
752 */
753bool ext2fs_is_dots(const uint8_t *name, size_t name_size) {
754 if (name_size == 1 && name[0] == '.') {
755 return true;
756 }
757
758 if (name_size == 2 && name[0] == '.' && name[1] == '.') {
759 return true;
760 }
761
762 return false;
763}
764
[efcebe1]765int ext2fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size,
766 ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
[b83e16ff]767{
768 ext2_directory_iterator_t it;
[4e36219]769 aoff64_t next;
[b83e16ff]770 uint8_t *buf;
771 size_t name_size;
772 int rc;
[df38657]773 bool found = false;
[b83e16ff]774
[4e36219]775 rc = ext2_directory_iterator_init(&it, inst->filesystem, inode_ref, pos);
[b83e16ff]776 if (rc != EOK) {
777 async_answer_0(callid, rc);
[efcebe1]778 return rc;
[b83e16ff]779 }
780
[4e36219]781 /* Find next interesting directory entry.
782 * We want to skip . and .. entries
[1a86c50]783 * as these are not used in HelenOS
784 */
[b83e16ff]785 while (it.current != NULL) {
[df38657]786 if (it.current->inode == 0) {
787 goto skip;
788 }
789
790 name_size = ext2_directory_entry_ll_get_name_length(
[efcebe1]791 inst->filesystem->superblock, it.current);
[df38657]792
[1a86c50]793 /* skip . and .. */
[84226f0]794 if (ext2fs_is_dots(&it.current->name, name_size)) {
795 goto skip;
[4dc6a32]796 }
797
[4e36219]798 /* The on-disk entry does not contain \0 at the end
[efcebe1]799 * end of entry name, so we copy it to new buffer
800 * and add the \0 at the end
801 */
[4e36219]802 buf = malloc(name_size+1);
803 if (buf == NULL) {
804 ext2_directory_iterator_fini(&it);
805 async_answer_0(callid, ENOMEM);
[efcebe1]806 return ENOMEM;
[df38657]807 }
[4e36219]808 memcpy(buf, &it.current->name, name_size);
[efcebe1]809 *(buf + name_size) = 0;
[4e36219]810 found = true;
[efcebe1]811 (void) async_data_read_finalize(callid, buf, name_size + 1);
[4e36219]812 free(buf);
813 break;
[df38657]814
815skip:
[b83e16ff]816 rc = ext2_directory_iterator_next(&it);
[4dc6a32]817 if (rc != EOK) {
[b83e16ff]818 ext2_directory_iterator_fini(&it);
819 async_answer_0(callid, rc);
[efcebe1]820 return rc;
[4dc6a32]821 }
822 }
823
[4e36219]824 if (found) {
825 rc = ext2_directory_iterator_next(&it);
[efcebe1]826 if (rc != EOK)
827 return rc;
[4e36219]828 next = it.current_offset;
[b83e16ff]829 }
830
831 rc = ext2_directory_iterator_fini(&it);
[efcebe1]832 if (rc != EOK)
833 return rc;
[b83e16ff]834
[df38657]835 if (found) {
[efcebe1]836 *rbytes = next - pos;
837 return EOK;
838 } else {
[df38657]839 async_answer_0(callid, ENOENT);
[efcebe1]840 return ENOENT;
[df38657]841 }
[796c276]842}
843
[efcebe1]844int ext2fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size,
845 ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
[529edc66]846{
847 int rc;
848 uint32_t block_size;
849 aoff64_t file_block;
850 uint64_t file_size;
851 uint32_t fs_block;
852 size_t offset_in_block;
853 size_t bytes;
854 block_t *block;
[7ea69a6]855 uint8_t *buffer;
[529edc66]856
857 file_size = ext2_inode_get_size(inst->filesystem->superblock,
858 inode_ref->inode);
859
860 if (pos >= file_size) {
[1a86c50]861 /* Read 0 bytes successfully */
[529edc66]862 async_data_read_finalize(callid, NULL, 0);
[efcebe1]863 *rbytes = 0;
864 return EOK;
[529edc66]865 }
866
[1a86c50]867 /* For now, we only read data from one block at a time */
[529edc66]868 block_size = ext2_superblock_get_block_size(inst->filesystem->superblock);
869 file_block = pos / block_size;
870 offset_in_block = pos % block_size;
871 bytes = min(block_size - offset_in_block, size);
872
[1a86c50]873 /* Handle end of file */
[7ea69a6]874 if (pos + bytes > file_size) {
875 bytes = file_size - pos;
876 }
877
[1a86c50]878 /* Get the real block number */
[529edc66]879 rc = ext2_filesystem_get_inode_data_block_index(inst->filesystem,
880 inode_ref->inode, file_block, &fs_block);
881 if (rc != EOK) {
882 async_answer_0(callid, rc);
[efcebe1]883 return rc;
[529edc66]884 }
885
[1a86c50]886 /* Check for sparse file
887 * If ext2_filesystem_get_inode_data_block_index returned
888 * fs_block == 0, it means that the given block is not allocated for the
889 * file and we need to return a buffer of zeros
890 */
[7ea69a6]891 if (fs_block == 0) {
892 buffer = malloc(bytes);
893 if (buffer == NULL) {
894 async_answer_0(callid, ENOMEM);
[efcebe1]895 return ENOMEM;
[7ea69a6]896 }
897
898 memset(buffer, 0, bytes);
899
900 async_data_read_finalize(callid, buffer, bytes);
[efcebe1]901 *rbytes = bytes;
[7ea69a6]902
903 free(buffer);
904
[efcebe1]905 return EOK;
[7ea69a6]906 }
907
[1a86c50]908 /* Usual case - we need to read a block from device */
[15f3c3f]909 rc = block_get(&block, inst->service_id, fs_block, BLOCK_FLAGS_NONE);
[529edc66]910 if (rc != EOK) {
911 async_answer_0(callid, rc);
[efcebe1]912 return rc;
[529edc66]913 }
914
[7ea69a6]915 assert(offset_in_block + bytes <= block_size);
916 async_data_read_finalize(callid, block->data + offset_in_block, bytes);
[529edc66]917
918 rc = block_put(block);
[efcebe1]919 if (rc != EOK)
920 return rc;
[796c276]921
[efcebe1]922 *rbytes = bytes;
923 return EOK;
[796c276]924}
925
[efcebe1]926static int
[86ffa27f]927ext2fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]928 size_t *wbytes, aoff64_t *nsize)
[796c276]929{
[4dc6a32]930 EXT2FS_DBG("");
[efcebe1]931 return ENOTSUP;
[796c276]932}
933
[efcebe1]934static int
[86ffa27f]935ext2fs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
[796c276]936{
[4dc6a32]937 EXT2FS_DBG("");
[efcebe1]938 return ENOTSUP;
[796c276]939}
940
[86ffa27f]941static int ext2fs_close(service_id_t service_id, fs_index_t index)
[796c276]942{
[4dc6a32]943 EXT2FS_DBG("");
[efcebe1]944 return EOK;
[796c276]945}
946
[86ffa27f]947static int ext2fs_destroy(service_id_t service_id, fs_index_t index)
[796c276]948{
[4dc6a32]949 EXT2FS_DBG("");
[efcebe1]950 return ENOTSUP;
[796c276]951}
952
[86ffa27f]953static int ext2fs_sync(service_id_t service_id, fs_index_t index)
[796c276]954{
[4dc6a32]955 EXT2FS_DBG("");
[efcebe1]956 return ENOTSUP;
[796c276]957}
958
[efcebe1]959vfs_out_ops_t ext2fs_ops = {
960 .mounted = ext2fs_mounted,
961 .unmounted = ext2fs_unmounted,
962 .read = ext2fs_read,
963 .write = ext2fs_write,
964 .truncate = ext2fs_truncate,
965 .close = ext2fs_close,
966 .destroy = ext2fs_destroy,
967 .sync = ext2fs_sync,
968};
[796c276]969
970/**
971 * @}
972 */
[efcebe1]973
Note: See TracBrowser for help on using the repository browser.