[pacman-dev] [PATCH] Allow querying directory ownership
Allan McRae
allan at archlinux.org
Mon May 21 11:22:17 EDT 2012
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 at gmail.com>
Original-work-by: Dan McGee <dan at archlinux.org>
Signed-off-by: Allan McRae <allan at 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]) {
+ continue;
+ }
}
/* for files in '/', there is no directory name to match */
if(!rpath) {
print_query_fileowner(filename, info);
found = 1;
- continue;
+ break;
}
if(rootlen + 1 + strlen(pkgfile) > PATH_MAX) {
--
1.7.10.2
More information about the pacman-dev
mailing list