1 |
commit: b811b9afd740e8f4cc73f096e8c162d5d332aed2 |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sun Nov 17 15:01:00 2019 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Nov 17 15:01:00 2019 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=b811b9af |
7 |
|
8 |
libq/tree: add support for binpgks and Packages file |
9 |
|
10 |
This allows to foreach binpkgs (without Packages file index) as well as |
11 |
use the Packages file to loop over them. |
12 |
|
13 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
14 |
|
15 |
libq/tree.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
16 |
libq/tree.h | 13 +++- |
17 |
2 files changed, 251 insertions(+), 16 deletions(-) |
18 |
|
19 |
diff --git a/libq/tree.c b/libq/tree.c |
20 |
index b0d0b5b..427281f 100644 |
21 |
--- a/libq/tree.c |
22 |
+++ b/libq/tree.c |
23 |
@@ -21,6 +21,7 @@ |
24 |
#include "scandirat.h" |
25 |
#include "set.h" |
26 |
#include "tree.h" |
27 |
+#include "xpak.h" |
28 |
|
29 |
#include <ctype.h> |
30 |
#include <xalloc.h> |
31 |
@@ -30,7 +31,7 @@ static int tree_pkg_compar(const void *l, const void *r); |
32 |
static tree_ctx * |
33 |
tree_open_int(const char *sroot, const char *tdir, bool quiet) |
34 |
{ |
35 |
- tree_ctx *ctx = xmalloc(sizeof(*ctx)); |
36 |
+ tree_ctx *ctx = xzalloc(sizeof(*ctx)); |
37 |
|
38 |
ctx->portroot_fd = open(sroot, O_RDONLY | O_CLOEXEC | O_PATH); |
39 |
if (ctx->portroot_fd == -1) { |
40 |
@@ -56,12 +57,8 @@ tree_open_int(const char *sroot, const char *tdir, bool quiet) |
41 |
goto cv_error; |
42 |
|
43 |
ctx->do_sort = false; |
44 |
- ctx->cat_de = NULL; |
45 |
ctx->catsortfunc = alphasort; |
46 |
ctx->pkgsortfunc = tree_pkg_compar; |
47 |
- ctx->repo = NULL; |
48 |
- ctx->ebuilddir_ctx = NULL; |
49 |
- ctx->ebuilddir_pkg_ctx = NULL; |
50 |
return ctx; |
51 |
|
52 |
cv_error: |
53 |
@@ -130,6 +127,24 @@ tree_open_vdb(const char *sroot, const char *svdb) |
54 |
return ret; |
55 |
} |
56 |
|
57 |
+static const char binpkg_packages[] = "Packages"; |
58 |
+tree_ctx * |
59 |
+tree_open_binpkg(const char *sroot, const char *spkg) |
60 |
+{ |
61 |
+ tree_ctx *ret = tree_open_int(sroot, spkg, true); |
62 |
+ char buf[_Q_PATH_MAX]; |
63 |
+ |
64 |
+ if (ret != NULL) { |
65 |
+ ret->cachetype = CACHE_BINPKGS; |
66 |
+ |
67 |
+ snprintf(buf, sizeof(buf), "%s%s/%s", sroot, spkg, binpkg_packages); |
68 |
+ if (eat_file(buf, &ret->pkgs, &ret->pkgslen)) |
69 |
+ ret->cachetype = CACHE_PACKAGES; |
70 |
+ } |
71 |
+ |
72 |
+ return ret; |
73 |
+} |
74 |
+ |
75 |
void |
76 |
tree_close(tree_ctx *ctx) |
77 |
{ |
78 |
@@ -141,6 +156,8 @@ tree_close(tree_ctx *ctx) |
79 |
scandir_free(ctx->cat_de, ctx->cat_cnt); |
80 |
if (ctx->repo != NULL) |
81 |
free(ctx->repo); |
82 |
+ if (ctx->pkgs != NULL) |
83 |
+ free(ctx->pkgs); |
84 |
if (ctx->ebuilddir_ctx != NULL) |
85 |
free(ctx->ebuilddir_ctx); |
86 |
free(ctx); |
87 |
@@ -443,6 +460,13 @@ tree_next_pkg(tree_cat_ctx *cat_ctx) |
88 |
} |
89 |
} |
90 |
} while (ret == NULL); |
91 |
+ } else if (ctx->cachetype == CACHE_BINPKGS) { |
92 |
+ char *p = NULL; |
93 |
+ do { |
94 |
+ ret = tree_next_pkg_int(cat_ctx); |
95 |
+ } while (ret != NULL && (p = strstr(ret->name, ".tbz2")) == NULL); |
96 |
+ if (p != NULL) |
97 |
+ *p = '\0'; |
98 |
} else { |
99 |
ret = tree_next_pkg_int(cat_ctx); |
100 |
} |
101 |
@@ -805,22 +829,96 @@ err: |
102 |
return NULL; |
103 |
} |
104 |
|
105 |
+static void |
106 |
+tree_read_file_binpkg_xpak_cb( |
107 |
+ void *ctx, |
108 |
+ char *pathname, |
109 |
+ int pathname_len, |
110 |
+ int data_offset, |
111 |
+ int data_len, |
112 |
+ char *data) |
113 |
+{ |
114 |
+ tree_pkg_meta *m = (tree_pkg_meta *)ctx; |
115 |
+ char **key; |
116 |
+ size_t pos; |
117 |
+ size_t len; |
118 |
+ |
119 |
+#define match_path(K) \ |
120 |
+ else if (pathname_len == (sizeof(#K) - 1) && strcmp(pathname, #K) == 0) \ |
121 |
+ key = &m->K |
122 |
+ if (1 == 0); /* dummy for syntax */ |
123 |
+ match_path(DEPEND); |
124 |
+ match_path(RDEPEND); |
125 |
+ match_path(SLOT); |
126 |
+ match_path(SRC_URI); |
127 |
+ match_path(RESTRICT); |
128 |
+ match_path(HOMEPAGE); |
129 |
+ match_path(DESCRIPTION); |
130 |
+ match_path(KEYWORDS); |
131 |
+ match_path(INHERITED); |
132 |
+ match_path(IUSE); |
133 |
+ match_path(CDEPEND); |
134 |
+ match_path(PDEPEND); |
135 |
+ match_path(PROVIDE); |
136 |
+ match_path(EAPI); |
137 |
+ match_path(PROPERTIES); |
138 |
+ match_path(DEFINED_PHASES); |
139 |
+ match_path(REQUIRED_USE); |
140 |
+ match_path(BDEPEND); |
141 |
+ match_path(CONTENTS); |
142 |
+ match_path(USE); |
143 |
+ match_path(repository); |
144 |
+ else |
145 |
+ return; |
146 |
+#undef match_path |
147 |
+ |
148 |
+ /* hijack unused members */ |
149 |
+ pos = (size_t)m->_eclasses_; |
150 |
+ len = (size_t)m->_md5_; |
151 |
+ |
152 |
+ /* trim whitespace (mostly trailing newline) */ |
153 |
+ while (isspace((int)data[data_offset + data_len - 1])) |
154 |
+ data_len--; |
155 |
+ |
156 |
+ if (len - pos < (size_t)data_len) { |
157 |
+ len += (((data_len + 1) / BUFSIZ) + 1) * BUFSIZ; |
158 |
+ m->_data = xrealloc(m->_data, len); |
159 |
+ m->_md5_ = (char *)len; |
160 |
+ } |
161 |
+ |
162 |
+ *key = m->_data + pos; |
163 |
+ snprintf(*key, len - pos, "%.*s", data_len, data + data_offset); |
164 |
+ pos += data_len + 1; |
165 |
+ m->_eclasses_ = (char *)pos; |
166 |
+} |
167 |
+ |
168 |
+static tree_pkg_meta * |
169 |
+tree_read_file_binpkg(tree_pkg_ctx *pkg_ctx) |
170 |
+{ |
171 |
+ tree_pkg_meta *m = xzalloc(sizeof(tree_pkg_meta)); |
172 |
+ |
173 |
+ xpak_process_fd(pkg_ctx->fd, true, m, tree_read_file_binpkg_xpak_cb); |
174 |
+ pkg_ctx->fd = -1; /* closed by xpak_process_fd */ |
175 |
+ |
176 |
+ return m; |
177 |
+} |
178 |
+ |
179 |
tree_pkg_meta * |
180 |
tree_pkg_read(tree_pkg_ctx *pkg_ctx) |
181 |
{ |
182 |
tree_ctx *ctx = pkg_ctx->cat_ctx->ctx; |
183 |
|
184 |
if (pkg_ctx->fd == -1) { |
185 |
- if (ctx->cachetype != CACHE_EBUILD) { |
186 |
- pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name, |
187 |
- O_RDONLY | O_CLOEXEC); |
188 |
- } else { |
189 |
+ if (ctx->cachetype == CACHE_EBUILD || ctx->cachetype == CACHE_BINPKGS) { |
190 |
char *p = (char *)pkg_ctx->name; |
191 |
p += strlen(p); |
192 |
*p = '.'; |
193 |
pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name, |
194 |
O_RDONLY | O_CLOEXEC); |
195 |
*p = '\0'; |
196 |
+ } else { |
197 |
+ pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name, |
198 |
+ O_RDONLY | O_CLOEXEC); |
199 |
} |
200 |
if (pkg_ctx->fd == -1) |
201 |
return NULL; |
202 |
@@ -832,6 +930,10 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx) |
203 |
return tree_read_file_pms(pkg_ctx); |
204 |
} else if (ctx->cachetype == CACHE_EBUILD) { |
205 |
return tree_read_file_ebuild(pkg_ctx); |
206 |
+ } else if (ctx->cachetype == CACHE_BINPKGS) { |
207 |
+ return tree_read_file_binpkg(pkg_ctx); |
208 |
+ } else if (ctx->cachetype == CACHE_PACKAGES) { |
209 |
+ return (tree_pkg_meta *)pkg_ctx->cat_ctx->ctx->pkgs; |
210 |
} |
211 |
|
212 |
warn("Unknown metadata cache type!"); |
213 |
@@ -841,8 +943,10 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx) |
214 |
void |
215 |
tree_close_meta(tree_pkg_meta *cache) |
216 |
{ |
217 |
- if (!cache) |
218 |
+ if (cache == NULL) |
219 |
errf("Cache is empty !"); |
220 |
+ if (cache->_data != NULL) |
221 |
+ free(cache->_data); |
222 |
free(cache); |
223 |
} |
224 |
|
225 |
@@ -952,6 +1056,112 @@ tree_close_pkg(tree_pkg_ctx *pkg_ctx) |
226 |
free(pkg_ctx); |
227 |
} |
228 |
|
229 |
+static int |
230 |
+tree_foreach_packages(tree_ctx *ctx, tree_pkg_cb callback, void *priv) |
231 |
+{ |
232 |
+ char *p = ctx->pkgs; |
233 |
+ char *q; |
234 |
+ char *c; |
235 |
+ size_t len = ctx->pkgslen; |
236 |
+ int ret = 0; |
237 |
+ |
238 |
+ /* reused for every entry */ |
239 |
+ tree_cat_ctx *cat = xzalloc(sizeof(tree_cat_ctx)); |
240 |
+ tree_pkg_ctx *pkg = xzalloc(sizeof(tree_pkg_ctx)); |
241 |
+ tree_pkg_meta *meta = xzalloc(sizeof(tree_pkg_meta)); |
242 |
+ depend_atom *atom = NULL; |
243 |
+ |
244 |
+ cat->ctx = ctx; |
245 |
+ pkg->cat_ctx = cat; |
246 |
+ |
247 |
+ do { |
248 |
+ /* find next line */ |
249 |
+ c = NULL; |
250 |
+ for (q = p; len > 0 && *q != '\n'; q++, len--) |
251 |
+ if (c == NULL && *q == ':') |
252 |
+ c = q; |
253 |
+ |
254 |
+ if (len == 0) |
255 |
+ break; |
256 |
+ |
257 |
+ /* empty line, end of a block */ |
258 |
+ if (p == q) { |
259 |
+ /* make callback with populated atom */ |
260 |
+ if (atom != NULL) { |
261 |
+ /* store meta ptr in repo->pkgs, such that get_pkg_meta |
262 |
+ * can grab it from there (for free) */ |
263 |
+ ctx->pkgs = (char *)meta; |
264 |
+ |
265 |
+ cat->name = atom->CATEGORY; |
266 |
+ pkg->name = atom->PN; |
267 |
+ pkg->slot = meta->SLOT == NULL ? "0" : meta->SLOT; |
268 |
+ pkg->repo = ctx->repo; |
269 |
+ pkg->atom = atom; |
270 |
+ |
271 |
+ /* do call callback with pkg_atom (populate cat and pkg) */ |
272 |
+ ret |= callback(pkg, priv); |
273 |
+ |
274 |
+ atom_implode(atom); |
275 |
+ } |
276 |
+ |
277 |
+ memset(meta, 0, sizeof(meta[0])); |
278 |
+ atom = NULL; |
279 |
+ if (len > 0) { /* hop over \n */ |
280 |
+ p++; |
281 |
+ len--; |
282 |
+ } |
283 |
+ continue; |
284 |
+ } |
285 |
+ |
286 |
+ /* skip invalid lines */ |
287 |
+ if (c == NULL || q - c < 3 || c[1] != ' ') |
288 |
+ continue; |
289 |
+ |
290 |
+ /* NULL-terminate p and c, file should end with \n */ |
291 |
+ *q = '\0'; |
292 |
+ *c = '\0'; |
293 |
+ c += 2; /* hop over ": " */ |
294 |
+ if (len > 0) { /* hop over \n */ |
295 |
+ q++; |
296 |
+ len--; |
297 |
+ } |
298 |
+ |
299 |
+ if (strcmp(p, "REPO") == 0) { /* from global section in older files */ |
300 |
+ ctx->repo = c; |
301 |
+ } else if (strcmp(p, "CPV") == 0) { |
302 |
+ if (atom != NULL) |
303 |
+ atom_implode(atom); |
304 |
+ atom = atom_explode(c); |
305 |
+#define match_key(X) match_key2(X,X) |
306 |
+#define match_key2(X,Y) \ |
307 |
+ } else if (strcmp(p, #X) == 0) { \ |
308 |
+ meta->Y = c |
309 |
+ match_key(DEFINED_PHASES); |
310 |
+ match_key(DEPEND); |
311 |
+ match_key2(DESC, DESCRIPTION); |
312 |
+ match_key(EAPI); |
313 |
+ match_key(IUSE); |
314 |
+ match_key(KEYWORDS); |
315 |
+ match_key(LICENSE); |
316 |
+ match_key2(MD5, _md5_); |
317 |
+ match_key2(SHA1, _eclasses_); |
318 |
+ match_key(RDEPEND); |
319 |
+ match_key(SLOT); |
320 |
+ match_key(USE); |
321 |
+ match_key(PDEPEND); |
322 |
+#undef match_key |
323 |
+#undef match_key2 |
324 |
+ } |
325 |
+ |
326 |
+ p = q; |
327 |
+ } while (len > 0); |
328 |
+ |
329 |
+ /* ensure we don't free a garbage pointer */ |
330 |
+ ctx->repo = NULL; |
331 |
+ |
332 |
+ return ret; |
333 |
+} |
334 |
+ |
335 |
int |
336 |
tree_foreach_pkg(tree_ctx *ctx, |
337 |
tree_pkg_cb callback, void *priv, tree_cat_filter filter, |
338 |
@@ -964,6 +1174,10 @@ tree_foreach_pkg(tree_ctx *ctx, |
339 |
if (ctx == NULL) |
340 |
return EXIT_FAILURE; |
341 |
|
342 |
+ /* handle Packages (binpkgs index) file separately */ |
343 |
+ if (ctx->cachetype == CACHE_PACKAGES) |
344 |
+ return tree_foreach_packages(ctx, callback, priv); |
345 |
+ |
346 |
ctx->do_sort = sort; |
347 |
if (catsortfunc != NULL) |
348 |
ctx->catsortfunc = catsortfunc; |
349 |
@@ -1009,23 +1223,35 @@ tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete) |
350 |
&pkg_ctx->repo, &pkg_ctx->repo_len); |
351 |
pkg_ctx->atom->REPO = pkg_ctx->repo; |
352 |
} |
353 |
- } else { /* metadata or ebuild */ |
354 |
+ } else { /* metadata, ebuild, binpkg or Packages */ |
355 |
+ tree_pkg_meta *meta = NULL; |
356 |
if (pkg_ctx->atom->SLOT == NULL) { |
357 |
if (pkg_ctx->slot == NULL) { |
358 |
- tree_pkg_meta *meta = tree_pkg_read(pkg_ctx); |
359 |
+ meta = tree_pkg_read(pkg_ctx); |
360 |
if (meta != NULL) { |
361 |
if (meta->SLOT != NULL) { |
362 |
pkg_ctx->slot = xstrdup(meta->SLOT); |
363 |
pkg_ctx->slot_len = strlen(pkg_ctx->slot); |
364 |
} |
365 |
- tree_close_meta(meta); |
366 |
} |
367 |
} |
368 |
pkg_ctx->atom->SLOT = pkg_ctx->slot; |
369 |
} |
370 |
/* repo is set from the tree, when found */ |
371 |
- if (pkg_ctx->atom->REPO == NULL) |
372 |
+ if (pkg_ctx->atom->REPO == NULL) { |
373 |
+ if (pkg_ctx->repo == NULL && ctx->cachetype == CACHE_BINPKGS) { |
374 |
+ if (meta == NULL) |
375 |
+ meta = tree_pkg_read(pkg_ctx); |
376 |
+ if (meta != NULL && meta->repository != NULL) { |
377 |
+ pkg_ctx->repo = xstrdup(meta->repository); |
378 |
+ pkg_ctx->repo_len = strlen(pkg_ctx->repo); |
379 |
+ } |
380 |
+ } |
381 |
pkg_ctx->atom->REPO = pkg_ctx->repo; |
382 |
+ } |
383 |
+ |
384 |
+ if (meta != NULL) |
385 |
+ tree_close_meta(meta); |
386 |
} |
387 |
|
388 |
/* this is a bit atom territory, but since we pulled in SLOT we |
389 |
|
390 |
diff --git a/libq/tree.h b/libq/tree.h |
391 |
index c2a30f1..d769b7b 100644 |
392 |
--- a/libq/tree.h |
393 |
+++ b/libq/tree.h |
394 |
@@ -18,7 +18,7 @@ typedef struct tree_pkg_ctx tree_pkg_ctx; |
395 |
typedef struct tree_pkg_meta tree_pkg_meta; |
396 |
typedef struct tree_metadata_xml tree_metadata_xml; |
397 |
|
398 |
-/* VDB context */ |
399 |
+/* tree context */ |
400 |
struct tree_ctx { |
401 |
int portroot_fd; |
402 |
int tree_fd; |
403 |
@@ -35,11 +35,15 @@ struct tree_ctx { |
404 |
CACHE_METADATA_PMS, |
405 |
CACHE_EBUILD, |
406 |
CACHE_VDB, |
407 |
+ CACHE_PACKAGES, |
408 |
+ CACHE_BINPKGS, |
409 |
} cachetype:3; |
410 |
tree_pkg_ctx *ebuilddir_pkg_ctx; |
411 |
tree_cat_ctx *ebuilddir_cat_ctx; |
412 |
tree_ctx *ebuilddir_ctx; |
413 |
char *repo; |
414 |
+ char *pkgs; |
415 |
+ size_t pkgslen; |
416 |
}; |
417 |
|
418 |
/* Category context */ |
419 |
@@ -90,6 +94,10 @@ struct tree_pkg_meta { |
420 |
char *BDEPEND; |
421 |
char *_eclasses_; |
422 |
char *_md5_; |
423 |
+ /* binpkgs/vdb */ |
424 |
+ char *CONTENTS; |
425 |
+ char *USE; |
426 |
+ char *repository; |
427 |
}; |
428 |
|
429 |
/* Metadata.xml */ |
430 |
@@ -104,8 +112,9 @@ struct tree_metadata_xml { |
431 |
typedef int (tree_pkg_cb)(tree_pkg_ctx *, void *priv); |
432 |
typedef int (tree_cat_filter)(tree_cat_ctx *, void *priv); |
433 |
|
434 |
-tree_ctx *tree_open_vdb(const char *sroot, const char *svdb); |
435 |
tree_ctx *tree_open(const char *sroot, const char *portdir); |
436 |
+tree_ctx *tree_open_vdb(const char *sroot, const char *svdb); |
437 |
+tree_ctx *tree_open_binpkg(const char *sroot, const char *spkg); |
438 |
void tree_close(tree_ctx *ctx); |
439 |
int tree_filter_cat(const struct dirent *de); |
440 |
tree_cat_ctx *tree_open_cat(tree_ctx *ctx, const char *name); |