commit: 23c09a20dfcc044343b16bfe4b5873f663a46286 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> AuthorDate: Sun Apr 15 12:03:14 2018 +0000 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> CommitDate: Sun Apr 15 12:03:14 2018 +0000 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=23c09a20
qfile: fix matching of files A bit overenthusiastic check for files in the current directory caused weird directory prefixes to be ignored. Bug: https://bugs.gentoo.org/652720 man/include/qfile-01-owners.include | 9 ++-- qfile.c | 94 ++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 43 deletions(-) diff --git a/man/include/qfile-01-owners.include b/man/include/qfile-01-owners.include index c9ce378..a4bdc76 100644 --- a/man/include/qfile-01-owners.include +++ b/man/include/qfile-01-owners.include @@ -1,13 +1,14 @@ -.SH "FINDING FILES OWNERS" +.SH "FINDING FILE OWNERS" .PP This is the default behavior of \fBqfile\fP. It will list the packages which own the files (or directories, or symlinks, or anything else Portage can -install) you are querying. Query items may be file paths or simple file names. +install) you are querying. Query items may be file paths or simple file +names when the \fB\-b\fP option is used. By default, output includes packages names and the complete paths to the matching files. If using \fB\-\-exact\fP, versions of the packages will also be shown. At the contrary, when using \fB\-\-quiet\fP, only package names are listed, without files paths. Finally, \fB\-\-verbose\fP is similar -to \fB\-\-exact\fP, but may adds a few warnings. The return status of +to \fB\-\-exact\fP, but may add a few warnings. The return status of \fBqfile\fP will be \fI0\fP as soon as an owning package has been found for one of the query items. .PP @@ -19,7 +20,7 @@ Find names of package(s) owning "/bin/bash": .PP Find package(s) owning any file named "bash", and show paths of this files: .nf\fI - $ qfile bash + $ qfile -b bash app-shells/bash (/bin/bash) app-shells/bash (/etc/bash) .fi diff --git a/qfile.c b/qfile.c index 08ba642..285277b 100644 --- a/qfile.c +++ b/qfile.c @@ -118,66 +118,73 @@ static int qfile_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv) goto qlist_done; while (getline(&state->buf, &state->buflen, fp) != -1) { + size_t dirname_len; contents_entry *e; + e = contents_parse_line(state->buf); if (!e) continue; - /* assume sane basename() -- doesnt modify argument */ - if ((base = basename(e->name)) == NULL) + /* basename(3) possibly modifies e->name (if it has trailing + * slashes) but this is not likely since it comes from VDB which + * has normalised everything, so effectively e->name isn't + * touched, however, it /can/ return a pointer to a private + * allocation */ + base = basename(e->name); + if (base < e->name || base > (e->name + strlen(e->name))) continue; + /* basename(/usr) = usr, dirname(/usr) = / + * basename(/usr/bin) = bin, dirname(/usr/bin) = /usr */ + if ((dirname_len = (base - e->name - 1)) == 0) + dirname_len = 1; + for (i = 0; i < args->length; i++) { if (base_names[i] == NULL) continue; if (non_orphans && non_orphans[i]) continue; - /* For optimization of qfile(), we also give it an array of the first char - * of each basename. This way we avoid numerous strcmp() calls. - */ - if (base[0] != base_names[i][0] || strcmp(base, base_names[i])) + /* For optimization of qfile(), we also give it an array of + * the first char of each basename. This way we avoid + * numerous strcmp() calls. */ + if (base[0] != base_names[i][0] || strcmp(base, base_names[i]) != 0) continue; path_ok = false; - /* check the full filepath ... */ - size_t dirname_len = (base - e->name - 1); - /* basename(/usr) = usr, dirname(/usr) = / - * basename(/usr/bin) = bin, dirname(/usr/bin) = /usr - */ - if (dirname_len == 0) - dirname_len = 1; - if (dir_names[i] && strncmp(e->name, dir_names[i], dirname_len) == 0 && - dir_names[i][dirname_len] == '\0') { + dir_names[i][dirname_len] == '\0') + { /* dir_name == dirname(CONTENTS) */ path_ok = true; - } else if (real_dir_names[i] && - strncmp(e->name, real_dir_names[i], dirname_len) == 0 && - real_dir_names[i][dirname_len] == '\0') { + strncmp(e->name, real_dir_names[i], dirname_len) == 0 && + real_dir_names[i][dirname_len] == '\0') + { /* real_dir_name == dirname(CONTENTS) */ path_ok = true; - } else if (real_root[0]) { - char rpath[_Q_PATH_MAX + 1], *_rpath; - char *fullpath; + char rpath[_Q_PATH_MAX + 1]; + char *_rpath; + char fullpath[_Q_PATH_MAX + 1]; size_t real_root_len = state->real_root_len; - xasprintf(&fullpath, "%s%s", real_root, e->name); - fullpath[real_root_len + dirname_len] = '\0'; + snprintf(fullpath, sizeof(fullpath), "%s%s", + real_root, e->name); _rpath = rpath + real_root_len; if (realpath(fullpath, rpath) == NULL) { if (verbose) { - warnp("Could not read real path of \"%s\" (from %s)", fullpath, pkg); - warn("We'll never know whether \"%s\" was a result for your query...", - e->name); + warnp("Could not read real path of \"%s\" (from %s)", + fullpath, pkg); + warn("We'll never know whether \"%s\" was a result " + "for your query...", e->name); } } else if (!qfile_is_prefix(rpath, real_root, real_root_len)) { if (verbose) - warn("Real path of \"%s\" is not under ROOT: %s", fullpath, rpath); + warn("Real path of \"%s\" is not under ROOT: %s", + fullpath, rpath); } else if (dir_names[i] && strcmp(_rpath, dir_names[i]) == 0) { /* dir_name == realpath(dirname(CONTENTS)) */ @@ -187,11 +194,12 @@ static int qfile_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv) /* real_dir_name == realpath(dirname(CONTENTS)) */ path_ok = true; } - free(fullpath); } else if (state->basename) { path_ok = true; - } else if (state->pwd) { - if (!strncmp(e->name, state->pwd, dirname_len)) + } else if (state->pwd && dir_names[i] == NULL) { + /* try to match file in current directory */ + if (strncmp(e->name, state->pwd, dirname_len) == 0 && + state->pwd[dirname_len] == '\0') path_ok = true; } if (!path_ok) @@ -222,7 +230,6 @@ static int qfile_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv) puts(""); else printf(" (%s%s)\n", state->root ? : "", e->name); - } else { non_orphans[i] = 1; } @@ -285,7 +292,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st for (i = 0; i < argc; ++i) { /* Record basename, but if it is ".", ".." or "/" */ - strncpy(abspath, argv[i], _Q_PATH_MAX); /* strncopy so that "argv" can be "const" */ + /* strncopy so that "argv" can be "const" */ + strncpy(abspath, argv[i], _Q_PATH_MAX); strncpy(tmppath, basename(abspath), _Q_PATH_MAX); if ((strlen(tmppath) > 2) || (strncmp(tmppath, "..", strlen(tmppath)) @@ -299,7 +307,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st continue; } - /* Make sure we have an absolute path available (with "realpath(ROOT)" prefix) */ + /* Make sure we have an absolute path available (with + * "realpath(ROOT)" prefix) */ if (argv[i][0] == '/') { if (state->assume_root_prefix) strncpy(abspath, argv[i], _Q_PATH_MAX); @@ -309,9 +318,11 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st if (state->assume_root_prefix) snprintf(abspath, _Q_PATH_MAX, "%s/%s", pwd, argv[i]); else - snprintf(abspath, _Q_PATH_MAX, "%s%s/%s", real_root, pwd, argv[i]); + snprintf(abspath, _Q_PATH_MAX, "%s%s/%s", + real_root, pwd, argv[i]); } else { - warn("$PWD was not found in environment, or is not an absolute path"); + warn("$PWD was not found in environment, " + "or is not an absolute path"); goto skip_query_item; } @@ -328,12 +339,14 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st if (realpath(abspath, tmppath) == NULL) { if (verbose) { warnp("Could not read real path of \"%s\"", abspath); - warn("Results for query item \"%s\" may be inaccurate.", argv[i]); + warn("Results for query item \"%s\" may be inaccurate.", + argv[i]); } continue; } if (!qfile_is_prefix(tmppath, real_root, real_root_len)) { - warn("Real path of \"%s\" is not under ROOT: %s", abspath, tmppath); + warn("Real path of \"%s\" is not under ROOT: %s", + abspath, tmppath); goto skip_query_item; } if (tmppath[real_root_len] == '\0') @@ -350,7 +363,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st goto skip_query_item; } if (!qfile_is_prefix(tmppath, real_root, real_root_len)) { - warn("Real path of \"%s\" is not under ROOT: %s", abspath, tmppath); + warn("Real path of \"%s\" is not under ROOT: %s", + abspath, tmppath); goto skip_query_item; } strncpy(abspath, tmppath, _Q_PATH_MAX); @@ -470,7 +484,9 @@ int qfile_main(int argc, char **argv) if (state.args.non_orphans[i]) continue; if (state.args.basenames[i]) { - found = 0; /* ~inverse return code (as soon as an orphan is found, return non-zero) */ + /* inverse return code (as soon as an orphan is found, + * return non-zero) */ + found = 0; if (!quiet) puts(argv[i]); else