1/*
2 * Copyright 2016, NICTA
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(NICTA_GPL)
9 */
10
11#include <bilbyfs.h>
12
13void rdx_init(struct bilbyfs_info *bi, struct fsop_readdir_ctx *rdx, ino_t ino)
14{
15        BUILD_BUG_ON(sizeof(struct fsop_readdir_ctx) > BILBYFS_MAX_READDIR_DATA_SIZE);
16        rdx->id = inode_id_init(ino);
17        rdx->dentarr = NULL;
18        rdx->de = NULL;
19}
20
21void rdx_clean(struct fsop_readdir_ctx *rdx)
22{
23        rdx->id = NIL_ID;
24        kfree(rdx->dentarr);
25        rdx->dentarr = NULL;
26        rdx->de = NULL;
27}
28
29static struct obj_dentry *next_dentarr_dentry(struct bilbyfs_info *bi,
30                                              struct fsop_readdir_ctx *rdx)
31{
32        struct obj_dentarr *dentarr;
33
34        do {
35                kfree(rdx->dentarr);
36                rdx->dentarr = NULL;
37                rdx->id = ostore_next_obj_id(bi, rdx->id);
38                if (!is_dentarr_id(rdx->id) || rdx->id == NIL_ID)
39                        return ERR_PTR(-ENOENT);
40
41                dentarr = dentarr_read(bi, rdx->id);
42                if (IS_ERR(dentarr))
43                        return (void *)dentarr;
44                rdx->dentarr = dentarr;
45                /* FIXME dentarr_read() should never return an empty
46                 * dentarr, I believe this check is useless */
47        } while (!dentarr_check_empty(bi, rdx->dentarr));
48        /* As the dentarr object is non-empty: no risk to return NULL */
49        return dentarr_first_dentry(rdx->dentarr);
50}
51
52struct obj_dentry *rdx_next_dentry(struct bilbyfs_info *bi,
53                                   struct fsop_readdir_ctx *rdx)
54{
55        struct obj_dentry *de;
56
57        if (!rdx->dentarr) {
58                de = next_dentarr_dentry(bi, rdx);
59                rdx->de = IS_ERR(de) ? NULL : de;
60                return de;
61        }
62
63        /* Here rdx->de should always be a valid dentry within dentarr
64         * unless rdx_next_dentry has already return -ENOENT */
65        rdx->de = rdx->de ? dentarr_next_dentry(rdx->dentarr, rdx->de) : NULL;
66        if (!rdx->de) {
67                de = next_dentarr_dentry(bi, rdx);
68                rdx->de = IS_ERR(de) ? NULL : de;
69                return de;
70        }
71        return rdx->de ? rdx->de : ERR_PTR(-ENOENT);
72}
73