From: Michael Schroeder Date: Mon, 8 Jul 2024 10:27:35 +0000 (+0200) Subject: repo2solv: no longer use "find" to find rpms X-Git-Tag: 0.7.30~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5c3047a780035bff18eb75306ff7c4063da87216;p=thirdparty%2Flibsolv.git 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. --- 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; }