2 * Copyright (c) 2008, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
17 /* directories are stored as components,
18 * components are simple ids from the string pool
19 * /usr/bin -> "", "usr", "bin"
20 * /usr/lib -> "", "usr", "lib"
21 * foo/bar -> "foo", "bar"
22 * /usr/games -> "", "usr", "games"
24 * all directories are stores in the "dirs" array
25 * dirs[id] > 0 : component string pool id
26 * dirs[id] <= 0 : -(parent directory id)
28 * Directories with the same parent are stored as
29 * multiple blocks. We need multiple blocks because
30 * we cannot insert entries into old blocks, as that
31 * would shift the ids of already used directories.
32 * Each block starts with (-parent_dirid) and contains
33 * component ids of the directory entries.
34 * (The (-parent_dirid) entry is not a valid directory
35 * id, it's just used internally)
37 * There is also the aux "dirtraverse" array, which
38 * is created on demand to speed things up a bit.
39 * if dirs[id] > 0, dirtravers[id] points to the first
40 * entry in the last block with parent id.
41 * if dirs[id] <= 0, dirtravers[id] points to the entry
42 * in the previous block with the same parent.
43 * (Thus it acts as a linked list that starts at the
44 * parent dirid and chains all the blocks with that
47 * id dirs[id] dirtraverse[id]
48 * 0 0 8 [no parent, block#0]
50 * 2 -1 [parent 1, /, block #0]
52 * 4 -3 [parent 3, /usr, block #0]
55 * 7 0 1 [no parent, block#1]
57 * 9 -8 [parent 8, foo, block #0]
59 * 11 -3 5 [parent 3, /usr, block #1]
62 * to find all children of dirid 3 ("/usr"), follow the
63 * dirtraverse link to 12 -> "games". Then follow the
64 * dirtraverse link of this block to 5 -> "bin", "lib"
68 dirpool_init(Dirpool *dp)
70 memset(dp, 0, sizeof(*dp));
74 dirpool_free(Dirpool *dp)
77 solv_free(dp->dirtraverse);
81 dirpool_make_dirtraverse(Dirpool *dp)
83 Id parent, i, *dirtraverse;
86 dp->dirs = solv_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
87 dirtraverse = solv_calloc_block(dp->ndirs, sizeof(Id), DIR_BLOCK);
88 for (parent = 0, i = 0; i < dp->ndirs; i++)
92 parent = -dp->dirs[i];
93 dirtraverse[i] = dirtraverse[parent];
94 dirtraverse[parent] = i + 1;
96 dp->dirtraverse = dirtraverse;
100 dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create)
102 Id did, d, ds, *dirtraverse;
109 dp->dirs = solv_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
111 dp->dirs[1] = 1; /* "" */
113 if (parent == 0 && comp == 1)
115 if (!dp->dirtraverse)
116 dirpool_make_dirtraverse(dp);
117 /* check all entries with this parent if we
118 * already have this component */
119 dirtraverse = dp->dirtraverse;
120 ds = dirtraverse[parent];
123 /* ds: first component in this block
124 * ds-1: parent link */
125 for (d = ds--; d < dp->ndirs; d++)
127 if (dp->dirs[d] == comp)
129 if (dp->dirs[d] <= 0) /* reached end of this block */
133 ds = dp->dirtraverse[ds];
137 /* a new one, find last parent */
138 for (did = dp->ndirs - 1; did > 0; did--)
139 if (dp->dirs[did] <= 0)
141 if (dp->dirs[did] != -parent)
143 /* make room for parent entry */
144 dp->dirs = solv_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
145 dp->dirtraverse = solv_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
146 /* new parent block, link in */
147 dp->dirs[dp->ndirs] = -parent;
148 dp->dirtraverse[dp->ndirs] = dp->dirtraverse[parent];
149 dp->dirtraverse[parent] = ++dp->ndirs;
151 /* make room for new entry */
152 dp->dirs = solv_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
153 dp->dirtraverse = solv_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
154 dp->dirs[dp->ndirs] = comp;
155 dp->dirtraverse[dp->ndirs] = 0;