source: mainline/uspace/srv/fs/ext4fs/ext4fs_ops.c@ 36d2c6f

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

successful reading indexed directory if item is in the first leaf block

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