Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: libq/, /
Date: Thu, 09 May 2019 20:19:46
Message-Id: 1557433066.7cf702111a7350b17443f4d9d0d76138b503dac3.grobian@gentoo
1 commit: 7cf702111a7350b17443f4d9d0d76138b503dac3
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Thu May 9 20:17:46 2019 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Thu May 9 20:17:46 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=7cf70211
7
8 libq/tree: merge vdb and cache
9
10 since cache was basically a shadow of vdb, and vdb grew too many
11 non-vdb-like behaviour, renamed to tree such that further features only
12 have to be implemented once
13
14 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
15
16 TODO.md | 7 +-
17 libq/Makefile.am | 3 +-
18 libq/Makefile.in | 31 +-
19 libq/cache.c | 687 -----------------------------------
20 libq/cache.h | 74 ----
21 libq/tree.c | 1066 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
22 libq/tree.h | 141 ++++++++
23 libq/vdb.c | 515 --------------------------
24 libq/vdb.h | 96 -----
25 main.c | 20 -
26 q.c | 2 -
27 qcheck.c | 37 +-
28 qdepends.c | 22 +-
29 qfile.c | 19 +-
30 qgrep.c | 29 +-
31 qkeyword.c | 43 ++-
32 qlist.c | 35 +-
33 qmerge.c | 66 ++--
34 qpkg.c | 30 +-
35 qsearch.c | 20 +-
36 qsize.c | 13 +-
37 quse.c | 17 +-
38 22 files changed, 1419 insertions(+), 1554 deletions(-)
39
40 diff --git a/TODO.md b/TODO.md
41 index 3333fd6..ec5f843 100644
42 --- a/TODO.md
43 +++ b/TODO.md
44 @@ -23,10 +23,11 @@
45 we end up getting just:<br>
46 `ACCEPT_LICENSE=" bar"`
47
48 -- vdb\_foreach\_pkg should have variant that takes an atom (or just
49 - cat?) to reduce search space, same for cache\_foreach\_pkg
50 +- tree\_foreach\_pkg should have variant that takes an atom (or just
51 + cat?) to reduce search space
52
53 -- vdb repo/slot think about when it is freed (see cache\_pkg\_close)
54 +- tree\_get\_atoms should return atoms iso string set, needs a rewrite
55 + to use foreach\_pkg and get\_atom
56
57 # Atoms
58
59
60 diff --git a/libq/Makefile.am b/libq/Makefile.am
61 index 765347f..62ffb83 100644
62 --- a/libq/Makefile.am
63 +++ b/libq/Makefile.am
64 @@ -3,7 +3,6 @@ QFILES = \
65 atom.c atom.h \
66 basename.c basename.h \
67 busybox.h \
68 - cache.c cache.h \
69 colors.c colors.h \
70 contents.c contents.h \
71 copy_file.c copy_file.h \
72 @@ -19,7 +18,7 @@ QFILES = \
73 safe_io.c safe_io.h \
74 scandirat.c scandirat.h \
75 set.c set.h \
76 - vdb.c vdb.h \
77 + tree.c tree.h \
78 xarray.c xarray.h \
79 xasprintf.h \
80 xchdir.c xchdir.h \
81
82 diff --git a/libq/Makefile.in b/libq/Makefile.in
83 index 5f118fc..c359f4b 100644
84 --- a/libq/Makefile.in
85 +++ b/libq/Makefile.in
86 @@ -241,13 +241,13 @@ CONFIG_CLEAN_FILES =
87 CONFIG_CLEAN_VPATH_FILES =
88 LTLIBRARIES = $(noinst_LTLIBRARIES)
89 libq_la_LIBADD =
90 -am__objects_1 = libq_la-atom.lo libq_la-basename.lo libq_la-cache.lo \
91 - libq_la-colors.lo libq_la-contents.lo libq_la-copy_file.lo \
92 - libq_la-dep.lo libq_la-eat_file.lo libq_la-hash_fd.lo \
93 +am__objects_1 = libq_la-atom.lo libq_la-basename.lo libq_la-colors.lo \
94 + libq_la-contents.lo libq_la-copy_file.lo libq_la-dep.lo \
95 + libq_la-eat_file.lo libq_la-hash_fd.lo \
96 libq_la-human_readable.lo libq_la-md5_sha1_sum.lo \
97 libq_la-prelink.lo libq_la-profile.lo libq_la-rmspace.lo \
98 libq_la-safe_io.lo libq_la-scandirat.lo libq_la-set.lo \
99 - libq_la-vdb.lo libq_la-xarray.lo libq_la-xchdir.lo \
100 + libq_la-tree.lo libq_la-xarray.lo libq_la-xchdir.lo \
101 libq_la-xmkdir.lo libq_la-xpak.lo libq_la-xregex.lo \
102 libq_la-xsystem.lo
103 am_libq_la_OBJECTS = $(am__objects_1)
104 @@ -1447,7 +1447,6 @@ QFILES = \
105 atom.c atom.h \
106 basename.c basename.h \
107 busybox.h \
108 - cache.c cache.h \
109 colors.c colors.h \
110 contents.c contents.h \
111 copy_file.c copy_file.h \
112 @@ -1463,7 +1462,7 @@ QFILES = \
113 safe_io.c safe_io.h \
114 scandirat.c scandirat.h \
115 set.c set.h \
116 - vdb.c vdb.h \
117 + tree.c tree.h \
118 xarray.c xarray.h \
119 xasprintf.h \
120 xchdir.c xchdir.h \
121 @@ -1535,7 +1534,6 @@ distclean-compile:
122
123 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-atom.Plo@am__quote@
124 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-basename.Plo@am__quote@
125 -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-cache.Plo@am__quote@
126 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-colors.Plo@am__quote@
127 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-contents.Plo@am__quote@
128 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-copy_file.Plo@am__quote@
129 @@ -1550,7 +1548,7 @@ distclean-compile:
130 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-safe_io.Plo@am__quote@
131 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-scandirat.Plo@am__quote@
132 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-set.Plo@am__quote@
133 -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-vdb.Plo@am__quote@
134 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-tree.Plo@am__quote@
135 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-xarray.Plo@am__quote@
136 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-xchdir.Plo@am__quote@
137 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libq_la-xmkdir.Plo@am__quote@
138 @@ -1593,13 +1591,6 @@ libq_la-basename.lo: basename.c
139 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
140 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libq_la-basename.lo `test -f 'basename.c' || echo '$(srcdir)/'`basename.c
141
142 -libq_la-cache.lo: cache.c
143 -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libq_la-cache.lo -MD -MP -MF $(DEPDIR)/libq_la-cache.Tpo -c -o libq_la-cache.lo `test -f 'cache.c' || echo '$(srcdir)/'`cache.c
144 -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libq_la-cache.Tpo $(DEPDIR)/libq_la-cache.Plo
145 -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cache.c' object='libq_la-cache.lo' libtool=yes @AMDEPBACKSLASH@
146 -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
147 -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libq_la-cache.lo `test -f 'cache.c' || echo '$(srcdir)/'`cache.c
148 -
149 libq_la-colors.lo: colors.c
150 @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libq_la-colors.lo -MD -MP -MF $(DEPDIR)/libq_la-colors.Tpo -c -o libq_la-colors.lo `test -f 'colors.c' || echo '$(srcdir)/'`colors.c
151 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libq_la-colors.Tpo $(DEPDIR)/libq_la-colors.Plo
152 @@ -1698,12 +1689,12 @@ libq_la-set.lo: set.c
153 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
154 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libq_la-set.lo `test -f 'set.c' || echo '$(srcdir)/'`set.c
155
156 -libq_la-vdb.lo: vdb.c
157 -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libq_la-vdb.lo -MD -MP -MF $(DEPDIR)/libq_la-vdb.Tpo -c -o libq_la-vdb.lo `test -f 'vdb.c' || echo '$(srcdir)/'`vdb.c
158 -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libq_la-vdb.Tpo $(DEPDIR)/libq_la-vdb.Plo
159 -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vdb.c' object='libq_la-vdb.lo' libtool=yes @AMDEPBACKSLASH@
160 +libq_la-tree.lo: tree.c
161 +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libq_la-tree.lo -MD -MP -MF $(DEPDIR)/libq_la-tree.Tpo -c -o libq_la-tree.lo `test -f 'tree.c' || echo '$(srcdir)/'`tree.c
162 +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libq_la-tree.Tpo $(DEPDIR)/libq_la-tree.Plo
163 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tree.c' object='libq_la-tree.lo' libtool=yes @AMDEPBACKSLASH@
164 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
165 -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libq_la-vdb.lo `test -f 'vdb.c' || echo '$(srcdir)/'`vdb.c
166 +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libq_la-tree.lo `test -f 'tree.c' || echo '$(srcdir)/'`tree.c
167
168 libq_la-xarray.lo: xarray.c
169 @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libq_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libq_la-xarray.lo -MD -MP -MF $(DEPDIR)/libq_la-xarray.Tpo -c -o libq_la-xarray.lo `test -f 'xarray.c' || echo '$(srcdir)/'`xarray.c
170
171 diff --git a/libq/cache.c b/libq/cache.c
172 deleted file mode 100644
173 index 304cd34..0000000
174 --- a/libq/cache.c
175 +++ /dev/null
176 @@ -1,687 +0,0 @@
177 -/*
178 - * Copyright 2005-2019 Gentoo Foundation
179 - * Distributed under the terms of the GNU General Public License v2
180 - *
181 - * Copyright 2005-2008 Ned Ludd - <solar@g.o>
182 - * Copyright 2005-2014 Mike Frysinger - <vapier@g.o>
183 - * Copyright 2018- Fabian Groffen - <grobian@g.o>
184 - */
185 -
186 -#include "main.h"
187 -
188 -#include <fcntl.h>
189 -#include <sys/types.h>
190 -#include <sys/stat.h>
191 -#include <ctype.h>
192 -#include <xalloc.h>
193 -
194 -#include "cache.h"
195 -#include "eat_file.h"
196 -#include "rmspace.h"
197 -#include "scandirat.h"
198 -#include "vdb.h"
199 -
200 -#ifdef EBUG
201 -static void
202 -cache_dump(cache_pkg_meta *cache)
203 -{
204 - if (!cache)
205 - errf("Cache is empty !");
206 -
207 - printf("DEPEND : %s\n", cache->DEPEND);
208 - printf("RDEPEND : %s\n", cache->RDEPEND);
209 - printf("SLOT : %s\n", cache->SLOT);
210 - printf("SRC_URI : %s\n", cache->SRC_URI);
211 - printf("RESTRICT : %s\n", cache->RESTRICT);
212 - printf("HOMEPAGE : %s\n", cache->HOMEPAGE);
213 - printf("LICENSE : %s\n", cache->LICENSE);
214 - printf("DESCRIPTION: %s\n", cache->DESCRIPTION);
215 - printf("KEYWORDS : %s\n", cache->KEYWORDS);
216 - printf("INHERITED : %s\n", cache->INHERITED);
217 - printf("IUSE : %s\n", cache->IUSE);
218 - printf("CDEPEND : %s\n", cache->CDEPEND);
219 - printf("PDEPEND : %s\n", cache->PDEPEND);
220 - printf("PROVIDE : %s\n", cache->PROVIDE);
221 - printf("EAPI : %s\n", cache->EAPI);
222 - printf("PROPERTIES : %s\n", cache->PROPERTIES);
223 -}
224 -#endif
225 -
226 -static const char portcachedir_pms[] = "metadata/cache";
227 -static const char portcachedir_md5[] = "metadata/md5-cache";
228 -static const char portrepo_name[] = "profiles/repo_name";
229 -cache_ctx *
230 -cache_open(const char *sroot, const char *portdir)
231 -{
232 - cache_ctx *ret;
233 - char buf[_Q_PATH_MAX];
234 - char *repo = NULL;
235 - size_t repolen = 0;
236 -
237 - snprintf(buf, sizeof(buf), "%s%s/%s", sroot, portdir, portrepo_name);
238 - if (eat_file(buf, &repo, &repolen)) {
239 - (void)rmspace(repo);
240 - } else {
241 - repo = NULL; /* ignore missing repo file */
242 - }
243 -
244 - snprintf(buf, sizeof(buf), "%s/%s", portdir, portcachedir_md5);
245 - ret = vdb_open2(sroot, buf, true);
246 - if (ret != NULL) {
247 - ret->cachetype = CACHE_METADATA_MD5;
248 - ret->repo = repo;
249 - return ret;
250 - }
251 -
252 - snprintf(buf, sizeof(buf), "%s/%s", portdir, portcachedir_pms);
253 - ret = vdb_open2(sroot, buf, true);
254 - if (ret != NULL) {
255 - ret->cachetype = CACHE_METADATA_PMS;
256 - ret->repo = repo;
257 - return ret;
258 - }
259 -
260 - ret = vdb_open2(sroot, portdir, true);
261 - if (ret != NULL) {
262 - ret->cachetype = CACHE_EBUILD;
263 - ret->repo = repo;
264 - return ret;
265 - }
266 -
267 - cache_close(ret);
268 - warnf("could not open repository at %s (under root %s)", portdir, sroot);
269 -
270 - return NULL;
271 -}
272 -
273 -void
274 -cache_close(cache_ctx *ctx)
275 -{
276 - if (ctx->repo != NULL)
277 - free(ctx->repo);
278 - if (ctx->ebuilddir_ctx != NULL)
279 - free(ctx->ebuilddir_ctx);
280 - vdb_close(ctx);
281 -}
282 -
283 -cache_cat_ctx *
284 -cache_open_cat(cache_ctx *ctx, const char *name)
285 -{
286 - return vdb_open_cat(ctx, name);
287 -}
288 -
289 -cache_cat_ctx *
290 -cache_next_cat(cache_ctx *ctx)
291 -{
292 - return vdb_next_cat(ctx);
293 -}
294 -
295 -void
296 -cache_close_cat(cache_cat_ctx *cat_ctx)
297 -{
298 - return vdb_close_cat(cat_ctx);
299 -}
300 -
301 -cache_pkg_ctx *
302 -cache_open_pkg(cache_cat_ctx *cat_ctx, const char *name)
303 -{
304 - return vdb_open_pkg(cat_ctx, name);
305 -}
306 -
307 -cache_pkg_ctx *
308 -cache_next_pkg(cache_cat_ctx *cat_ctx)
309 -{
310 - cache_ctx *ctx = (cache_ctx *)cat_ctx->ctx;
311 - cache_pkg_ctx *ret = NULL;
312 -
313 - if (ctx->cachetype == CACHE_EBUILD) {
314 - char *p;
315 -
316 - /* serve *.ebuild files each as separate pkg_ctx with name set
317 - * to CAT/P like in VDB and metadata */
318 - do {
319 - if (ctx->ebuilddir_pkg_ctx == NULL) {
320 - vdb_ctx *pkgdir = ctx->ebuilddir_ctx;
321 -
322 - if (pkgdir == NULL)
323 - pkgdir = ctx->ebuilddir_ctx = xmalloc(sizeof(vdb_ctx));
324 - memset(ctx->ebuilddir_ctx, '\0', sizeof(*ctx->ebuilddir_ctx));
325 -
326 - if ((ctx->ebuilddir_pkg_ctx = vdb_next_pkg(cat_ctx)) == NULL)
327 - return NULL;
328 -
329 - pkgdir->portroot_fd = -1;
330 - pkgdir->vdb_fd = cat_ctx->fd;
331 - pkgdir->do_sort = ctx->do_sort;
332 - pkgdir->catsortfunc = ctx->catsortfunc;
333 - pkgdir->pkgsortfunc = ctx->pkgsortfunc;
334 - pkgdir->repo = ctx->repo;
335 - pkgdir->cachetype = ctx->cachetype;
336 -
337 - ctx->ebuilddir_cat_ctx =
338 - vdb_open_cat(pkgdir, ctx->ebuilddir_pkg_ctx->name);
339 -
340 - /* opening might fail if what we found wasn't a
341 - * directory or something */
342 - if (ctx->ebuilddir_cat_ctx == NULL) {
343 - ctx->ebuilddir_pkg_ctx = NULL;
344 - return NULL;
345 - }
346 -
347 - /* "zap" the pkg such that it looks like CAT/P */
348 - ctx->ebuilddir_cat_ctx->name = cat_ctx->name;
349 - }
350 -
351 - ret = vdb_next_pkg(ctx->ebuilddir_cat_ctx);
352 - if (ret == NULL) {
353 - vdb_close_cat(ctx->ebuilddir_cat_ctx);
354 - ctx->ebuilddir_pkg_ctx = NULL;
355 - } else {
356 - if ((p = strstr(ret->name, ".ebuild")) == NULL) {
357 - cache_close_pkg(ret);
358 - ret = NULL;
359 - } else {
360 - *p = '\0';
361 - }
362 - }
363 - } while (ret == NULL);
364 - } else {
365 - ret = vdb_next_pkg(cat_ctx);
366 - }
367 -
368 - return ret;
369 -}
370 -
371 -static cache_pkg_meta *
372 -cache_read_file_pms(cache_pkg_ctx *pkg_ctx)
373 -{
374 - struct stat s;
375 - char *ptr;
376 - FILE *f;
377 - cache_pkg_meta *ret = NULL;
378 - size_t len;
379 - char buf[_Q_PATH_MAX];
380 -
381 - if ((f = fdopen(pkg_ctx->fd, "r")) == NULL)
382 - goto err;
383 -
384 - if (fstat(pkg_ctx->fd, &s) != 0)
385 - goto err;
386 -
387 - len = sizeof(*ret) + s.st_size + 1;
388 - ret = xzalloc(len);
389 - ptr = (char*)ret;
390 - ret->_data = ptr + sizeof(*ret);
391 - if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
392 - goto err;
393 -
394 - ret->DEPEND = ret->_data;
395 -#define next_line(curr, next) \
396 - if ((ptr = strchr(ret->curr, '\n')) == NULL) { \
397 - warn("Invalid cache file for '%s'", buf); \
398 - goto err; \
399 - } \
400 - ret->next = ptr+1; \
401 - *ptr = '\0';
402 - next_line(DEPEND, RDEPEND)
403 - next_line(RDEPEND, SLOT)
404 - next_line(SLOT, SRC_URI)
405 - next_line(SRC_URI, RESTRICT)
406 - next_line(RESTRICT, HOMEPAGE)
407 - next_line(HOMEPAGE, LICENSE)
408 - next_line(LICENSE, DESCRIPTION)
409 - next_line(DESCRIPTION, KEYWORDS)
410 - next_line(KEYWORDS, INHERITED)
411 - next_line(INHERITED, IUSE)
412 - next_line(IUSE, CDEPEND)
413 - next_line(CDEPEND, PDEPEND)
414 - next_line(PDEPEND, PROVIDE)
415 - next_line(PROVIDE, EAPI)
416 - next_line(EAPI, PROPERTIES)
417 -#undef next_line
418 - ptr = strchr(ptr+1, '\n');
419 - if (ptr == NULL) {
420 - warn("Invalid cache file for '%s' - could not find end of cache data",
421 - buf);
422 - goto err;
423 - }
424 - *ptr = '\0';
425 -
426 - fclose(f);
427 - pkg_ctx->fd = -1;
428 -
429 - return ret;
430 -
431 -err:
432 - if (f)
433 - fclose(f);
434 - pkg_ctx->fd = -1;
435 - if (ret)
436 - cache_close_meta(ret);
437 - return NULL;
438 -}
439 -
440 -static cache_pkg_meta *
441 -cache_read_file_md5(cache_pkg_ctx *pkg_ctx)
442 -{
443 - struct stat s;
444 - char *ptr, *endptr;
445 - FILE *f;
446 - cache_pkg_meta *ret = NULL;
447 - size_t len;
448 -
449 - if ((f = fdopen(pkg_ctx->fd, "r")) == NULL)
450 - goto err;
451 -
452 - if (fstat(pkg_ctx->fd, &s) != 0)
453 - goto err;
454 -
455 - len = sizeof(*ret) + s.st_size + 1;
456 - ret = xzalloc(len);
457 - ptr = (char*)ret;
458 - ret->_data = ptr + sizeof(*ret);
459 - if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
460 - goto err;
461 -
462 - /* We have a block of key=value\n data.
463 - * KEY=VALUE\n
464 - * Where KEY does NOT contain:
465 - * \0 \n =
466 - * And VALUE does NOT contain:
467 - * \0 \n
468 - * */
469 -#define assign_var_cmp(keyname, cmpkey) \
470 - if (strncmp(keyptr, cmpkey, strlen(cmpkey)) == 0) { \
471 - ret->keyname = valptr; \
472 - continue; \
473 - }
474 -#define assign_var(keyname) \
475 - assign_var_cmp(keyname, #keyname);
476 -
477 - ptr = ret->_data;
478 - endptr = strchr(ptr, '\0');
479 - if (endptr == NULL) {
480 - warn("Invalid cache file for '%s/%s': "
481 - "could not find end of cache data",
482 - pkg_ctx->cat_ctx->name, pkg_ctx->name);
483 - goto err;
484 - }
485 -
486 - while (ptr != NULL && ptr != endptr) {
487 - char *keyptr;
488 - char *valptr;
489 - keyptr = ptr;
490 - valptr = strchr(ptr, '=');
491 - if (valptr == NULL) {
492 - warn("Invalid cache file for '%s/%s': missing val",
493 - pkg_ctx->cat_ctx->name, pkg_ctx->name);
494 - goto err;
495 - }
496 - *valptr = '\0';
497 - valptr++;
498 - ptr = strchr(valptr, '\n');
499 - if (ptr == NULL) {
500 - warn("Invalid cache file for '%s/%s': missing key",
501 - pkg_ctx->cat_ctx->name, pkg_ctx->name);
502 - goto err;
503 - }
504 - *ptr = '\0';
505 - ptr++;
506 -
507 - assign_var(CDEPEND);
508 - assign_var(DEPEND);
509 - assign_var(DESCRIPTION);
510 - assign_var(EAPI);
511 - assign_var(HOMEPAGE);
512 - assign_var(INHERITED);
513 - assign_var(IUSE);
514 - assign_var(KEYWORDS);
515 - assign_var(LICENSE);
516 - assign_var(PDEPEND);
517 - assign_var(PROPERTIES);
518 - assign_var(PROVIDE);
519 - assign_var(RDEPEND);
520 - assign_var(RESTRICT);
521 - assign_var(SLOT);
522 - assign_var(SRC_URI);
523 - assign_var(DEFINED_PHASES);
524 - assign_var(REQUIRED_USE);
525 - assign_var(BDEPEND);
526 - assign_var(_eclasses_);
527 - assign_var(_md5_);
528 - warn("Cache file for '%s/%s' has unknown key %s",
529 - pkg_ctx->cat_ctx->name, pkg_ctx->name, keyptr);
530 - }
531 -#undef assign_var
532 -#undef assign_var_cmp
533 -
534 - fclose(f);
535 - pkg_ctx->fd = -1;
536 -
537 - return ret;
538 -
539 -err:
540 - if (f)
541 - fclose(f);
542 - pkg_ctx->fd = -1;
543 - if (ret)
544 - cache_close_meta(ret);
545 - return NULL;
546 -}
547 -
548 -static cache_pkg_meta *
549 -cache_read_file_ebuild(cache_pkg_ctx *pkg_ctx)
550 -{
551 - FILE *f;
552 - struct stat s;
553 - cache_pkg_meta *ret = NULL;
554 - size_t len;
555 - char *p;
556 - char *q;
557 - char *w;
558 - char **key;
559 - bool esc;
560 - bool findnl;
561 -
562 - if ((f = fdopen(pkg_ctx->fd, "r")) == NULL)
563 - goto err;
564 -
565 - if (fstat(pkg_ctx->fd, &s) != 0)
566 - goto err;
567 -
568 - len = sizeof(*ret) + s.st_size + 1;
569 - ret = xzalloc(len);
570 - p = (char *)ret;
571 - ret->_data = p + sizeof(*ret);
572 - if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
573 - goto err;
574 -
575 - p = ret->_data;
576 - do {
577 - q = p;
578 - while (*p >= 'A' && *p <= 'Z')
579 - p++;
580 -
581 - key = NULL;
582 - if (q < p && *p == '=') {
583 - *p++ = '\0';
584 - /* match variable against which ones we look for */
585 -#define match_key(X) else if (strcmp(q, #X) == 0) key = &ret->X
586 - if (1 == 0); /* dummy for syntax */
587 - match_key(DEPEND);
588 - match_key(RDEPEND);
589 - match_key(SLOT);
590 - match_key(SRC_URI);
591 - match_key(RESTRICT);
592 - match_key(HOMEPAGE);
593 - match_key(LICENSE);
594 - match_key(DESCRIPTION);
595 - match_key(KEYWORDS);
596 - match_key(IUSE);
597 - match_key(CDEPEND);
598 - match_key(PDEPEND);
599 - match_key(EAPI);
600 - match_key(REQUIRED_USE);
601 -#undef match_key
602 - }
603 -
604 - findnl = true;
605 - if (key != NULL) {
606 - q = p;
607 - if (*q == '"' || *q == '\'') {
608 - /* find matching quote */
609 - p++;
610 - w = p;
611 - esc = false;
612 - do {
613 - while (*p != '\0' && *p != *q) {
614 - if (*p == '\\') {
615 - esc = !esc;
616 - if (esc) {
617 - p++;
618 - continue;
619 - }
620 - } else {
621 - /* implement line continuation (\ before newline) */
622 - if (esc && (*p == '\n' || *p == '\r'))
623 - *p = ' ';
624 - esc = false;
625 - }
626 -
627 - *w++ = *p++;
628 - }
629 - if (*p == *q && esc) {
630 - /* escaped, move along */
631 - esc = false;
632 - *w++ = *p++;
633 - continue;
634 - }
635 - break;
636 - } while (1);
637 - q++;
638 - *w = '\0';
639 - } else {
640 - /* find first whitespace */
641 - while (!isspace((int)*p))
642 - p++;
643 - if (*p == '\n')
644 - findnl = false;
645 - }
646 - *p++ = '\0';
647 - *key = q;
648 - }
649 -
650 - if (findnl && (p = strchr(p, '\n')) != NULL)
651 - p++;
652 - } while (p != NULL);
653 -
654 - fclose(f);
655 - pkg_ctx->fd = -1;
656 -
657 - return ret;
658 -
659 -err:
660 - if (f)
661 - fclose(f);
662 - pkg_ctx->fd = -1;
663 - if (ret)
664 - cache_close_meta(ret);
665 - return NULL;
666 -}
667 -
668 -cache_pkg_meta *
669 -cache_pkg_read(cache_pkg_ctx *pkg_ctx)
670 -{
671 - cache_ctx *ctx = (cache_ctx *)(pkg_ctx->cat_ctx->ctx);
672 -
673 - if (pkg_ctx->fd == -1) {
674 - if (ctx->cachetype != CACHE_EBUILD) {
675 - pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name,
676 - O_RDONLY|O_CLOEXEC);
677 - } else {
678 - char *p = (char *)pkg_ctx->name;
679 - p += strlen(p);
680 - *p = '.';
681 - pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name,
682 - O_RDONLY|O_CLOEXEC);
683 - *p = '\0';
684 - }
685 - if (pkg_ctx->fd == -1)
686 - return NULL;
687 - }
688 -
689 - if (ctx->cachetype == CACHE_METADATA_MD5) {
690 - return cache_read_file_md5(pkg_ctx);
691 - } else if (ctx->cachetype == CACHE_METADATA_PMS) {
692 - return cache_read_file_pms(pkg_ctx);
693 - } else if (ctx->cachetype == CACHE_EBUILD) {
694 - return cache_read_file_ebuild(pkg_ctx);
695 - }
696 -
697 - warn("Unknown metadata cache type!");
698 - return NULL;
699 -}
700 -
701 -void
702 -cache_close_meta(cache_pkg_meta *cache)
703 -{
704 - if (!cache)
705 - errf("Cache is empty !");
706 - free(cache);
707 -}
708 -
709 -cache_metadata_xml *
710 -cache_read_metadata(cache_pkg_ctx *pkg_ctx)
711 -{
712 - cache_ctx *ctx = (cache_ctx *)(pkg_ctx->cat_ctx->ctx);
713 - int fd;
714 - FILE *f;
715 - struct stat s;
716 - char *xbuf;
717 - char *p;
718 - char *q;
719 - size_t len;
720 - cache_metadata_xml *ret = NULL;
721 - struct elist *emailw = NULL;
722 - char buf[_Q_PATH_MAX];
723 -
724 - /* lame @$$ XML parsing, I don't want to pull in a real parser
725 - * library because we only retrieve one element for now: email
726 - * technically speaking, email may occur only once in a maintainer
727 - * tag, but practically speaking we don't care at all, so we can
728 - * just extract everything between <email> and </email> */
729 -
730 - if (ctx->cachetype == CACHE_EBUILD) {
731 - fd = openat(pkg_ctx->cat_ctx->fd, "metadata", O_RDONLY | O_CLOEXEC);
732 - } else {
733 - depend_atom *atom;
734 - snprintf(buf, sizeof(buf), "%s/%s",
735 - pkg_ctx->cat_ctx->name, pkg_ctx->name);
736 - atom = atom_explode(buf);
737 - snprintf(buf, sizeof(buf), "../../%s/%s/metadata.xml",
738 - atom->CATEGORY, atom->PN);
739 - atom_implode(atom);
740 - fd = openat(ctx->vdb_fd, buf, O_RDONLY | O_CLOEXEC);
741 - }
742 -
743 - if (fd == -1)
744 - return NULL;
745 -
746 - if ((f = fdopen(fd, "r")) == NULL) {
747 - close(fd);
748 - return NULL;
749 - }
750 -
751 - if (fstat(fd, &s) != 0) {
752 - fclose(f);
753 - return NULL;
754 - }
755 -
756 - len = sizeof(*ret) + s.st_size + 1;
757 - p = xbuf = xzalloc(len);
758 - if ((off_t)fread(p, 1, s.st_size, f) != s.st_size) {
759 - free(p);
760 - fclose(f);
761 - pkg_ctx->fd = -1;
762 - return NULL;
763 - }
764 -
765 - ret = xmalloc(sizeof(*ret));
766 - ret->email = NULL;
767 -
768 - while ((q = strstr(p, "<email>")) != NULL) {
769 - p = q + sizeof("<email>") - 1;
770 - if ((q = strstr(p, "</email>")) == NULL)
771 - break;
772 - *q = '\0';
773 - rmspace(p);
774 - if (emailw == NULL) {
775 - emailw = ret->email = xmalloc(sizeof(*emailw));
776 - } else {
777 - emailw = emailw->next = xmalloc(sizeof(*emailw));
778 - }
779 - emailw->next = NULL;
780 - emailw->addr = xstrdup(p);
781 - p = q + 1;
782 - }
783 -
784 - free(xbuf);
785 - fclose(f);
786 - return ret;
787 -}
788 -
789 -void
790 -cache_close_metadata(cache_metadata_xml *meta_ctx)
791 -{
792 - struct elist *e;
793 - while (meta_ctx->email != NULL) {
794 - e = meta_ctx->email;
795 - free(e->addr);
796 - e = e->next;
797 - free(meta_ctx->email);
798 - meta_ctx->email = e;
799 - }
800 - free(meta_ctx);
801 -}
802 -
803 -void
804 -cache_close_pkg(cache_pkg_ctx *pkg_ctx)
805 -{
806 - /* avoid free of cache_ctx' repo by vdb_close_pkg */
807 - if (pkg_ctx->cat_ctx->ctx->repo == pkg_ctx->repo)
808 - pkg_ctx->repo = NULL;
809 -
810 - vdb_close_pkg(pkg_ctx);
811 -}
812 -
813 -static int
814 -cache_foreach_pkg_int(const char *sroot, const char *portdir,
815 - vdb_pkg_cb callback, void *priv, vdb_cat_filter filter,
816 - bool sort, void *catsortfunc, void *pkgsortfunc)
817 -{
818 - cache_ctx *ctx;
819 - cache_cat_ctx *cat_ctx;
820 - cache_pkg_ctx *pkg_ctx;
821 - int ret;
822 -
823 - ctx = cache_open(sroot, portdir);
824 - if (!ctx)
825 - return EXIT_FAILURE;
826 -
827 - ctx->do_sort = sort;
828 - if (catsortfunc != NULL)
829 - ctx->catsortfunc = catsortfunc;
830 - if (pkgsortfunc != NULL)
831 - ctx->pkgsortfunc = pkgsortfunc;
832 -
833 - ret = 0;
834 - while ((cat_ctx = cache_next_cat(ctx))) {
835 - if (filter && !filter(cat_ctx, priv))
836 - continue;
837 - while ((pkg_ctx = cache_next_pkg(cat_ctx))) {
838 - ret |= callback(pkg_ctx, priv);
839 - cache_close_pkg(pkg_ctx);
840 - }
841 - cache_close_cat(cat_ctx);
842 - }
843 - cache_close(ctx);
844 -
845 - return ret;
846 -}
847 -
848 -int
849 -cache_foreach_pkg(const char *sroot, const char *portdir,
850 - vdb_pkg_cb callback, void *priv, vdb_cat_filter filter)
851 -{
852 - return cache_foreach_pkg_int(sroot, portdir, callback, priv,
853 - filter, false, NULL, NULL);
854 -}
855 -
856 -int
857 -cache_foreach_pkg_sorted(const char *sroot, const char *portdir,
858 - vdb_pkg_cb callback, void *priv,
859 - void *catsortfunc, void *pkgsortfunc)
860 -{
861 - return cache_foreach_pkg_int(sroot, portdir, callback, priv,
862 - NULL, true, catsortfunc, pkgsortfunc);
863 -}
864
865 diff --git a/libq/cache.h b/libq/cache.h
866 deleted file mode 100644
867 index e863daf..0000000
868 --- a/libq/cache.h
869 +++ /dev/null
870 @@ -1,74 +0,0 @@
871 -/*
872 - * Copyright 2005-2019 Gentoo Foundation
873 - * Distributed under the terms of the GNU General Public License v2
874 - *
875 - * Copyright 2005-2010 Ned Ludd - <solar@g.o>
876 - * Copyright 2005-2014 Mike Frysinger - <vapier@g.o>
877 - * Copyright 2019- Fabian Groffen - <grobian@g.o>
878 - */
879 -
880 -#ifndef _CACHE_H
881 -#define _CACHE_H 1
882 -
883 -#include "atom.h"
884 -#include "vdb.h"
885 -
886 -#define cache_ctx vdb_ctx
887 -#define cache_cat_ctx vdb_cat_ctx
888 -#define cache_pkg_ctx vdb_pkg_ctx
889 -
890 -typedef struct {
891 - char *_data;
892 - char *DEPEND; /* line 1 */
893 - char *RDEPEND;
894 - char *SLOT;
895 - char *SRC_URI;
896 - char *RESTRICT; /* line 5 */
897 - char *HOMEPAGE;
898 - char *LICENSE;
899 - char *DESCRIPTION;
900 - char *KEYWORDS;
901 - char *INHERITED; /* line 10 */
902 - char *IUSE;
903 - char *CDEPEND;
904 - char *PDEPEND;
905 - char *PROVIDE; /* line 14 */
906 - char *EAPI;
907 - char *PROPERTIES;
908 - /* These are MD5-Cache only */
909 - char *DEFINED_PHASES;
910 - char *REQUIRED_USE;
911 - char *BDEPEND;
912 - char *_eclasses_;
913 - char *_md5_;
914 -} cache_pkg_meta;
915 -
916 -typedef struct {
917 - struct elist {
918 - char *addr;
919 - struct elist *next;
920 - } *email;
921 -} cache_metadata_xml;
922 -
923 -typedef int (cache_pkg_cb)(cache_pkg_ctx *, void *priv);
924 -typedef int (cache_cat_filter)(cache_cat_ctx *, void *priv);
925 -
926 -cache_ctx *cache_open(const char *sroot, const char *portdir);
927 -void cache_close(cache_ctx *ctx);
928 -cache_cat_ctx *cache_open_cat(cache_ctx *ctx, const char *name);
929 -cache_cat_ctx *cache_next_cat(cache_ctx *ctx);
930 -void cache_close_cat(cache_cat_ctx *cat_ctx);
931 -cache_pkg_ctx *cache_open_pkg(cache_cat_ctx *cat_ctx, const char *name);
932 -cache_pkg_ctx *cache_next_pkg(cache_cat_ctx *cat_ctx);
933 -cache_pkg_meta *cache_pkg_read(cache_pkg_ctx *pkg_ctx);
934 -void cache_close_meta(cache_pkg_meta *cache);
935 -cache_metadata_xml *cache_read_metadata(cache_pkg_ctx *pkg_ctx);
936 -void cache_close_metadata(cache_metadata_xml *meta_ctx);
937 -void cache_close_pkg(cache_pkg_ctx *pkg_ctx);
938 -int cache_foreach_pkg(const char *sroot, const char *portdir,
939 - cache_pkg_cb callback, void *priv, cache_cat_filter filter);
940 -int cache_foreach_pkg_sorted(const char *sroot, const char *portdir,
941 - cache_pkg_cb callback, void *priv,
942 - void *catsortfunc, void *pkgsortfunc);
943 -
944 -#endif
945
946 diff --git a/libq/tree.c b/libq/tree.c
947 new file mode 100644
948 index 0000000..bb7eefa
949 --- /dev/null
950 +++ b/libq/tree.c
951 @@ -0,0 +1,1066 @@
952 +/*
953 + * Copyright 2005-2019 Gentoo Foundation
954 + * Distributed under the terms of the GNU General Public License v2
955 + *
956 + * Copyright 2005-2008 Ned Ludd - <solar@g.o>
957 + * Copyright 2005-2014 Mike Frysinger - <vapier@g.o>
958 + * Copyright 2018- Fabian Groffen - <grobian@g.o>
959 + */
960 +
961 +#include "main.h"
962 +
963 +#include <fcntl.h>
964 +#include <sys/types.h>
965 +#include <sys/stat.h>
966 +#include <ctype.h>
967 +#include <xalloc.h>
968 +
969 +#include "atom.h"
970 +#include "eat_file.h"
971 +#include "rmspace.h"
972 +#include "scandirat.h"
973 +#include "set.h"
974 +#include "tree.h"
975 +
976 +#include <ctype.h>
977 +#include <xalloc.h>
978 +
979 +static tree_ctx *
980 +tree_open_int(const char *sroot, const char *tdir, bool quiet)
981 +{
982 + tree_ctx *ctx = xmalloc(sizeof(*ctx));
983 +
984 + ctx->portroot_fd = open(sroot, O_RDONLY | O_CLOEXEC | O_PATH);
985 + if (ctx->portroot_fd == -1) {
986 + if (!quiet)
987 + warnp("could not open root: %s", sroot);
988 + goto f_error;
989 + }
990 +
991 + /* Skip the leading slash */
992 + tdir++;
993 + if (*tdir == '\0')
994 + tdir = ".";
995 + /* Cannot use O_PATH as we want to use fdopendir() */
996 + ctx->tree_fd = openat(ctx->portroot_fd, tdir, O_RDONLY | O_CLOEXEC);
997 + if (ctx->tree_fd == -1) {
998 + if (!quiet)
999 + warnp("could not open tree: %s (in root %s)", tdir, sroot);
1000 + goto cp_error;
1001 + }
1002 +
1003 + ctx->dir = fdopendir(ctx->tree_fd);
1004 + if (ctx->dir == NULL)
1005 + goto cv_error;
1006 +
1007 + ctx->do_sort = false;
1008 + ctx->cat_de = NULL;
1009 + ctx->catsortfunc = alphasort;
1010 + ctx->pkgsortfunc = alphasort;
1011 + ctx->repo = NULL;
1012 + ctx->ebuilddir_ctx = NULL;
1013 + ctx->ebuilddir_pkg_ctx = NULL;
1014 + return ctx;
1015 +
1016 + cv_error:
1017 + close(ctx->tree_fd);
1018 + cp_error:
1019 + close(ctx->portroot_fd);
1020 + f_error:
1021 + free(ctx);
1022 + return NULL;
1023 +}
1024 +
1025 +static const char portcachedir_pms[] = "metadata/cache";
1026 +static const char portcachedir_md5[] = "metadata/md5-cache";
1027 +static const char portrepo_name[] = "profiles/repo_name";
1028 +tree_ctx *
1029 +tree_open(const char *sroot, const char *portdir)
1030 +{
1031 + tree_ctx *ret;
1032 + char buf[_Q_PATH_MAX];
1033 + char *repo = NULL;
1034 + size_t repolen = 0;
1035 +
1036 + snprintf(buf, sizeof(buf), "%s%s/%s", sroot, portdir, portrepo_name);
1037 + if (eat_file(buf, &repo, &repolen)) {
1038 + (void)rmspace(repo);
1039 + } else {
1040 + repo = NULL; /* ignore missing repo file */
1041 + }
1042 +
1043 + snprintf(buf, sizeof(buf), "%s/%s", portdir, portcachedir_md5);
1044 + ret = tree_open_int(sroot, buf, true);
1045 + if (ret != NULL) {
1046 + ret->cachetype = CACHE_METADATA_MD5;
1047 + ret->repo = repo;
1048 + return ret;
1049 + }
1050 +
1051 + snprintf(buf, sizeof(buf), "%s/%s", portdir, portcachedir_pms);
1052 + ret = tree_open_int(sroot, buf, true);
1053 + if (ret != NULL) {
1054 + ret->cachetype = CACHE_METADATA_PMS;
1055 + ret->repo = repo;
1056 + return ret;
1057 + }
1058 +
1059 + ret = tree_open_int(sroot, portdir, true);
1060 + if (ret != NULL) {
1061 + ret->cachetype = CACHE_EBUILD;
1062 + ret->repo = repo;
1063 + return ret;
1064 + }
1065 +
1066 + tree_close(ret);
1067 + warnf("could not open repository at %s (under root %s)", portdir, sroot);
1068 +
1069 + return NULL;
1070 +}
1071 +
1072 +tree_ctx *
1073 +tree_open_vdb(const char *sroot, const char *svdb)
1074 +{
1075 + tree_ctx *ret = tree_open_int(sroot, svdb, false);
1076 + if (ret != NULL)
1077 + ret->cachetype = CACHE_VDB;
1078 + return ret;
1079 +}
1080 +
1081 +void
1082 +tree_close(tree_ctx *ctx)
1083 +{
1084 + closedir(ctx->dir);
1085 + /* closedir() above does this for us: */
1086 + /* close(ctx->tree_fd); */
1087 + close(ctx->portroot_fd);
1088 + if (ctx->do_sort)
1089 + scandir_free(ctx->cat_de, ctx->cat_cnt);
1090 + if (ctx->repo != NULL)
1091 + free(ctx->repo);
1092 + if (ctx->ebuilddir_ctx != NULL)
1093 + free(ctx->ebuilddir_ctx);
1094 + free(ctx);
1095 +}
1096 +
1097 +int
1098 +tree_filter_cat(const struct dirent *de)
1099 +{
1100 + int i;
1101 + bool founddash;
1102 +
1103 +#ifdef DT_UNKNOWN
1104 + /* cat must be a dir */
1105 + if (de->d_type != DT_UNKNOWN &&
1106 + de->d_type != DT_DIR &&
1107 + de->d_type != DT_LNK)
1108 + return 0;
1109 +#endif
1110 +
1111 + /* PMS 3.1.1 */
1112 + founddash = false;
1113 + for (i = 0; de->d_name[i] != '\0'; i++) {
1114 + switch (de->d_name[i]) {
1115 + case '_':
1116 + break;
1117 + case '-':
1118 + founddash = true;
1119 + /* fall through */
1120 + case '+':
1121 + case '.':
1122 + if (i)
1123 + break;
1124 + return 0;
1125 + default:
1126 + if ((de->d_name[i] >= 'A' && de->d_name[i] <= 'Z') ||
1127 + (de->d_name[i] >= 'a' && de->d_name[i] <= 'z') ||
1128 + (de->d_name[i] >= '0' && de->d_name[i] <= '9'))
1129 + break;
1130 + return 0;
1131 + }
1132 + }
1133 + if (!founddash && strcmp(de->d_name, "virtual") != 0)
1134 + return 0;
1135 +
1136 + return i;
1137 +}
1138 +
1139 +tree_cat_ctx *
1140 +tree_open_cat(tree_ctx *ctx, const char *name)
1141 +{
1142 + tree_cat_ctx *cat_ctx;
1143 + int fd;
1144 + DIR *dir;
1145 +
1146 + /* Cannot use O_PATH as we want to use fdopendir() */
1147 + fd = openat(ctx->tree_fd, name, O_RDONLY | O_CLOEXEC);
1148 + if (fd == -1)
1149 + return NULL;
1150 +
1151 + dir = fdopendir(fd);
1152 + if (!dir) {
1153 + close(fd);
1154 + return NULL;
1155 + }
1156 +
1157 + cat_ctx = xmalloc(sizeof(*cat_ctx));
1158 + cat_ctx->name = name;
1159 + cat_ctx->fd = fd;
1160 + cat_ctx->dir = dir;
1161 + cat_ctx->ctx = ctx;
1162 + cat_ctx->pkg_de = NULL;
1163 + return cat_ctx;
1164 +}
1165 +
1166 +tree_cat_ctx *
1167 +tree_next_cat(tree_ctx *ctx)
1168 +{
1169 + /* search for a category directory */
1170 + tree_cat_ctx *cat_ctx = NULL;
1171 +
1172 + if (ctx->do_sort) {
1173 + if (ctx->cat_de == NULL) {
1174 + ctx->cat_cnt = scandirat(ctx->tree_fd,
1175 + ".", &ctx->cat_de, tree_filter_cat, ctx->catsortfunc);
1176 + ctx->cat_cur = 0;
1177 + }
1178 +
1179 + while (ctx->cat_cur < ctx->cat_cnt) {
1180 + cat_ctx = tree_open_cat(ctx, ctx->cat_de[ctx->cat_cur++]->d_name);
1181 + if (!cat_ctx)
1182 + continue;
1183 + break;
1184 + }
1185 + } else {
1186 + /* cheaper "streaming" variant */
1187 + const struct dirent *de;
1188 + do {
1189 + de = readdir(ctx->dir);
1190 + if (!de)
1191 + break;
1192 +
1193 + if (tree_filter_cat(de) == 0)
1194 + continue;
1195 +
1196 + cat_ctx = tree_open_cat(ctx, de->d_name);
1197 + if (!cat_ctx)
1198 + continue;
1199 +
1200 + break;
1201 + } while (1);
1202 + }
1203 +
1204 + return cat_ctx;
1205 +}
1206 +
1207 +void
1208 +tree_close_cat(tree_cat_ctx *cat_ctx)
1209 +{
1210 + closedir(cat_ctx->dir);
1211 + /* closedir() above does this for us: */
1212 + /* close(ctx->fd); */
1213 + if (cat_ctx->ctx->do_sort)
1214 + scandir_free(cat_ctx->pkg_de, cat_ctx->pkg_cnt);
1215 + free(cat_ctx);
1216 +}
1217 +
1218 +int
1219 +tree_filter_pkg(const struct dirent *de)
1220 +{
1221 + int i;
1222 + bool founddash = false;
1223 +
1224 + /* PMS 3.1.2 */
1225 + for (i = 0; de->d_name[i] != '\0'; i++) {
1226 + switch (de->d_name[i]) {
1227 + case '_':
1228 + break;
1229 + case '-':
1230 + founddash = true;
1231 + /* fall through */
1232 + case '+':
1233 + if (i)
1234 + break;
1235 + return 0;
1236 + default:
1237 + if ((de->d_name[i] >= 'A' && de->d_name[i] <= 'Z') ||
1238 + (de->d_name[i] >= 'a' && de->d_name[i] <= 'z') ||
1239 + (de->d_name[i] >= '0' && de->d_name[i] <= '9'))
1240 + break;
1241 + if (founddash)
1242 + return 1;
1243 + return 0;
1244 + }
1245 + }
1246 +
1247 + return i;
1248 +}
1249 +
1250 +tree_pkg_ctx *
1251 +tree_open_pkg(tree_cat_ctx *cat_ctx, const char *name)
1252 +{
1253 + tree_pkg_ctx *pkg_ctx = xmalloc(sizeof(*pkg_ctx));
1254 + pkg_ctx->name = name;
1255 + pkg_ctx->slot = NULL;
1256 + pkg_ctx->repo = cat_ctx->ctx->repo;
1257 + pkg_ctx->fd = -1;
1258 + pkg_ctx->cat_ctx = cat_ctx;
1259 + pkg_ctx->atom = NULL;
1260 + return pkg_ctx;
1261 +}
1262 +
1263 +static tree_pkg_ctx *
1264 +tree_next_pkg_int(tree_cat_ctx *cat_ctx);
1265 +static tree_pkg_ctx *
1266 +tree_next_pkg_int(tree_cat_ctx *cat_ctx)
1267 +{
1268 + tree_pkg_ctx *pkg_ctx = NULL;
1269 +
1270 + if (cat_ctx->ctx->do_sort) {
1271 + if (cat_ctx->pkg_de == NULL) {
1272 + cat_ctx->pkg_cnt = scandirat(cat_ctx->fd, ".", &cat_ctx->pkg_de,
1273 + tree_filter_pkg, cat_ctx->ctx->pkgsortfunc);
1274 + cat_ctx->pkg_cur = 0;
1275 + }
1276 +
1277 + while (cat_ctx->pkg_cur < cat_ctx->pkg_cnt) {
1278 + pkg_ctx =
1279 + tree_open_pkg(cat_ctx,
1280 + cat_ctx->pkg_de[cat_ctx->pkg_cur++]->d_name);
1281 + if (!pkg_ctx)
1282 + continue;
1283 + break;
1284 + }
1285 + } else {
1286 + const struct dirent *de;
1287 + do {
1288 + de = readdir(cat_ctx->dir);
1289 + if (!de)
1290 + break;
1291 +
1292 + if (tree_filter_pkg(de) == 0)
1293 + continue;
1294 +
1295 + pkg_ctx = tree_open_pkg(cat_ctx, de->d_name);
1296 + if (!pkg_ctx)
1297 + continue;
1298 +
1299 + break;
1300 + } while (1);
1301 + }
1302 +
1303 + return pkg_ctx;
1304 +}
1305 +
1306 +tree_pkg_ctx *
1307 +tree_next_pkg(tree_cat_ctx *cat_ctx)
1308 +{
1309 + tree_ctx *ctx = cat_ctx->ctx;
1310 + tree_pkg_ctx *ret = NULL;
1311 +
1312 + if (ctx->cachetype == CACHE_EBUILD) {
1313 + char *p;
1314 +
1315 + /* serve *.ebuild files each as separate pkg_ctx with name set
1316 + * to CAT/P like in VDB and metadata */
1317 + do {
1318 + if (ctx->ebuilddir_pkg_ctx == NULL) {
1319 + tree_ctx *pkgdir = ctx->ebuilddir_ctx;
1320 +
1321 + if (pkgdir == NULL)
1322 + pkgdir = ctx->ebuilddir_ctx = xmalloc(sizeof(tree_ctx));
1323 + memset(ctx->ebuilddir_ctx, '\0', sizeof(*ctx->ebuilddir_ctx));
1324 +
1325 + ctx->ebuilddir_pkg_ctx = tree_next_pkg_int(cat_ctx);
1326 + if (ctx->ebuilddir_pkg_ctx == NULL)
1327 + return NULL;
1328 +
1329 + pkgdir->portroot_fd = -1;
1330 + pkgdir->tree_fd = cat_ctx->fd;
1331 + pkgdir->do_sort = ctx->do_sort;
1332 + pkgdir->catsortfunc = ctx->catsortfunc;
1333 + pkgdir->pkgsortfunc = ctx->pkgsortfunc;
1334 + pkgdir->repo = ctx->repo;
1335 + pkgdir->cachetype = ctx->cachetype;
1336 +
1337 + ctx->ebuilddir_cat_ctx =
1338 + tree_open_cat(pkgdir, ctx->ebuilddir_pkg_ctx->name);
1339 +
1340 + /* opening might fail if what we found wasn't a
1341 + * directory or something */
1342 + if (ctx->ebuilddir_cat_ctx == NULL) {
1343 + ctx->ebuilddir_pkg_ctx = NULL;
1344 + return NULL;
1345 + }
1346 +
1347 + /* "zap" the pkg such that it looks like CAT/P */
1348 + ctx->ebuilddir_cat_ctx->name = cat_ctx->name;
1349 + }
1350 +
1351 + ret = tree_next_pkg_int(ctx->ebuilddir_cat_ctx);
1352 + if (ret == NULL) {
1353 + tree_close_cat(ctx->ebuilddir_cat_ctx);
1354 + ctx->ebuilddir_pkg_ctx = NULL;
1355 + } else {
1356 + if ((p = strstr(ret->name, ".ebuild")) == NULL) {
1357 + tree_close_pkg(ret);
1358 + ret = NULL;
1359 + } else {
1360 + *p = '\0';
1361 + }
1362 + }
1363 + } while (ret == NULL);
1364 + } else {
1365 + ret = tree_next_pkg_int(cat_ctx);
1366 + }
1367 +
1368 + return ret;
1369 +}
1370 +
1371 +int
1372 +tree_pkg_vdb_openat(
1373 + tree_pkg_ctx *pkg_ctx,
1374 + const char *file,
1375 + int flags, mode_t mode)
1376 +{
1377 + if (pkg_ctx->fd == -1) {
1378 + pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name,
1379 + O_RDONLY | O_CLOEXEC | O_PATH);
1380 + if (pkg_ctx->fd == -1)
1381 + return -1;
1382 + }
1383 +
1384 + return openat(pkg_ctx->fd, file, flags | O_CLOEXEC, mode);
1385 +}
1386 +
1387 +FILE *
1388 +tree_pkg_vdb_fopenat(
1389 + tree_pkg_ctx *pkg_ctx,
1390 + const char *file,
1391 + int flags,
1392 + mode_t mode,
1393 + const char *fmode)
1394 +{
1395 + FILE *fp;
1396 + int fd;
1397 +
1398 + fd = tree_pkg_vdb_openat(pkg_ctx, file, flags, mode);
1399 + if (fd == -1)
1400 + return NULL;
1401 +
1402 + fp = fdopen(fd, fmode);
1403 + if (!fp)
1404 + close(fd);
1405 +
1406 + return fp;
1407 +}
1408 +
1409 +bool
1410 +tree_pkg_vdb_eat(
1411 + tree_pkg_ctx *pkg_ctx,
1412 + const char *file,
1413 + char **bufptr,
1414 + size_t *buflen)
1415 +{
1416 + int fd = tree_pkg_vdb_openat(pkg_ctx, file, O_RDONLY, 0);
1417 + bool ret = eat_file_fd(fd, bufptr, buflen);
1418 + rmspace(*bufptr);
1419 + if (fd != -1)
1420 + close(fd);
1421 + return ret;
1422 +}
1423 +
1424 +static tree_pkg_meta *
1425 +tree_read_file_pms(tree_pkg_ctx *pkg_ctx)
1426 +{
1427 + struct stat s;
1428 + char *ptr;
1429 + FILE *f;
1430 + tree_pkg_meta *ret = NULL;
1431 + size_t len;
1432 + char buf[_Q_PATH_MAX];
1433 +
1434 + if ((f = fdopen(pkg_ctx->fd, "r")) == NULL)
1435 + goto err;
1436 +
1437 + if (fstat(pkg_ctx->fd, &s) != 0)
1438 + goto err;
1439 +
1440 + len = sizeof(*ret) + s.st_size + 1;
1441 + ret = xzalloc(len);
1442 + ptr = (char*)ret;
1443 + ret->_data = ptr + sizeof(*ret);
1444 + if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
1445 + goto err;
1446 +
1447 + ret->DEPEND = ret->_data;
1448 +#define next_line(curr, next) \
1449 + if ((ptr = strchr(ret->curr, '\n')) == NULL) { \
1450 + warn("Invalid cache file for '%s'", buf); \
1451 + goto err; \
1452 + } \
1453 + ret->next = ptr+1; \
1454 + *ptr = '\0';
1455 + next_line(DEPEND, RDEPEND)
1456 + next_line(RDEPEND, SLOT)
1457 + next_line(SLOT, SRC_URI)
1458 + next_line(SRC_URI, RESTRICT)
1459 + next_line(RESTRICT, HOMEPAGE)
1460 + next_line(HOMEPAGE, LICENSE)
1461 + next_line(LICENSE, DESCRIPTION)
1462 + next_line(DESCRIPTION, KEYWORDS)
1463 + next_line(KEYWORDS, INHERITED)
1464 + next_line(INHERITED, IUSE)
1465 + next_line(IUSE, CDEPEND)
1466 + next_line(CDEPEND, PDEPEND)
1467 + next_line(PDEPEND, PROVIDE)
1468 + next_line(PROVIDE, EAPI)
1469 + next_line(EAPI, PROPERTIES)
1470 +#undef next_line
1471 + ptr = strchr(ptr+1, '\n');
1472 + if (ptr == NULL) {
1473 + warn("Invalid cache file for '%s' - could not find end of cache data",
1474 + buf);
1475 + goto err;
1476 + }
1477 + *ptr = '\0';
1478 +
1479 + fclose(f);
1480 + pkg_ctx->fd = -1;
1481 +
1482 + return ret;
1483 +
1484 +err:
1485 + if (f)
1486 + fclose(f);
1487 + pkg_ctx->fd = -1;
1488 + if (ret)
1489 + tree_close_meta(ret);
1490 + return NULL;
1491 +}
1492 +
1493 +static tree_pkg_meta *
1494 +tree_read_file_md5(tree_pkg_ctx *pkg_ctx)
1495 +{
1496 + struct stat s;
1497 + char *ptr, *endptr;
1498 + FILE *f;
1499 + tree_pkg_meta *ret = NULL;
1500 + size_t len;
1501 +
1502 + if ((f = fdopen(pkg_ctx->fd, "r")) == NULL)
1503 + goto err;
1504 +
1505 + if (fstat(pkg_ctx->fd, &s) != 0)
1506 + goto err;
1507 +
1508 + len = sizeof(*ret) + s.st_size + 1;
1509 + ret = xzalloc(len);
1510 + ptr = (char*)ret;
1511 + ret->_data = ptr + sizeof(*ret);
1512 + if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
1513 + goto err;
1514 +
1515 + /* We have a block of key=value\n data.
1516 + * KEY=VALUE\n
1517 + * Where KEY does NOT contain:
1518 + * \0 \n =
1519 + * And VALUE does NOT contain:
1520 + * \0 \n
1521 + * */
1522 +#define assign_var_cmp(keyname, cmpkey) \
1523 + if (strncmp(keyptr, cmpkey, strlen(cmpkey)) == 0) { \
1524 + ret->keyname = valptr; \
1525 + continue; \
1526 + }
1527 +#define assign_var(keyname) \
1528 + assign_var_cmp(keyname, #keyname);
1529 +
1530 + ptr = ret->_data;
1531 + endptr = strchr(ptr, '\0');
1532 + if (endptr == NULL) {
1533 + warn("Invalid cache file for '%s/%s': "
1534 + "could not find end of cache data",
1535 + pkg_ctx->cat_ctx->name, pkg_ctx->name);
1536 + goto err;
1537 + }
1538 +
1539 + while (ptr != NULL && ptr != endptr) {
1540 + char *keyptr;
1541 + char *valptr;
1542 + keyptr = ptr;
1543 + valptr = strchr(ptr, '=');
1544 + if (valptr == NULL) {
1545 + warn("Invalid cache file for '%s/%s': missing val",
1546 + pkg_ctx->cat_ctx->name, pkg_ctx->name);
1547 + goto err;
1548 + }
1549 + *valptr = '\0';
1550 + valptr++;
1551 + ptr = strchr(valptr, '\n');
1552 + if (ptr == NULL) {
1553 + warn("Invalid cache file for '%s/%s': missing key",
1554 + pkg_ctx->cat_ctx->name, pkg_ctx->name);
1555 + goto err;
1556 + }
1557 + *ptr = '\0';
1558 + ptr++;
1559 +
1560 + assign_var(CDEPEND);
1561 + assign_var(DEPEND);
1562 + assign_var(DESCRIPTION);
1563 + assign_var(EAPI);
1564 + assign_var(HOMEPAGE);
1565 + assign_var(INHERITED);
1566 + assign_var(IUSE);
1567 + assign_var(KEYWORDS);
1568 + assign_var(LICENSE);
1569 + assign_var(PDEPEND);
1570 + assign_var(PROPERTIES);
1571 + assign_var(PROVIDE);
1572 + assign_var(RDEPEND);
1573 + assign_var(RESTRICT);
1574 + assign_var(SLOT);
1575 + assign_var(SRC_URI);
1576 + assign_var(DEFINED_PHASES);
1577 + assign_var(REQUIRED_USE);
1578 + assign_var(BDEPEND);
1579 + assign_var(_eclasses_);
1580 + assign_var(_md5_);
1581 + warn("Cache file for '%s/%s' has unknown key %s",
1582 + pkg_ctx->cat_ctx->name, pkg_ctx->name, keyptr);
1583 + }
1584 +#undef assign_var
1585 +#undef assign_var_cmp
1586 +
1587 + fclose(f);
1588 + pkg_ctx->fd = -1;
1589 +
1590 + return ret;
1591 +
1592 +err:
1593 + if (f)
1594 + fclose(f);
1595 + pkg_ctx->fd = -1;
1596 + if (ret)
1597 + tree_close_meta(ret);
1598 + return NULL;
1599 +}
1600 +
1601 +static tree_pkg_meta *
1602 +tree_read_file_ebuild(tree_pkg_ctx *pkg_ctx)
1603 +{
1604 + FILE *f;
1605 + struct stat s;
1606 + tree_pkg_meta *ret = NULL;
1607 + size_t len;
1608 + char *p;
1609 + char *q;
1610 + char *w;
1611 + char **key;
1612 + bool esc;
1613 + bool findnl;
1614 +
1615 + if ((f = fdopen(pkg_ctx->fd, "r")) == NULL)
1616 + goto err;
1617 +
1618 + if (fstat(pkg_ctx->fd, &s) != 0)
1619 + goto err;
1620 +
1621 + len = sizeof(*ret) + s.st_size + 1;
1622 + ret = xzalloc(len);
1623 + p = (char *)ret;
1624 + ret->_data = p + sizeof(*ret);
1625 + if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
1626 + goto err;
1627 +
1628 + p = ret->_data;
1629 + do {
1630 + q = p;
1631 + while (*p >= 'A' && *p <= 'Z')
1632 + p++;
1633 +
1634 + key = NULL;
1635 + if (q < p && *p == '=') {
1636 + *p++ = '\0';
1637 + /* match variable against which ones we look for */
1638 +#define match_key(X) else if (strcmp(q, #X) == 0) key = &ret->X
1639 + if (1 == 0); /* dummy for syntax */
1640 + match_key(DEPEND);
1641 + match_key(RDEPEND);
1642 + match_key(SLOT);
1643 + match_key(SRC_URI);
1644 + match_key(RESTRICT);
1645 + match_key(HOMEPAGE);
1646 + match_key(LICENSE);
1647 + match_key(DESCRIPTION);
1648 + match_key(KEYWORDS);
1649 + match_key(IUSE);
1650 + match_key(CDEPEND);
1651 + match_key(PDEPEND);
1652 + match_key(EAPI);
1653 + match_key(REQUIRED_USE);
1654 +#undef match_key
1655 + }
1656 +
1657 + findnl = true;
1658 + if (key != NULL) {
1659 + q = p;
1660 + if (*q == '"' || *q == '\'') {
1661 + /* find matching quote */
1662 + p++;
1663 + w = p;
1664 + esc = false;
1665 + do {
1666 + while (*p != '\0' && *p != *q) {
1667 + if (*p == '\\') {
1668 + esc = !esc;
1669 + if (esc) {
1670 + p++;
1671 + continue;
1672 + }
1673 + } else {
1674 + /* implement line continuation (\ before newline) */
1675 + if (esc && (*p == '\n' || *p == '\r'))
1676 + *p = ' ';
1677 + esc = false;
1678 + }
1679 +
1680 + *w++ = *p++;
1681 + }
1682 + if (*p == *q && esc) {
1683 + /* escaped, move along */
1684 + esc = false;
1685 + *w++ = *p++;
1686 + continue;
1687 + }
1688 + break;
1689 + } while (1);
1690 + q++;
1691 + *w = '\0';
1692 + } else {
1693 + /* find first whitespace */
1694 + while (!isspace((int)*p))
1695 + p++;
1696 + if (*p == '\n')
1697 + findnl = false;
1698 + }
1699 + *p++ = '\0';
1700 + *key = q;
1701 + }
1702 +
1703 + if (findnl && (p = strchr(p, '\n')) != NULL)
1704 + p++;
1705 + } while (p != NULL);
1706 +
1707 + fclose(f);
1708 + pkg_ctx->fd = -1;
1709 +
1710 + return ret;
1711 +
1712 +err:
1713 + if (f)
1714 + fclose(f);
1715 + pkg_ctx->fd = -1;
1716 + if (ret)
1717 + tree_close_meta(ret);
1718 + return NULL;
1719 +}
1720 +
1721 +tree_pkg_meta *
1722 +tree_pkg_read(tree_pkg_ctx *pkg_ctx)
1723 +{
1724 + tree_ctx *ctx = pkg_ctx->cat_ctx->ctx;
1725 +
1726 + if (pkg_ctx->fd == -1) {
1727 + if (ctx->cachetype != CACHE_EBUILD) {
1728 + pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name,
1729 + O_RDONLY | O_CLOEXEC);
1730 + } else {
1731 + char *p = (char *)pkg_ctx->name;
1732 + p += strlen(p);
1733 + *p = '.';
1734 + pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name,
1735 + O_RDONLY | O_CLOEXEC);
1736 + *p = '\0';
1737 + }
1738 + if (pkg_ctx->fd == -1)
1739 + return NULL;
1740 + }
1741 +
1742 + if (ctx->cachetype == CACHE_METADATA_MD5) {
1743 + return tree_read_file_md5(pkg_ctx);
1744 + } else if (ctx->cachetype == CACHE_METADATA_PMS) {
1745 + return tree_read_file_pms(pkg_ctx);
1746 + } else if (ctx->cachetype == CACHE_EBUILD) {
1747 + return tree_read_file_ebuild(pkg_ctx);
1748 + }
1749 +
1750 + warn("Unknown metadata cache type!");
1751 + return NULL;
1752 +}
1753 +
1754 +void
1755 +tree_close_meta(tree_pkg_meta *cache)
1756 +{
1757 + if (!cache)
1758 + errf("Cache is empty !");
1759 + free(cache);
1760 +}
1761 +
1762 +tree_metadata_xml *
1763 +tree_pkg_metadata(tree_pkg_ctx *pkg_ctx)
1764 +{
1765 + tree_ctx *ctx = pkg_ctx->cat_ctx->ctx;
1766 + int fd;
1767 + FILE *f;
1768 + struct stat s;
1769 + char *xbuf;
1770 + char *p;
1771 + char *q;
1772 + size_t len;
1773 + tree_metadata_xml *ret = NULL;
1774 + struct elist *emailw = NULL;
1775 + char buf[_Q_PATH_MAX];
1776 +
1777 + /* lame @$$ XML parsing, I don't want to pull in a real parser
1778 + * library because we only retrieve one element for now: email
1779 + * technically speaking, email may occur only once in a maintainer
1780 + * tag, but practically speaking we don't care at all, so we can
1781 + * just extract everything between <email> and </email> */
1782 +
1783 + if (ctx->cachetype == CACHE_EBUILD) {
1784 + fd = openat(pkg_ctx->cat_ctx->fd, "metadata", O_RDONLY | O_CLOEXEC);
1785 + } else {
1786 + depend_atom *atom;
1787 + snprintf(buf, sizeof(buf), "%s/%s",
1788 + pkg_ctx->cat_ctx->name, pkg_ctx->name);
1789 + atom = atom_explode(buf);
1790 + snprintf(buf, sizeof(buf), "../../%s/%s/metadata.xml",
1791 + atom->CATEGORY, atom->PN);
1792 + atom_implode(atom);
1793 + fd = openat(ctx->tree_fd, buf, O_RDONLY | O_CLOEXEC);
1794 + }
1795 +
1796 + if (fd == -1)
1797 + return NULL;
1798 +
1799 + if ((f = fdopen(fd, "r")) == NULL) {
1800 + close(fd);
1801 + return NULL;
1802 + }
1803 +
1804 + if (fstat(fd, &s) != 0) {
1805 + fclose(f);
1806 + return NULL;
1807 + }
1808 +
1809 + len = sizeof(*ret) + s.st_size + 1;
1810 + p = xbuf = xzalloc(len);
1811 + if ((off_t)fread(p, 1, s.st_size, f) != s.st_size) {
1812 + free(p);
1813 + fclose(f);
1814 + pkg_ctx->fd = -1;
1815 + return NULL;
1816 + }
1817 +
1818 + ret = xmalloc(sizeof(*ret));
1819 + ret->email = NULL;
1820 +
1821 + while ((q = strstr(p, "<email>")) != NULL) {
1822 + p = q + sizeof("<email>") - 1;
1823 + if ((q = strstr(p, "</email>")) == NULL)
1824 + break;
1825 + *q = '\0';
1826 + rmspace(p);
1827 + if (emailw == NULL) {
1828 + emailw = ret->email = xmalloc(sizeof(*emailw));
1829 + } else {
1830 + emailw = emailw->next = xmalloc(sizeof(*emailw));
1831 + }
1832 + emailw->next = NULL;
1833 + emailw->addr = xstrdup(p);
1834 + p = q + 1;
1835 + }
1836 +
1837 + free(xbuf);
1838 + fclose(f);
1839 + return ret;
1840 +}
1841 +
1842 +void
1843 +tree_close_metadata(tree_metadata_xml *meta_ctx)
1844 +{
1845 + struct elist *e;
1846 + while (meta_ctx->email != NULL) {
1847 + e = meta_ctx->email;
1848 + free(e->addr);
1849 + e = e->next;
1850 + free(meta_ctx->email);
1851 + meta_ctx->email = e;
1852 + }
1853 + free(meta_ctx);
1854 +}
1855 +
1856 +void
1857 +tree_close_pkg(tree_pkg_ctx *pkg_ctx)
1858 +{
1859 + if (pkg_ctx->fd != -1)
1860 + close(pkg_ctx->fd);
1861 + if (pkg_ctx->atom != NULL)
1862 + atom_implode(pkg_ctx->atom);
1863 + /* avoid freeing tree_ctx' repo */
1864 + if (pkg_ctx->cat_ctx->ctx->repo != pkg_ctx->repo)
1865 + free(pkg_ctx->repo);
1866 + free(pkg_ctx->slot);
1867 + free(pkg_ctx);
1868 +}
1869 +
1870 +int
1871 +tree_foreach_pkg(tree_ctx *ctx,
1872 + tree_pkg_cb callback, void *priv, tree_cat_filter filter,
1873 + bool sort, void *catsortfunc, void *pkgsortfunc)
1874 +{
1875 + tree_cat_ctx *cat_ctx;
1876 + tree_pkg_ctx *pkg_ctx;
1877 + int ret;
1878 +
1879 + if (ctx == NULL)
1880 + return EXIT_FAILURE;
1881 +
1882 + ctx->do_sort = sort;
1883 + if (catsortfunc != NULL)
1884 + ctx->catsortfunc = catsortfunc;
1885 + if (pkgsortfunc != NULL)
1886 + ctx->pkgsortfunc = pkgsortfunc;
1887 +
1888 + ret = 0;
1889 + while ((cat_ctx = tree_next_cat(ctx))) {
1890 + if (filter && !filter(cat_ctx, priv))
1891 + continue;
1892 + while ((pkg_ctx = tree_next_pkg(cat_ctx))) {
1893 + ret |= callback(pkg_ctx, priv);
1894 + tree_close_pkg(pkg_ctx);
1895 + }
1896 + tree_close_cat(cat_ctx);
1897 + }
1898 +
1899 + return ret;
1900 +}
1901 +
1902 +depend_atom *
1903 +tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete)
1904 +{
1905 + if (pkg_ctx->atom == NULL) {
1906 + pkg_ctx->atom = atom_explode(pkg_ctx->name);
1907 + if (pkg_ctx->atom == NULL)
1908 + return NULL;
1909 + pkg_ctx->atom->CATEGORY = (char *)pkg_ctx->cat_ctx->name;
1910 + }
1911 +
1912 + if (complete) {
1913 + tree_ctx *ctx = pkg_ctx->cat_ctx->ctx;
1914 + if (ctx->cachetype == CACHE_VDB) {
1915 + if (pkg_ctx->atom->SLOT == NULL) {
1916 + tree_pkg_vdb_eat(pkg_ctx, "SLOT",
1917 + &pkg_ctx->slot, &pkg_ctx->slot_len);
1918 + pkg_ctx->atom->SLOT = pkg_ctx->slot;
1919 + }
1920 + if (pkg_ctx->atom->REPO == NULL) {
1921 + tree_pkg_vdb_eat(pkg_ctx, "repository",
1922 + &pkg_ctx->repo, &pkg_ctx->repo_len);
1923 + pkg_ctx->atom->REPO = pkg_ctx->repo;
1924 + }
1925 + } else { /* metadata or ebuild */
1926 + if (pkg_ctx->atom->SLOT == NULL) {
1927 + tree_pkg_meta *meta = tree_pkg_read(pkg_ctx);
1928 + if (meta != NULL) {
1929 + pkg_ctx->slot = xstrdup(meta->SLOT);
1930 + pkg_ctx->slot_len = strlen(pkg_ctx->slot);
1931 + pkg_ctx->atom->SLOT = pkg_ctx->slot;
1932 + tree_close_meta(meta);
1933 + }
1934 + }
1935 + /* repo is set from the tree, when found */
1936 + if (pkg_ctx->atom->REPO == NULL)
1937 + pkg_ctx->atom->REPO = pkg_ctx->repo;
1938 + }
1939 + }
1940 +
1941 + return pkg_ctx->atom;
1942 +}
1943 +
1944 +set *
1945 +tree_get_vdb_atoms(const char *sroot, const char *svdb, int fullcpv)
1946 +{
1947 + tree_ctx *ctx;
1948 +
1949 + int cfd, j;
1950 + int dfd, i;
1951 +
1952 + char buf[_Q_PATH_MAX];
1953 + char slot[_Q_PATH_MAX];
1954 + char *slotp = slot;
1955 + size_t slot_len;
1956 +
1957 + struct dirent **cat;
1958 + struct dirent **pf;
1959 +
1960 + depend_atom *atom = NULL;
1961 + set *cpf = NULL;
1962 +
1963 + ctx = tree_open_vdb(sroot, svdb);
1964 + if (!ctx)
1965 + return NULL;
1966 +
1967 + /* scan the cat first */
1968 + cfd = scandirat(ctx->tree_fd, ".", &cat, tree_filter_cat, alphasort);
1969 + if (cfd < 0)
1970 + goto fuckit;
1971 +
1972 + for (j = 0; j < cfd; j++) {
1973 + dfd = scandirat(ctx->tree_fd, cat[j]->d_name,
1974 + &pf, tree_filter_pkg, alphasort);
1975 + if (dfd < 0)
1976 + continue;
1977 + for (i = 0; i < dfd; i++) {
1978 + int blen = snprintf(buf, sizeof(buf), "%s/%s/SLOT",
1979 + cat[j]->d_name, pf[i]->d_name);
1980 + if (blen < 0 || (size_t)blen >= sizeof(buf)) {
1981 + warnf("unable to parse long package: %s/%s",
1982 + cat[j]->d_name, pf[i]->d_name);
1983 + continue;
1984 + }
1985 +
1986 + /* Chop the SLOT for the atom parsing. */
1987 + buf[blen - 5] = '\0';
1988 + if ((atom = atom_explode(buf)) == NULL)
1989 + continue;
1990 + /* Restore the SLOT. */
1991 + buf[blen - 5] = '/';
1992 +
1993 + slot_len = sizeof(slot);
1994 + eat_file_at(ctx->tree_fd, buf, &slotp, &slot_len);
1995 + rmspace(slot);
1996 +
1997 + if (fullcpv) {
1998 + if (atom->PR_int)
1999 + snprintf(buf, sizeof(buf), "%s/%s-%s-r%i",
2000 + atom->CATEGORY, atom->PN, atom->PV, atom->PR_int);
2001 + else
2002 + snprintf(buf, sizeof(buf), "%s/%s-%s",
2003 + atom->CATEGORY, atom->PN, atom->PV);
2004 + } else {
2005 + snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, atom->PN);
2006 + }
2007 + atom_implode(atom);
2008 + cpf = add_set(buf, cpf);
2009 + }
2010 + scandir_free(pf, dfd);
2011 + }
2012 + scandir_free(cat, cfd);
2013 +
2014 + fuckit:
2015 + tree_close(ctx);
2016 + return cpf;
2017 +}
2018
2019 diff --git a/libq/tree.h b/libq/tree.h
2020 new file mode 100644
2021 index 0000000..7f05819
2022 --- /dev/null
2023 +++ b/libq/tree.h
2024 @@ -0,0 +1,141 @@
2025 +/*
2026 + * Copyright 2005-2019 Gentoo Foundation
2027 + * Distributed under the terms of the GNU General Public License v2
2028 + */
2029 +
2030 +#ifndef _TREE_H
2031 +#define _TREE_H 1
2032 +
2033 +#include <dirent.h>
2034 +#include <stdbool.h>
2035 +
2036 +#include "atom.h"
2037 +#include "set.h"
2038 +
2039 +typedef struct tree_ctx tree_ctx;
2040 +typedef struct tree_cat_ctx tree_cat_ctx;
2041 +typedef struct tree_pkg_ctx tree_pkg_ctx;
2042 +typedef struct tree_pkg_meta tree_pkg_meta;
2043 +typedef struct tree_metadata_xml tree_metadata_xml;
2044 +
2045 +/* VDB context */
2046 +struct tree_ctx {
2047 + int portroot_fd;
2048 + int tree_fd;
2049 + DIR *dir;
2050 + struct dirent **cat_de;
2051 + size_t cat_cnt;
2052 + size_t cat_cur;
2053 + void *catsortfunc;
2054 + void *pkgsortfunc;
2055 + bool do_sort:1;
2056 + enum {
2057 + CACHE_UNSET = 0,
2058 + CACHE_METADATA_MD5,
2059 + CACHE_METADATA_PMS,
2060 + CACHE_EBUILD,
2061 + CACHE_VDB,
2062 + } cachetype:3;
2063 + tree_pkg_ctx *ebuilddir_pkg_ctx;
2064 + tree_cat_ctx *ebuilddir_cat_ctx;
2065 + tree_ctx *ebuilddir_ctx;
2066 + char *repo;
2067 +};
2068 +
2069 +/* Category context */
2070 +struct tree_cat_ctx {
2071 + const char *name;
2072 + int fd;
2073 + DIR *dir;
2074 + tree_ctx *ctx;
2075 + struct dirent **pkg_de;
2076 + size_t pkg_cnt;
2077 + size_t pkg_cur;
2078 +};
2079 +
2080 +/* Package context */
2081 +struct tree_pkg_ctx {
2082 + const char *name;
2083 + char *slot;
2084 + char *repo;
2085 + size_t slot_len;
2086 + size_t repo_len;
2087 + int fd;
2088 + tree_cat_ctx *cat_ctx;
2089 + depend_atom *atom;
2090 +};
2091 +
2092 +/* Ebuild data */
2093 +struct tree_pkg_meta {
2094 + char *_data;
2095 + char *DEPEND; /* line 1 */
2096 + char *RDEPEND;
2097 + char *SLOT;
2098 + char *SRC_URI;
2099 + char *RESTRICT; /* line 5 */
2100 + char *HOMEPAGE;
2101 + char *LICENSE;
2102 + char *DESCRIPTION;
2103 + char *KEYWORDS;
2104 + char *INHERITED; /* line 10 */
2105 + char *IUSE;
2106 + char *CDEPEND;
2107 + char *PDEPEND;
2108 + char *PROVIDE; /* line 14 */
2109 + char *EAPI;
2110 + char *PROPERTIES;
2111 + /* These are MD5-Cache only */
2112 + char *DEFINED_PHASES;
2113 + char *REQUIRED_USE;
2114 + char *BDEPEND;
2115 + char *_eclasses_;
2116 + char *_md5_;
2117 +};
2118 +
2119 +/* Metadata.xml */
2120 +struct tree_metadata_xml {
2121 + struct elist {
2122 + char *addr;
2123 + struct elist *next;
2124 + } *email;
2125 +};
2126 +
2127 +/* Global helpers */
2128 +typedef int (tree_pkg_cb)(tree_pkg_ctx *, void *priv);
2129 +typedef int (tree_cat_filter)(tree_cat_ctx *, void *priv);
2130 +
2131 +tree_ctx *tree_open_vdb(const char *sroot, const char *svdb);
2132 +tree_ctx *tree_open(const char *sroot, const char *portdir);
2133 +void tree_close(tree_ctx *ctx);
2134 +int tree_filter_cat(const struct dirent *de);
2135 +tree_cat_ctx *tree_open_cat(tree_ctx *ctx, const char *name);
2136 +tree_cat_ctx *tree_next_cat(tree_ctx *ctx);
2137 +void tree_close_cat(tree_cat_ctx *cat_ctx);
2138 +int tree_filter_pkg(const struct dirent *de);
2139 +tree_pkg_ctx *tree_open_pkg(tree_cat_ctx *cat_ctx, const char *name);
2140 +tree_pkg_ctx *tree_next_pkg(tree_cat_ctx *cat_ctx);
2141 +int tree_pkg_vdb_openat(tree_pkg_ctx *pkg_ctx, const char *file, int flags, mode_t mode);
2142 +FILE *tree_pkg_vdb_fopenat(tree_pkg_ctx *pkg_ctx, const char *file,
2143 + int flags, mode_t mode, const char *fmode);
2144 +#define tree_pkg_vdb_fopenat_ro(pkg_ctx, file) \
2145 + tree_pkg_vdb_fopenat(pkg_ctx, file, O_RDONLY, 0, "r")
2146 +#define tree_pkg_vdb_fopenat_rw(pkg_ctx, file) \
2147 + tree_pkg_vdb_fopenat(pkg_ctx, file, O_RDWR | O_CREAT | O_TRUNC, 0644, "w")
2148 +bool tree_pkg_vdb_eat(tree_pkg_ctx *pkg_ctx, const char *file, char **bufptr, size_t *buflen);
2149 +tree_pkg_meta *tree_pkg_read(tree_pkg_ctx *pkg_ctx);
2150 +void tree_close_meta(tree_pkg_meta *cache);
2151 +tree_metadata_xml *tree_pkg_metadata(tree_pkg_ctx *pkg_ctx);
2152 +void tree_close_metadata(tree_metadata_xml *meta_ctx);
2153 +void tree_close_pkg(tree_pkg_ctx *pkg_ctx);
2154 +int tree_foreach_pkg(tree_ctx *ctx,
2155 + tree_pkg_cb callback, void *priv, tree_cat_filter filter,
2156 + bool sort, void *catsortfunc, void *pkgsortfunc);
2157 +#define tree_foreach_pkg_fast(ctx, cb, priv, filter) \
2158 + tree_foreach_pkg(ctx, cb, priv, filter, false, NULL, NULL);
2159 +#define tree_foreach_pkg_sorted(ctx, cb, priv) \
2160 + tree_foreach_pkg(ctx, cb, priv, NULL, true, NULL, NULL);
2161 +struct dirent *tree_get_next_dir(DIR *dir);
2162 +set *tree_get_vdb_atoms(const char *sroot, const char *svdb, int fullcpv);
2163 +depend_atom *tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete);
2164 +
2165 +#endif
2166
2167 diff --git a/libq/vdb.c b/libq/vdb.c
2168 deleted file mode 100644
2169 index 810a84c..0000000
2170 --- a/libq/vdb.c
2171 +++ /dev/null
2172 @@ -1,515 +0,0 @@
2173 -/*
2174 - * Copyright 2005-2019 Gentoo Foundation
2175 - * Distributed under the terms of the GNU General Public License v2
2176 - *
2177 - * Copyright 2005-2010 Ned Ludd - <solar@g.o>
2178 - * Copyright 2005-2014 Mike Frysinger - <vapier@g.o>
2179 - * Copyright 2019- Fabian Groffen - <grobian@g.o>
2180 - */
2181 -
2182 -#include "main.h"
2183 -#include "rmspace.h"
2184 -#include "scandirat.h"
2185 -#include "eat_file.h"
2186 -#include "set.h"
2187 -#include "atom.h"
2188 -#include "vdb.h"
2189 -
2190 -#include <ctype.h>
2191 -#include <xalloc.h>
2192 -
2193 -vdb_ctx *
2194 -vdb_open2(const char *sroot, const char *svdb, bool quiet)
2195 -{
2196 - vdb_ctx *ctx = xmalloc(sizeof(*ctx));
2197 -
2198 - ctx->portroot_fd = open(sroot, O_RDONLY|O_CLOEXEC|O_PATH);
2199 - if (ctx->portroot_fd == -1) {
2200 - if (!quiet)
2201 - warnp("could not open root: %s", sroot);
2202 - goto f_error;
2203 - }
2204 -
2205 - /* Skip the leading slash */
2206 - svdb++;
2207 - if (*svdb == '\0')
2208 - svdb = ".";
2209 - /* Cannot use O_PATH as we want to use fdopendir() */
2210 - ctx->vdb_fd = openat(ctx->portroot_fd, svdb, O_RDONLY|O_CLOEXEC);
2211 - if (ctx->vdb_fd == -1) {
2212 - if (!quiet)
2213 - warnp("could not open vdb: %s (in root %s)", svdb, sroot);
2214 - goto cp_error;
2215 - }
2216 -
2217 - ctx->dir = fdopendir(ctx->vdb_fd);
2218 - if (ctx->dir == NULL)
2219 - goto cv_error;
2220 -
2221 - ctx->do_sort = false;
2222 - ctx->cat_de = NULL;
2223 - ctx->catsortfunc = alphasort;
2224 - ctx->pkgsortfunc = alphasort;
2225 - ctx->repo = NULL;
2226 - ctx->ebuilddir_ctx = NULL;
2227 - ctx->ebuilddir_pkg_ctx = NULL;
2228 - return ctx;
2229 -
2230 - cv_error:
2231 - close(ctx->vdb_fd);
2232 - cp_error:
2233 - close(ctx->portroot_fd);
2234 - f_error:
2235 - free(ctx);
2236 - return NULL;
2237 -}
2238 -
2239 -vdb_ctx *
2240 -vdb_open(const char *sroot, const char *svdb)
2241 -{
2242 - return vdb_open2(sroot, svdb, false);
2243 -}
2244 -
2245 -void
2246 -vdb_close(vdb_ctx *ctx)
2247 -{
2248 - closedir(ctx->dir);
2249 - /* closedir() above does this for us: */
2250 - /* close(ctx->vdb_fd); */
2251 - close(ctx->portroot_fd);
2252 - if (ctx->do_sort)
2253 - scandir_free(ctx->cat_de, ctx->cat_cnt);
2254 - free(ctx);
2255 -}
2256 -
2257 -int
2258 -vdb_filter_cat(const struct dirent *de)
2259 -{
2260 - int i;
2261 - bool founddash;
2262 -
2263 -#ifdef DT_UNKNOWN
2264 - /* cat must be a dir */
2265 - if (de->d_type != DT_UNKNOWN &&
2266 - de->d_type != DT_DIR &&
2267 - de->d_type != DT_LNK)
2268 - return 0;
2269 -#endif
2270 -
2271 - /* PMS 3.1.1 */
2272 - founddash = false;
2273 - for (i = 0; de->d_name[i] != '\0'; i++) {
2274 - switch (de->d_name[i]) {
2275 - case '_':
2276 - break;
2277 - case '-':
2278 - founddash = true;
2279 - /* fall through */
2280 - case '+':
2281 - case '.':
2282 - if (i)
2283 - break;
2284 - return 0;
2285 - default:
2286 - if ((de->d_name[i] >= 'A' && de->d_name[i] <= 'Z') ||
2287 - (de->d_name[i] >= 'a' && de->d_name[i] <= 'z') ||
2288 - (de->d_name[i] >= '0' && de->d_name[i] <= '9'))
2289 - break;
2290 - return 0;
2291 - }
2292 - }
2293 - if (!founddash && strcmp(de->d_name, "virtual") != 0)
2294 - return 0;
2295 -
2296 - return i;
2297 -}
2298 -
2299 -vdb_cat_ctx *
2300 -vdb_open_cat(vdb_ctx *ctx, const char *name)
2301 -{
2302 - vdb_cat_ctx *cat_ctx;
2303 - int fd;
2304 - DIR *dir;
2305 -
2306 - /* Cannot use O_PATH as we want to use fdopendir() */
2307 - fd = openat(ctx->vdb_fd, name, O_RDONLY|O_CLOEXEC);
2308 - if (fd == -1)
2309 - return NULL;
2310 -
2311 - dir = fdopendir(fd);
2312 - if (!dir) {
2313 - close(fd);
2314 - return NULL;
2315 - }
2316 -
2317 - cat_ctx = xmalloc(sizeof(*cat_ctx));
2318 - cat_ctx->name = name;
2319 - cat_ctx->fd = fd;
2320 - cat_ctx->dir = dir;
2321 - cat_ctx->ctx = ctx;
2322 - cat_ctx->pkg_de = NULL;
2323 - return cat_ctx;
2324 -}
2325 -
2326 -vdb_cat_ctx *
2327 -vdb_next_cat(vdb_ctx *ctx)
2328 -{
2329 - /* search for a category directory */
2330 - vdb_cat_ctx *cat_ctx = NULL;
2331 -
2332 - if (ctx->do_sort) {
2333 - if (ctx->cat_de == NULL) {
2334 - ctx->cat_cnt = scandirat(ctx->vdb_fd,
2335 - ".", &ctx->cat_de, vdb_filter_cat, ctx->catsortfunc);
2336 - ctx->cat_cur = 0;
2337 - }
2338 -
2339 - while (ctx->cat_cur < ctx->cat_cnt) {
2340 - cat_ctx = vdb_open_cat(ctx, ctx->cat_de[ctx->cat_cur++]->d_name);
2341 - if (!cat_ctx)
2342 - continue;
2343 - break;
2344 - }
2345 - } else {
2346 - /* cheaper "streaming" variant */
2347 - const struct dirent *de;
2348 - do {
2349 - de = readdir(ctx->dir);
2350 - if (!de)
2351 - break;
2352 -
2353 - if (vdb_filter_cat(de) == 0)
2354 - continue;
2355 -
2356 - cat_ctx = vdb_open_cat(ctx, de->d_name);
2357 - if (!cat_ctx)
2358 - continue;
2359 -
2360 - break;
2361 - } while (1);
2362 - }
2363 -
2364 - return cat_ctx;
2365 -}
2366 -
2367 -void
2368 -vdb_close_cat(vdb_cat_ctx *cat_ctx)
2369 -{
2370 - closedir(cat_ctx->dir);
2371 - /* closedir() above does this for us: */
2372 - /* close(ctx->fd); */
2373 - if (cat_ctx->ctx->do_sort)
2374 - scandir_free(cat_ctx->pkg_de, cat_ctx->pkg_cnt);
2375 - free(cat_ctx);
2376 -}
2377 -
2378 -int
2379 -vdb_filter_pkg(const struct dirent *de)
2380 -{
2381 - int i;
2382 - bool founddash = false;
2383 -
2384 - /* PMS 3.1.2 */
2385 - for (i = 0; de->d_name[i] != '\0'; i++) {
2386 - switch (de->d_name[i]) {
2387 - case '_':
2388 - break;
2389 - case '-':
2390 - founddash = true;
2391 - /* fall through */
2392 - case '+':
2393 - if (i)
2394 - break;
2395 - return 0;
2396 - default:
2397 - if ((de->d_name[i] >= 'A' && de->d_name[i] <= 'Z') ||
2398 - (de->d_name[i] >= 'a' && de->d_name[i] <= 'z') ||
2399 - (de->d_name[i] >= '0' && de->d_name[i] <= '9'))
2400 - break;
2401 - if (founddash)
2402 - return 1;
2403 - return 0;
2404 - }
2405 - }
2406 -
2407 - return i;
2408 -}
2409 -
2410 -vdb_pkg_ctx *
2411 -vdb_open_pkg(vdb_cat_ctx *cat_ctx, const char *name)
2412 -{
2413 - vdb_pkg_ctx *pkg_ctx = xmalloc(sizeof(*pkg_ctx));
2414 - pkg_ctx->name = name;
2415 - pkg_ctx->slot = NULL;
2416 - pkg_ctx->repo = cat_ctx->ctx->repo;
2417 - pkg_ctx->fd = -1;
2418 - pkg_ctx->cat_ctx = cat_ctx;
2419 - pkg_ctx->atom = NULL;
2420 - return pkg_ctx;
2421 -}
2422 -
2423 -vdb_pkg_ctx *
2424 -vdb_next_pkg(vdb_cat_ctx *cat_ctx)
2425 -{
2426 - vdb_pkg_ctx *pkg_ctx = NULL;
2427 -
2428 - if (cat_ctx->ctx->do_sort) {
2429 - if (cat_ctx->pkg_de == NULL) {
2430 - cat_ctx->pkg_cnt = scandirat(cat_ctx->fd, ".", &cat_ctx->pkg_de,
2431 - vdb_filter_pkg, cat_ctx->ctx->pkgsortfunc);
2432 - cat_ctx->pkg_cur = 0;
2433 - }
2434 -
2435 - while (cat_ctx->pkg_cur < cat_ctx->pkg_cnt) {
2436 - pkg_ctx =
2437 - vdb_open_pkg(cat_ctx,
2438 - cat_ctx->pkg_de[cat_ctx->pkg_cur++]->d_name);
2439 - if (!pkg_ctx)
2440 - continue;
2441 - break;
2442 - }
2443 - } else {
2444 - const struct dirent *de;
2445 - do {
2446 - de = readdir(cat_ctx->dir);
2447 - if (!de)
2448 - break;
2449 -
2450 - if (vdb_filter_pkg(de) == 0)
2451 - continue;
2452 -
2453 - pkg_ctx = vdb_open_pkg(cat_ctx, de->d_name);
2454 - if (!pkg_ctx)
2455 - continue;
2456 -
2457 - break;
2458 - } while (1);
2459 - }
2460 -
2461 - return pkg_ctx;
2462 -}
2463 -
2464 -int
2465 -vdb_pkg_openat(vdb_pkg_ctx *pkg_ctx, const char *file, int flags, mode_t mode)
2466 -{
2467 - if (pkg_ctx->fd == -1) {
2468 - pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name,
2469 - O_RDONLY|O_CLOEXEC|O_PATH);
2470 - if (pkg_ctx->fd == -1)
2471 - return -1;
2472 - }
2473 -
2474 - return openat(pkg_ctx->fd, file, flags|O_CLOEXEC, mode);
2475 -}
2476 -
2477 -FILE *
2478 -vdb_pkg_fopenat(vdb_pkg_ctx *pkg_ctx, const char *file,
2479 - int flags, mode_t mode, const char *fmode)
2480 -{
2481 - FILE *fp;
2482 - int fd;
2483 -
2484 - fd = vdb_pkg_openat(pkg_ctx, file, flags, mode);
2485 - if (fd == -1)
2486 - return NULL;
2487 -
2488 - fp = fdopen(fd, fmode);
2489 - if (!fp)
2490 - close(fd);
2491 -
2492 - return fp;
2493 -}
2494 -
2495 -bool
2496 -vdb_pkg_eat(vdb_pkg_ctx *pkg_ctx, const char *file, char **bufptr, size_t *buflen)
2497 -{
2498 - int fd = vdb_pkg_openat(pkg_ctx, file, O_RDONLY, 0);
2499 - bool ret = eat_file_fd(fd, bufptr, buflen);
2500 - rmspace(*bufptr);
2501 - if (fd != -1)
2502 - close(fd);
2503 - return ret;
2504 -}
2505 -
2506 -void
2507 -vdb_close_pkg(vdb_pkg_ctx *pkg_ctx)
2508 -{
2509 - if (pkg_ctx->fd != -1)
2510 - close(pkg_ctx->fd);
2511 - if (pkg_ctx->atom != NULL)
2512 - atom_implode(pkg_ctx->atom);
2513 - free(pkg_ctx->slot);
2514 - free(pkg_ctx->repo);
2515 - free(pkg_ctx);
2516 -}
2517 -
2518 -static int
2519 -vdb_foreach_pkg_int(const char *sroot, const char *svdb,
2520 - vdb_pkg_cb callback, void *priv, vdb_cat_filter filter,
2521 - bool sort, void *catsortfunc, void *pkgsortfunc)
2522 -{
2523 - vdb_ctx *ctx;
2524 - vdb_cat_ctx *cat_ctx;
2525 - vdb_pkg_ctx *pkg_ctx;
2526 - int ret;
2527 -
2528 - ctx = vdb_open(sroot, svdb);
2529 - if (!ctx)
2530 - return EXIT_FAILURE;
2531 -
2532 - ctx->do_sort = sort;
2533 - if (catsortfunc != NULL)
2534 - ctx->catsortfunc = catsortfunc;
2535 - if (pkgsortfunc != NULL)
2536 - ctx->pkgsortfunc = pkgsortfunc;
2537 -
2538 - ret = 0;
2539 - while ((cat_ctx = vdb_next_cat(ctx))) {
2540 - if (filter && !filter(cat_ctx, priv))
2541 - continue;
2542 - while ((pkg_ctx = vdb_next_pkg(cat_ctx))) {
2543 - ret |= callback(pkg_ctx, priv);
2544 - vdb_close_pkg(pkg_ctx);
2545 - }
2546 - vdb_close_cat(cat_ctx);
2547 - }
2548 - vdb_close(ctx);
2549 -
2550 - return ret;
2551 -}
2552 -
2553 -int
2554 -vdb_foreach_pkg(const char *sroot, const char *svdb,
2555 - vdb_pkg_cb callback, void *priv, vdb_cat_filter filter)
2556 -{
2557 - return vdb_foreach_pkg_int(sroot, svdb, callback, priv,
2558 - filter, false, NULL, NULL);
2559 -}
2560 -
2561 -int
2562 -vdb_foreach_pkg_sorted(const char *sroot, const char *svdb,
2563 - vdb_pkg_cb callback, void *priv)
2564 -{
2565 - return vdb_foreach_pkg_int(sroot, svdb, callback, priv,
2566 - NULL, true, NULL, NULL);
2567 -}
2568 -
2569 -struct dirent *
2570 -vdb_get_next_dir(DIR *dir)
2571 -{
2572 - /* search for a category directory */
2573 - struct dirent *ret;
2574 -
2575 -next_entry:
2576 - ret = readdir(dir);
2577 - if (ret == NULL) {
2578 - closedir(dir);
2579 - return NULL;
2580 - }
2581 -
2582 - if (vdb_filter_cat(ret) == 0)
2583 - goto next_entry;
2584 -
2585 - return ret;
2586 -}
2587 -
2588 -depend_atom *
2589 -vdb_get_atom(vdb_pkg_ctx *pkg_ctx, bool complete)
2590 -{
2591 - if (pkg_ctx->atom == NULL) {
2592 - pkg_ctx->atom = atom_explode(pkg_ctx->name);
2593 - if (pkg_ctx->atom == NULL)
2594 - return NULL;
2595 - pkg_ctx->atom->CATEGORY = (char *)pkg_ctx->cat_ctx->name;
2596 - }
2597 -
2598 - if (complete) {
2599 - if (pkg_ctx->atom->SLOT == NULL) {
2600 - vdb_pkg_eat(pkg_ctx, "SLOT",
2601 - &pkg_ctx->slot, &pkg_ctx->slot_len);
2602 - pkg_ctx->atom->SLOT = pkg_ctx->slot;
2603 - }
2604 - if (pkg_ctx->atom->REPO == NULL) {
2605 - vdb_pkg_eat(pkg_ctx, "repository",
2606 - &pkg_ctx->repo, &pkg_ctx->repo_len);
2607 - pkg_ctx->atom->REPO = pkg_ctx->repo;
2608 - }
2609 - }
2610 -
2611 - return pkg_ctx->atom;
2612 -}
2613 -
2614 -set *
2615 -get_vdb_atoms(const char *sroot, const char *svdb, int fullcpv)
2616 -{
2617 - vdb_ctx *ctx;
2618 -
2619 - int cfd, j;
2620 - int dfd, i;
2621 -
2622 - char buf[_Q_PATH_MAX];
2623 - char slot[_Q_PATH_MAX];
2624 - char *slotp = slot;
2625 - size_t slot_len;
2626 -
2627 - struct dirent **cat;
2628 - struct dirent **pf;
2629 -
2630 - depend_atom *atom = NULL;
2631 - set *cpf = NULL;
2632 -
2633 - ctx = vdb_open(sroot, svdb);
2634 - if (!ctx)
2635 - return NULL;
2636 -
2637 - /* scan the cat first */
2638 - cfd = scandirat(ctx->vdb_fd, ".", &cat, vdb_filter_cat, alphasort);
2639 - if (cfd < 0)
2640 - goto fuckit;
2641 -
2642 - for (j = 0; j < cfd; j++) {
2643 - dfd = scandirat(ctx->vdb_fd, cat[j]->d_name,
2644 - &pf, vdb_filter_pkg, alphasort);
2645 - if (dfd < 0)
2646 - continue;
2647 - for (i = 0; i < dfd; i++) {
2648 - int blen = snprintf(buf, sizeof(buf), "%s/%s/SLOT",
2649 - cat[j]->d_name, pf[i]->d_name);
2650 - if (blen < 0 || (size_t)blen >= sizeof(buf)) {
2651 - warnf("unable to parse long package: %s/%s",
2652 - cat[j]->d_name, pf[i]->d_name);
2653 - continue;
2654 - }
2655 -
2656 - /* Chop the SLOT for the atom parsing. */
2657 - buf[blen - 5] = '\0';
2658 - if ((atom = atom_explode(buf)) == NULL)
2659 - continue;
2660 - /* Restore the SLOT. */
2661 - buf[blen - 5] = '/';
2662 -
2663 - slot_len = sizeof(slot);
2664 - eat_file_at(ctx->vdb_fd, buf, &slotp, &slot_len);
2665 - rmspace(slot);
2666 -
2667 - if (fullcpv) {
2668 - if (atom->PR_int)
2669 - snprintf(buf, sizeof(buf), "%s/%s-%s-r%i",
2670 - atom->CATEGORY, atom->PN, atom->PV, atom->PR_int);
2671 - else
2672 - snprintf(buf, sizeof(buf), "%s/%s-%s",
2673 - atom->CATEGORY, atom->PN, atom->PV);
2674 - } else {
2675 - snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, atom->PN);
2676 - }
2677 - atom_implode(atom);
2678 - cpf = add_set(buf, cpf);
2679 - }
2680 - scandir_free(pf, dfd);
2681 - }
2682 - scandir_free(cat, cfd);
2683 -
2684 - fuckit:
2685 - vdb_close(ctx);
2686 - return cpf;
2687 -}
2688
2689 diff --git a/libq/vdb.h b/libq/vdb.h
2690 deleted file mode 100644
2691 index 28ca040..0000000
2692 --- a/libq/vdb.h
2693 +++ /dev/null
2694 @@ -1,96 +0,0 @@
2695 -/*
2696 - * Copyright 2005-2019 Gentoo Foundation
2697 - * Distributed under the terms of the GNU General Public License v2
2698 - */
2699 -
2700 -#ifndef _VDB_H
2701 -#define _VDB_H 1
2702 -
2703 -#include <dirent.h>
2704 -#include <stdbool.h>
2705 -
2706 -#include "set.h"
2707 -
2708 -typedef struct vdb_ctx vdb_ctx;
2709 -typedef struct vdb_cat_ctx vdb_cat_ctx;
2710 -typedef struct vdb_pkg_ctx vdb_pkg_ctx;
2711 -
2712 -/* VDB context */
2713 -struct vdb_ctx {
2714 - int portroot_fd;
2715 - int vdb_fd;
2716 - DIR *dir;
2717 - struct dirent **cat_de;
2718 - size_t cat_cnt;
2719 - size_t cat_cur;
2720 - void *catsortfunc;
2721 - void *pkgsortfunc;
2722 - bool do_sort:1;
2723 - enum {
2724 - CACHE_UNSET = 0,
2725 - CACHE_METADATA_MD5,
2726 - CACHE_METADATA_PMS,
2727 - CACHE_EBUILD,
2728 - CACHE_VDB,
2729 - } cachetype:3;
2730 - vdb_pkg_ctx *ebuilddir_pkg_ctx;
2731 - vdb_cat_ctx *ebuilddir_cat_ctx;
2732 - vdb_ctx *ebuilddir_ctx;
2733 - char *repo;
2734 -};
2735 -
2736 -/* Category context */
2737 -struct vdb_cat_ctx {
2738 - const char *name;
2739 - int fd;
2740 - DIR *dir;
2741 - const vdb_ctx *ctx;
2742 - struct dirent **pkg_de;
2743 - size_t pkg_cnt;
2744 - size_t pkg_cur;
2745 -};
2746 -
2747 -/* Package context */
2748 -struct vdb_pkg_ctx {
2749 - const char *name;
2750 - char *slot;
2751 - char *repo;
2752 - size_t slot_len;
2753 - size_t repo_len;
2754 - int fd;
2755 - vdb_cat_ctx *cat_ctx;
2756 - depend_atom *atom;
2757 -};
2758 -
2759 -/* Global helpers */
2760 -typedef int (vdb_pkg_cb)(vdb_pkg_ctx *, void *priv);
2761 -typedef int (vdb_cat_filter)(vdb_cat_ctx *, void *priv);
2762 -
2763 -vdb_ctx *vdb_open(const char *sroot, const char *svdb);
2764 -vdb_ctx *vdb_open2(const char *sroot, const char *svdb, bool quiet);
2765 -void vdb_close(vdb_ctx *ctx);
2766 -int vdb_filter_cat(const struct dirent *de);
2767 -vdb_cat_ctx *vdb_open_cat(vdb_ctx *ctx, const char *name);
2768 -vdb_cat_ctx *vdb_next_cat(vdb_ctx *ctx);
2769 -void vdb_close_cat(vdb_cat_ctx *cat_ctx);
2770 -int vdb_filter_pkg(const struct dirent *de);
2771 -vdb_pkg_ctx *vdb_open_pkg(vdb_cat_ctx *cat_ctx, const char *name);
2772 -vdb_pkg_ctx *vdb_next_pkg(vdb_cat_ctx *cat_ctx);
2773 -int vdb_pkg_openat(vdb_pkg_ctx *pkg_ctx, const char *file, int flags, mode_t mode);
2774 -FILE *vdb_pkg_fopenat(vdb_pkg_ctx *pkg_ctx, const char *file,
2775 - int flags, mode_t mode, const char *fmode);
2776 -#define vdb_pkg_fopenat_ro(pkg_ctx, file) \
2777 - vdb_pkg_fopenat(pkg_ctx, file, O_RDONLY, 0, "r")
2778 -#define vdb_pkg_fopenat_rw(pkg_ctx, file) \
2779 - vdb_pkg_fopenat(pkg_ctx, file, O_RDWR|O_CREAT|O_TRUNC, 0644, "w")
2780 -bool vdb_pkg_eat(vdb_pkg_ctx *pkg_ctx, const char *file, char **bufptr, size_t *buflen);
2781 -void vdb_close_pkg(vdb_pkg_ctx *pkg_ctx);
2782 -int vdb_foreach_pkg(const char *sroot, const char *svdb,
2783 - vdb_pkg_cb callback, void *priv, vdb_cat_filter filter);
2784 -int vdb_foreach_pkg_sorted(const char *sroot, const char *svdb,
2785 - vdb_pkg_cb callback, void *priv);
2786 -struct dirent *vdb_get_next_dir(DIR *dir);
2787 -set *get_vdb_atoms(const char *sroot, const char *svdb, int fullcpv);
2788 -depend_atom *vdb_get_atom(vdb_pkg_ctx *pkg_ctx, bool complete);
2789 -
2790 -#endif
2791
2792 diff --git a/main.c b/main.c
2793 index 159b262..944950e 100644
2794 --- a/main.c
2795 +++ b/main.c
2796 @@ -17,30 +17,10 @@
2797 #include <sys/time.h>
2798 #include <limits.h>
2799
2800 -#include "atom.h"
2801 -#include "basename.h"
2802 -#include "busybox.h"
2803 -#include "cache.h"
2804 -#include "colors.h"
2805 -#include "copy_file.h"
2806 #include "eat_file.h"
2807 -#include "hash_fd.h"
2808 -#include "human_readable.h"
2809 -#include "i18n.h"
2810 -#include "md5_sha1_sum.h"
2811 -#include "prelink.h"
2812 -#include "profile.h"
2813 #include "rmspace.h"
2814 -#include "safe_io.h"
2815 #include "scandirat.h"
2816 -#include "set.h"
2817 -#include "vdb.h"
2818 -#include "xarray.h"
2819 #include "xasprintf.h"
2820 -#include "xchdir.h"
2821 -#include "xmkdir.h"
2822 -#include "xregex.h"
2823 -#include "xsystem.h"
2824
2825 /* variables to control runtime behavior */
2826 char *module_name = NULL;
2827
2828 diff --git a/q.c b/q.c
2829 index a18c791..b6486ee 100644
2830 --- a/q.c
2831 +++ b/q.c
2832 @@ -19,9 +19,7 @@
2833 #include <libproc.h>
2834 #endif
2835
2836 -#include "atom.h"
2837 #include "basename.h"
2838 -#include "cache.h"
2839
2840 #define Q_FLAGS "iM:" COMMON_FLAGS
2841 static struct option const q_long_opts[] = {
2842
2843 diff --git a/qcheck.c b/qcheck.c
2844 index 68cdb30..a26b25d 100644
2845 --- a/qcheck.c
2846 +++ b/qcheck.c
2847 @@ -20,7 +20,7 @@
2848 #include "md5_sha1_sum.h"
2849 #include "prelink.h"
2850 #include "set.h"
2851 -#include "vdb.h"
2852 +#include "tree.h"
2853 #include "xarray.h"
2854 #include "xasprintf.h"
2855 #include "xregex.h"
2856 @@ -65,7 +65,7 @@ struct qcheck_opt_state {
2857 };
2858
2859 static int
2860 -qcheck_process_contents(vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
2861 +qcheck_process_contents(tree_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
2862 {
2863 int fd_contents;
2864 FILE *fp_contents, *fp_contents_update;
2865 @@ -80,7 +80,8 @@ qcheck_process_contents(vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
2866 fp_contents_update = NULL;
2867
2868 /* Open contents */
2869 - fd_contents = vdb_pkg_openat(pkg_ctx, "CONTENTS", O_RDONLY|O_CLOEXEC, 0);
2870 + fd_contents = tree_pkg_vdb_openat(pkg_ctx, "CONTENTS",
2871 + O_RDONLY | O_CLOEXEC, 0);
2872 if (fd_contents == -1)
2873 return EXIT_SUCCESS;
2874 if (fstat(fd_contents, &cst)) {
2875 @@ -93,13 +94,13 @@ qcheck_process_contents(vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
2876 }
2877
2878 /* Open contents_update, if needed */
2879 - atom = vdb_get_atom(pkg_ctx, false);
2880 + atom = tree_get_atom(pkg_ctx, false);
2881 num_files = num_files_ok = num_files_unknown = num_files_ignored = 0;
2882 qcprintf("%sing %s ...\n",
2883 (state->qc_update ? "Updat" : "Check"),
2884 atom_format("%[CATEGORY]%[PF]", atom, 0));
2885 if (state->qc_update) {
2886 - fp_contents_update = vdb_pkg_fopenat_rw(pkg_ctx, "CONTENTS~");
2887 + fp_contents_update = tree_pkg_vdb_fopenat_rw(pkg_ctx, "CONTENTS~");
2888 if (fp_contents_update == NULL) {
2889 fclose(fp_contents);
2890 warnp("unable to fopen(%s/%s, w)", atom->P, "CONTENTS~");
2891 @@ -355,7 +356,7 @@ qcheck_process_contents(vdb_pkg_ctx *pkg_ctx, struct qcheck_opt_state *state)
2892 }
2893
2894 static int
2895 -qcheck_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
2896 +qcheck_cb(tree_pkg_ctx *pkg_ctx, void *priv)
2897 {
2898 struct qcheck_opt_state *state = priv;
2899 bool showit = false;
2900 @@ -366,7 +367,7 @@ qcheck_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
2901 depend_atom *qatom;
2902 depend_atom *atom;
2903
2904 - qatom = vdb_get_atom(pkg_ctx, false);
2905 + qatom = tree_get_atom(pkg_ctx, false);
2906 array_for_each(state->atoms, i, atom) {
2907 if (atom_compare(atom, qatom) == EQUAL) {
2908 showit = true;
2909 @@ -384,6 +385,7 @@ int qcheck_main(int argc, char **argv)
2910 {
2911 size_t i;
2912 int ret;
2913 + tree_ctx *vdb;
2914 DECLARE_ARRAY(regex_arr);
2915 depend_atom *atom;
2916 DECLARE_ARRAY(atoms);
2917 @@ -403,9 +405,9 @@ int qcheck_main(int argc, char **argv)
2918 switch (ret) {
2919 COMMON_GETOPTS_CASES(qcheck)
2920 case 's': {
2921 - regex_t regex;
2922 - xregcomp(&regex, optarg, REG_EXTENDED|REG_NOSUB);
2923 - xarraypush(regex_arr, &regex, sizeof(regex));
2924 + regex_t preg;
2925 + xregcomp(&preg, optarg, REG_EXTENDED | REG_NOSUB);
2926 + xarraypush(regex_arr, &preg, sizeof(preg));
2927 break;
2928 }
2929 case 'u': state.qc_update = true; break;
2930 @@ -428,11 +430,16 @@ int qcheck_main(int argc, char **argv)
2931 xarraypush_ptr(atoms, atom);
2932 }
2933
2934 - ret = vdb_foreach_pkg_sorted(portroot, portvdb, qcheck_cb, &state);
2935 - {
2936 - void *regex;
2937 - array_for_each(regex_arr, i, regex)
2938 - regfree(regex);
2939 + vdb = tree_open_vdb(portroot, portvdb);
2940 + ret = -1;
2941 + if (vdb != NULL) {
2942 + ret = tree_foreach_pkg_sorted(vdb, qcheck_cb, &state);
2943 + tree_close(vdb);
2944 + }
2945 + if (array_cnt(regex_arr) > 0) {
2946 + void *preg;
2947 + array_for_each(regex_arr, i, preg)
2948 + regfree(preg);
2949 }
2950 xarrayfree(regex_arr);
2951 array_for_each(atoms, i, atom)
2952
2953 diff --git a/qdepends.c b/qdepends.c
2954 index 64bf991..15d5253 100644
2955 --- a/qdepends.c
2956 +++ b/qdepends.c
2957 @@ -17,7 +17,7 @@
2958 #include "atom.h"
2959 #include "dep.h"
2960 #include "set.h"
2961 -#include "vdb.h"
2962 +#include "tree.h"
2963 #include "xarray.h"
2964 #include "xasprintf.h"
2965 #include "xregex.h"
2966 @@ -92,7 +92,7 @@ qdepends_print_depend(FILE *fp, const char *depend)
2967 }
2968
2969 static int
2970 -qdepends_results_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
2971 +qdepends_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
2972 {
2973 struct qdepends_opt_state *state = priv;
2974 depend_atom *atom;
2975 @@ -116,7 +116,7 @@ qdepends_results_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
2976 * *DEPEND alters the search somewhat and affects results printing.
2977 */
2978
2979 - datom = vdb_get_atom(pkg_ctx, false);
2980 + datom = tree_get_atom(pkg_ctx, false);
2981 if (datom == NULL)
2982 return ret;
2983
2984 @@ -135,7 +135,7 @@ qdepends_results_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
2985
2986 ret = 1;
2987
2988 - datom = vdb_get_atom(pkg_ctx, true);
2989 + datom = tree_get_atom(pkg_ctx, true);
2990 printf("%s:", atom_format(state->format, datom, 0));
2991 }
2992
2993 @@ -146,7 +146,7 @@ qdepends_results_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
2994 for (i = QMODE_DEPEND; i <= QMODE_BDEPEND; i <<= 1, dfile++) {
2995 if (!(state->qmode & i))
2996 continue;
2997 - if (!vdb_pkg_eat(pkg_ctx, *dfile,
2998 + if (!tree_pkg_vdb_eat(pkg_ctx, *dfile,
2999 &state->depend, &state->depend_len))
3000 continue;
3001
3002 @@ -174,7 +174,7 @@ qdepends_results_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3003 ret = 1;
3004
3005 if (!firstmatch) {
3006 - datom = vdb_get_atom(pkg_ctx, true);
3007 + datom = tree_get_atom(pkg_ctx, true);
3008 printf("%s:", atom_format(state->format, datom, 0));
3009 }
3010 firstmatch = true;
3011 @@ -203,7 +203,7 @@ qdepends_results_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3012 ret = 1;
3013
3014 if (!firstmatch) {
3015 - datom = vdb_get_atom(pkg_ctx, true);
3016 + datom = tree_get_atom(pkg_ctx, true);
3017 printf("%s:", atom_format(state->format, datom, 0));
3018 }
3019 firstmatch = true;
3020 @@ -243,6 +243,7 @@ qdepends_results_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3021 int qdepends_main(int argc, char **argv)
3022 {
3023 depend_atom *atom;
3024 + tree_ctx *vdb;
3025 DECLARE_ARRAY(atoms);
3026 DECLARE_ARRAY(deps);
3027 struct qdepends_opt_state state = {
3028 @@ -307,8 +308,11 @@ int qdepends_main(int argc, char **argv)
3029 xarraypush_ptr(atoms, atom);
3030 }
3031
3032 - ret = vdb_foreach_pkg(portroot, portvdb,
3033 - qdepends_results_cb, &state, NULL);
3034 + vdb = tree_open_vdb(portroot, portvdb);
3035 + if (vdb != NULL) {
3036 + ret = tree_foreach_pkg_fast(vdb, qdepends_results_cb, &state, NULL);
3037 + tree_close(vdb);
3038 + }
3039
3040 if (state.depend != NULL)
3041 free(state.depend);
3042
3043 diff --git a/qfile.c b/qfile.c
3044 index 3d1543e..c451ae4 100644
3045 --- a/qfile.c
3046 +++ b/qfile.c
3047 @@ -18,7 +18,7 @@
3048 #include "basename.h"
3049 #include "contents.h"
3050 #include "rmspace.h"
3051 -#include "vdb.h"
3052 +#include "tree.h"
3053
3054 #define QFILE_FLAGS "boRx:S" COMMON_FLAGS
3055 static struct option const qfile_long_opts[] = {
3056 @@ -74,7 +74,7 @@ struct qfile_opt_state {
3057 * We assume the people calling us have chdir(/var/db/pkg) and so
3058 * we use relative paths throughout here.
3059 */
3060 -static int qfile_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3061 +static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3062 {
3063 struct qfile_opt_state *state = priv;
3064 const char *catname = pkg_ctx->cat_ctx->name;
3065 @@ -115,14 +115,14 @@ static int qfile_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3066 }
3067 if (state->exclude_slot == NULL)
3068 goto qlist_done; /* "(CAT/)?(PN|PF)" matches, and no SLOT specified */
3069 - vdb_pkg_eat(pkg_ctx, "SLOT", &state->buf, &state->buflen);
3070 + tree_pkg_vdb_eat(pkg_ctx, "SLOT", &state->buf, &state->buflen);
3071 rmspace(state->buf);
3072 if (strcmp(state->exclude_slot, state->buf) == 0)
3073 goto qlist_done; /* "(CAT/)?(PN|PF):SLOT" matches */
3074 }
3075 dont_skip_pkg: /* End of the package exclusion tests. */
3076
3077 - fp = vdb_pkg_fopenat_ro(pkg_ctx, "CONTENTS");
3078 + fp = tree_pkg_vdb_fopenat_ro(pkg_ctx, "CONTENTS");
3079 if (fp == NULL)
3080 goto qlist_done;
3081
3082 @@ -227,7 +227,7 @@ static int qfile_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3083 /* XXX: This assumes the buf is big enough. */
3084 char *slot_hack = slot + 1;
3085 size_t slot_len = sizeof(slot) - 1;
3086 - vdb_pkg_eat(pkg_ctx, "SLOT", &slot_hack, &slot_len);
3087 + tree_pkg_vdb_eat(pkg_ctx, "SLOT", &slot_hack, &slot_len);
3088 rmspace(slot_hack);
3089 slot[0] = ':';
3090 } else
3091 @@ -478,8 +478,13 @@ int qfile_main(int argc, char **argv)
3092 /* Prepare the qfile(...) arguments structure */
3093 nb_of_queries = prepare_qfile_args(argc, (const char **) argv, &state);
3094 /* Now do the actual `qfile` checking */
3095 - if (nb_of_queries > 0)
3096 - found += vdb_foreach_pkg_sorted(portroot, portvdb, qfile_cb, &state);
3097 + if (nb_of_queries > 0) {
3098 + tree_ctx *vdb = tree_open_vdb(portroot, portvdb);
3099 + if (vdb != NULL) {
3100 + found += tree_foreach_pkg_sorted(vdb, qfile_cb, &state);
3101 + tree_close(vdb);
3102 + }
3103 + }
3104
3105 if (state.args.non_orphans) {
3106 /* display orphan files */
3107
3108 diff --git a/qgrep.c b/qgrep.c
3109 index f38f461..8e240f3 100644
3110 --- a/qgrep.c
3111 +++ b/qgrep.c
3112 @@ -19,8 +19,7 @@
3113 #include <fcntl.h>
3114
3115 #include "atom.h"
3116 -#include "cache.h"
3117 -#include "vdb.h"
3118 +#include "tree.h"
3119 #include "xarray.h"
3120 #include "xchdir.h"
3121 #include "xregex.h"
3122 @@ -381,14 +380,14 @@ print_after_context:
3123 }
3124
3125 static int
3126 -qgrep_cache_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3127 +qgrep_cache_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3128 {
3129 struct qgrep_grepargs *data = (struct qgrep_grepargs *)priv;
3130 char buf[_Q_PATH_MAX];
3131 char name[_Q_PATH_MAX];
3132 char *label;
3133 depend_atom *patom = NULL;
3134 - cache_ctx *cctx;
3135 + tree_ctx *cctx;
3136 int ret;
3137 int pfd;
3138
3139 @@ -411,11 +410,11 @@ qgrep_cache_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3140 }
3141
3142 /* need to construct path in portdir to ebuild, pass it to grep */
3143 - cctx = (cache_ctx *)(pkg_ctx->cat_ctx->ctx);
3144 + cctx = (tree_ctx *)(pkg_ctx->cat_ctx->ctx);
3145 if (cctx->cachetype == CACHE_EBUILD) {
3146 - pfd = cctx->vdb_fd;
3147 + pfd = cctx->tree_fd;
3148 } else {
3149 - pfd = openat(cctx->vdb_fd, "../..", O_RDONLY|O_CLOEXEC);
3150 + pfd = openat(cctx->tree_fd, "../..", O_RDONLY|O_CLOEXEC);
3151 }
3152
3153 /* cat/pkg/pkg-ver.ebuild */
3154 @@ -441,7 +440,7 @@ qgrep_cache_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3155 }
3156
3157 static int
3158 -qgrep_vdb_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3159 +qgrep_vdb_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3160 {
3161 struct qgrep_grepargs *data = (struct qgrep_grepargs *)priv;
3162 char buf[_Q_PATH_MAX];
3163 @@ -687,11 +686,17 @@ int qgrep_main(int argc, char **argv)
3164 }
3165 closedir(eclass_dir);
3166 } else if (do_installed) {
3167 - status = vdb_foreach_pkg(portroot, portvdb,
3168 - qgrep_vdb_cb, &args, NULL);
3169 + tree_ctx *t = tree_open_vdb(portroot, portvdb);
3170 + if (t != NULL) {
3171 + status = tree_foreach_pkg_fast(t, qgrep_vdb_cb, &args, NULL);
3172 + tree_close(t);
3173 + }
3174 } else { /* do_ebuild */
3175 - status = cache_foreach_pkg(portroot, overlay,
3176 - qgrep_cache_cb, &args, NULL);
3177 + tree_ctx *t = tree_open(portroot, overlay);
3178 + if (t != NULL) {
3179 + status = tree_foreach_pkg_fast(t, qgrep_cache_cb, &args, NULL);
3180 + tree_close(t);
3181 + }
3182 }
3183 }
3184
3185
3186 diff --git a/qkeyword.c b/qkeyword.c
3187 index ef61fba..b9792af 100644
3188 --- a/qkeyword.c
3189 +++ b/qkeyword.c
3190 @@ -18,10 +18,10 @@
3191 #include <sys/stat.h>
3192
3193 #include "atom.h"
3194 -#include "cache.h"
3195 -#include "scandirat.h"
3196 #include "rmspace.h"
3197 +#include "scandirat.h"
3198 #include "set.h"
3199 +#include "tree.h"
3200 #include "xasprintf.h"
3201
3202 /********************************************************************/
3203 @@ -62,7 +62,7 @@ typedef struct {
3204 int *keywordsbuf;
3205 size_t keywordsbuflen;
3206 const char *arch;
3207 - cache_pkg_cb *runfunc;
3208 + tree_pkg_cb *runfunc;
3209 } qkeyword_data;
3210
3211 static set *archs = NULL;
3212 @@ -214,7 +214,7 @@ qkeyword_vercmp(const struct dirent **x, const struct dirent **y)
3213 }
3214
3215 static int
3216 -qkeyword_imlate(cache_pkg_ctx *pkg_ctx, void *priv)
3217 +qkeyword_imlate(tree_pkg_ctx *pkg_ctx, void *priv)
3218 {
3219 size_t a;
3220 qkeyword_data *data = (qkeyword_data *)priv;
3221 @@ -241,7 +241,7 @@ qkeyword_imlate(cache_pkg_ctx *pkg_ctx, void *priv)
3222 }
3223
3224 static int
3225 -qkeyword_not(cache_pkg_ctx *pkg_ctx, void *priv)
3226 +qkeyword_not(tree_pkg_ctx *pkg_ctx, void *priv)
3227 {
3228 size_t a;
3229 qkeyword_data *data = (qkeyword_data *)priv;
3230 @@ -266,7 +266,7 @@ qkeyword_not(cache_pkg_ctx *pkg_ctx, void *priv)
3231 }
3232
3233 static int
3234 -qkeyword_all(cache_pkg_ctx *pkg_ctx, void *priv)
3235 +qkeyword_all(tree_pkg_ctx *pkg_ctx, void *priv)
3236 {
3237 qkeyword_data *data = (qkeyword_data *)priv;
3238
3239 @@ -282,7 +282,7 @@ qkeyword_all(cache_pkg_ctx *pkg_ctx, void *priv)
3240 }
3241
3242 static int
3243 -qkeyword_dropped(cache_pkg_ctx *pkg_ctx, void *priv)
3244 +qkeyword_dropped(tree_pkg_ctx *pkg_ctx, void *priv)
3245 {
3246 static bool candidate = false;
3247 static char pkg1[_Q_PATH_MAX];
3248 @@ -393,7 +393,7 @@ print_seconds_for_earthlings(const unsigned long t)
3249 }
3250
3251 static int
3252 -qkeyword_stats(cache_pkg_ctx *pkg_ctx, void *priv)
3253 +qkeyword_stats(tree_pkg_ctx *pkg_ctx, void *priv)
3254 {
3255 static time_t runtime;
3256 static int numpkg = 0;
3257 @@ -536,7 +536,7 @@ qkeyword_stats(cache_pkg_ctx *pkg_ctx, void *priv)
3258 }
3259
3260 static int
3261 -qkeyword_testing_only(cache_pkg_ctx *pkg_ctx, void *priv)
3262 +qkeyword_testing_only(tree_pkg_ctx *pkg_ctx, void *priv)
3263 {
3264 static bool candidate = false;
3265 static char pkg1[_Q_PATH_MAX];
3266 @@ -606,14 +606,14 @@ qkeyword_testing_only(cache_pkg_ctx *pkg_ctx, void *priv)
3267 }
3268
3269 static int
3270 -qkeyword_results_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3271 +qkeyword_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3272 {
3273 int *keywords;
3274 qkeyword_data *data = (qkeyword_data *)priv;
3275 char buf[_Q_PATH_MAX];
3276 depend_atom *patom = NULL;
3277 - cache_pkg_meta *meta;
3278 - cache_metadata_xml *metadata;
3279 + tree_pkg_meta *meta;
3280 + tree_metadata_xml *metadata;
3281 struct elist *emailw;
3282 int ret;
3283
3284 @@ -638,7 +638,7 @@ qkeyword_results_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3285 }
3286
3287 if (data->qmaint != NULL) {
3288 - metadata = cache_read_metadata(pkg_ctx);
3289 + metadata = tree_pkg_metadata(pkg_ctx);
3290 if (metadata == NULL)
3291 return EXIT_SUCCESS;
3292
3293 @@ -650,13 +650,13 @@ qkeyword_results_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3294 /* arbitrary pointer to trigger exit below */
3295 emailw = (struct elist *)buf;
3296
3297 - cache_close_metadata(metadata);
3298 + tree_close_metadata(metadata);
3299 if (emailw != NULL)
3300 return EXIT_SUCCESS;
3301 }
3302
3303 keywords = data->keywordsbuf;
3304 - meta = cache_pkg_read(pkg_ctx);
3305 + meta = tree_pkg_read(pkg_ctx);
3306 if (meta == NULL) {
3307 atom_implode(patom);
3308 return EXIT_FAILURE;
3309 @@ -731,7 +731,7 @@ qkeyword_load_arches(const char *overlay)
3310 }
3311
3312 static int
3313 -qkeyword_traverse(cache_pkg_cb func, void *priv)
3314 +qkeyword_traverse(tree_pkg_cb func, void *priv)
3315 {
3316 int ret;
3317 size_t n;
3318 @@ -756,9 +756,14 @@ qkeyword_traverse(cache_pkg_cb func, void *priv)
3319
3320 data->runfunc = func;
3321 ret = 0;
3322 - array_for_each(overlays, n, overlay)
3323 - ret |= cache_foreach_pkg_sorted(portroot, overlay,
3324 - qkeyword_results_cb, priv, NULL, qkeyword_vercmp);
3325 + array_for_each(overlays, n, overlay) {
3326 + tree_ctx *t = tree_open(portroot, overlay);
3327 + if (t != NULL) {
3328 + ret |= tree_foreach_pkg(t, qkeyword_results_cb, priv,
3329 + NULL, true, NULL, qkeyword_vercmp);
3330 + tree_close(t);
3331 + }
3332 + }
3333
3334 return ret;
3335 }
3336
3337 diff --git a/qlist.c b/qlist.c
3338 index 9314385..abefbcf 100644
3339 --- a/qlist.c
3340 +++ b/qlist.c
3341 @@ -18,7 +18,7 @@
3342
3343 #include "atom.h"
3344 #include "contents.h"
3345 -#include "vdb.h"
3346 +#include "tree.h"
3347 #include "xregex.h"
3348
3349 #define QLIST_FLAGS "ISRUcDeados" COMMON_FLAGS
3350 @@ -96,7 +96,7 @@ cmpstringp(const void *p1, const void *p2)
3351 */
3352 static char _umapstr_buf[BUFSIZ];
3353 static const char *
3354 -umapstr(char display, vdb_pkg_ctx *pkg_ctx)
3355 +umapstr(char display, tree_pkg_ctx *pkg_ctx)
3356 {
3357 char *bufp = _umapstr_buf;
3358 char *use = NULL;
3359 @@ -115,10 +115,10 @@ umapstr(char display, vdb_pkg_ctx *pkg_ctx)
3360 if (!display)
3361 return bufp;
3362
3363 - vdb_pkg_eat(pkg_ctx, "USE", &use, &use_len);
3364 + tree_pkg_vdb_eat(pkg_ctx, "USE", &use, &use_len);
3365 if (!use[0])
3366 return bufp;
3367 - vdb_pkg_eat(pkg_ctx, "IUSE", &iuse, &iuse_len);
3368 + tree_pkg_vdb_eat(pkg_ctx, "IUSE", &iuse, &iuse_len);
3369 if (!iuse[0])
3370 return bufp;
3371
3372 @@ -173,13 +173,13 @@ umapstr(char display, vdb_pkg_ctx *pkg_ctx)
3373 /* forward declaration necessary for misuse from qmerge.c, see HACK there */
3374 bool
3375 qlist_match(
3376 - vdb_pkg_ctx *pkg_ctx,
3377 + tree_pkg_ctx *pkg_ctx,
3378 const char *name,
3379 depend_atom **name_atom,
3380 bool exact);
3381 bool
3382 qlist_match(
3383 - vdb_pkg_ctx *pkg_ctx,
3384 + tree_pkg_ctx *pkg_ctx,
3385 const char *name,
3386 depend_atom **name_atom,
3387 bool exact)
3388 @@ -200,7 +200,7 @@ qlist_match(
3389 uslot = NULL;
3390 else {
3391 if (!pkg_ctx->slot)
3392 - vdb_pkg_eat(pkg_ctx, "SLOT", &pkg_ctx->slot,
3393 + tree_pkg_vdb_eat(pkg_ctx, "SLOT", &pkg_ctx->slot,
3394 &pkg_ctx->slot_len);
3395 uslot_len = strlen(uslot);
3396 }
3397 @@ -209,7 +209,7 @@ qlist_match(
3398 urepo = strstr(name, "::");
3399 if (urepo) {
3400 if (!pkg_ctx->repo)
3401 - vdb_pkg_eat(pkg_ctx, "repository", &pkg_ctx->repo,
3402 + tree_pkg_vdb_eat(pkg_ctx, "repository", &pkg_ctx->repo,
3403 &pkg_ctx->repo_len);
3404 urepo += 2;
3405 urepo_len = strlen(urepo);
3406 @@ -338,7 +338,7 @@ struct qlist_opt_state {
3407 };
3408
3409 static int
3410 -qlist_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3411 +qlist_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3412 {
3413 struct qlist_opt_state *state = priv;
3414 int i;
3415 @@ -359,7 +359,7 @@ qlist_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3416 atom = (verbose ? NULL : atom_explode(pkgname));
3417 if ((state->all + state->just_pkgname) < 2) {
3418 if (state->show_slots && !pkg_ctx->slot) {
3419 - vdb_pkg_eat(pkg_ctx, "SLOT",
3420 + tree_pkg_vdb_eat(pkg_ctx, "SLOT",
3421 &pkg_ctx->slot, &pkg_ctx->slot_len);
3422 /* chop off the subslot if desired */
3423 if (state->show_slots == 1) {
3424 @@ -369,7 +369,7 @@ qlist_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3425 }
3426 }
3427 if (state->show_repo && !pkg_ctx->repo)
3428 - vdb_pkg_eat(pkg_ctx, "repository",
3429 + tree_pkg_vdb_eat(pkg_ctx, "repository",
3430 &pkg_ctx->repo, &pkg_ctx->repo_len);
3431 /* display it */
3432 printf("%s%s/%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
3433 @@ -398,7 +398,7 @@ qlist_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3434 printf("%s%s/%s%s%s %sCONTENTS%s:\n",
3435 BOLD, catname, BLUE, pkgname, NORM, DKBLUE, NORM);
3436
3437 - fp = vdb_pkg_fopenat_ro(pkg_ctx, "CONTENTS");
3438 + fp = tree_pkg_vdb_fopenat_ro(pkg_ctx, "CONTENTS");
3439 if (fp == NULL)
3440 return 1;
3441
3442 @@ -444,6 +444,9 @@ qlist_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3443
3444 int qlist_main(int argc, char **argv)
3445 {
3446 + int i;
3447 + int ret;
3448 + tree_ctx *vdb;
3449 struct qlist_opt_state state = {
3450 .argc = argc,
3451 .argv = argv,
3452 @@ -460,7 +463,6 @@ int qlist_main(int argc, char **argv)
3453 .columns = false,
3454 .buflen = _Q_PATH_MAX,
3455 };
3456 - int i, ret;
3457
3458 while ((i = GETOPT_LONG(QLIST, qlist, "")) != -1) {
3459 switch (i) {
3460 @@ -489,7 +491,12 @@ int qlist_main(int argc, char **argv)
3461
3462 state.buf = xmalloc(state.buflen);
3463 state.atoms = xcalloc(argc - optind, sizeof(*state.atoms));
3464 - ret = vdb_foreach_pkg_sorted(portroot, portvdb, qlist_cb, &state);
3465 + ret = 1;
3466 + vdb = tree_open_vdb(portroot, portvdb);
3467 + if (vdb != NULL) {
3468 + ret = tree_foreach_pkg_sorted(vdb, qlist_cb, &state);
3469 + tree_close(vdb);
3470 + }
3471 free(state.buf);
3472 for (i = optind; i < state.argc; ++i)
3473 if (state.atoms[i - optind])
3474
3475 diff --git a/qmerge.c b/qmerge.c
3476 index 41488fa..e6bbdb5 100644
3477 --- a/qmerge.c
3478 +++ b/qmerge.c
3479 @@ -30,7 +30,7 @@
3480 #include "rmspace.h"
3481 #include "scandirat.h"
3482 #include "set.h"
3483 -#include "vdb.h"
3484 +#include "tree.h"
3485 #include "xasprintf.h"
3486 #include "xchdir.h"
3487 #include "xmkdir.h"
3488 @@ -118,7 +118,7 @@ typedef struct llist_char_t llist_char;
3489
3490 static void pkg_fetch(int, const depend_atom *, const struct pkg_t *);
3491 static void pkg_merge(int, const depend_atom *, const struct pkg_t *);
3492 -static int pkg_unmerge(vdb_pkg_ctx *, set *, int, char **, int, char **);
3493 +static int pkg_unmerge(tree_pkg_ctx *, set *, int, char **, int, char **);
3494 static struct pkg_t *grab_binpkg_info(const char *);
3495 static char *find_binpkg(const char *);
3496
3497 @@ -282,7 +282,7 @@ struct qmerge_bv_state {
3498 };
3499
3500 static int
3501 -qmerge_filter_cat(vdb_cat_ctx *cat_ctx, void *priv)
3502 +qmerge_filter_cat(tree_cat_ctx *cat_ctx, void *priv)
3503 {
3504 struct qmerge_bv_state *state = priv;
3505 return !state->catname || strcmp(cat_ctx->name, state->catname) == 0;
3506 @@ -292,13 +292,13 @@ qmerge_filter_cat(vdb_cat_ctx *cat_ctx, void *priv)
3507 * should however figure out how to do what match does here from e.g.
3508 * atom */
3509 extern bool qlist_match(
3510 - vdb_pkg_ctx *pkg_ctx,
3511 + tree_pkg_ctx *pkg_ctx,
3512 const char *name,
3513 depend_atom **name_atom,
3514 bool exact);
3515
3516 static int
3517 -qmerge_best_version_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3518 +qmerge_best_version_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3519 {
3520 struct qmerge_bv_state *state = priv;
3521 if (qlist_match(pkg_ctx, state->buf, NULL, true))
3522 @@ -312,6 +312,8 @@ best_version(const char *catname, const char *pkgname, const char *slot)
3523 {
3524 static int vdb_check = 1;
3525 static char retbuf[4096];
3526 +
3527 + tree_ctx *vdb;
3528 struct qmerge_bv_state state = {
3529 .catname = catname,
3530 .pkgname = pkgname,
3531 @@ -338,8 +340,12 @@ best_version(const char *catname, const char *pkgname, const char *slot)
3532 retbuf[0] = '\0';
3533 snprintf(state.buf, sizeof(state.buf), "%s%s%s:%s",
3534 catname ? : "", catname ? "/" : "", pkgname, slot);
3535 - vdb_foreach_pkg(portroot, portvdb,
3536 - qmerge_best_version_cb, &state, qmerge_filter_cat);
3537 + vdb = tree_open_vdb(portroot, portvdb);
3538 + if (vdb != NULL) {
3539 + tree_foreach_pkg_fast(vdb,
3540 + qmerge_best_version_cb, &state, qmerge_filter_cat);
3541 + tree_close(vdb);
3542 + }
3543
3544 done:
3545 return retbuf;
3546 @@ -999,8 +1005,8 @@ static void
3547 pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
3548 {
3549 set *objs;
3550 - vdb_ctx *vdb;
3551 - vdb_cat_ctx *cat_ctx;
3552 + tree_ctx *vdb;
3553 + tree_cat_ctx *cat_ctx;
3554 FILE *fp, *contents;
3555 static char *phases;
3556 static size_t phases_len;
3557 @@ -1122,19 +1128,19 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
3558 }
3559
3560 /* Get a handle on the main vdb repo */
3561 - vdb = vdb_open(portroot, portvdb);
3562 + vdb = tree_open(portroot, portvdb);
3563 if (!vdb)
3564 return;
3565 - cat_ctx = vdb_open_cat(vdb, pkg->CATEGORY);
3566 + cat_ctx = tree_open_cat(vdb, pkg->CATEGORY);
3567 if (!cat_ctx) {
3568 if (errno != ENOENT) {
3569 - vdb_close(vdb);
3570 + tree_close(vdb);
3571 return;
3572 }
3573 - mkdirat(vdb->vdb_fd, pkg->CATEGORY, 0755);
3574 - cat_ctx = vdb_open_cat(vdb, pkg->CATEGORY);
3575 + mkdirat(vdb->tree_fd, pkg->CATEGORY, 0755);
3576 + cat_ctx = tree_open_cat(vdb, pkg->CATEGORY);
3577 if (!cat_ctx) {
3578 - vdb_close(vdb);
3579 + tree_close(vdb);
3580 return;
3581 }
3582 }
3583 @@ -1345,10 +1351,10 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
3584 /* TODO: Should see about merging with unmerge_packages() */
3585 while (1) {
3586 int ret;
3587 - vdb_pkg_ctx *pkg_ctx;
3588 + tree_pkg_ctx *pkg_ctx;
3589 depend_atom *old_atom;
3590
3591 - pkg_ctx = vdb_next_pkg(cat_ctx);
3592 + pkg_ctx = tree_next_pkg(cat_ctx);
3593 if (!pkg_ctx)
3594 break;
3595
3596 @@ -1377,7 +1383,7 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
3597
3598 pkg_unmerge(pkg_ctx, objs, cp_argc, cp_argv, cpm_argc, cpm_argv);
3599 next_pkg:
3600 - vdb_close_pkg(pkg_ctx);
3601 + tree_close_pkg(pkg_ctx);
3602 }
3603
3604 freeargv(cp_argc, cp_argv);
3605 @@ -1416,14 +1422,14 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
3606 printf("%s>>>%s %s%s%s/%s%s%s\n",
3607 YELLOW, NORM, WHITE, atom->CATEGORY, NORM, CYAN, atom->PN, NORM);
3608
3609 - vdb_close(vdb);
3610 + tree_close(vdb);
3611 }
3612
3613 static int
3614 -pkg_unmerge(vdb_pkg_ctx *pkg_ctx, set *keep,
3615 +pkg_unmerge(tree_pkg_ctx *pkg_ctx, set *keep,
3616 int cp_argc, char **cp_argv, int cpm_argc, char **cpm_argv)
3617 {
3618 - vdb_cat_ctx *cat_ctx = pkg_ctx->cat_ctx;
3619 + tree_cat_ctx *cat_ctx = pkg_ctx->cat_ctx;
3620 const char *cat = cat_ctx->name;
3621 const char *pkgname = pkg_ctx->name;
3622 size_t buflen;
3623 @@ -1447,7 +1453,7 @@ pkg_unmerge(vdb_pkg_ctx *pkg_ctx, set *keep,
3624 return 0;
3625
3626 /* First get a handle on the things to clean up */
3627 - fp = vdb_pkg_fopenat_ro(pkg_ctx, "CONTENTS");
3628 + fp = tree_pkg_vdb_fopenat_ro(pkg_ctx, "CONTENTS");
3629 if (fp == NULL)
3630 return ret;
3631
3632 @@ -1455,7 +1461,7 @@ pkg_unmerge(vdb_pkg_ctx *pkg_ctx, set *keep,
3633
3634 /* Then execute the pkg_prerm step */
3635 if (!pretend) {
3636 - vdb_pkg_eat(pkg_ctx, "DEFINED_PHASES", &phases, &phases_len);
3637 + tree_pkg_vdb_eat(pkg_ctx, "DEFINED_PHASES", &phases, &phases_len);
3638 mkdirat(pkg_ctx->fd, "temp", 0755);
3639 pkg_run_func_at(pkg_ctx->fd, ".", phases, "pkg_prerm", T, T);
3640 }
3641 @@ -1587,7 +1593,7 @@ pkg_unmerge(vdb_pkg_ctx *pkg_ctx, set *keep,
3642 unlinkat(cat_ctx->fd, pkg_ctx->name, AT_REMOVEDIR);
3643
3644 /* And prune the category if it's empty */
3645 - unlinkat(cat_ctx->ctx->vdb_fd, cat_ctx->name, AT_REMOVEDIR);
3646 + unlinkat(cat_ctx->ctx->tree_fd, cat_ctx->name, AT_REMOVEDIR);
3647 }
3648
3649 ret = 0;
3650 @@ -1776,7 +1782,7 @@ print_Pkg(int full, const depend_atom *atom, const struct pkg_t *pkg)
3651 }
3652
3653 static int
3654 -qmerge_unmerge_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3655 +qmerge_unmerge_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3656 {
3657 int cp_argc;
3658 int cpm_argc;
3659 @@ -1804,7 +1810,13 @@ qmerge_unmerge_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3660 static int
3661 unmerge_packages(set *todo)
3662 {
3663 - return vdb_foreach_pkg(portroot, portvdb, qmerge_unmerge_cb, todo, NULL);
3664 + tree_ctx *vdb = tree_open_vdb(portroot, portvdb);
3665 + int ret = 1;
3666 + if (vdb != NULL) {
3667 + ret = tree_foreach_pkg_fast(vdb, qmerge_unmerge_cb, todo, NULL);
3668 + tree_close(vdb);
3669 + }
3670 + return ret;
3671 }
3672
3673 static FILE *
3674 @@ -2315,7 +2327,7 @@ qmerge_add_set(char *buf, set *q)
3675 if (strcmp(buf, "world") == 0)
3676 return qmerge_add_set_file("/var/lib/portage", "world", q);
3677 else if (strcmp(buf, "all") == 0)
3678 - return get_vdb_atoms(portroot, portvdb, 0);
3679 + return tree_get_vdb_atoms(portroot, portvdb, 0);
3680 else if (strcmp(buf, "system") == 0)
3681 return q_profile_walk("packages", qmerge_add_set_system, q);
3682 else if (buf[0] == '@')
3683
3684 diff --git a/qpkg.c b/qpkg.c
3685 index b93823b..26c14d1 100644
3686 --- a/qpkg.c
3687 +++ b/qpkg.c
3688 @@ -20,13 +20,12 @@
3689
3690 #include "atom.h"
3691 #include "basename.h"
3692 -#include "cache.h"
3693 #include "contents.h"
3694 #include "human_readable.h"
3695 #include "md5_sha1_sum.h"
3696 #include "scandirat.h"
3697 #include "set.h"
3698 -#include "vdb.h"
3699 +#include "tree.h"
3700 #include "xarray.h"
3701 #include "xasprintf.h"
3702 #include "xchdir.h"
3703 @@ -125,7 +124,7 @@ qpkg_clean_dir(char *dirp, set *vdb)
3704 }
3705
3706 static int
3707 -qpkg_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3708 +qpkg_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3709 {
3710 set *vdb = (set *)priv;
3711 depend_atom *atom;
3712 @@ -156,14 +155,19 @@ qpkg_clean(char *dirp)
3713 if ((count = scandir(".", &dnames, filter_hidden, alphasort)) < 0)
3714 return 1;
3715
3716 - vdb = get_vdb_atoms(portroot, portvdb, 1);
3717 + vdb = tree_get_vdb_atoms(portroot, portvdb, 1);
3718
3719 if (eclean) {
3720 size_t n;
3721 const char *overlay;
3722
3723 - array_for_each(overlays, n, overlay)
3724 - cache_foreach_pkg(portroot, overlay, qpkg_cb, vdb, NULL);
3725 + array_for_each(overlays, n, overlay) {
3726 + tree_ctx *t = tree_open(portroot, overlay);
3727 + if (t != NULL) {
3728 + tree_foreach_pkg_fast(t, qpkg_cb, vdb, NULL);
3729 + tree_close(t);
3730 + }
3731 + }
3732 }
3733
3734 num_all_bytes = qpkg_clean_dir(dirp, vdb);
3735 @@ -334,9 +338,9 @@ qpkg_make(depend_atom *atom)
3736
3737 int qpkg_main(int argc, char **argv)
3738 {
3739 - vdb_ctx *ctx;
3740 - vdb_cat_ctx *cat_ctx;
3741 - vdb_pkg_ctx *pkg_ctx;
3742 + tree_ctx *ctx;
3743 + tree_cat_ctx *cat_ctx;
3744 + tree_pkg_ctx *pkg_ctx;
3745 size_t s, pkgs_made;
3746 int i;
3747 struct stat st;
3748 @@ -417,15 +421,15 @@ retry_mkdir:
3749 }
3750
3751 /* now try to run through vdb and locate matches for user inputs */
3752 - ctx = vdb_open(portroot, portvdb);
3753 + ctx = tree_open_vdb(portroot, portvdb);
3754 if (!ctx)
3755 return EXIT_FAILURE;
3756
3757 /* scan all the categories */
3758 - while ((cat_ctx = vdb_next_cat(ctx))) {
3759 + while ((cat_ctx = tree_next_cat(ctx))) {
3760 /* scan all the packages in this category */
3761 const char *catname = cat_ctx->name;
3762 - while ((pkg_ctx = vdb_next_pkg(cat_ctx))) {
3763 + while ((pkg_ctx = tree_next_pkg(cat_ctx))) {
3764 const char *pkgname = pkg_ctx->name;
3765
3766 /* see if user wants any of these packages */
3767 @@ -449,7 +453,7 @@ retry_mkdir:
3768 atom_implode(atom);
3769
3770 next_pkg:
3771 - vdb_close_pkg(pkg_ctx);
3772 + tree_close_pkg(pkg_ctx);
3773 }
3774 }
3775
3776
3777 diff --git a/qsearch.c b/qsearch.c
3778 index b6d7410..f52a5ff 100644
3779 --- a/qsearch.c
3780 +++ b/qsearch.c
3781 @@ -20,8 +20,8 @@
3782
3783 #include "atom.h"
3784 #include "basename.h"
3785 -#include "cache.h"
3786 #include "rmspace.h"
3787 +#include "tree.h"
3788 #include "xarray.h"
3789 #include "xregex.h"
3790
3791 @@ -57,14 +57,14 @@ struct qsearch_state {
3792 };
3793
3794 static int
3795 -qsearch_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3796 +qsearch_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3797 {
3798 static depend_atom *last_atom;
3799
3800 struct qsearch_state *state = (struct qsearch_state *)priv;
3801 depend_atom *atom;
3802 char buf[_Q_PATH_MAX];
3803 - cache_pkg_meta *meta;
3804 + tree_pkg_meta *meta;
3805 char *desc;
3806 char *repo;
3807 bool match;
3808 @@ -90,7 +90,7 @@ qsearch_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3809 if ((match && (state->show_homepage || state->show_desc)) ||
3810 (!match && state->search_desc))
3811 {
3812 - meta = cache_pkg_read(pkg_ctx);
3813 + meta = tree_pkg_read(pkg_ctx);
3814 if (meta != NULL) {
3815 if (state->show_homepage)
3816 desc = meta->HOMEPAGE;
3817 @@ -115,7 +115,7 @@ qsearch_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3818 }
3819
3820 if (meta != NULL)
3821 - cache_close_meta(meta);
3822 + tree_close_meta(meta);
3823
3824 if (last_atom != NULL)
3825 atom_implode(last_atom);
3826 @@ -167,9 +167,13 @@ int qsearch_main(int argc, char **argv)
3827 xregcomp(&state.search_expr, search_me, REG_EXTENDED | REG_ICASE);
3828
3829 /* use sorted order here so the duplicate reduction works reliably */
3830 - array_for_each(overlays, n, overlay)
3831 - ret |= cache_foreach_pkg_sorted(portroot, overlay, qsearch_cb,
3832 - &state, NULL, NULL);
3833 + array_for_each(overlays, n, overlay) {
3834 + tree_ctx *t = tree_open(portroot, overlay);
3835 + if (t != NULL) {
3836 + ret |= tree_foreach_pkg_sorted(t, qsearch_cb, &state);
3837 + tree_close(t);
3838 + }
3839 + }
3840
3841 return ret;
3842 }
3843
3844 diff --git a/qsize.c b/qsize.c
3845 index 4fbbe47..1ae942d 100644
3846 --- a/qsize.c
3847 +++ b/qsize.c
3848 @@ -51,7 +51,7 @@
3849 #include "atom.h"
3850 #include "contents.h"
3851 #include "human_readable.h"
3852 -#include "vdb.h"
3853 +#include "tree.h"
3854 #include "xarray.h"
3855 #include "xregex.h"
3856
3857 @@ -97,7 +97,7 @@ struct qsize_opt_state {
3858 };
3859
3860 static int
3861 -qsize_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3862 +qsize_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3863 {
3864 struct qsize_opt_state *state = priv;
3865 const char *catname = pkg_ctx->cat_ctx->name;
3866 @@ -126,7 +126,7 @@ qsize_cb(vdb_pkg_ctx *pkg_ctx, void *priv)
3867 if (!showit)
3868 return EXIT_SUCCESS;
3869
3870 - if ((fp = vdb_pkg_fopenat_ro(pkg_ctx, "CONTENTS")) == NULL)
3871 + if ((fp = tree_pkg_vdb_fopenat_ro(pkg_ctx, "CONTENTS")) == NULL)
3872 return EXIT_SUCCESS;
3873
3874 num_ignored = num_files = num_nonfiles = num_bytes = 0;
3875 @@ -181,6 +181,7 @@ int qsize_main(int argc, char **argv)
3876 {
3877 size_t i;
3878 int ret;
3879 + tree_ctx *vdb;
3880 DECLARE_ARRAY(ignore_regexp);
3881 depend_atom *atom;
3882 DECLARE_ARRAY(atoms);
3883 @@ -230,7 +231,11 @@ int qsize_main(int argc, char **argv)
3884 state.buflen = _Q_PATH_MAX;
3885 state.buf = xmalloc(state.buflen);
3886
3887 - ret = vdb_foreach_pkg(portroot, portvdb, qsize_cb, &state, NULL);
3888 + vdb = tree_open_vdb(portroot, portvdb);
3889 + if (vdb != NULL) {
3890 + ret = tree_foreach_pkg_fast(vdb, qsize_cb, &state, NULL);
3891 + tree_close(vdb);
3892 + }
3893
3894 if (state.summary) {
3895 printf(" %sTotals%s: %'zu files, %'zu non-files, ", BOLD, NORM,
3896
3897 diff --git a/quse.c b/quse.c
3898 index 604efdf..6def799 100644
3899 --- a/quse.c
3900 +++ b/quse.c
3901 @@ -21,8 +21,8 @@
3902 #include <ctype.h>
3903 #include <assert.h>
3904
3905 -#include "cache.h"
3906 #include "rmspace.h"
3907 +#include "tree.h"
3908 #include "xarray.h"
3909 #include "xregex.h"
3910
3911 @@ -401,12 +401,12 @@ quse_describe_flag(const char *root, const char *overlay,
3912 }
3913
3914 static int
3915 -quse_results_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3916 +quse_results_cb(tree_pkg_ctx *pkg_ctx, void *priv)
3917 {
3918 struct quse_state *state = (struct quse_state *)priv;
3919 depend_atom *atom = NULL; /* pacify compiler */
3920 char buf[8192];
3921 - cache_pkg_meta *meta;
3922 + tree_pkg_meta *meta;
3923 bool match;
3924 char *p;
3925 char *q;
3926 @@ -436,7 +436,7 @@ quse_results_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3927 }
3928 }
3929
3930 - meta = cache_pkg_read(pkg_ctx);
3931 + meta = tree_pkg_read(pkg_ctx);
3932 if (meta == NULL)
3933 return 0;
3934
3935 @@ -591,7 +591,7 @@ quse_results_cb(cache_pkg_ctx *pkg_ctx, void *priv)
3936 }
3937 }
3938
3939 - cache_close_meta(meta);
3940 + tree_close_meta(meta);
3941 if (state->match && verbose)
3942 atom_implode(atom);
3943 if (verbose)
3944 @@ -656,9 +656,12 @@ int quse_main(int argc, char **argv)
3945 quse_describe_flag(portroot, overlay, &state);
3946 } else {
3947 array_for_each(overlays, n, overlay) {
3948 + tree_ctx *t = tree_open(portroot, overlay);
3949 state.overlay = overlay;
3950 - cache_foreach_pkg_sorted(portroot, overlay,
3951 - quse_results_cb, &state, NULL, NULL);
3952 + if (t != NULL) {
3953 + tree_foreach_pkg_sorted(t, quse_results_cb, &state);
3954 + tree_close(t);
3955 + }
3956 }
3957 }