From 5c3047a780035bff18eb75306ff7c4063da87216 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Mon, 8 Jul 2024 12:27:35 +0200 Subject: [PATCH] repo2solv: no longer use "find" to find rpms This commit implements the file tree work needed for the "plaindir" format. Like with the "find" command, we do not follow symlinks to directories in recursive mode. --- package/libsolv.spec.in | 1 - tools/repo2solv.c | 168 ++++++++++++++++++---------------------- 2 files changed, 75 insertions(+), 94 deletions(-) diff --git a/package/libsolv.spec.in b/package/libsolv.spec.in index 59562b37..dde4f7a1 100644 --- a/package/libsolv.spec.in +++ b/package/libsolv.spec.in @@ -182,7 +182,6 @@ Group: System/Management Conflicts: satsolver-tools-obsolete Obsoletes: satsolver-tools < 0.18 Provides: satsolver-tools = 0.18 -Requires: findutils Requires: libsolv-tools-base = %{version} %description tools diff --git a/tools/repo2solv.c b/tools/repo2solv.c index b3907439..af9409d7 100644 --- a/tools/repo2solv.c +++ b/tools/repo2solv.c @@ -119,111 +119,93 @@ autodetect_repotype(Pool *pool, const char *dir) #ifdef ENABLE_RPMPKG +static int +plaindir_entry_cmp(const struct dirent **a, const struct dirent **b) +{ + return strcmp((*a)->d_name, (*b)->d_name); +} + int read_plaindir_repo(Repo *repo, const char *dir) { Pool *pool = repo->pool; Repodata *data; - int c; - FILE *fp; - int wstatus; - int fds[2]; - pid_t pid; - char *buf = 0; - char *buf_end = 0; - char *bp = 0; - char *rpm; + Queue todo; + Stringpool ss; + struct dirent **namelist; + int nents, i; + Id p, id; + size_t namel, dirl = strlen(dir); int res = 0; - Id p; + int isfirst = 1; - /* run find command */ - if (pipe(fds)) - { - perror("pipe"); - exit(1); - } - while ((pid = fork()) == (pid_t)-1) - { - if (errno != EAGAIN) - { - perror("fork"); - exit(1); - } - sleep(3); - } - if (pid == 0) - { - if (chdir(dir)) - { - perror(dir); - _exit(1); - } - close(fds[0]); - if (fds[1] != 1) - { - if (dup2(fds[1], 1) == -1) - { - perror("dup2"); - _exit(1); - } - close(fds[1]); - } - if (recursive) - execl("/usr/bin/find", "/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0); - else - execl("/usr/bin/find", "/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0); - perror("/usr/bin/find"); - _exit(1); - } - close(fds[1]); - if ((fp = fdopen(fds[0], "r")) == 0) - { - perror("fdopen"); - exit(1); - } data = repo_add_repodata(repo, 0); - bp = buf; - while ((c = getc(fp)) != EOF) - { - if (bp == buf_end) - { - size_t len = bp - buf; - buf = solv_realloc(buf, len + 4096); - bp = buf + len; - buf_end = bp + 4096; + queue_init(&todo); + stringpool_init_empty(&ss); + queue_push(&todo, stringpool_str2id(&ss, dir, 1)); + while (todo.count) { + id = queue_shift(&todo); + nents = scandir(stringpool_id2str(&ss, id), &namelist, NULL, plaindir_entry_cmp); + if (nents == -1) { + perror(stringpool_id2str(&ss, id)); + if (isfirst) + res = 1; /* return error if we cannot read the passed dir */ + continue; + } + isfirst = 0; + for (i = 0; i < nents; i++) { + struct stat stb; + char *path; + const char *name = namelist[i]->d_name; + int isrpm = 0; + + if (!*name) + continue; + if (*name == '.' && (!name[1] || (name[1] == '.' && !name[2]))) + continue; + namel = strlen(name); + if (namel > 4 && !strcmp(name + namel - 4, ".rpm")) { + isrpm = 1; + if (namel >= 10 && (!strcmp(name + namel - 10, ".patch.rpm") || !strcmp(name + namel - 10, ".delta.rpm"))) + isrpm = 0; + } + if (!isrpm && !recursive) + continue; + path = pool_tmpjoin(pool, stringpool_id2str(&ss, id), "/", name); + if (lstat(path, &stb)) { + perror(path); + continue; + } + if (S_ISLNK(stb.st_mode)) { + if (stat(path, &stb)) { + perror(path); + continue; } - *bp++ = c; - if (c) + if (S_ISDIR(stb.st_mode)) + continue; /* ignore symlinks to directories */ + } + if (S_ISDIR(stb.st_mode)) { + if (recursive) + queue_push(&todo, stringpool_str2id(&ss, path, 1)); + continue; + } + if (!S_ISREG(stb.st_mode)) + continue; + if (!isrpm) continue; - bp = buf; - rpm = solv_dupjoin(dir, "/", bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp); - if ((p = repo_add_rpm(repo, rpm, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0))) == 0) + if ((p = repo_add_rpm(repo, path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0))) == 0) { - fprintf(stderr, "%s: %s\n", rpm, pool_errstr(pool)); -#if 0 - res = 1; -#endif + fprintf(stderr, "%s: %s\n", path, pool_errstr(pool)); + continue; } - else - repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp); - solv_free(rpm); - } - solv_free(buf); - fclose(fp); - while (waitpid(pid, &wstatus, 0) == -1) - { - if (errno == EINTR) - continue; - perror("waitpid"); - exit(1); - } - if (wstatus) - { - fprintf(stderr, "find: exit status %d\n", (wstatus >> 8) | (wstatus & 255) << 8); -#if 0 - res = 1; -#endif - } + repodata_set_location(data, p, 0, 0, path + dirl + 1); + } + for (i = 0; i < nents; i++) + free(namelist[i]); + free(namelist); + } + queue_free(&todo); + stringpool_free(&ss); repo_internalize(repo); return res; } -- 2.47.3