Extract common OMFS code into a library
[omfsprogs.git] / dirscan.c
blobe4c3e9d2b73dd182c939ed39a8387f6eb46352a9
1 /*
2 * dirscan.c - iterator for traversing the directory tree.
4 * We never have to hold more than a few inodes in memory. Let
5 * the OS cache em.
7 * TODO: add cycle detection
8 */
10 #include <stdlib.h>
11 #include "dirscan.h"
13 static dirscan_entry_t *_create_entry(omfs_inode_t *inode,
14 int level, int hindex, u64 parent, u64 block)
16 dirscan_entry_t *entry = malloc(sizeof(dirscan_entry_t));
17 entry->inode = inode;
18 entry->level = level;
19 entry->hindex = hindex;
20 entry->parent = parent;
21 entry->block = block;
23 return entry;
26 static void dirscan_release_entry(dirscan_entry_t *entry)
28 omfs_release_inode(entry->inode);
29 free(entry);
33 int traverse (dirscan_t *d, dirscan_entry_t *entry)
35 omfs_inode_t *ino, *tmp;
36 dirscan_entry_t *enew;
37 int res;
39 d->visit_error = d->visit(d, entry, d->user_data);
41 ino = entry->inode;
43 /* push next sibling all then all children */
44 if (ino->i_sibling != ~0)
46 tmp = omfs_get_inode(d->omfs_info, swap_be64(ino->i_sibling));
47 if (!tmp)
49 res = -1;
50 goto out;
53 enew = _create_entry(tmp, entry->level, entry->hindex,
54 entry->parent, swap_be64(ino->i_sibling));
55 traverse(d, enew);
57 if (ino->i_type == OMFS_DIR)
59 int i;
60 u64 *ptr = (u64*) ((u8*) ino + OMFS_DIR_START);
62 int num_entries = (swap_be32(ino->i_head.h_body_size) +
63 sizeof(omfs_header_t) - OMFS_DIR_START) / 8;
65 for (i=0; i<num_entries; i++, ptr++)
67 u64 inum = swap_be64(*ptr);
68 if (inum != ~0)
70 tmp = omfs_get_inode(d->omfs_info, inum);
71 if (!tmp) {
72 res = -1;
73 goto out;
75 enew = _create_entry(tmp, entry->level+1, i,
76 entry->block, inum);
77 traverse(d, enew);
81 out:
82 dirscan_release_entry(entry);
83 return res;
86 static void dirscan_end(dirscan_t *d)
88 free(d);
91 int dirscan_begin(omfs_info_t *info, int (*visit)(dirscan_t *,
92 dirscan_entry_t*, void*), void *user_data)
94 omfs_inode_t *root_ino;
95 int res;
97 dirscan_t *d = calloc(sizeof(dirscan_t), 1);
98 if (!d)
99 goto error;
101 d->omfs_info = info;
102 d->visit = visit;
103 d->user_data = user_data;
105 root_ino = omfs_get_inode(info, swap_be64(info->root->r_root_dir));
106 if (!root_ino)
107 goto error;
108 res = traverse(d, _create_entry(root_ino, 0, 0, ~0,
109 swap_be64(info->root->r_root_dir)));
111 dirscan_end(d);
113 return !d->visit_error;
115 error:
116 if (d) free(d);
117 return -1;