commit: 9220a81b2a67a0c6c4a439f68995523a90de2d61 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> AuthorDate: Fri Apr 18 19:28:52 2025 +0000 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> CommitDate: Fri Apr 18 19:28:52 2025 +0000 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=9220a81b
qfile: avoid repeated strlen() calls during qfile_cb Precompute strlen of dirnames, basename and realdirnames so it can be reused instead of re-computed every time. Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> qfile.c | 172 +++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 95 insertions(+), 77 deletions(-) diff --git a/qfile.c b/qfile.c index efac60e..7fe2685 100644 --- a/qfile.c +++ b/qfile.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2020 Gentoo Foundation + * Copyright 2005-2025 Gentoo Foundation * Distributed under the terms of the GNU General Public License v2 * * Copyright 2005-2010 Ned Ludd - <[email protected]> @@ -51,12 +51,17 @@ static const char * const qfile_opts_help[] = { && !strncmp(path, prefix, prefix_length))) typedef struct { - int length; - char **basenames; - char **dirnames; - char **realdirnames; - short *non_orphans; - int *results; + char *str; + size_t len; +} qfile_str_len_t; + +typedef struct { + size_t length; + qfile_str_len_t *basenames; + qfile_str_len_t *dirnames; + qfile_str_len_t *realdirnames; + short *non_orphans; + int *results; } qfile_args_t; struct qfile_opt_state { @@ -65,6 +70,7 @@ struct qfile_opt_state { qfile_args_t args; char *root; char *pwd; + size_t pwd_len; char *real_root; size_t real_root_len; char *exclude_pkg; @@ -83,7 +89,12 @@ struct qfile_opt_state { */ static int qfile_check_plibreg(void *priv) { - struct qfile_opt_state *state = priv; + struct qfile_opt_state *state = priv; + qfile_args_t *args = &state->args; + qfile_str_len_t *base_names = args->basenames; + qfile_str_len_t *dir_names = args->dirnames; + short *non_orphans = args->non_orphans; + int *results = args->results; char fn_plibreg[_Q_PATH_MAX]; int fd_plibreg; @@ -94,13 +105,7 @@ static int qfile_check_plibreg(void *priv) char *line = NULL; size_t len = 0; int found = 0; - int i; - - qfile_args_t *args = &state->args; - char **base_names = args->basenames; - char **dir_names = args->dirnames; - short *non_orphans = args->non_orphans; - int *results = args->results; + size_t i; /* Open plibreg */ snprintf(fn_plibreg, _Q_PATH_MAX, "%s%s", @@ -119,17 +124,18 @@ static int qfile_check_plibreg(void *priv) } for (i = 0; i < args->length; i++) { - if (base_names[i] == NULL || base_names[i][0] == '\0') + if (base_names[i].len == 0) continue; if (non_orphans && non_orphans[i]) continue; if (results[i] == 1) continue; - if (dir_names[i] != NULL) - snprintf(file, sizeof(file), "%s/%s", dir_names[i], base_names[i]); + if (dir_names[i].len > 0) + snprintf(file, sizeof(file), "%s/%s", + dir_names[i].str, base_names[i].str); else - snprintf(file, sizeof(file), "%s", base_names[i]); + snprintf(file, sizeof(file), "%s", base_names[i].str); while (getline(&line, &len, fp_plibreg) != -1) if (strstr(line, file) != NULL) { @@ -158,23 +164,22 @@ static int qfile_check_plibreg(void *priv) */ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) { - struct qfile_opt_state *state = priv; - const char *catname = pkg_ctx->cat_ctx->name; - qfile_args_t *args = &state->args; + struct qfile_opt_state *state = priv; + const char *catname = pkg_ctx->cat_ctx->name; + char *real_root = state->real_root; + qfile_args_t *args = &state->args; + qfile_str_len_t *base_names = args->basenames; + qfile_str_len_t *dir_names = args->dirnames; + qfile_str_len_t *real_dir_names = args->dirnames; + short *non_orphans = args->non_orphans; + int *results = args->results; char *line; char *savep; const char *base; depend_atom *atom = NULL; - int i; + size_t i; bool path_ok; - char *real_root = state->real_root; - char **base_names = args->basenames; - char **dir_names = args->dirnames; - char **real_dir_names = args->realdirnames; - short *non_orphans = args->non_orphans; - int *results = args->results; int found = 0; - size_t len; /* If exclude_pkg is not NULL, check it. We are looking for files * collisions, and must exclude one package. */ @@ -222,27 +227,28 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) dirname_len = 1; for (i = 0; i < args->length; i++) { - if (base_names[i] == NULL) + if (base_names[i].len == 0) continue; if (non_orphans != NULL && non_orphans[i]) continue; /* Try to avoid numerous strcmp() calls. */ - if (base[0] != base_names[i][0] || strcmp(base, base_names[i]) != 0) + if (base[0] != base_names[i].str[0] || + strcmp(base, base_names[i].str) != 0) continue; path_ok = false; - if (dir_names[i] && (len = strlen(dir_names[i])) > 0 && - len == dirname_len && - memcmp(e->name, dir_names[i], len) == 0) + if (dir_names[i].len > 0 && + dir_names[i].len == dirname_len && + memcmp(e->name, dir_names[i].str, dir_names[i].len) == 0) { /* dir_name == dirname(CONTENTS) */ path_ok = true; - } else if (real_dir_names[i] && - (len = strlen(real_dir_names[i])) > 0 && - len == dirname_len && - memcmp(e->name, real_dir_names[i], len) == 0) + } else if (real_dir_names[i].len > 0 && + real_dir_names[i].len == dirname_len && + memcmp(e->name, real_dir_names[i].str, + real_dir_names[i].len) == 0) { /* real_dir_name == dirname(CONTENTS) */ path_ok = true; @@ -268,12 +274,12 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) if (verbose) warn("Real path of \"%s\" is not under ROOT: %s", fullpath, rpath); - } else if (dir_names[i] && - strcmp(_rpath, dir_names[i]) == 0) { + } else if (dir_names[i].len > 0 && + strcmp(_rpath, dir_names[i].str) == 0) { /* dir_name == realpath(dirname(CONTENTS)) */ path_ok = true; - } else if (real_dir_names[i] && - strcmp(_rpath, real_dir_names[i]) == 0) { + } else if (real_dir_names[i].len > 0 && + strcmp(_rpath, real_dir_names[i].str) == 0) { /* real_dir_name == realpath(dirname(CONTENTS)) */ path_ok = true; } @@ -282,15 +288,17 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) if (!path_ok && state->basename) path_ok = true; - if (!path_ok && state->pwd && dir_names[i] == NULL) { + if (!path_ok && state->pwd && dir_names[i].len == 0) { /* try to match file in current directory */ - if ((len = strlen(state->pwd)) > 0 && - len == dirname_len && - memcmp(e->name, state->pwd, len) == 0) + if (state->pwd_len > 0 && + state->pwd_len == dirname_len && + memcmp(e->name, state->pwd, state->pwd_len) == 0) path_ok = true; } - if (!path_ok && dir_names[i] == NULL && real_dir_names[i] == NULL) { + if (!path_ok && dir_names[i].len == 0 && + real_dir_names[i].len == 0) + { /* basename match */ if (e->type != CONTENTS_DIR) path_ok = true; @@ -327,15 +335,15 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) static void destroy_qfile_args(qfile_args_t *qfile_args) { - int i; + size_t i; for (i = 0; i < qfile_args->length; ++i) { - if (qfile_args->basenames) - free(qfile_args->basenames[i]); - if (qfile_args->dirnames) - free(qfile_args->dirnames[i]); - if (qfile_args->realdirnames) - free(qfile_args->realdirnames[i]); + if (qfile_args->basenames[i].len > 0) + free(qfile_args->basenames[i].str); + if (qfile_args->dirnames[i].len > 0) + free(qfile_args->dirnames[i].str); + if (qfile_args->realdirnames[i].len > 0) + free(qfile_args->realdirnames[i].str); } free(qfile_args->basenames); @@ -358,9 +366,9 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st size_t real_root_len = state->real_root_len; size_t len; char *real_root = state->real_root; - char **basenames = NULL; - char **dirnames = NULL; - char **realdirnames = NULL; + qfile_str_len_t *basenames = NULL; + qfile_str_len_t *dirnames = NULL; + qfile_str_len_t *realdirnames = NULL; int *results = NULL; char tmppath[_Q_PATH_MAX]; char abspath[_Q_PATH_MAX * 2]; @@ -370,9 +378,9 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st * are stored without their $ROOT prefix, but $ROOT is used when * checking realpaths. */ - basenames = xcalloc(argc, sizeof(char*)); - dirnames = xcalloc(argc, sizeof(char*)); - realdirnames = xcalloc(argc, sizeof(char*)); + basenames = xcalloc(argc, sizeof(basenames[0])); + dirnames = xcalloc(argc, sizeof(dirnames[0])); + realdirnames = xcalloc(argc, sizeof(realdirnames[0])); results = xcalloc(argc, sizeof(int)); for (i = 0; i < argc; ++i) { @@ -389,7 +397,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st (strncmp(tmppath, "..", len) != 0 && strncmp(tmppath, "/", len) != 0)) { - basenames[i] = xstrdup(p); + basenames[i].str = xstrdup(p); + basenames[i].len = strlen(p); /* If there is no "/" in the argument, then it's over. * (we are searching a simple file name) */ if (strchr(argv[i], '/') == NULL) @@ -413,14 +422,15 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st goto skip_query_item; } - if (basenames[i] != NULL) { + if (basenames[i].len > 0) { /* Get both the dirname and its realpath. These paths will * have no trailing slash, except if it is the only char (ie., * when searching for "/foobar"). */ snprintf(tmppath, sizeof(tmppath), "%s%s", dirname(abspath), abspath[real_root_len] == '\0' ? "/" : ""); - dirnames[i] = xstrdup(tmppath + real_root_len); + dirnames[i].str = xstrdup(tmppath + real_root_len); + dirnames[i].len = strlen(dirnames[i].str); if (realpath(tmppath, abspath) == NULL) { if (verbose) { warnp("Could not read real path of \"%s\"", tmppath); @@ -434,8 +444,11 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st tmppath, abspath); goto skip_query_item; } - if (strcmp(dirnames[i], abspath + real_root_len)) - realdirnames[i] = xstrdup(abspath + real_root_len); + if (strcmp(dirnames[i].str, abspath + real_root_len)) + { + realdirnames[i].str = xstrdup(abspath + real_root_len); + realdirnames[i].len = strlen(realdirnames[i].str); + } } else { /* No basename means we are looking for something like "/foo/bar/.." * Dirname is meaningless here, we can only get realpath of the full @@ -449,21 +462,23 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st abspath, tmppath); goto skip_query_item; } - basenames[i] = xstrdup(basename(tmppath)); + basenames[i].str = xstrdup(basename(tmppath)); + basenames[i].len = strlen(basenames[i].str); snprintf(abspath, sizeof(abspath), "%s%s", dirname(tmppath), tmppath[real_root_len] == '\0' ? "/" : ""); - realdirnames[i] = xstrdup(abspath + real_root_len); + realdirnames[i].str = xstrdup(abspath + real_root_len); + realdirnames[i].len = strlen(realdirnames[i].str); } continue; skip_query_item: --nb_of_queries; warn("Skipping query item \"%s\".", argv[i]); - free(basenames[i]); - free(dirnames[i]); - free(realdirnames[i]); - basenames[i] = dirnames[i] = realdirnames[i] = NULL; + free(basenames[i].str); + free(dirnames[i].str); + free(realdirnames[i].str); + basenames[i].len = dirnames[i].len = realdirnames[i].len = 0; } args->basenames = basenames; @@ -489,7 +504,9 @@ int qfile_main(int argc, char **argv) .skip_plibreg = false, .format = NULL, }; - int i, nb_of_queries, found = 0; + int i; + int nb_of_queries; + int found = 0; char *p; while ((i = GETOPT_LONG(QFILE, qfile, "")) != -1) { @@ -588,16 +605,17 @@ int qfile_main(int argc, char **argv) found += qfile_check_plibreg(&state); if (state.args.non_orphans) { + size_t j; /* display orphan files */ - for (i = 0; i < state.args.length; i++) { - if (state.args.non_orphans[i]) + for (j = 0; j < state.args.length; j++) { + if (state.args.non_orphans[j]) continue; - if (state.args.basenames[i]) { + if (state.args.basenames[j].len > 0) { /* inverse return code (as soon as an orphan is found, * return non-zero) */ found = 0; if (!quiet) - puts(argv[i]); + puts(argv[j]); else break; }
