Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> --- Updated to include lrealpath definition and a buffer overflow check.. src/pacman/query.c | 137 +++++++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 73 deletions(-) diff --git a/src/pacman/query.c b/src/pacman/query.c index f051571..f5862a2 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -90,6 +90,49 @@ static void print_query_fileowner(const char *filename, alpm_pkg_t *info) } } +/** Resolve the canonicalized absolute path of a symlink. + * @param path path to resolve + * @param resolved_path destination for the resolved path, will be malloc'd if + * NULL + * @return the resolved path + */ +static char *lrealpath(const char *path, char *resolved_path) +{ + const char *bname = mbasename(path); + char *rpath = NULL, *dname = NULL; + int success = 0; + + if(strcmp(path, ".") == 0 || strcmp(path, "..") == 0) { + /* the entire path needs to be resolved */ + return realpath(path, resolved_path); + } + + if(!(dname = mdirname(path))) { + goto cleanup; + } + if(!(rpath = realpath(dname, NULL))) { + goto cleanup; + } + if(!resolved_path) { + if(!(resolved_path = malloc(strlen(rpath) + strlen(bname) + 2))) { + goto cleanup; + } + } + + strcpy(resolved_path, rpath); + if(resolved_path[strlen(resolved_path) - 1] != '/') { + strcat(resolved_path, "/"); + } + strcat(resolved_path, bname); + success = 1; + +cleanup: + free(dname); + free(rpath); + + return (success ? resolved_path : NULL); +} + static int query_fileowner(alpm_list_t *targets) { int ret = 0; @@ -133,11 +176,11 @@ static int query_fileowner(alpm_list_t *targets) packages = alpm_db_get_pkgcache(db_local); for(t = targets; t; t = alpm_list_next(t)) { - char *filename = NULL, *dname = NULL, *rpath = NULL; - const char *bname; + char *filename = NULL; + char rpath[PATH_MAX], *rel_path; struct stat buf; alpm_list_t *i; - size_t len, is_dir, bname_len, pbname_len; + size_t len, is_dir; unsigned int found = 0; if((filename = strdup(t->data)) == NULL) { @@ -165,82 +208,32 @@ static int query_fileowner(alpm_list_t *targets) } } - is_dir = S_ISDIR(buf.st_mode) ? 1 : 0; - if(is_dir) { - /* the entire filename is safe to resolve if we know it points to a dir, - * and it's necessary in case it ends in . or .. */ - dname = realpath(filename, NULL); - bname = mbasename(dname); - rpath = mdirname(dname); - } else { - bname = mbasename(filename); - dname = mdirname(filename); - rpath = realpath(dname, NULL); - } - - bname_len = strlen(bname); - pbname_len = bname_len + is_dir; - - if(!dname || !rpath) { + if(!lrealpath(filename, rpath)) { pm_printf(ALPM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"), filename, strerror(errno)); goto targcleanup; } - for(i = packages; i && (!found || is_dir); i = alpm_list_next(i)) { - alpm_pkg_t *info = i->data; - alpm_filelist_t *filelist = alpm_pkg_get_files(info); - size_t j; - - for(j = 0; j < filelist->count; j++) { - const alpm_file_t *file = filelist->files + j; - char *ppath; - const char *pkgfile = file->name; - size_t pkgfile_len = strlen(pkgfile); - - /* make sure pkgfile and target are of the same type */ - if(is_dir != (pkgfile[pkgfile_len - 1] == '/')) { - continue; - } - - /* make sure pkgfile is long enough */ - if(pkgfile_len < pbname_len) { - continue; - } - - /* make sure pbname_len takes us to the start of a path component */ - if(pbname_len != pkgfile_len && pkgfile[pkgfile_len - pbname_len - 1] != '/') { - continue; - } + if(strncmp(rpath, path, rootlen) != 0) { + /* file is outside root, we know nothing can own it */ + pm_printf(ALPM_LOG_ERROR, _("No package owns %s\n"), filename); + goto targcleanup; + } - /* compare basename with bname */ - if(strncmp(pkgfile + pkgfile_len - pbname_len, bname, bname_len) != 0) { - continue; - } + rel_path = rpath + rootlen; - /* concatenate our dirname and the root path */ - if(rootlen + 1 + pkgfile_len - pbname_len > PATH_MAX) { - path[rootlen] = '\0'; /* reset path for error message */ - pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), path, pkgfile); - continue; - } - strncpy(path + rootlen, pkgfile, pkgfile_len - pbname_len); - path[rootlen + pkgfile_len - pbname_len] = '\0'; - - ppath = realpath(path, NULL); - if(!ppath) { - pm_printf(ALPM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"), - path, strerror(errno)); - continue; - } + if((is_dir = S_ISDIR(buf.st_mode))) { + size_t rlen = strlen(rpath); + if(rlen + 2 >= PATH_MAX) { + pm_printf(ALPM_LOG_ERROR, _("path too long: %s/\n"), rpath); + } + strcat(rpath + rlen, "/"); + } - if(strcmp(ppath, rpath) == 0) { - print_query_fileowner(filename, info); - found = 1; - free(ppath); - break; - } - free(ppath); + for(i = packages; i && (!found || is_dir); i = alpm_list_next(i)) { + if(alpm_filelist_contains(alpm_pkg_get_files(i->data), rel_path)) { + print_query_fileowner(rpath, i->data); + found = 1; } } if(!found) { @@ -252,8 +245,6 @@ targcleanup: ret++; } free(filename); - free(rpath); - free(dname); } return ret; -- 1.8.2.2