diff options
author | Dan McGee <dan@archlinux.org> | 2011-07-05 15:11:11 -0500 |
---|---|---|
committer | Dan McGee <dan@archlinux.org> | 2011-11-22 12:17:47 -0600 |
commit | 18a402d71e1efe41ced03933e439d0c253ce1a11 (patch) | |
tree | e4526ddbcdff614bb933fbf5d437f08cbbf4614c | |
parent | 96b3ba3470f11842312e4fdb34b74b391842fc33 (diff) | |
download | pacman-dir-ownership.tar.gz pacman-dir-ownership.zip |
Allow checking ownership of directoriesdir-ownership
We have had this restriction in place for a while, but we do in fact
have directory entries in all of our filelists. Allow passing a
directory to the -Qo operation, with the knowledge that you might get
multiple results returned for a given directory, for example:
Signed-off-by: Dan McGee <dan@archlinux.org>
-rw-r--r-- | src/pacman/query.c | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/src/pacman/query.c b/src/pacman/query.c index 4c2ea817..b80799e9 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -115,6 +115,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) { @@ -135,15 +136,21 @@ static int query_fileowner(alpm_list_t *targets) strcpy(path, root); db_local = alpm_option_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; + size_t len, bname_len; struct stat buf; alpm_list_t *i; - int found = 0; + int found = 0, isdir; filename = strdup(t->data); + len = strlen(filename); + if(len != 0 && filename[len - 1] == '/') { + filename[len - 1] = '\0'; + } if(lstat(filename, &buf) == -1) { /* if it is not a path but a program name, then check in PATH */ @@ -164,16 +171,11 @@ 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; - } - + isdir = S_ISDIR(buf.st_mode); bname = mbasename(filename); + bname_len = strlen(bname); dname = mdirname(filename); + /* for files in '/', there is no directory name to match */ if(strcmp(dname, "") == 0) { rpath = NULL; @@ -185,14 +187,13 @@ static int query_fileowner(alpm_list_t *targets) filename, strerror(errno)); free(filename); free(dname); - free(rpath); ret++; continue; } } 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; @@ -201,17 +202,33 @@ 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) { + const char *pkgfile_bname; + /* database path will have the trailing slash */ + if(pkgfile_len - 2 < bname_len || pkgfile[pkgfile_len - 1] != '/' || + pkgfile[pkgfile_len - bname_len - 2] != '/') { + continue; + } + /* we have a directory, so compare only the final directory portion */ + pkgfile_bname = pkgfile + pkgfile_len - bname_len - 1; + if(strncmp(bname, pkgfile_bname, bname_len) != 0) { + 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) { @@ -219,6 +236,9 @@ static int query_fileowner(alpm_list_t *targets) } /* concatenate our file and the root path */ strcpy(path + rootlen, pkgfile); + if(pkgfile_len != 0 && path[rootlen + pkgfile_len - 1] == '/') { + path[rootlen + pkgfile_len - 1] = '\0'; + } pdname = mdirname(path); ppath = resolve_path(pdname); @@ -227,6 +247,8 @@ static int query_fileowner(alpm_list_t *targets) if(ppath && strcmp(ppath, rpath) == 0) { print_query_fileowner(filename, info); found = 1; + free(ppath); + break; } free(ppath); } |