diff options
| -rw-r--r-- | src/pacman/query.c | 137 | 
1 files changed, 64 insertions, 73 deletions
| diff --git a/src/pacman/query.c b/src/pacman/query.c index f051571c..f5862a2d 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; | 
