On 22/05/12 01:22, Allan McRae wrote:
The restriction of not checking the ownership of a directory is unnecessary given that all the package filelists contain this information. Remove this restriction, with the expectation that you might get multiple packages returned for a given directory. Additionally attempt to minimise the number of files getting through to the slow realpath call.
This combines ideas from two patches that have been around for a long time.
Original-work-by: Andrew Gregory <andrew.gregory.8@gmail.com> Original-work-by: Dan McGee <dan@archlinux.org> Signed-off-by: Allan McRae <allan@archlinux.org> ---
Not having this feature is beginning to annoy me! Hopefully I have captured the important bits of both patches...
src/pacman/query.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-)
diff --git a/src/pacman/query.c b/src/pacman/query.c index 464efbf..beaf76c 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -113,6 +113,7 @@ static int query_fileowner(alpm_list_t *targets) size_t rootlen; alpm_list_t *t; alpm_db_t *db_local; + alpm_list_t *packages;
/* This code is here for safety only */ if(targets == NULL) { @@ -133,13 +134,14 @@ static int query_fileowner(alpm_list_t *targets) strcpy(path, root);
db_local = alpm_get_localdb(config->handle); + packages = alpm_db_get_pkgcache(db_local);
for(t = targets; t; t = alpm_list_next(t)) { char *filename, *dname, *rpath; const char *bname; struct stat buf; alpm_list_t *i; - int found = 0; + size_t found = 0, isdir, bname_len, dname_len;
filename = strdup(t->data);
@@ -162,16 +164,20 @@ static int query_fileowner(alpm_list_t *targets) } }
- if(S_ISDIR(buf.st_mode)) { - pm_printf(ALPM_LOG_ERROR, - _("cannot determine ownership of directory '%s'\n"), filename); - ret++; - free(filename); - continue; + /* make sure directories have a trailing '/' */ + if((isdir = S_ISDIR(buf.st_mode))) { + size_t len = strlen(filename); + if(filename[len-1] != '/') { + filename = realloc(filename, sizeof(char) * (len + 2)); + strcat(filename, "/"); + } }
bname = mbasename(filename); + bname_len = strlen(bname); dname = mdirname(filename); + dname_len = strlen(dname); + /* for files in '/', there is no directory name to match */ if(strcmp(dname, "") == 0) { rpath = NULL; @@ -190,7 +196,7 @@ static int query_fileowner(alpm_list_t *targets) } free(dname);
- for(i = alpm_db_get_pkgcache(db_local); i && !found; i = alpm_list_next(i)) { + for(i = packages; i && (!found || isdir); i = alpm_list_next(i)) { alpm_pkg_t *info = i->data; alpm_filelist_t *filelist = alpm_pkg_get_files(info); size_t j; @@ -199,17 +205,27 @@ static int query_fileowner(alpm_list_t *targets) const alpm_file_t *file = filelist->files + j; char *ppath, *pdname; const char *pkgfile = file->name; + size_t pkgfile_len = strlen(pkgfile);
- /* avoid the costly resolve_path usage if the basenames don't match */ - if(strcmp(mbasename(pkgfile), bname) != 0) { + /* avoid the costly resolve_path usage if the basenames don't match; + * we can also cheat by comparing the final characters first and avoid + * a full string comparison */ + if(!isdir && (pkgfile[pkgfile_len - 1] != bname[bname_len - 1] || + strcmp(mbasename(pkgfile), bname) != 0)) { continue; + } else if(isdir) { + /* database path needs trailing slash */ + if(pkgfile[pkgfile_len - 1] != '/' && + pkgfile[pkgfile_len - 2] != dname[dname_len - 2]) {
BAD! Will fix...