diff --git a/TODO b/TODO
index eb95ee6e3..405b5bf4b 100644
--- a/TODO
+++ b/TODO
@@ -21,4 +21,7 @@ xbps-fetch:
xbps-digest:
- blake2b support
+xbps-rindex:
+ - clean should also clean files.plist entries
+
Issues listed at https://github.com/void-linux/xbps/issues
diff --git a/bin/xbps-query/Makefile b/bin/xbps-query/Makefile
index 23aa3afdc..f2ee56db7 100644
--- a/bin/xbps-query/Makefile
+++ b/bin/xbps-query/Makefile
@@ -3,6 +3,6 @@ TOPDIR = ../..
BIN = xbps-query
OBJS = main.o list.o show-deps.o show-info-files.o
-OBJS += ownedby.o search.o ../xbps-install/util.o
+OBJS += ownedby.o search.o ../xbps-install/util.o ../xbps-install/fetch_cb.o
include $(TOPDIR)/mk/prog.mk
diff --git a/bin/xbps-query/defs.h b/bin/xbps-query/defs.h
index 2a1747253..5c12564e8 100644
--- a/bin/xbps-query/defs.h
+++ b/bin/xbps-query/defs.h
@@ -50,6 +50,7 @@ int repo_show_pkg_namedesc(struct xbps_handle *, xbps_object_t, void *,
/* from ownedby.c */
int ownedby(struct xbps_handle *, const char *, bool, bool);
+int ownedhash(struct xbps_handle *, const char *, bool, bool);
/* From list.c */
unsigned int find_longest_pkgver(struct xbps_handle *, xbps_object_t);
diff --git a/bin/xbps-query/main.c b/bin/xbps-query/main.c
index 44316c1ad..292f81c88 100644
--- a/bin/xbps-query/main.c
+++ b/bin/xbps-query/main.c
@@ -42,7 +42,8 @@ usage(bool fail)
" -c, --cachedir
Path to cachedir\n"
" -d, --debug Debug mode shown to stderr\n"
" -h, --help Show usage\n"
- " -i, --ignore-conf-repos Ignore repositories defined in xbps.d\n"
+ " -F, --update-files Updates the files-database\n"
+ " -i, --ignore-conf-repos Ignore repositories defined in xbps.d\n"
" -M, --memory-sync Remote repository data is fetched and stored\n"
" in memory, ignoring on-disk repodata archives\n"
" -p, --property PROP[,...] Show properties for PKGNAME\n"
@@ -64,7 +65,9 @@ usage(bool fail)
" -m, --list-manual-pkgs List packages installed explicitly\n"
" -O, --list-orphans List package orphans\n"
" -o, --ownedby FILE Search for package files by matching STRING or REGEX\n"
- " -S, --show PKG Show information for PKG [default mode]\n"
+ " --ownedhash FILE Search for package files by matching hash of FILE\n"
+ " or treating FILE as hash if not present\n"
+ " -S, --show PKG Show information for PKG [default mode]\n"
" -s, --search PKG Search for packages by matching PKG, STRING or REGEX\n"
" --cat=FILE PKG Print FILE from PKG binpkg to stdout\n"
" -f, --files PKG Show package files for PKG\n"
@@ -77,13 +80,14 @@ usage(bool fail)
int
main(int argc, char **argv)
{
- const char *shortopts = "C:c:df:hHiLlMmOo:p:Rr:s:S:VvX:x:";
+ const char *shortopts = "C:c:dFf:hHiLlMmOo:p:Rr:s:S:VvX:x:";
const struct option longopts[] = {
{ "config", required_argument, NULL, 'C' },
{ "cachedir", required_argument, NULL, 'c' },
{ "debug", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "ignore-conf-repos", no_argument, NULL, 'i' },
+ { "update-files", no_argument, NULL, 'F' },
{ "list-repos", no_argument, NULL, 'L' },
{ "list-pkgs", no_argument, NULL, 'l' },
{ "list-hold-pkgs", no_argument, NULL, 'H' },
@@ -92,6 +96,7 @@ main(int argc, char **argv)
{ "list-manual-pkgs", no_argument, NULL, 'm' },
{ "list-orphans", no_argument, NULL, 'O' },
{ "ownedby", required_argument, NULL, 'o' },
+ { "ownedhash", required_argument, NULL, 4 },
{ "property", required_argument, NULL, 'p' },
{ "repository", optional_argument, NULL, 'R' },
{ "rootdir", required_argument, NULL, 'r' },
@@ -108,17 +113,18 @@ main(int argc, char **argv)
{ NULL, 0, NULL, 0 },
};
struct xbps_handle xh;
+ struct xbps_fetch_cb_data xfer;
const char *pkg, *rootdir, *cachedir, *confdir, *props, *catfile;
int c, flags, rv;
- bool list_pkgs, list_repos, orphans, own, list_repolock;
+ bool list_pkgs, list_repos, orphans, own, ownhash, list_repolock;
bool list_manual, list_hold, show_prop, show_files, show_deps, show_rdeps;
- bool show, pkg_search, regex, repo_mode, opmode, fulldeptree;
+ bool show, pkg_search, regex, repo_mode, opmode, fulldeptree, update_files;
rootdir = cachedir = confdir = props = pkg = catfile = NULL;
flags = rv = c = 0;
- list_pkgs = list_repos = list_hold = orphans = pkg_search = own = false;
+ list_pkgs = list_repos = list_hold = orphans = pkg_search = own = ownhash = false;
list_manual = list_repolock = show_prop = show_files = false;
- regex = show = show_deps = show_rdeps = fulldeptree = false;
+ regex = show = show_deps = show_rdeps = fulldeptree = false, update_files = false;
repo_mode = opmode = false;
memset(&xh, 0, sizeof(xh));
@@ -138,6 +144,9 @@ main(int argc, char **argv)
pkg = optarg;
show_files = opmode = true;
break;
+ case 'F':
+ update_files = true;
+ break;
case 'H':
list_hold = opmode = true;
break;
@@ -213,6 +222,10 @@ main(int argc, char **argv)
case 3:
list_repolock = opmode = true;
break;
+ case 4:
+ pkg = optarg;
+ ownhash = opmode = true;
+ break;
case '?':
default:
usage(true);
@@ -247,6 +260,8 @@ main(int argc, char **argv)
xbps_strlcpy(xh.confdir, confdir, sizeof(xh.confdir));
xh.flags = flags;
+ xh.fetch_cb = fetch_file_progress_cb;
+ xh.fetch_cb_data = &xfer;
if ((rv = xbps_init(&xh)) != 0) {
xbps_error_printf("Failed to initialize libxbps: %s\n",
@@ -254,6 +269,9 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
+ if (update_files)
+ xbps_rpool_sync_files(&xh);
+
if (list_repos) {
/* list repositories */
rv = repo_list(&xh);
@@ -282,6 +300,10 @@ main(int argc, char **argv)
/* ownedby mode */
rv = ownedby(&xh, pkg, repo_mode, regex);
+ } else if (ownhash) {
+ /* ownedby mode */
+ rv = ownedhash(&xh, pkg, repo_mode, regex);
+
} else if (pkg_search) {
/* search mode */
rv = search(&xh, repo_mode, pkg, props, regex);
diff --git a/bin/xbps-query/ownedby.c b/bin/xbps-query/ownedby.c
index baa82c3b4..2d8783a11 100644
--- a/bin/xbps-query/ownedby.c
+++ b/bin/xbps-query/ownedby.c
@@ -23,185 +23,263 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include
-#include
+#include "defs.h"
+#include "fetch.h"
+#include "xbps_api_impl.h"
+
+#include
+#include
+#include
#include
-#include
-#include
+#include
+#include
+#include
#include
-#include
#include
#include
#include
-
+#include
+#include
#include
-#include "defs.h"
-struct ffdata {
- bool rematch;
- const char *pat, *repouri;
- regex_t regex;
- xbps_array_t allkeys;
- xbps_dictionary_t filesd;
+
+struct thread_data {
+ pthread_t this_thread;
+ struct archive* ar;
+ bool byhash;
+ const char* expr;
+ const regex_t* regex;
+ pthread_mutex_t* archive_mutex;
+ pthread_mutex_t* print_mutex;
};
-static void
-match_files_by_pattern(xbps_dictionary_t pkg_filesd,
- xbps_dictionary_keysym_t key,
- struct ffdata *ffd,
- const char *pkgver)
-{
- xbps_array_t array;
- const char *keyname = NULL, *typestr = NULL;
-
- keyname = xbps_dictionary_keysym_cstring_nocopy(key);
-
- if (strcmp(keyname, "files") == 0)
- typestr = "regular file";
- else if (strcmp(keyname, "links") == 0)
- typestr = "link";
- else if (strcmp(keyname, "conf_files") == 0)
- typestr = "configuration file";
- else
- return;
-
- array = xbps_dictionary_get_keysym(pkg_filesd, key);
- for (unsigned int i = 0; i < xbps_array_count(array); i++) {
- xbps_object_t obj;
- const char *filestr = NULL, *tgt = NULL;
-
- obj = xbps_array_get(array, i);
- xbps_dictionary_get_cstring_nocopy(obj, "file", &filestr);
- if (filestr == NULL)
- continue;
- xbps_dictionary_get_cstring_nocopy(obj, "target", &tgt);
- if (ffd->rematch) {
- if (regexec(&ffd->regex, filestr, 0, 0, 0) == 0) {
- printf("%s: %s%s%s (%s)\n",
- pkgver, filestr,
- tgt ? " -> " : "",
- tgt ? tgt : "",
- typestr);
- }
- } else {
- if ((fnmatch(ffd->pat, filestr, FNM_PERIOD)) == 0) {
- printf("%s: %s%s%s (%s)\n",
- pkgver, filestr,
- tgt ? " -> " : "",
- tgt ? tgt : "",
- typestr);
- }
- }
+static inline int parse_line(char** fields, int fields_size, char* line) {
+ char* next;
+ int i = 0;
+
+ while (i < fields_size - 1) {
+ if (!(next = strchr(line, '%')))
+ break;
+
+ *next = '\0';
+
+ fields[i++] = *line ? line : NULL;
+ line = next + 1;
}
+ fields[i++] = *line ? line : NULL;
+
+ return i;
+}
+
+static inline void print_line(pthread_mutex_t* mutex, const char* pkg, char** file) {
+ if (mutex) pthread_mutex_lock(mutex);
+ printf("%s: %s", pkg, file[1]);
+ if (file[2])
+ printf(" -> %s", file[2]);
+ printf("\n");
+ if (mutex) pthread_mutex_unlock(mutex);
}
-static int
-ownedby_pkgdb_cb(struct xbps_handle *xhp,
- xbps_object_t obj,
- const char *obj_key UNUSED,
- void *arg,
- bool *done UNUSED)
-{
- xbps_dictionary_t pkgmetad;
- xbps_array_t files_keys;
- struct ffdata *ffd = arg;
- const char *pkgver = NULL;
-
- (void)obj_key;
- (void)done;
-
- xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
- pkgmetad = xbps_pkgdb_get_pkg_files(xhp, pkgver);
- if (pkgmetad == NULL)
- return 0;
-
- files_keys = xbps_dictionary_all_keys(pkgmetad);
- for (unsigned int i = 0; i < xbps_array_count(files_keys); i++) {
- match_files_by_pattern(pkgmetad,
- xbps_array_get(files_keys, i), ffd, pkgver);
+static char* archive_get_file(struct archive* ar, struct archive_entry* entry) {
+ ssize_t buflen;
+ char* buf;
+
+ assert(ar != NULL);
+ assert(entry != NULL);
+
+ buflen = archive_entry_size(entry);
+ buf = malloc(buflen + 1);
+ if (buf == NULL)
+ return NULL;
+ if (archive_read_data(ar, buf, buflen) != buflen) {
+ free(buf);
+ return NULL;
}
- xbps_object_release(pkgmetad);
- xbps_object_release(files_keys);
+ buf[buflen] = '\0';
+ return buf;
+}
- return 0;
+static void* thread_func(void* data_ptr) {
+ struct thread_data* data = data_ptr;
+ struct archive_entry* entry;
+
+ for (;;) {
+ char* pkg;
+ char* content;
+ char* line, *end_line;
+ char* file[3];
+ int ar_rv;
+
+ if (data->archive_mutex) pthread_mutex_lock(data->archive_mutex);
+ if ((ar_rv = archive_read_next_header(data->ar, &entry)) == ARCHIVE_OK) {
+ pkg = strdup(archive_entry_pathname(entry));
+ content = archive_get_file(data->ar, entry);
+ }
+ if (data->archive_mutex) pthread_mutex_unlock(data->archive_mutex);
+
+ if (ar_rv != ARCHIVE_OK)
+ break;
+
+ line = strtok_r(content, "\n", &end_line);
+ while (line) {
+ parse_line(file, 3, line);
+ if (data->byhash) {
+ if (file[0] != NULL && strcasecmp(file[0], data->expr) == 0)
+ print_line(data->print_mutex, pkg, file);
+ } else if (data->expr != NULL) {
+ if (strcasestr(file[1], data->expr) != NULL || (file[2] && strcasestr(file[2], data->expr))) {
+ print_line(data->print_mutex, pkg, file);
+ }
+ } else { // regex
+ if (!regexec(data->regex, file[1], 0, NULL, 0) ||
+ (file[2] && !regexec(data->regex, file[2], 0, NULL, 0))) {
+ print_line(data->print_mutex, pkg, file);
+ }
+ }
+ line = strtok_r(NULL, "\n", &end_line);
+ }
+
+ free(pkg);
+ free(content);
+ }
+
+ return NULL;
}
+static int repo_search_files(struct xbps_handle* xh, const char* repouri, bool byhash, const char* expr, regex_t* regex) {
+ struct archive* ar;
+ FILE* ar_file;
+ char* files_uri;
+ char* reponame_escaped;
+ pthread_mutex_t archive_mutex, print_mutex;
+ int maxthreads;
+ struct thread_data* thds;
-static int
-repo_match_cb(struct xbps_handle *xhp,
- xbps_object_t obj,
- const char *key UNUSED,
- void *arg,
- bool *done UNUSED)
-{
- char bfile[PATH_MAX];
- xbps_dictionary_t filesd;
- xbps_array_t files_keys;
- struct ffdata *ffd = arg;
- const char *pkgver = NULL;
- int r;
-
- xbps_dictionary_set_cstring_nocopy(obj, "repository", ffd->repouri);
- xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
-
- r = xbps_pkg_path_or_url(xhp, bfile, sizeof(bfile), obj);
- if (r < 0) {
- xbps_error_printf("could not get package path: %s\n", strerror(-r));
- return -r;
+ if (!xbps_repository_is_remote(repouri)) {
+ files_uri = xbps_xasprintf("%s/%s-files", repouri, xh->target_arch ? xh->target_arch : xh->native_arch);
+ } else {
+ if (!(reponame_escaped = xbps_get_remote_repo_string(repouri)))
+ return false;
+ files_uri = xbps_xasprintf("%s/%s/%s-files", xh->metadir, reponame_escaped, xh->target_arch ? xh->target_arch : xh->native_arch);
+ free(reponame_escaped);
}
- filesd = xbps_archive_fetch_plist(bfile, "/files.plist");
- if (!filesd) {
- xbps_error_printf("%s: couldn't fetch files.plist from %s: %s\n",
- pkgver, bfile, strerror(errno));
- return EINVAL;
+
+ if ((ar_file = fopen(files_uri, "r")) == NULL) {
+ xbps_dbg_printf("[repo] `%s' failed to open file-data archive %s\n", files_uri, strerror(errno));
+ return false;
}
- files_keys = xbps_dictionary_all_keys(filesd);
- for (unsigned int i = 0; i < xbps_array_count(files_keys); i++) {
- match_files_by_pattern(filesd,
- xbps_array_get(files_keys, i), ffd, pkgver);
+
+ ar = archive_read_new();
+ assert(ar);
+
+ archive_read_support_filter_gzip(ar);
+ archive_read_support_filter_bzip2(ar);
+ archive_read_support_filter_xz(ar);
+ archive_read_support_filter_lz4(ar);
+ archive_read_support_filter_zstd(ar);
+ archive_read_support_format_tar(ar);
+
+ if (archive_read_open_FILE(ar, ar_file) != ARCHIVE_OK) {
+ xbps_dbg_printf("[repo] `%s' failed to open repodata archive %s\n", files_uri, archive_error_string(ar));
+ archive_read_close(ar);
+ fclose(ar_file);
+ return false;
}
- xbps_object_release(files_keys);
- xbps_object_release(filesd);
+ maxthreads = (int) sysconf(_SC_NPROCESSORS_ONLN);
+ if (maxthreads <= 1) {
+ struct thread_data thd = {
+ .ar = ar,
+ .byhash = byhash,
+ .expr = expr,
+ .regex = regex,
+ .archive_mutex = NULL,
+ .print_mutex = NULL
+ };
+
+ thread_func(&thd);
+ } else {
+ thds = calloc(maxthreads, sizeof(*thds));
+ assert(thds);
+
+ pthread_mutex_init(&archive_mutex, NULL);
+ pthread_mutex_init(&print_mutex, NULL);
+
+ for (int i = 0; i < maxthreads; i++) {
+ int rv;
+
+ thds[i].ar = ar;
+ thds[i].byhash = byhash;
+ thds[i].expr = expr;
+ thds[i].regex = regex;
+ thds[i].archive_mutex = &archive_mutex;
+ thds[i].print_mutex = &print_mutex;
+
+ if ((rv = pthread_create(&thds[i].this_thread, NULL, thread_func, &thds[i])) != 0) {
+ xbps_error_printf("unable to create thread: %s, retrying...\n", strerror(rv));
+ i--;
+ }
+ }
+
+ for (int i = 0; i < maxthreads; i++) {
+ pthread_join(thds[i].this_thread, NULL);
+ }
+ }
+
+ fclose(ar_file);
+ free(files_uri);
return 0;
}
-static int
-repo_ownedby_cb(struct xbps_repo *repo, void *arg, bool *done UNUSED)
-{
- xbps_array_t allkeys;
- struct ffdata *ffd = arg;
- int rv;
+int ownedby(struct xbps_handle* xh, const char* file, bool repo_mode UNUSED, bool useregex) {
+ const char* expr = NULL;
+ regex_t regex;
- ffd->repouri = repo->uri;
- allkeys = xbps_dictionary_all_keys(repo->idx);
- rv = xbps_array_foreach_cb_multi(repo->xhp, allkeys, repo->idx, repo_match_cb, ffd);
- xbps_object_release(allkeys);
+ if (useregex) {
+ if (regcomp(®ex, file, REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) {
+ xbps_error_printf("xbps-locate: invalid regular expression\n");
+ exit(1);
+ }
+ } else {
+ expr = file;
+ }
- return rv;
-}
+ for (unsigned int i = 0; i < xbps_array_count(xh->repositories); i++) {
+ const char* repo_uri;
+ xbps_array_get_cstring_nocopy(xh->repositories, i, &repo_uri);
+ repo_search_files(xh, repo_uri, false, expr, ®ex);
+ }
-int
-ownedby(struct xbps_handle *xhp, const char *pat, bool repo, bool regex)
-{
- struct ffdata ffd;
- int rv;
+ if (useregex)
+ regfree(®ex);
- ffd.rematch = false;
- ffd.pat = pat;
+ return 0;
+}
+
+int ownedhash(struct xbps_handle* xh, const char* file, bool repo_mode UNUSED, bool regex UNUSED) {
+ const char* expr;
+ struct stat fstat;
+ char hash[XBPS_SHA256_SIZE];
- if (regex) {
- ffd.rematch = true;
- if (regcomp(&ffd.regex, ffd.pat, REG_EXTENDED|REG_NOSUB|REG_ICASE) != 0)
- return EINVAL;
+ if (stat(file, &fstat) != -1) {
+ if (!S_ISREG(fstat.st_mode)) {
+ xbps_error_printf("query: `%s' exist but is not a regular file\n", file);
+ return 1;
+ }
+ if (!xbps_file_sha256(hash, sizeof(hash), file)) {
+ xbps_error_printf("query: cannot get hash of `%s': %s\n", file, strerror(errno));
+ return 1;
+ }
+ expr = hash;
+ } else {
+ expr = file;
}
- if (repo)
- rv = xbps_rpool_foreach(xhp, repo_ownedby_cb, &ffd);
- else
- rv = xbps_pkgdb_foreach_cb(xhp, ownedby_pkgdb_cb, &ffd);
- if (regex)
- regfree(&ffd.regex);
+ for (unsigned int i = 0; i < xbps_array_count(xh->repositories); i++) {
+ const char* repo_uri;
+ xbps_array_get_cstring_nocopy(xh->repositories, i, &repo_uri);
+ repo_search_files(xh, repo_uri, true, expr, NULL);
+ }
- return rv;
+ return 0;
}
diff --git a/bin/xbps-rindex/Makefile b/bin/xbps-rindex/Makefile
index 6dc200fb4..5e62569ce 100644
--- a/bin/xbps-rindex/Makefile
+++ b/bin/xbps-rindex/Makefile
@@ -2,7 +2,7 @@ TOPDIR = ../..
-include $(TOPDIR)/config.mk
BIN = xbps-rindex
-OBJS = main.o index-add.o index-clean.o remove-obsoletes.o repoflush.o sign.o
+OBJS = main.o index-add.o files-add.o index-clean.o remove-obsoletes.o repoflush.o sign.o
include $(TOPDIR)/mk/prog.mk
diff --git a/bin/xbps-rindex/defs.h b/bin/xbps-rindex/defs.h
index d99b59f38..2de6b0086 100644
--- a/bin/xbps-rindex/defs.h
+++ b/bin/xbps-rindex/defs.h
@@ -31,7 +31,10 @@
#define _XBPS_RINDEX "xbps-rindex"
/* From index-add.c */
-int index_add(struct xbps_handle *, int, int, char **, bool, const char *);
+int index_add(struct xbps_handle *, int, int, char **, bool, const char *, int*);
+
+/* From files-add.c */
+int files_add(struct xbps_handle *, int, int, char **, bool, const char *, int*, int*);
/* From index-clean.c */
int index_clean(struct xbps_handle *, const char *, bool, const char *);
@@ -45,7 +48,7 @@ int sign_repo(struct xbps_handle *, const char *, const char *,
int sign_pkgs(struct xbps_handle *, int, int, char **, const char *, bool);
/* From repoflush.c */
-bool repodata_flush(struct xbps_handle *, const char *, const char *,
- xbps_dictionary_t, xbps_dictionary_t, const char *);
+bool repodata_flush(struct xbps_handle *, const char *, const char *, xbps_dictionary_t, xbps_dictionary_t, const char *);
+bool repodata_flush_files(struct xbps_handle *, const char *, const char *, const char *);
#endif /* !_XBPS_RINDEX_DEFS_H_ */
diff --git a/bin/xbps-rindex/files-add.c b/bin/xbps-rindex/files-add.c
new file mode 100644
index 000000000..660aa809a
--- /dev/null
+++ b/bin/xbps-rindex/files-add.c
@@ -0,0 +1,432 @@
+/*-
+ * Copyright (c) 2023 Friedel Schon.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+#include "xbps/xbps_array.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define OPEN_AR_READ(ar) \
+ { \
+ (ar) = archive_read_new(); \
+ assert(ar); \
+ archive_read_support_filter_gzip(ar); \
+ archive_read_support_filter_bzip2(ar); \
+ archive_read_support_filter_xz(ar); \
+ archive_read_support_filter_lz4(ar); \
+ archive_read_support_filter_zstd(ar); \
+ archive_read_support_format_tar(ar); \
+ }
+
+
+static void
+list_packages(xbps_array_t dest, struct archive* ar) {
+ struct archive_entry* entry;
+ const char* path;
+
+ while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
+ path = archive_entry_pathname(entry);
+ if (strcmp(path, "HASHES") == 0)
+ continue;
+ xbps_array_add_cstring(dest, path);
+ archive_read_data_skip(ar);
+ }
+}
+
+static const char* match_pkgname_in_array(xbps_array_t array, const char* str) {
+ xbps_object_iterator_t iter;
+ xbps_object_t obj;
+ const char* pkgdep = NULL;
+ char pkgname[XBPS_NAME_SIZE];
+
+ assert(xbps_object_type(array) == XBPS_TYPE_ARRAY);
+ assert(str != NULL);
+
+ iter = xbps_array_iterator(array);
+ assert(iter);
+
+ while ((obj = xbps_object_iterator_next(iter))) {
+ /* match by pkgname against pkgver */
+ pkgdep = xbps_string_cstring_nocopy(obj);
+ if (!xbps_pkg_name(pkgname, XBPS_NAME_SIZE, pkgdep))
+ break;
+ if (strcmp(pkgname, str) == 0) {
+ xbps_object_iterator_release(iter);
+ return pkgdep;
+ }
+ }
+
+ xbps_object_iterator_release(iter);
+ return NULL;
+}
+
+static inline struct archive_entry*
+make_entry(const char* pkgname, size_t size) {
+ struct archive_entry* entry;
+
+ entry = archive_entry_new();
+ if (entry == NULL)
+ return NULL;
+
+ archive_entry_set_filetype(entry, AE_IFREG);
+ archive_entry_set_perm(entry, 0644);
+ archive_entry_set_uname(entry, "root");
+ archive_entry_set_gname(entry, "root");
+ archive_entry_set_pathname(entry, pkgname);
+ archive_entry_set_size(entry, size);
+
+ return entry;
+}
+
+static inline int
+make_file_string(xbps_dictionary_t pkg, char* buffer, int buffer_size) {
+ const char *pkg_file, *pkg_target, *pkg_sha256;
+ int result;
+
+ if (!xbps_dictionary_get_cstring_nocopy(pkg, "file", &pkg_file))
+ return errno = EINVAL, 0;
+
+ if (!xbps_dictionary_get_cstring_nocopy(pkg, "target", &pkg_target))
+ pkg_target = "";
+
+ if (!xbps_dictionary_get_cstring_nocopy(pkg, "sha256", &pkg_sha256))
+ pkg_sha256 = "";
+
+ if ((result = snprintf(buffer, buffer_size, "%s%%%s%%%s\n", pkg_sha256, pkg_file, pkg_target)) >= buffer_size)
+ return errno = ENOBUFS, 0;
+
+ if (result == -1)
+ return 0;
+
+ return result;
+}
+
+static inline int
+length_file_string(xbps_dictionary_t pkg) {
+ const char* field;
+ size_t size = 3; // 2x ':' + '\n'
+
+ size += xbps_dictionary_get_cstring_nocopy(pkg, "file", &field)
+ ? strlen(field)
+ : 0;
+
+ size += xbps_dictionary_get_cstring_nocopy(pkg, "target", &field)
+ ? strlen(field)
+ : 0;
+
+ size += xbps_dictionary_get_cstring_nocopy(pkg, "sha256", &field)
+ ? strlen(field)
+ : 0;
+
+ return size;
+}
+
+int files_add(struct xbps_handle* xhp, int args, int argmax, char** argv, bool force, const char* compression, int* count_added, int* count_total) {
+ static char pkg_line[4096];
+ xbps_dictionary_t props_plist, files_plist;
+ xbps_array_t existing_files, ignore_packages;
+ char * tmprepodir = NULL, *repodir = NULL, *new_ar_path, *rlockfname = NULL, *files_uri = NULL;
+ int rv = 0, ret = 0, rlockfd = -1;
+ FILE* old_ar_file;
+ int new_ar_file;
+ struct archive * old_ar = NULL, *new_ar;
+ struct archive_entry* entry;
+ mode_t mask;
+
+ *count_added = 0, *count_total = 0;
+
+ existing_files = xbps_array_create();
+ ignore_packages = xbps_array_create();
+
+ assert(argv);
+ /*
+ * Read the repository data or create index dictionaries otherwise.
+ */
+ if ((tmprepodir = strdup(argv[args])) == NULL)
+ return ENOMEM;
+
+ repodir = dirname(tmprepodir);
+ if (!xbps_repo_lock(xhp, repodir, &rlockfd, &rlockfname)) {
+ xbps_error_printf("xbps-rindex: cannot lock repository "
+ "%s: %s\n",
+ repodir, strerror(errno));
+ rv = -1;
+ goto out;
+ }
+
+ files_uri = xbps_repo_path_with_name(xhp, repodir, "files");
+ if ((old_ar_file = fopen(files_uri, "r")) == NULL) {
+ if (errno != ENOENT) {
+ xbps_error_printf("[repo] `%s' failed to open archive %s\n", files_uri, strerror(errno));
+ goto out;
+ }
+ } else {
+ OPEN_AR_READ(old_ar);
+
+ if (archive_read_open_FILE(old_ar, old_ar_file) == ARCHIVE_FATAL) {
+ xbps_dbg_printf("[repo] `%s' failed to open repodata archive %s\n", files_uri, archive_error_string(old_ar));
+ return false;
+ }
+
+ list_packages(existing_files, old_ar);
+ *count_total = xbps_array_count(existing_files);
+ archive_read_close(old_ar);
+ fseek(old_ar_file, 0, SEEK_SET);
+ OPEN_AR_READ(old_ar);
+ if (archive_read_open_FILE(old_ar, old_ar_file) == ARCHIVE_FATAL) {
+ xbps_dbg_printf("[repo] `%s' failed to open repodata archive %s\n", files_uri, archive_error_string(old_ar));
+ return false;
+ }
+ }
+
+ new_ar_path = xbps_xasprintf("%s.XXXXXXXXXX", files_uri);
+ assert(new_ar_path);
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+ if ((new_ar_file = mkstemp(new_ar_path)) == -1)
+ return false;
+
+ umask(mask);
+
+ new_ar = archive_write_new();
+ assert(new_ar);
+
+ if (compression == NULL || strcmp(compression, "zstd") == 0) {
+ archive_write_add_filter_zstd(new_ar);
+ archive_write_set_options(new_ar, "compression-level=9");
+ } else if (strcmp(compression, "gzip") == 0) {
+ archive_write_add_filter_gzip(new_ar);
+ archive_write_set_options(new_ar, "compression-level=9");
+ } else if (strcmp(compression, "bzip2") == 0) {
+ archive_write_add_filter_bzip2(new_ar);
+ archive_write_set_options(new_ar, "compression-level=9");
+ } else if (strcmp(compression, "lz4") == 0) {
+ archive_write_add_filter_lz4(new_ar);
+ archive_write_set_options(new_ar, "compression-level=9");
+ } else if (strcmp(compression, "xz") == 0) {
+ archive_write_add_filter_xz(new_ar);
+ archive_write_set_options(new_ar, "compression-level=9");
+ } else if (strcmp(compression, "none") == 0) {
+ /* empty */
+ } else {
+ return false;
+ }
+
+ archive_write_set_format_pax_restricted(new_ar);
+ if (archive_write_open_fd(new_ar, new_ar_file) != ARCHIVE_OK)
+ return false;
+
+ /*
+ * Process all packages specified in argv.
+ */
+ for (int i = args; i < argmax; i++) {
+ const char * arch = NULL, *pkg = argv[i], *dbpkgver = NULL, *pkgname = NULL, *pkgver = NULL;
+ struct archive_entry* file_entry;
+ xbps_array_t keys;
+ size_t total_size = 0;
+
+ assert(pkg);
+ /*
+ * Read metadata props plist dictionary from binary package.
+ */
+ if ((props_plist = xbps_archive_fetch_plist(pkg, "/props.plist")) == NULL) {
+ xbps_error_printf("index: failed to read %s metadata for `%s', skipping!\n", XBPS_PKGPROPS, pkg);
+ continue;
+ }
+
+ xbps_dictionary_get_cstring_nocopy(props_plist, "architecture", &arch);
+ xbps_dictionary_get_cstring_nocopy(props_plist, "pkgver", &pkgver);
+ if (!xbps_pkg_arch_match(xhp, arch, NULL)) {
+ fprintf(stderr, "index: skipping %s, unmatched arch (%s)\n", pkgver, arch);
+ xbps_object_release(props_plist);
+ }
+
+ xbps_dictionary_get_cstring_nocopy(props_plist, "pkgname", &pkgname);
+ if (!force && (dbpkgver = match_pkgname_in_array(existing_files, pkgname))) {
+ /* Only check version if !force */
+ ret = xbps_cmpver(pkgver, dbpkgver);
+
+ /*
+ * If the considered package reverts the package in the index,
+ * consider the current package as the newer one.
+ */
+ if (ret < 0 && xbps_pkg_reverts(props_plist, dbpkgver)) {
+ ret = 1;
+ /*
+ * If package in the index reverts considered package, consider the
+ * package in the index as the newer one.
+ */
+ } else if (ret > 0 && xbps_pkg_reverts(props_plist, pkgver)) {
+ ret = -1;
+ }
+
+ /* Same version or index version greater */
+ if (ret <= 0) {
+ xbps_object_release(props_plist);
+ continue;
+ }
+
+ xbps_array_add_cstring(ignore_packages, dbpkgver);
+
+ (*count_total)--;
+ printf("files: updating `%s' -> `%s' (%s)\n", dbpkgver, pkgver, arch);
+ }
+
+ if ((files_plist = xbps_archive_fetch_plist(pkg, "/files.plist")) == NULL) {
+ xbps_error_printf("files: failed to read files.plist metadata for `%s', skipping!\n", pkg);
+ xbps_object_release(props_plist);
+ continue;
+ }
+
+ keys = xbps_dictionary_all_keys(files_plist);
+ for (unsigned int j = 0; j < xbps_array_count(keys); j++) {
+ xbps_array_t files = xbps_dictionary_get_keysym(files_plist, xbps_array_get(keys, j));
+
+ for (unsigned int k = 0; k < xbps_array_count(files); k++)
+ total_size += length_file_string(xbps_array_get(files, k));
+ }
+
+ file_entry = make_entry(pkgver, total_size);
+ if (archive_write_header(new_ar, file_entry) != ARCHIVE_OK) {
+ xbps_warn_printf("files: unable to write entry for %s: %s\n", pkgver, archive_error_string(new_ar));
+ archive_entry_free(file_entry);
+ xbps_object_release(props_plist);
+ xbps_object_release(files_plist);
+ continue;
+ }
+
+ for (unsigned int j = 0; j < xbps_array_count(keys); j++) {
+ int size;
+ xbps_array_t files = xbps_dictionary_get_keysym(files_plist, xbps_array_get(keys, j));
+
+ for (unsigned int k = 0; k < xbps_array_count(files); k++) {
+ if (!(size = make_file_string(xbps_array_get(files, k), pkg_line, sizeof(pkg_line)))) {
+ xbps_warn_printf("files: unable to create file-entry for %s: %s\n", pkgver, strerror(errno));
+ continue;
+ }
+
+ if (archive_write_data(new_ar, pkg_line, size) == -1) {
+ xbps_warn_printf("files: unable to file-write entry for %s: %s\n", pkgver, archive_error_string(new_ar));
+ continue;
+ }
+ }
+ }
+
+
+ if (archive_write_finish_entry(new_ar) != ARCHIVE_OK) {
+ archive_entry_free(file_entry);
+ exit(archive_errno(new_ar));
+ }
+ archive_entry_free(file_entry);
+
+ (*count_added)++;
+ (*count_total)++;
+ printf("files: added `%s' (%s)\n", pkgver, arch);
+
+ xbps_object_release(props_plist);
+ xbps_object_release(files_plist);
+ }
+
+ if (*count_added > 0) {
+ if (old_ar != NULL) {
+ char buffer[1024];
+ size_t buffer_size;
+ const char* pkgname;
+
+ while (archive_read_next_header(old_ar, &entry) == ARCHIVE_OK) {
+ pkgname = archive_entry_pathname(entry);
+ if (xbps_match_string_in_array(ignore_packages, pkgname)) {
+ archive_read_data_skip(old_ar);
+ continue;
+ }
+
+ printf("files: copying `%s' from old archive\n", pkgname);
+
+ if (archive_write_header(new_ar, entry) != ARCHIVE_OK) {
+ archive_entry_free(entry);
+ continue;
+ }
+
+ while ((buffer_size = archive_read_data(old_ar, buffer, sizeof(buffer))) > 0) {
+ assert(archive_write_data(new_ar, buffer, buffer_size) > 0);
+ }
+
+ archive_write_finish_entry(new_ar);
+ }
+
+ archive_read_free(old_ar);
+ }
+ /* Write data to tempfile and rename */
+ if (archive_write_close(new_ar) != ARCHIVE_OK)
+ return false;
+ if (archive_write_free(new_ar) != ARCHIVE_OK)
+ return false;
+
+ if (fchmod(new_ar_file, 0664) == -1) {
+ close(new_ar_file);
+ unlink(new_ar_path);
+ goto out;
+ }
+ close(new_ar_file);
+ if (rename(new_ar_path, files_uri) == -1) {
+ unlink(new_ar_path);
+ goto out;
+ }
+ } else {
+ if (old_ar != NULL)
+ archive_read_free(old_ar);
+
+ /* Write data to tempfile and rename */
+ if (archive_write_close(new_ar) != ARCHIVE_OK)
+ return false;
+ if (archive_write_free(new_ar) != ARCHIVE_OK)
+ return false;
+
+ close(new_ar_file);
+ unlink(new_ar_path);
+ }
+
+out:
+ xbps_repo_unlock(rlockfd, rlockfname);
+
+ if (tmprepodir)
+ free(tmprepodir);
+
+ return rv;
+}
diff --git a/bin/xbps-rindex/index-add.c b/bin/xbps-rindex/index-add.c
index 00b3132c9..fc3c25d40 100644
--- a/bin/xbps-rindex/index-add.c
+++ b/bin/xbps-rindex/index-add.c
@@ -200,7 +200,7 @@ repodata_commit(struct xbps_handle *xhp, const char *repodir,
}
int
-index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force, const char *compression)
+index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force, const char *compression, int *count)
{
xbps_dictionary_t idx, idxmeta, idxstage, binpkgd, curpkgd;
struct xbps_repo *repo = NULL, *stage = NULL;
@@ -383,7 +383,7 @@ index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force
_XBPS_RINDEX, strerror(errno));
goto out;
}
- printf("index: %u packages registered.\n", xbps_dictionary_count(idx));
+ *count = xbps_dictionary_count(idx);
out:
xbps_object_release(idx);
diff --git a/bin/xbps-rindex/main.c b/bin/xbps-rindex/main.c
index da80d3d00..4a156d827 100644
--- a/bin/xbps-rindex/main.c
+++ b/bin/xbps-rindex/main.c
@@ -159,9 +159,16 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
- if (add_mode)
- rv = index_add(&xh, optind, argc, argv, force, compression);
- else if (clean_mode)
+ if (add_mode) {
+ int index_count = 0, files_count = 0, files_added = 0;
+
+ rv = index_add(&xh, optind, argc, argv, force, compression, &index_count);
+ if (rv == 0)
+ rv = files_add(&xh, optind, argc, argv, force, compression, &files_added, &files_count);
+
+ printf("index: %d packages registered\n", index_count);
+ printf("files: %d packages registered, %d new packages\n", files_count, files_added);
+ } else if (clean_mode)
rv = index_clean(&xh, argv[optind], hashcheck, compression);
else if (rm_mode)
rv = remove_obsoletes(&xh, argv[optind]);
diff --git a/include/xbps.h.in b/include/xbps.h.in
index 5ccd51e94..70b6beafb 100644
--- a/include/xbps.h.in
+++ b/include/xbps.h.in
@@ -121,6 +121,12 @@
*/
#define XBPS_REPOIDX_META "index-meta.plist"
+/**
+ * @def XBPS_REPO_FILES
+ * Filename for the repository files property list.
+ */
+#define XBPS_REPO_FILES "files.plist"
+
/**
* @def XBPS_FLAG_VERBOSE
* Verbose flag that can be used in the function callbacks to alter
@@ -1431,7 +1437,13 @@ struct xbps_repo {
*
* Proplib dictionary associated with the repository index-meta.
*/
- xbps_dictionary_t idxmeta;
+ xbps_dictionary_t idxmeta;
+ /**
+ * @var files
+ *
+ * Proplib dictionary associated with the repository files.
+ */
+ xbps_dictionary_t files;
/**
* @var uri
*
@@ -1442,6 +1454,12 @@ struct xbps_repo {
* @private
*/
int fd;
+ /**
+ * @var filear
+ *
+ * archive_read instance for *-files
+ */
+ struct archive *filear;
/**
* var is_remote
*
@@ -1471,6 +1489,8 @@ void xbps_rpool_release(struct xbps_handle *xhp);
*/
int xbps_rpool_sync(struct xbps_handle *xhp, const char *uri);
+int xbps_rpool_sync_files(struct xbps_handle* xhp);
+
/**
* Iterates over the repository pool and executes the \a fn function
* callback passing in the void * \a arg argument to it. The bool pointer
@@ -2368,6 +2388,11 @@ xbps_plist_array_from_file(const char *path);
xbps_dictionary_t
xbps_plist_dictionary_from_file(const char *path);
+/**
+
+*/
+char* xbps_get_remote_repo_string(const char *path);
+
/**@}*/
#ifdef __cplusplus
diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h
index aac5b11b5..f4a7f8d7f 100644
--- a/include/xbps_api_impl.h
+++ b/include/xbps_api_impl.h
@@ -99,7 +99,6 @@ int HIDDEN xbps_transaction_fetch(struct xbps_handle *,
int HIDDEN xbps_transaction_pkg_deps(struct xbps_handle *, xbps_array_t, xbps_dictionary_t);
int HIDDEN xbps_transaction_internalize(struct xbps_handle *, xbps_object_iterator_t);
-char HIDDEN *xbps_get_remote_repo_string(const char *);
int HIDDEN xbps_repo_sync(struct xbps_handle *, const char *);
int HIDDEN xbps_file_hash_check_dictionary(struct xbps_handle *,
xbps_dictionary_t, const char *, const char *);
@@ -120,5 +119,6 @@ xbps_array_t HIDDEN xbps_get_pkg_fulldeptree(struct xbps_handle *,
struct xbps_repo HIDDEN *xbps_regget_repo(struct xbps_handle *,
const char *);
int HIDDEN xbps_conf_init(struct xbps_handle *);
+int HIDDEN xbps_repo_sync_files(struct xbps_handle* xh, const char* uri);
#endif /* !_XBPS_API_IMPL_H_ */
diff --git a/lib/Makefile b/lib/Makefile
index 0cf6ac84f..481f82cc7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -48,7 +48,7 @@ OBJS += pubkey2fp.o package_fulldeptree.o
OBJS += download.o initend.o pkgdb.o
OBJS += plist.o plist_find.o plist_match.o archive.o
OBJS += plist_remove.o plist_fetch.o util.o util_path.o util_hash.o
-OBJS += repo.o repo_sync.o
+OBJS += repo.o repo_sync.o repo_sync_files.o
OBJS += rpool.o cb_util.o proplib_wrapper.o
OBJS += package_alternatives.o
OBJS += conf.o log.o
diff --git a/lib/repo.c b/lib/repo.c
index 8d2aa6bd1..6808f9716 100644
--- a/lib/repo.c
+++ b/lib/repo.c
@@ -40,6 +40,7 @@
#include
#include
+#include "fetch.h"
#include "xbps_api_impl.h"
/**
@@ -58,7 +59,7 @@ xbps_repo_path_with_name(struct xbps_handle *xhp, const char *url, const char *n
{
assert(xhp);
assert(url);
- assert(strcmp(name, "repodata") == 0 || strcmp(name, "stagedata") == 0);
+ assert(strcmp(name, "repodata") == 0 || strcmp(name, "stagedata") == 0 || strcmp(name, "files") == 0);
return xbps_xasprintf("%s/%s-%s",
url, xhp->target_arch ? xhp->target_arch : xhp->native_arch, name);
@@ -707,3 +708,39 @@ xbps_repo_key_import(struct xbps_repo *repo)
free(rkeyfile);
return rv;
}
+
+char*
+xbps_get_remote_repo_string(const char *uri)
+{
+ struct url *url;
+ size_t i;
+ char *p;
+
+ if ((url = fetchParseURL(uri)) == NULL)
+ return NULL;
+
+ /*
+ * Replace '.' ':' and '/' characters with underscores, so that
+ * provided URL:
+ *
+ * http://nocturno.local:8080/repo/x86_64
+ *
+ * becomes:
+ *
+ * http___nocturno_local_8080_repo_x86_64
+ */
+ if (url->port != 0)
+ p = xbps_xasprintf("%s://%s:%u%s", url->scheme,
+ url->host, url->port, url->doc);
+ else
+ p = xbps_xasprintf("%s://%s%s", url->scheme,
+ url->host, url->doc);
+
+ fetchFreeURL(url);
+ for (i = 0; i < strlen(p); i++) {
+ if (p[i] == '.' || p[i] == '/' || p[i] == ':')
+ p[i] = '_';
+ }
+
+ return p;
+}
\ No newline at end of file
diff --git a/lib/repo_sync.c b/lib/repo_sync.c
index 2f803a0c4..8eedc2c06 100644
--- a/lib/repo_sync.c
+++ b/lib/repo_sync.c
@@ -34,42 +34,6 @@
#include "xbps_api_impl.h"
#include "fetch.h"
-char HIDDEN *
-xbps_get_remote_repo_string(const char *uri)
-{
- struct url *url;
- size_t i;
- char *p;
-
- if ((url = fetchParseURL(uri)) == NULL)
- return NULL;
-
- /*
- * Replace '.' ':' and '/' characters with underscores, so that
- * provided URL:
- *
- * http://nocturno.local:8080/repo/x86_64
- *
- * becomes:
- *
- * http___nocturno_local_8080_repo_x86_64
- */
- if (url->port != 0)
- p = xbps_xasprintf("%s://%s:%u%s", url->scheme,
- url->host, url->port, url->doc);
- else
- p = xbps_xasprintf("%s://%s%s", url->scheme,
- url->host, url->doc);
-
- fetchFreeURL(url);
- for (i = 0; i < strlen(p); i++) {
- if (p[i] == '.' || p[i] == '/' || p[i] == ':')
- p[i] = '_';
- }
-
- return p;
-}
-
/*
* Returns -1 on error, 0 if transfer was not necessary (local/remote
* size and/or mtime match) and 1 if downloaded successfully.
diff --git a/lib/repo_sync_files.c b/lib/repo_sync_files.c
new file mode 100644
index 000000000..005826bc4
--- /dev/null
+++ b/lib/repo_sync_files.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2009-2014 Juan Romero Pardines.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "xbps.h"
+#include "xbps_api_impl.h"
+#include "fetch.h"
+
+
+int HIDDEN xbps_repo_sync_files(struct xbps_handle* xh, const char* uri) {
+ mode_t prev_umask;
+ const char *arch, *fetchstr = NULL;
+ char * repodata, *lrepodir, *uri_fixedp;
+ int rv = 0;
+
+ /* ignore non remote repositories */
+ if (!xbps_repository_is_remote(uri))
+ return 0;
+
+ uri_fixedp = xbps_get_remote_repo_string(uri);
+ if (uri_fixedp == NULL)
+ return -1;
+
+ if (xh->target_arch)
+ arch = xh->target_arch;
+ else
+ arch = xh->native_arch;
+
+ /*
+ * Full path to repository directory to store the plist
+ * index file.
+ */
+ lrepodir = xbps_xasprintf("%s/%s", xh->metadir, uri_fixedp);
+ free(uri_fixedp);
+ /*
+ * Create repodir in metadir.
+ */
+ prev_umask = umask(022);
+ if ((rv = xbps_mkpath(lrepodir, 0755)) == -1 && errno != EEXIST) {
+ xbps_error_printf("[reposync] to create repodir `%s': %s\n", lrepodir, strerror(errno));
+ umask(prev_umask);
+ free(lrepodir);
+ return rv;
+ }
+ if (chdir(lrepodir) == -1) {
+ xbps_error_printf("[reposync] failed to change dir to repodir `%s': %s\n", lrepodir, strerror(errno));
+ umask(prev_umask);
+ free(lrepodir);
+ return -1;
+ }
+ free(lrepodir);
+ /*
+ * Remote repository plist index full URL.
+ */
+ repodata = xbps_xasprintf("%s/%s-files", uri, arch);
+
+ /* reposync start cb */
+ printf("[*] Updating file-database `%s' ...\n", repodata);
+ /*
+ * Download plist index file from repository.
+ */
+ if ((rv = xbps_fetch_file(xh, repodata, NULL)) != 1 && fetchLastErrCode != FETCH_UNCHANGED) {
+ /* reposync error cb */
+ fetchstr = xbps_fetch_error_string();
+
+ xbps_error_printf("[reposync] failed to fetch file `%s': %s\n", repodata, fetchstr ? fetchstr : strerror(errno));
+ } else if (rv == 1)
+ rv = 0;
+ umask(prev_umask);
+
+ free(repodata);
+
+ return rv;
+}
+
+int xbps_rpool_sync_files(struct xbps_handle* xhp) {
+ const char* repouri = NULL;
+
+ for (unsigned int i = 0; i < xbps_array_count(xhp->repositories); i++) {
+ xbps_array_get_cstring_nocopy(xhp->repositories, i, &repouri);
+ if (xbps_repo_sync_files(xhp, repouri) == -1) {
+ xbps_dbg_printf(
+ "[rpool] `%s' failed to fetch repository data: %s\n",
+ repouri, fetchLastErrCode == 0 ? strerror(errno) : xbps_fetch_error_string());
+ continue;
+ }
+ }
+ return 0;
+}
\ No newline at end of file