2 * Copyright (c) 2012, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
22 #include "solv_xfopen.h"
23 #include "repo_arch.h"
25 static long long parsenum(unsigned char *p, int cnt)
33 x = *p & 0x40 ? (-1 << 8 | *p) : (*p ^ 0x80);
38 while (cnt > 0 && (*p == ' ' || *p == '\t'))
42 for (; cnt > 0 && *p >= '0' && *p < '8'; cnt--, p++)
43 x = (x << 3) | (*p - '0');
47 static int readblock(FILE *fp, unsigned char *blk)
52 r = fread(blk + l, 1, 512 - l, fp);
62 unsigned char blk[512];
72 static char *getsentry(struct tarhead *th, char *s, int size)
75 if (th->eof || size <= 1)
77 size--; /* terminating 0 */
81 for (i = th->off; i < th->end; i++)
85 if (!size || th->blk[i] == '\n')
96 th->end = fread(th->blk, 1, 512, th->fp);
107 if (readblock(th->fp, th->blk))
113 th->end = th->length > 512 ? 512 : th->length;
114 th->length -= th->end;
118 static void skipentry(struct tarhead *th)
120 for (; th->length > 0; th->length -= 512)
122 if (readblock(th->fp, th->blk))
130 th->off = th->end = 0;
133 static void inittarhead(struct tarhead *th, FILE *fp)
135 memset(th, 0, sizeof(*th));
139 static void freetarhead(struct tarhead *th)
144 static int gettarhead(struct tarhead *th)
149 th->path = solv_free(th->path);
159 int r = readblock(th->fp, th->blk);
174 length = parsenum(th->blk + 124, 12);
178 switch (th->blk[156])
184 /* hard link, special length magic... */
191 case '2': case '3': case '4': case '6':
194 case 'X': case 'x': case 'L':
197 if (length < 1 || length >= 1024 * 1024)
199 data = pp = solv_malloc(length + 512);
200 for (l = length; l > 0; l -= 512, pp += 512)
201 if (readblock(th->fp, (unsigned char *)pp))
207 type = 3; /* extension */
208 if (th->blk[156] == 'L')
219 for (l = 0; l < length && pp[l] >= '0' && pp[l] <= '9'; l++)
220 ll = ll * 10 + (pp[l] - '0');
221 if (l == length || pp[l] != ' ' || ll < 1 || ll > length || pp[ll - 1] != '\n')
230 if (!strncmp(pp, "path=", 5))
233 th->path = solv_strdup(pp + 5);
243 type = 3; /* extension */
246 if ((type == 1 || type == 2) && !th->path)
249 memcpy(path, th->blk, 156);
251 if (!memcmp(th->blk + 257, "ustar\0\060\060", 8) && !th->path && th->blk[345])
253 /* POSIX ustar with prefix */
255 memcpy(prefix, th->blk + 345, 155);
258 if (l && prefix[l - 1] == '/')
260 th->path = solv_dupjoin(prefix, "/", path);
263 th->path = solv_dupjoin(path, 0, 0);
265 if (type == 1 || type == 2)
267 l = strlen(th->path);
268 if (l && th->path[l - 1] == '/')
279 r = readblock(th->fp, th->blk);
291 adddep(Repo *repo, Offset olddeps, char *line)
293 Pool *pool = repo->pool;
297 while (*line == ' ' && *line == '\t')
300 while (*p && *p != ' ' && *p != '\t' && *p != '<' && *p != '=' && *p != '>')
302 id = pool_strn2id(pool, line, p - line, 1);
303 while (*p == ' ' && *p == '\t')
305 if (*p == '<' || *p == '=' || *p == '>')
319 while (*p == ' ' && *p == '\t')
322 while (*p && *p != ' ' && *p != '\t')
324 id = pool_rel2id(pool, id, pool_strn2id(pool, line, p - line, 1), flags, 1);
326 return repo_addid_dep(repo, olddeps, id, 0);
330 repo_add_arch_pkg(Repo *repo, const char *fn, int flags)
332 Pool *pool = repo->pool;
341 void *pkgidhandle = 0;
343 data = repo_add_repodata(repo, flags);
344 if ((fd = open(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, fn) : fn, O_RDONLY, 0)) < 0)
346 pool_error(pool, -1, "%s: %s", fn, strerror(errno));
351 pool_error(pool, -1, "%s: fstat: %s", fn, strerror(errno));
355 if (!(fp = solv_xfopen_fd(fn, fd, "r")))
357 pool_error(pool, -1, "%s: fdopen failed", fn);
362 inittarhead(&th, fp);
363 while (gettarhead(&th) > 0)
365 if (th.type != 1 || strcmp(th.path, ".PKGINFO") != 0)
371 s = pool_id2solvable(pool, repo_add_solvable(repo));
372 if (flags & ARCH_ADD_WITH_PKGID)
373 pkgidhandle = solv_chksum_create(REPOKEY_TYPE_MD5);
374 while (getsentry(&th, line, sizeof(line)))
380 solv_chksum_add(pkgidhandle, line, l);
381 if (line[l - 1] != '\n')
392 if (l == 0 || line[0] == '#')
394 if (!strncmp(line, "pkgname = ", 10))
395 s->name = pool_str2id(pool, line + 10, 1);
396 else if (!strncmp(line, "pkgver = ", 9))
397 s->evr = pool_str2id(pool, line + 9, 1);
398 else if (!strncmp(line, "pkgdesc = ", 10))
400 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 10);
401 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line + 10);
403 else if (!strncmp(line, "url = ", 6))
404 repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line + 6);
405 else if (!strncmp(line, "builddate = ", 12))
406 repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line + 12, 0, 10));
407 else if (!strncmp(line, "packager = ", 11))
408 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line + 11);
409 else if (!strncmp(line, "size = ", 7))
410 repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line + 7, 0, 10));
411 else if (!strncmp(line, "arch = ", 7))
412 s->arch = pool_str2id(pool, line + 7, 1);
413 else if (!strncmp(line, "license = ", 10))
414 repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line + 10);
415 else if (!strncmp(line, "replaces = ", 11))
416 s->obsoletes = adddep(repo, s->obsoletes, line + 11);
417 else if (!strncmp(line, "group = ", 8))
418 repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_GROUP, line + 8);
419 else if (!strncmp(line, "depend = ", 9))
420 s->requires = adddep(repo, s->requires, line + 9);
421 else if (!strncmp(line, "optdepend = ", 12))
423 char *p = strchr(line, ':');
426 s->suggests = adddep(repo, s->suggests, line + 12);
428 else if (!strncmp(line, "conflict = ", 11))
429 s->conflicts = adddep(repo, s->conflicts, line + 11);
430 else if (!strncmp(line, "provides = ", 11))
431 s->provides = adddep(repo, s->provides, line + 11);
439 pool_error(pool, -1, "%s: not an arch package", fn);
441 solv_chksum_free(pkgidhandle, 0);
446 pool_error(pool, -1, "%s: package has no name", fn);
447 repo_free_solvable(repo, s - pool->solvables, 1);
456 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
457 if (!(flags & REPO_NO_LOCATION))
458 repodata_set_location(data, s - pool->solvables, 0, 0, fn);
459 if (S_ISREG(stb.st_mode))
460 repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
463 unsigned char pkgid[16];
464 solv_chksum_free(pkgidhandle, pkgid);
465 repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
470 solv_chksum_free(pkgidhandle, 0);
471 if (!(flags & REPO_NO_INTERNALIZE))
472 repodata_internalize(data);
473 return s ? s - pool->solvables : 0;
476 static char *getsentrynl(struct tarhead *th, char *s, int size)
479 if (!getsentry(th, s, size))
487 if (l && s[l - 1] == '\n')
492 while (getsentry(th, s, size))
495 if (!l || s[l - 1] == '\n')
503 joinhash_init(Repo *repo, Hashval *hmp)
505 Hashval hm = mkmask(repo->nsolvables);
506 Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
511 FOR_REPO_SOLVABLES(repo, i, s)
513 hh = HASHCHAIN_START;
516 h = HASHCHAIN_NEXT(h, hh, hm);
524 joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn)
530 if ((p = strrchr(fn, '/')) != 0)
532 /* here we assume that the dirname is name-evr */
535 for (p = fn + strlen(fn) - 1; p > fn; p--)
537 while (p > fn && *p != '-')
541 name = pool_strn2id(repo->pool, fn, p - fn, 0);
544 evr = pool_str2id(repo->pool, p + 1, 0);
547 /* found valid name/evr combination, check hash */
548 hh = HASHCHAIN_START;
552 Solvable *s = repo->pool->solvables + ht[h];
553 if (s->name == name && s->evr == evr)
555 h = HASHCHAIN_NEXT(h, hh, hm);
562 adddata(Repodata *data, Solvable *s, struct tarhead *th)
564 Repo *repo = data->repo;
565 Pool *pool = repo->pool;
570 while (getsentry(th, line, sizeof(line)))
573 if (l == 0 || line[l - 1] != '\n')
576 if (l <= 2 || line[0] != '%' || line[l - 1] != '%')
578 if (!strcmp(line, "%FILENAME%"))
580 if (getsentrynl(th, line, sizeof(line)))
581 repodata_set_location(data, s - pool->solvables, 0, 0, line);
583 else if (!strcmp(line, "%NAME%"))
585 if (getsentrynl(th, line, sizeof(line)))
586 s->name = pool_str2id(pool, line, 1);
588 else if (!strcmp(line, "%VERSION%"))
590 if (getsentrynl(th, line, sizeof(line)))
591 s->evr = pool_str2id(pool, line, 1);
593 else if (!strcmp(line, "%DESC%"))
595 if (getsentrynl(th, line, sizeof(line)))
597 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line);
598 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line);
601 else if (!strcmp(line, "%GROUPS%"))
603 if (getsentrynl(th, line, sizeof(line)))
604 repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_GROUP, line);
606 else if (!strcmp(line, "%CSIZE%"))
608 if (getsentrynl(th, line, sizeof(line)))
609 repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(line, 0, 10));
611 else if (!strcmp(line, "%ISIZE%"))
613 if (getsentrynl(th, line, sizeof(line)))
614 repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line, 0, 10));
616 else if (!strcmp(line, "%MD5SUM%"))
618 if (getsentrynl(th, line, sizeof(line)) && !havesha256)
619 repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_MD5, line);
621 else if (!strcmp(line, "%SHA256SUM%"))
623 if (getsentrynl(th, line, sizeof(line)))
625 repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, line);
629 else if (!strcmp(line, "%URL%"))
631 if (getsentrynl(th, line, sizeof(line)))
632 repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line);
634 else if (!strcmp(line, "%LICENSE%"))
636 if (getsentrynl(th, line, sizeof(line)))
637 repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line);
639 else if (!strcmp(line, "%ARCH%"))
641 if (getsentrynl(th, line, sizeof(line)))
642 s->arch = pool_str2id(pool, line, 1);
644 else if (!strcmp(line, "%BUILDDATE%"))
646 if (getsentrynl(th, line, sizeof(line)))
647 repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line, 0, 10));
649 else if (!strcmp(line, "%PACKAGER%"))
651 if (getsentrynl(th, line, sizeof(line)))
652 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line);
654 else if (!strcmp(line, "%REPLACES%"))
656 while (getsentrynl(th, line, sizeof(line)) && *line)
657 s->obsoletes = adddep(repo, s->obsoletes, line);
659 else if (!strcmp(line, "%DEPENDS%"))
661 while (getsentrynl(th, line, sizeof(line)) && *line)
662 s->requires = adddep(repo, s->requires, line);
664 else if (!strcmp(line, "%CONFLICTS%"))
666 while (getsentrynl(th, line, sizeof(line)) && *line)
667 s->conflicts = adddep(repo, s->conflicts, line);
669 else if (!strcmp(line, "%PROVIDES%"))
671 while (getsentrynl(th, line, sizeof(line)) && *line)
672 s->provides = adddep(repo, s->provides, line);
674 else if (!strcmp(line, "%OPTDEPENDS%"))
676 while (getsentrynl(th, line, sizeof(line)) && *line)
678 char *p = strchr(line, ':');
681 s->suggests = adddep(repo, s->suggests, line);
684 else if (!strcmp(line, "%FILES%"))
686 while (getsentrynl(th, line, sizeof(line)) && *line)
691 if (l > 1 && line[l - 1] == '/')
692 line[--l] = 0; /* remove trailing slashes */
693 if ((p = strrchr(line , '/')) != 0)
696 if (line[0] != '/') /* anchor */
699 memmove(line + 1, line, p - 1 - line);
702 id = repodata_str2dir(data, line, 1);
706 id = repodata_str2dir(data, line, 1);
714 id = repodata_str2dir(data, "/", 1);
715 repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, id, p);
719 getsentrynl(th, line, sizeof(line));
724 finishsolvable(Repo *repo, Solvable *s)
726 Pool *pool = repo->pool;
731 repo_free_solvable(repo, s - pool->solvables, 1);
738 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
742 repo_add_arch_repo(Repo *repo, FILE *fp, int flags)
744 Pool *pool = repo->pool;
750 Hashtable joinhash = 0;
751 Hashval joinhashmask = 0;
753 data = repo_add_repodata(repo, flags);
755 if (flags & REPO_EXTEND_SOLVABLES)
756 joinhash = joinhash_init(repo, &joinhashmask);
758 inittarhead(&th, fp);
759 while (gettarhead(&th) > 0)
767 bn = strrchr(th.path, '/');
768 if (!bn || (strcmp(bn + 1, "desc") != 0 && strcmp(bn + 1, "depends") != 0 && strcmp(bn + 1, "files") != 0))
773 if ((flags & REPO_EXTEND_SOLVABLES) != 0 && (!strcmp(bn + 1, "desc") || !strcmp(bn + 1, "depends")))
776 continue; /* skip those when we're extending */
778 if (!lastdn || (bn - th.path) != lastdnlen || strncmp(lastdn, th.path, lastdnlen) != 0)
780 finishsolvable(repo, s);
782 lastdn = solv_strdup(th.path);
783 lastdnlen = bn - th.path;
784 lastdn[lastdnlen] = 0;
785 if (flags & REPO_EXTEND_SOLVABLES)
787 s = joinhash_lookup(repo, joinhash, joinhashmask, lastdn);
795 s = pool_id2solvable(pool, repo_add_solvable(repo));
797 adddata(data, s, &th);
799 finishsolvable(repo, s);
802 if (!(flags & REPO_NO_INTERNALIZE))
803 repodata_internalize(data);
808 repo_add_arch_local(Repo *repo, const char *dir, int flags)
810 Pool *pool = repo->pool;
814 char *entrydir, *file;
818 data = repo_add_repodata(repo, flags);
820 if (flags & REPO_USE_ROOTDIR)
821 dir = pool_prepend_rootdir(pool, dir);
825 while ((de = readdir(dp)) != 0)
827 if (!de->d_name[0] || de->d_name[0] == '.')
829 entrydir = solv_dupjoin(dir, "/", de->d_name);
830 file = pool_tmpjoin(repo->pool, entrydir, "/desc", 0);
832 if ((fp = fopen(file, "r")) != 0)
835 inittarhead(&th, fp);
836 s = pool_id2solvable(pool, repo_add_solvable(repo));
837 adddata(data, s, &th);
840 file = pool_tmpjoin(repo->pool, entrydir, "/files", 0);
841 if ((fp = fopen(file, "r")) != 0)
843 inittarhead(&th, fp);
844 adddata(data, s, &th);
853 if (!(flags & REPO_NO_INTERNALIZE))
854 repodata_internalize(data);
855 if (flags & REPO_USE_ROOTDIR)
856 solv_free((char *)dir);