source: mainline/uspace/srv/fs/ext4fs/ext4fs_ops.c@ 7bc4508

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

First part of reading htree directory index - the most important functionality (computing hashes) still missing

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