38#include <archive_entry.h>
40#include "xbps_api_impl.h"
58 r = snprintf(path,
sizeof(path),
"%s/%s-repodata.lock", repodir, arch);
59 if (r < 0 || (
size_t)r >
sizeof(path)) {
63 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC, 0660);
67 if (flock(fd, LOCK_EX|LOCK_NB) == 0)
69 if (errno != EWOULDBLOCK) {
75 xbps_warn_printf(
"repository locked: %s: waiting...", repodir);
76 if (flock(fd, LOCK_EX) == -1) {
94 r = snprintf(path,
sizeof(path),
"%s/%s-repodata.lock", repodir, arch);
95 if (r < 0 || (
size_t)r >
sizeof(path))
101repo_read_next(
struct xbps_repo *repo,
struct archive *ar,
struct archive_entry **entry)
105 r = archive_read_next_header(ar, entry);
106 if (r == ARCHIVE_FATAL) {
107 xbps_error_printf(
"failed to read repository: %s: %s\n",
108 repo->
uri, archive_error_string(ar));
109 return -xbps_archive_errno(ar);
110 }
else if (r == ARCHIVE_WARN) {
111 xbps_warn_printf(
"reading repository: %s: %s\n",
112 repo->
uri, archive_error_string(ar));
114 }
else if (r == ARCHIVE_EOF) {
121repo_read_index(
struct xbps_repo *repo,
struct archive *ar)
123 struct archive_entry *entry;
127 r = repo_read_next(repo, ar, &entry);
132 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_INDEX) != 0) {
133 xbps_error_printf(
"failed to read repository index: %s: unexpected archive entry\n",
139 if (archive_entry_size(entry) == 0) {
140 r = archive_read_data_skip(ar);
141 if (r == ARCHIVE_FATAL) {
142 xbps_error_printf(
"failed to read repository: %s: archive error: %s\n",
143 repo->
uri, archive_error_string(ar));
144 return -xbps_archive_errno(ar);
146 repo->
index = xbps_dictionary_create();
150 buf = xbps_archive_get_file(ar, entry);
154 "failed to open repository: %s: failed to read index: %s\n",
155 repo->
uri, strerror(-r));
158 repo->
index = xbps_dictionary_internalize(buf);
165 "failed to open repository: %s: failed to parse index: %s\n",
166 repo->
uri, strerror(-r));
170 xbps_dictionary_make_immutable(repo->
index);
175repo_read_meta(
struct xbps_repo *repo,
struct archive *ar)
177 struct archive_entry *entry;
181 r = repo_read_next(repo, ar, &entry);
185 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_META) != 0) {
186 xbps_error_printf(
"failed to read repository metadata: %s: unexpected archive entry\n",
191 if (archive_entry_size(entry) == 0) {
192 r = archive_read_data_skip(ar);
193 if (r == ARCHIVE_FATAL) {
194 xbps_error_printf(
"failed to read repository: %s: archive error: %s\n",
195 repo->
uri, archive_error_string(ar));
196 return -xbps_archive_errno(ar);
202 buf = xbps_archive_get_file(ar, entry);
206 "failed to read repository metadata: %s: failed to read "
208 repo->
uri, strerror(-r));
212 if (strcmp(buf,
"DEADBEEF") == 0) {
218 repo->
idxmeta = xbps_dictionary_internalize(buf);
225 "failed to read repository metadata: %s: failed to parse "
227 repo->
uri, strerror(-r));
232 xbps_dictionary_make_immutable(repo->
idxmeta);
237repo_read_stage(
struct xbps_repo *repo,
struct archive *ar)
239 struct archive_entry *entry;
242 r = repo_read_next(repo, ar, &entry);
246 repo->stage = xbps_dictionary_create();
252 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_STAGE) != 0) {
253 xbps_error_printf(
"failed to read repository stage: %s: unexpected archive entry\n",
258 if (archive_entry_size(entry) == 0) {
259 repo->stage = xbps_dictionary_create();
263 repo->stage = xbps_archive_get_dictionary(ar, entry);
265 xbps_error_printf(
"failed to open repository: %s: reading stage: %s\n",
266 repo->
uri, archive_error_string(ar));
269 xbps_dictionary_make_immutable(repo->stage);
274repo_read(
struct xbps_repo *repo,
struct archive *ar)
278 r = repo_read_index(repo, ar);
281 r = repo_read_meta(repo, ar);
284 r = repo_read_stage(repo, ar);
292repo_open_local(
struct xbps_repo *repo,
struct archive *ar)
299 cachedir = xbps_get_remote_repo_string(repo->
uri);
302 xbps_error_printf(
"failed to open repository: %s: invalid repository url\n",
306 r = snprintf(path,
sizeof(path),
"%s/%s/%s-repodata",
310 r = snprintf(path,
sizeof(path),
"%s/%s-repodata", repo->
uri, repo->
arch);
312 if (r < 0 || (
size_t)r >=
sizeof(path)) {
314 xbps_error_printf(
"failed to open repository: %s: repository path too long\n",
319 r = xbps_archive_read_open(ar, path);
322 xbps_error_printf(
"failed to open repodata: %s: %s\n",
334repo_open_remote(
struct xbps_repo *repo,
struct archive *ar)
339 r = snprintf(url,
sizeof(url),
"%s/%s-repodata", repo->
uri, repo->
arch);
340 if (r < 0 || (
size_t)r >=
sizeof(url)) {
341 xbps_error_printf(
"failed to open repository: %s: repository url too long\n",
343 return -ENAMETOOLONG;
346 r = xbps_archive_read_open_remote(ar, url);
348 xbps_error_printf(
"failed to open repository: %s: %s\n", repo->
uri, strerror(-r));
361 ar = xbps_archive_read_new();
364 xbps_error_printf(
"failed to open repo: %s\n", strerror(-r));
369 r = repo_open_remote(repo, ar);
371 r = repo_open_local(repo, ar);
375 r = repo_read(repo, ar);
379 r = archive_read_close(ar);
381 xbps_error_printf(
"failed to open repository: %s: closing archive: %s\n",
382 repo->
uri, archive_error_string(ar));
386 archive_read_free(ar);
389 archive_read_free(ar);
409 if (repo[0] !=
'/' && repo[0] !=
'\0') {
410 if ((url = realpath(repo, NULL)) == NULL)
411 xbps_dbg_printf(
"[repo] %s: realpath %s\n", __func__, repo);
415 xbps_dbg_printf(
"[repo] `%s' already stored\n", url ? url : repo);
420 if (xbps_array_add_cstring(xhp->
repositories, url ? url : repo)) {
421 xbps_dbg_printf(
"[repo] `%s' stored successfully\n", url ? url : repo);
447 xbps_dbg_printf(
"[repo] `%s' removed\n", url);
458 xbps_dictionary_t idx;
459 xbps_object_t keysym;
460 xbps_object_iterator_t iter;
463 idx = xbps_dictionary_copy_mutable(repo->
index);
467 iter = xbps_dictionary_iterator(repo->stage);
473 while ((keysym = xbps_object_iterator_next(iter))) {
474 const char *pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym);
475 xbps_dictionary_t pkgd = xbps_dictionary_get_keysym(repo->stage, keysym);
476 if (!xbps_dictionary_set(idx, pkgname, pkgd)) {
482 xbps_object_iterator_release(iter);
486 xbps_object_iterator_release(iter);
488 xbps_object_release(idx);
498 repo = calloc(1,
sizeof(*repo));
501 xbps_error_printf(
"failed to open repository: %s\n", strerror(-r));
510 r = repo_open(
xhp, repo);
517 if (xbps_dictionary_count(repo->stage) == 0 ||
520 xbps_object_retain(repo->
idx);
524 r = repo_merge_stage(repo);
527 "failed to open repository: %s: could not merge stage: %s\n",
545 xbps_object_release(repo->
idx);
549 xbps_object_release(repo->
index);
553 xbps_object_release(repo->stage);
557 xbps_object_release(repo->
idxmeta);
566 xbps_dictionary_t pkgd;
568 char pkgname[XBPS_NAME_SIZE] = {0};
570 if (!repo || !repo->
idx || !pkg) {
573 pkgd = xbps_find_virtualpkg_in_dict(repo->
xhp, repo->
idx, pkg);
577 if (xbps_dictionary_get(pkgd,
"repository") && xbps_dictionary_get(pkgd,
"pkgname")) {
580 if (!xbps_dictionary_set_cstring_nocopy(pkgd,
"repository", repo->
uri)) {
583 if (!xbps_dictionary_get_cstring_nocopy(pkgd,
"pkgver", &pkgver)) {
589 if (!xbps_dictionary_set_cstring(pkgd,
"pkgname", pkgname)) {
592 xbps_dbg_printf(
"%s: found %s\n", __func__, pkgver);
600 xbps_dictionary_t pkgd = NULL;
602 char pkgname[XBPS_NAME_SIZE] = {0};
604 if (!repo || !repo->
idx || !pkg) {
608 if ((pkgd = xbps_find_virtualpkg_in_conf(repo->
xhp, repo->
idx, pkg))) {
612 if ((pkgd = xbps_find_pkg_in_dict(repo->
idx, pkg))) {
617 if (xbps_dictionary_get(pkgd,
"repository") && xbps_dictionary_get(pkgd,
"pkgname")) {
620 if (!xbps_dictionary_set_cstring_nocopy(pkgd,
"repository", repo->
uri)) {
623 if (!xbps_dictionary_get_cstring_nocopy(pkgd,
"pkgver", &pkgver)) {
629 if (!xbps_dictionary_set_cstring(pkgd,
"pkgname", pkgname)) {
632 xbps_dbg_printf(
"%s: found %s\n", __func__, pkgver);
637revdeps_match(
struct xbps_repo *repo, xbps_dictionary_t tpkgd,
const char *str)
639 xbps_dictionary_t pkgd;
640 xbps_array_t revdeps = NULL, pkgdeps, provides;
641 xbps_object_iterator_t iter;
643 const char *pkgver = NULL, *tpkgver = NULL, *
arch = NULL, *vpkg = NULL;
645 iter = xbps_dictionary_iterator(repo->
idx);
648 while ((obj = xbps_object_iterator_next(iter))) {
649 pkgd = xbps_dictionary_get_keysym(repo->
idx, obj);
650 if (xbps_dictionary_equals(pkgd, tpkgd))
653 pkgdeps = xbps_dictionary_get(pkgd,
"run_depends");
654 if (!xbps_array_count(pkgdeps))
662 xbps_dictionary_get_cstring_nocopy(pkgd,
663 "architecture", &
arch);
667 xbps_dictionary_get_cstring_nocopy(pkgd,
671 revdeps = xbps_array_create();
674 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
681 provides = xbps_dictionary_get(tpkgd,
"provides");
682 for (
unsigned int i = 0; i < xbps_array_count(provides); i++) {
683 xbps_array_get_cstring_nocopy(provides, i, &vpkg);
687 xbps_dictionary_get_cstring_nocopy(pkgd,
688 "architecture", &
arch);
692 xbps_dictionary_get_cstring_nocopy(pkgd,
"pkgver",
696 revdeps = xbps_array_create();
699 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
704 xbps_dictionary_get_cstring_nocopy(tpkgd,
"pkgver", &pkgver);
708 xbps_dictionary_get_cstring_nocopy(pkgd,
709 "architecture", &
arch);
713 xbps_dictionary_get_cstring_nocopy(pkgd,
"pkgver", &tpkgver);
716 revdeps = xbps_array_create();
719 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
721 xbps_object_iterator_release(iter);
728 xbps_array_t revdeps = NULL, vdeps = NULL;
729 xbps_dictionary_t pkgd;
733 if (repo->
idx == NULL)
744 if ((vdeps = xbps_dictionary_get(pkgd,
"provides"))) {
745 for (
unsigned int i = 0; i < xbps_array_count(vdeps); i++) {
746 char vpkgn[XBPS_NAME_SIZE];
748 xbps_array_get_cstring_nocopy(vdeps, i, &vpkg);
752 if (strcmp(vpkgn, pkg) == 0) {
759 revdeps = revdeps_match(repo, pkgd, vpkg);
762 revdeps = revdeps_match(repo, pkgd, NULL);
770 xbps_dictionary_t repokeyd = NULL;
771 xbps_data_t pubkey = NULL;
772 uint16_t pubkey_size = 0;
773 const char *signedby = NULL;
775 char *p, *dbkeyd, *rkeyfile = NULL;
782 if (!xbps_dictionary_count(repo->
idxmeta)) {
783 xbps_dbg_printf(
"[repo] `%s' unsigned repository!\n", repo->
uri);
792 xbps_dictionary_get_cstring_nocopy(repo->
idxmeta,
"signature-by", &signedby);
793 xbps_dictionary_get_uint16(repo->
idxmeta,
"public-key-size", &pubkey_size);
794 pubkey = xbps_dictionary_get(repo->
idxmeta,
"public-key");
796 if (signedby == NULL || pubkey_size == 0 ||
797 xbps_object_type(pubkey) != XBPS_TYPE_DATA) {
798 xbps_dbg_printf(
"[repo] `%s': incomplete signed repository "
799 "(missing objs)\n", repo->
uri);
813 if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) {
814 xbps_dbg_printf(
"[repo] `%s' public key already stored.\n", repo->
uri);
822 import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0,
823 hexfp, "`%s' repository has been RSA signed by \"%s\
"",
824 repo->
uri, signedby);
830 p = strdup(rkeyfile);
833 if (access(dbkeyd, R_OK|W_OK) == -1) {
839 xbps_dbg_printf(
"[repo] `%s' cannot create %s: %s\n",
840 repo->
uri, dbkeyd, strerror(errno));
847 repokeyd = xbps_dictionary_create();
848 xbps_dictionary_set(repokeyd,
"public-key", pubkey);
849 xbps_dictionary_set_uint16(repokeyd,
"public-key-size", pubkey_size);
850 xbps_dictionary_set_cstring_nocopy(repokeyd,
"signature-by", signedby);
852 if (!xbps_dictionary_externalize_to_file(repokeyd, rkeyfile)) {
854 xbps_dbg_printf(
"[repo] `%s' failed to externalize %s: %s\n",
855 repo->
uri, rkeyfile, strerror(rv));
862 xbps_object_release(repokeyd);
xbps_array_t repositories
char metadir[XBPS_MAXPATH]
Generic XBPS structure handler for initialization.
bool xbps_match_pkgdep_in_array(xbps_array_t array, const char *pkgver)
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
xbps_dictionary_t xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
struct xbps_repo * xbps_repo_open(struct xbps_handle *xhp, const char *url)
void xbps_repo_release(struct xbps_repo *repo)
int xbps_repo_lock(const char *repodir, const char *arch)
bool xbps_repo_remove(struct xbps_handle *xhp, const char *repo)
int xbps_repo_key_import(struct xbps_repo *repo)
xbps_dictionary_t xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
void xbps_repo_unlock(const char *repodir, const char *arch, int fd)
bool xbps_repo_store(struct xbps_handle *xhp, const char *repo)
xbps_dictionary_t idxmeta
xbps_dictionary_t xbps_plist_dictionary_from_file(const char *path)
char * xbps_pubkey2fp(xbps_data_t pubkey)
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
int xbps_mkpath(const char *path, mode_t mode)
bool xbps_remove_string_from_array(xbps_array_t array, const char *str)
bool xbps_repository_is_remote(const char *uri)
bool xbps_pkg_arch_match(struct xbps_handle *xhp, const char *orig, const char *target)