source: mainline/uspace/srv/fs/ext4fs/ext4fs_ops.c@ 12f55220

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 12f55220 was 12f55220, checked in by Frantisek Princ <frantisek.princ@…>, 14 years ago

first structures for reading indexed directories

  • Property mode set to 100644
File size: 21.4 KB
Line 
1/*
2 * Copyright (c) 2011 Frantisek Princ
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 ext4fs_ops.c
35 * @brief VFS operations for EXT4 filesystem.
36 */
37
38#include <errno.h>
39#include <fibril_synch.h>
40#include <libext4.h>
41#include <libfs.h>
42#include <macros.h>
43#include <malloc.h>
44#include <adt/hash_table.h>
45#include <ipc/loc.h>
46#include "ext4fs.h"
47#include "../../vfs/vfs.h"
48
49#define EXT4FS_NODE(node) ((node) ? (ext4fs_node_t *) (node)->data : NULL)
50
51#define OPEN_NODES_KEYS 2
52#define OPEN_NODES_DEV_HANDLE_KEY 0
53#define OPEN_NODES_INODE_KEY 1
54#define OPEN_NODES_BUCKETS 256
55
56typedef struct ext4fs_instance {
57 link_t link;
58 service_id_t service_id;
59 ext4_filesystem_t *filesystem;
60 unsigned int open_nodes_count;
61} ext4fs_instance_t;
62
63typedef struct ext4fs_node {
64 ext4fs_instance_t *instance;
65 ext4_inode_ref_t *inode_ref;
66 fs_node_t *fs_node;
67 link_t link;
68 unsigned int references;
69} ext4fs_node_t;
70
71/*
72 * Forward declarations of auxiliary functions
73 */
74
75static int ext4fs_read_directory(ipc_callid_t, aoff64_t, size_t,
76 ext4fs_instance_t *, ext4_inode_ref_t *, size_t *);
77static int ext4fs_read_dx_directory(ipc_callid_t, aoff64_t, size_t,
78 ext4fs_instance_t *, ext4_inode_ref_t *, size_t *);
79static int ext4fs_read_file(ipc_callid_t, aoff64_t, size_t, ext4fs_instance_t *,
80 ext4_inode_ref_t *, size_t *);
81static bool ext4fs_is_dots(const uint8_t *, size_t);
82static int ext4fs_instance_get(service_id_t, ext4fs_instance_t **);
83static int ext4fs_node_get_core(fs_node_t **, ext4fs_instance_t *, fs_index_t);
84static int ext4fs_node_put_core(ext4fs_node_t *);
85
86/*
87 * Forward declarations of EXT4 libfs operations.
88 */
89static int ext4fs_root_get(fs_node_t **, service_id_t);
90static int ext4fs_match(fs_node_t **, fs_node_t *, const char *);
91static int ext4fs_node_get(fs_node_t **, service_id_t, fs_index_t);
92static int ext4fs_node_open(fs_node_t *);
93static int ext4fs_node_put(fs_node_t *);
94static int ext4fs_create_node(fs_node_t **, service_id_t, int);
95static int ext4fs_destroy_node(fs_node_t *);
96static int ext4fs_link(fs_node_t *, fs_node_t *, const char *);
97static int ext4fs_unlink(fs_node_t *, fs_node_t *, const char *);
98static int ext4fs_has_children(bool *, fs_node_t *);
99static fs_index_t ext4fs_index_get(fs_node_t *);
100static aoff64_t ext4fs_size_get(fs_node_t *);
101static unsigned ext4fs_lnkcnt_get(fs_node_t *);
102static bool ext4fs_is_directory(fs_node_t *);
103static bool ext4fs_is_file(fs_node_t *node);
104static service_id_t ext4fs_service_get(fs_node_t *node);
105
106/*
107 * Static variables
108 */
109static LIST_INITIALIZE(instance_list);
110static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
111static hash_table_t open_nodes;
112static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
113
114/* Hash table interface for open nodes hash table */
115static hash_index_t open_nodes_hash(unsigned long key[])
116{
117 /* TODO: This is very simple and probably can be improved */
118 return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
119}
120
121static int open_nodes_compare(unsigned long key[], hash_count_t keys,
122 link_t *item)
123{
124 ext4fs_node_t *enode = hash_table_get_instance(item, ext4fs_node_t, link);
125 assert(keys > 0);
126 if (enode->instance->service_id !=
127 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
128 return false;
129 }
130 if (keys == 1) {
131 return true;
132 }
133 assert(keys == 2);
134 return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
135}
136
137static void open_nodes_remove_cb(link_t *link)
138{
139 /* We don't use remove callback for this hash table */
140}
141
142static hash_table_operations_t open_nodes_ops = {
143 .hash = open_nodes_hash,
144 .compare = open_nodes_compare,
145 .remove_callback = open_nodes_remove_cb,
146};
147
148
149int ext4fs_global_init(void)
150{
151 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
152 OPEN_NODES_KEYS, &open_nodes_ops)) {
153 return ENOMEM;
154 }
155 return EOK;
156}
157
158
159int ext4fs_global_fini(void)
160{
161 hash_table_destroy(&open_nodes);
162 return EOK;
163}
164
165
166/*
167 * EXT4 libfs operations.
168 */
169
170int ext4fs_instance_get(service_id_t service_id, ext4fs_instance_t **inst)
171{
172 ext4fs_instance_t *tmp;
173
174 fibril_mutex_lock(&instance_list_mutex);
175
176 if (list_empty(&instance_list)) {
177 fibril_mutex_unlock(&instance_list_mutex);
178 return EINVAL;
179 }
180
181 list_foreach(instance_list, link) {
182 tmp = list_get_instance(link, ext4fs_instance_t, link);
183
184 if (tmp->service_id == service_id) {
185 *inst = tmp;
186 fibril_mutex_unlock(&instance_list_mutex);
187 return EOK;
188 }
189 }
190
191 fibril_mutex_unlock(&instance_list_mutex);
192 return EINVAL;
193}
194
195
196int ext4fs_root_get(fs_node_t **rfn, service_id_t service_id)
197{
198 return ext4fs_node_get(rfn, service_id, EXT4_INODE_ROOT_INDEX);
199}
200
201
202int ext4fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
203{
204 ext4fs_node_t *eparent = EXT4FS_NODE(pfn);
205 ext4_filesystem_t *fs;
206 ext4_directory_iterator_t it;
207 int rc;
208 size_t name_size;
209 size_t component_size;
210 bool found = false;
211 uint32_t inode;
212
213 fs = eparent->instance->filesystem;
214
215 if (!ext4_inode_is_type(fs->superblock, eparent->inode_ref->inode,
216 EXT4_INODE_MODE_DIRECTORY)) {
217 return ENOTDIR;
218 }
219
220 rc = ext4_directory_iterator_init(&it, fs, eparent->inode_ref, 0);
221 if (rc != EOK) {
222 return rc;
223 }
224
225 /* Find length of component in bytes
226 * TODO: check for library function call that does this
227 */
228 component_size = 0;
229 while (*(component+component_size) != 0) {
230 component_size++;
231 }
232
233 while (it.current != NULL) {
234 inode = ext4_directory_entry_ll_get_inode(it.current);
235
236 /* ignore empty directory entries */
237 if (inode != 0) {
238 name_size = ext4_directory_entry_ll_get_name_length(fs->superblock,
239 it.current);
240
241 if (name_size == component_size && bcmp(component, &it.current->name,
242 name_size) == 0) {
243 rc = ext4fs_node_get_core(rfn, eparent->instance,
244 inode);
245 if (rc != EOK) {
246 ext4_directory_iterator_fini(&it);
247 return rc;
248 }
249 found = true;
250 break;
251 }
252 }
253
254 rc = ext4_directory_iterator_next(&it);
255 if (rc != EOK) {
256 ext4_directory_iterator_fini(&it);
257 return rc;
258 }
259 }
260
261 ext4_directory_iterator_fini(&it);
262
263 if (!found) {
264 return ENOENT;
265 }
266
267 return EOK;
268}
269
270
271int ext4fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
272{
273 ext4fs_instance_t *inst = NULL;
274 int rc;
275
276 rc = ext4fs_instance_get(service_id, &inst);
277 if (rc != EOK) {
278 return rc;
279 }
280
281 return ext4fs_node_get_core(rfn, inst, index);
282}
283
284
285int ext4fs_node_get_core(fs_node_t **rfn, ext4fs_instance_t *inst,
286 fs_index_t index)
287{
288 int rc;
289 fs_node_t *node = NULL;
290 ext4fs_node_t *enode = NULL;
291
292 ext4_inode_ref_t *inode_ref = NULL;
293
294 fibril_mutex_lock(&open_nodes_lock);
295
296 /* Check if the node is not already open */
297 unsigned long key[] = {
298 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
299 [OPEN_NODES_INODE_KEY] = index,
300 };
301 link_t *already_open = hash_table_find(&open_nodes, key);
302
303 if (already_open) {
304 enode = hash_table_get_instance(already_open, ext4fs_node_t, link);
305 *rfn = enode->fs_node;
306 enode->references++;
307
308 fibril_mutex_unlock(&open_nodes_lock);
309 return EOK;
310 }
311
312 enode = malloc(sizeof(ext4fs_node_t));
313 if (enode == NULL) {
314 fibril_mutex_unlock(&open_nodes_lock);
315 return ENOMEM;
316 }
317
318 node = malloc(sizeof(fs_node_t));
319 if (node == NULL) {
320 free(enode);
321 fibril_mutex_unlock(&open_nodes_lock);
322 return ENOMEM;
323 }
324 fs_node_initialize(node);
325
326 rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
327 if (rc != EOK) {
328 free(enode);
329 free(node);
330 fibril_mutex_unlock(&open_nodes_lock);
331 return rc;
332 }
333
334 enode->inode_ref = inode_ref;
335 enode->instance = inst;
336 enode->references = 1;
337 enode->fs_node = node;
338 link_initialize(&enode->link);
339
340 node->data = enode;
341 *rfn = node;
342
343 hash_table_insert(&open_nodes, key, &enode->link);
344 inst->open_nodes_count++;
345
346 fibril_mutex_unlock(&open_nodes_lock);
347
348 return EOK;
349}
350
351
352int ext4fs_node_put_core(ext4fs_node_t *enode)
353{
354 int rc;
355 unsigned long key[] = {
356 [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
357 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
358 };
359
360 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
361 assert(enode->instance->open_nodes_count > 0);
362 enode->instance->open_nodes_count--;
363
364 rc = ext4_filesystem_put_inode_ref(enode->inode_ref);
365 if (rc != EOK) {
366 return rc;
367 }
368
369 free(enode->fs_node);
370 free(enode);
371
372 return EOK;
373}
374
375
376int ext4fs_node_open(fs_node_t *fn)
377{
378 // TODO stateless operation
379 return EOK;
380}
381
382int ext4fs_node_put(fs_node_t *fn)
383{
384 int rc;
385 ext4fs_node_t *enode = EXT4FS_NODE(fn);
386
387 fibril_mutex_lock(&open_nodes_lock);
388
389 assert(enode->references > 0);
390 enode->references--;
391 if (enode->references == 0) {
392 rc = ext4fs_node_put_core(enode);
393 if (rc != EOK) {
394 fibril_mutex_unlock(&open_nodes_lock);
395 return rc;
396 }
397 }
398
399 fibril_mutex_unlock(&open_nodes_lock);
400
401 return EOK;
402}
403
404
405int ext4fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
406{
407 EXT4FS_DBG("not supported");
408
409 // TODO
410 return ENOTSUP;
411}
412
413
414int ext4fs_destroy_node(fs_node_t *fn)
415{
416 EXT4FS_DBG("not supported");
417
418 // TODO
419 return ENOTSUP;
420}
421
422
423int ext4fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
424{
425 EXT4FS_DBG("not supported");
426
427 // TODO
428 return ENOTSUP;
429}
430
431
432int ext4fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
433{
434 EXT4FS_DBG("not supported");
435
436 // TODO
437 return ENOTSUP;
438}
439
440
441int ext4fs_has_children(bool *has_children, fs_node_t *fn)
442{
443 ext4fs_node_t *enode = EXT4FS_NODE(fn);
444 ext4_directory_iterator_t it;
445 ext4_filesystem_t *fs;
446 int rc;
447 bool found = false;
448 size_t name_size;
449
450 fs = enode->instance->filesystem;
451
452 if (!ext4_inode_is_type(fs->superblock, enode->inode_ref->inode,
453 EXT4_INODE_MODE_DIRECTORY)) {
454 *has_children = false;
455 return EOK;
456 }
457
458 rc = ext4_directory_iterator_init(&it, fs, enode->inode_ref, 0);
459 if (rc != EOK) {
460 return rc;
461 }
462
463 /* Find a non-empty directory entry */
464 while (it.current != NULL) {
465 if (it.current->inode != 0) {
466 name_size = ext4_directory_entry_ll_get_name_length(fs->superblock,
467 it.current);
468 if (!ext4fs_is_dots(it.current->name, name_size)) {
469 found = true;
470 break;
471 }
472 }
473
474 rc = ext4_directory_iterator_next(&it);
475 if (rc != EOK) {
476 ext4_directory_iterator_fini(&it);
477 return rc;
478 }
479 }
480
481 rc = ext4_directory_iterator_fini(&it);
482 if (rc != EOK) {
483 return rc;
484 }
485
486 *has_children = found;
487
488 return EOK;
489}
490
491
492fs_index_t ext4fs_index_get(fs_node_t *fn)
493{
494 ext4fs_node_t *enode = EXT4FS_NODE(fn);
495 return enode->inode_ref->index;
496}
497
498
499aoff64_t ext4fs_size_get(fs_node_t *fn)
500{
501 ext4fs_node_t *enode = EXT4FS_NODE(fn);
502 aoff64_t size = ext4_inode_get_size(enode->instance->filesystem->superblock,
503 enode->inode_ref->inode);
504 return size;
505}
506
507
508unsigned ext4fs_lnkcnt_get(fs_node_t *fn)
509{
510 ext4fs_node_t *enode = EXT4FS_NODE(fn);
511 unsigned count = ext4_inode_get_links_count(enode->inode_ref->inode);
512 return count;
513}
514
515
516bool ext4fs_is_directory(fs_node_t *fn)
517{
518 ext4fs_node_t *enode = EXT4FS_NODE(fn);
519 bool is_dir = ext4_inode_is_type(enode->instance->filesystem->superblock,
520 enode->inode_ref->inode, EXT4_INODE_MODE_DIRECTORY);
521 return is_dir;
522}
523
524
525bool ext4fs_is_file(fs_node_t *fn)
526{
527 ext4fs_node_t *enode = EXT4FS_NODE(fn);
528 bool is_file = ext4_inode_is_type(enode->instance->filesystem->superblock,
529 enode->inode_ref->inode, EXT4_INODE_MODE_FILE);
530 return is_file;
531}
532
533
534service_id_t ext4fs_service_get(fs_node_t *fn)
535{
536 ext4fs_node_t *enode = EXT4FS_NODE(fn);
537 return enode->instance->service_id;
538}
539
540/*
541 * libfs operations.
542 */
543libfs_ops_t ext4fs_libfs_ops = {
544 .root_get = ext4fs_root_get,
545 .match = ext4fs_match,
546 .node_get = ext4fs_node_get,
547 .node_open = ext4fs_node_open,
548 .node_put = ext4fs_node_put,
549 .create = ext4fs_create_node,
550 .destroy = ext4fs_destroy_node,
551 .link = ext4fs_link,
552 .unlink = ext4fs_unlink,
553 .has_children = ext4fs_has_children,
554 .index_get = ext4fs_index_get,
555 .size_get = ext4fs_size_get,
556 .lnkcnt_get = ext4fs_lnkcnt_get,
557 .is_directory = ext4fs_is_directory,
558 .is_file = ext4fs_is_file,
559 .service_get = ext4fs_service_get
560};
561
562
563/*
564 * VFS operations.
565 */
566
567static int ext4fs_mounted(service_id_t service_id, const char *opts,
568 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
569{
570 int rc;
571 ext4_filesystem_t *fs;
572 ext4fs_instance_t *inst;
573 bool read_only;
574
575 /* Allocate libext4 filesystem structure */
576 fs = (ext4_filesystem_t *) malloc(sizeof(ext4_filesystem_t));
577 if (fs == NULL) {
578 return ENOMEM;
579 }
580
581 /* Allocate instance structure */
582 inst = (ext4fs_instance_t *) malloc(sizeof(ext4fs_instance_t));
583 if (inst == NULL) {
584 free(fs);
585 return ENOMEM;
586 }
587
588 /* Initialize the filesystem */
589 rc = ext4_filesystem_init(fs, service_id);
590 if (rc != EOK) {
591 free(fs);
592 free(inst);
593 return rc;
594 }
595
596 /* Do some sanity checking */
597 rc = ext4_filesystem_check_sanity(fs);
598 if (rc != EOK) {
599 ext4_filesystem_fini(fs);
600 free(fs);
601 free(inst);
602 return rc;
603 }
604
605 /* Check flags */
606 rc = ext4_filesystem_check_features(fs, &read_only);
607 if (rc != EOK) {
608 ext4_filesystem_fini(fs);
609 free(fs);
610 free(inst);
611 return rc;
612 }
613
614 /* Initialize instance */
615 link_initialize(&inst->link);
616 inst->service_id = service_id;
617 inst->filesystem = fs;
618 inst->open_nodes_count = 0;
619
620 /* Read root node */
621 fs_node_t *root_node;
622 rc = ext4fs_node_get_core(&root_node, inst, EXT4_INODE_ROOT_INDEX);
623 if (rc != EOK) {
624 ext4_filesystem_fini(fs);
625 free(fs);
626 free(inst);
627 return rc;
628 }
629 ext4fs_node_t *enode = EXT4FS_NODE(root_node);
630
631 /* Add instance to the list */
632 fibril_mutex_lock(&instance_list_mutex);
633 list_append(&inst->link, &instance_list);
634 fibril_mutex_unlock(&instance_list_mutex);
635
636 *index = EXT4_INODE_ROOT_INDEX;
637 *size = 0;
638 *lnkcnt = ext4_inode_get_links_count(enode->inode_ref->inode);
639
640 ext4fs_node_put(root_node);
641
642 return EOK;
643}
644
645
646static int ext4fs_unmounted(service_id_t service_id)
647{
648 int rc;
649 ext4fs_instance_t *inst;
650
651 rc = ext4fs_instance_get(service_id, &inst);
652
653 if (rc != EOK) {
654 return rc;
655 }
656
657 fibril_mutex_lock(&open_nodes_lock);
658
659 if (inst->open_nodes_count != 0) {
660 fibril_mutex_unlock(&open_nodes_lock);
661 return EBUSY;
662 }
663
664 /* Remove the instance from the list */
665 fibril_mutex_lock(&instance_list_mutex);
666 list_remove(&inst->link);
667 fibril_mutex_unlock(&instance_list_mutex);
668
669 fibril_mutex_unlock(&open_nodes_lock);
670
671 ext4_filesystem_fini(inst->filesystem);
672
673 return EOK;
674}
675
676
677static int
678ext4fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
679 size_t *rbytes)
680{
681 ext4fs_instance_t *inst;
682 ext4_inode_ref_t *inode_ref;
683 int rc;
684
685 /*
686 * Receive the read request.
687 */
688 ipc_callid_t callid;
689 size_t size;
690 if (!async_data_read_receive(&callid, &size)) {
691 async_answer_0(callid, EINVAL);
692 return EINVAL;
693 }
694
695 rc = ext4fs_instance_get(service_id, &inst);
696 if (rc != EOK) {
697 async_answer_0(callid, rc);
698 return rc;
699 }
700
701 rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
702 if (rc != EOK) {
703 async_answer_0(callid, rc);
704 return rc;
705 }
706
707 if (ext4_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
708 EXT4_INODE_MODE_FILE)) {
709 rc = ext4fs_read_file(callid, pos, size, inst, inode_ref,
710 rbytes);
711 } else if (ext4_inode_is_type(inst->filesystem->superblock,
712 inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) {
713 rc = ext4fs_read_directory(callid, pos, size, inst, inode_ref,
714 rbytes);
715 } else {
716 /* Other inode types not supported */
717 async_answer_0(callid, ENOTSUP);
718 rc = ENOTSUP;
719 }
720
721 ext4_filesystem_put_inode_ref(inode_ref);
722
723 return rc;
724}
725
726bool ext4fs_is_dots(const uint8_t *name, size_t name_size)
727{
728 if (name_size == 1 && name[0] == '.') {
729 return true;
730 }
731
732 if (name_size == 2 && name[0] == '.' && name[1] == '.') {
733 return true;
734 }
735
736 return false;
737}
738
739int ext4fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size,
740 ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes)
741{
742
743 ext4_directory_iterator_t it;
744 aoff64_t next;
745 uint8_t *buf;
746 size_t name_size;
747 int rc;
748 bool found = false;
749
750 // TODO check super block COMPAT FEATURES
751 if (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_INDEX)) {
752 rc = ext4fs_read_dx_directory(callid, pos, size, inst, inode_ref, rbytes);
753 // TODO return...
754 // return rc;
755 }
756
757 rc = ext4_directory_iterator_init(&it, inst->filesystem, inode_ref, pos);
758 if (rc != EOK) {
759 async_answer_0(callid, rc);
760 return rc;
761 }
762
763 /* Find next interesting directory entry.
764 * We want to skip . and .. entries
765 * as these are not used in HelenOS
766 */
767 while (it.current != NULL) {
768
769 if (it.current->inode == 0) {
770 goto skip;
771 }
772
773 name_size = ext4_directory_entry_ll_get_name_length(
774 inst->filesystem->superblock, it.current);
775
776 /* skip . and .. */
777 if (ext4fs_is_dots(it.current->name, name_size)) {
778 goto skip;
779 }
780
781 /* The on-disk entry does not contain \0 at the end
782 * end of entry name, so we copy it to new buffer
783 * and add the \0 at the end
784 */
785 buf = malloc(name_size+1);
786 if (buf == NULL) {
787 ext4_directory_iterator_fini(&it);
788 async_answer_0(callid, ENOMEM);
789 return ENOMEM;
790 }
791 memcpy(buf, &it.current->name, name_size);
792 *(buf + name_size) = 0;
793 found = true;
794 (void) async_data_read_finalize(callid, buf, name_size + 1);
795 free(buf);
796 break;
797
798skip:
799 rc = ext4_directory_iterator_next(&it);
800 if (rc != EOK) {
801 ext4_directory_iterator_fini(&it);
802 async_answer_0(callid, rc);
803 return rc;
804 }
805 }
806
807 if (found) {
808 rc = ext4_directory_iterator_next(&it);
809 if (rc != EOK) {
810 return rc;
811 }
812 next = it.current_offset;
813 }
814
815 rc = ext4_directory_iterator_fini(&it);
816 if (rc != EOK) {
817 return rc;
818 }
819
820 if (found) {
821 *rbytes = next - pos;
822 return EOK;
823 } else {
824 async_answer_0(callid, ENOENT);
825 return ENOENT;
826 }
827}
828
829int ext4fs_read_dx_directory(ipc_callid_t callid, aoff64_t pos, size_t size,
830 ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes)
831{
832 EXT4FS_DBG("Directory using HTree index");
833 return ENOTSUP;
834}
835
836int ext4fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size,
837 ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes)
838{
839 int rc;
840 uint32_t block_size;
841 aoff64_t file_block;
842 uint64_t file_size;
843 uint32_t fs_block;
844 size_t offset_in_block;
845 size_t bytes;
846 block_t *block;
847 uint8_t *buffer;
848
849 file_size = ext4_inode_get_size(inst->filesystem->superblock,
850 inode_ref->inode);
851
852 if (pos >= file_size) {
853 /* Read 0 bytes successfully */
854 async_data_read_finalize(callid, NULL, 0);
855 *rbytes = 0;
856 return EOK;
857 }
858
859 /* For now, we only read data from one block at a time */
860 block_size = ext4_superblock_get_block_size(inst->filesystem->superblock);
861 file_block = pos / block_size;
862 offset_in_block = pos % block_size;
863 bytes = min(block_size - offset_in_block, size);
864
865 /* Handle end of file */
866 if (pos + bytes > file_size) {
867 bytes = file_size - pos;
868 }
869
870 /* Get the real block number */
871 rc = ext4_filesystem_get_inode_data_block_index(inst->filesystem,
872 inode_ref->inode, file_block, &fs_block);
873 if (rc != EOK) {
874 async_answer_0(callid, rc);
875 return rc;
876 }
877
878 /* Check for sparse file
879 * If ext2_filesystem_get_inode_data_block_index returned
880 * fs_block == 0, it means that the given block is not allocated for the
881 * file and we need to return a buffer of zeros
882 */
883 if (fs_block == 0) {
884 buffer = malloc(bytes);
885 if (buffer == NULL) {
886 async_answer_0(callid, ENOMEM);
887 return ENOMEM;
888 }
889
890 memset(buffer, 0, bytes);
891
892 async_data_read_finalize(callid, buffer, bytes);
893 *rbytes = bytes;
894
895 free(buffer);
896
897 return EOK;
898 }
899
900 /* Usual case - we need to read a block from device */
901 rc = block_get(&block, inst->service_id, fs_block, BLOCK_FLAGS_NONE);
902 if (rc != EOK) {
903 async_answer_0(callid, rc);
904 return rc;
905 }
906
907 assert(offset_in_block + bytes <= block_size);
908 async_data_read_finalize(callid, block->data + offset_in_block, bytes);
909
910 rc = block_put(block);
911 if (rc != EOK) {
912 return rc;
913 }
914
915 *rbytes = bytes;
916 return EOK;
917}
918
919static int
920ext4fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
921 size_t *wbytes, aoff64_t *nsize)
922{
923 EXT4FS_DBG("not supported");
924
925 // TODO
926 return ENOTSUP;
927}
928
929
930static int
931ext4fs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
932{
933 EXT4FS_DBG("not supported");
934
935 // TODO
936 return ENOTSUP;
937}
938
939
940static int ext4fs_close(service_id_t service_id, fs_index_t index)
941{
942 // TODO
943 return EOK;
944}
945
946
947static int ext4fs_destroy(service_id_t service_id, fs_index_t index)
948{
949 EXT4FS_DBG("not supported");
950
951 //TODO
952 return ENOTSUP;
953}
954
955
956static int ext4fs_sync(service_id_t service_id, fs_index_t index)
957{
958 EXT4FS_DBG("not supported");
959
960 // TODO
961 return ENOTSUP;
962}
963
964vfs_out_ops_t ext4fs_ops = {
965 .mounted = ext4fs_mounted,
966 .unmounted = ext4fs_unmounted,
967 .read = ext4fs_read,
968 .write = ext4fs_write,
969 .truncate = ext4fs_truncate,
970 .close = ext4fs_close,
971 .destroy = ext4fs_destroy,
972 .sync = ext4fs_sync,
973};
974
975/**
976 * @}
977 */
Note: See TracBrowser for help on using the repository browser.