source: mainline/uspace/srv/fs/ext4fs/ext4fs_ops.c@ 829d238

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

Basic extent structures + applied bugfix from M. Lombardi

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