aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Ludd <solar@gentoo.org>2006-07-09 18:36:48 +0000
committerNed Ludd <solar@gentoo.org>2006-07-09 18:36:48 +0000
commit4aaba3cf912db535c1cf25e9be0d58d7720dd08a (patch)
tree5043eeafd88e8772ab6291fe78e7f631bae26c16
parent- update q --option handling. bug 139772 ; TGL degrenier@easyconnect (diff)
downloadportage-utils-4aaba3cf912db535c1cf25e9be0d58d7720dd08a.tar.gz
portage-utils-4aaba3cf912db535c1cf25e9be0d58d7720dd08a.tar.bz2
portage-utils-4aaba3cf912db535c1cf25e9be0d58d7720dd08a.zip
- update qfile behavior with symlinks. Bug #130004 TGL degrenier@easyconnect
-rw-r--r--qfile.c175
1 files changed, 138 insertions, 37 deletions
diff --git a/qfile.c b/qfile.c
index e0be502d..dfb381bf 100644
--- a/qfile.c
+++ b/qfile.c
@@ -1,7 +1,7 @@
/*
* Copyright 2005-2006 Gentoo Foundation
* Distributed under the terms of the GNU General Public License v2
- * $Header: /var/cvsroot/gentoo-projects/portage-utils/qfile.c,v 1.29 2006/05/14 21:37:11 vapier Exp $
+ * $Header: /var/cvsroot/gentoo-projects/portage-utils/qfile.c,v 1.30 2006/07/09 18:36:48 solar Exp $
*
* Copyright 2005-2006 Ned Ludd - <solar@gentoo.org>
* Copyright 2005-2006 Mike Frysinger - <vapier@gentoo.org>
@@ -18,45 +18,33 @@ static const char *qfile_opts_help[] = {
"Exact match",
COMMON_OPTS_HELP
};
-static char qfile_rcsid[] = "$Id: qfile.c,v 1.29 2006/05/14 21:37:11 vapier Exp $";
+static char qfile_rcsid[] = "$Id: qfile.c,v 1.30 2006/07/09 18:36:48 solar Exp $";
#define qfile_usage(ret) usage(ret, QFILE_FLAGS, qfile_long_opts, qfile_opts_help, lookup_applet_idx("qfile"))
-void qfile(char *path, char *fullname);
-void qfile(char *path, char *fullname)
+void qfile(char *path, char *base_name, char *dir_name, char *real_dir_name);
+void qfile(char *path, char *base_name, char *dir_name, char *real_dir_name)
{
FILE *fp;
DIR *dir;
struct dirent *dentry;
char *p;
- size_t flen;
- int base = 0;
- char fname[_Q_PATH_MAX];
+ char *q;
+ size_t bnlen;
+ size_t dnlen = 0;
+ size_t rdnlen = 0;
char buf[1024];
char pkg[126];
depend_atom *atom;
- strncpy(fname, fullname, sizeof(fname));
-
- if ((fname[0] == '.') && ((p = getenv("PWD")) != NULL)) {
- char tmp[_Q_PATH_MAX];
- snprintf(tmp, sizeof(fname), "%s/%s", p, fullname);
- /* Don't check the return value here as it is ok if
- * the function fails. Think of the case where fname
- * is '...somefile', we don't want to abort then as
- * the value in fname will be unchanged. */
- realpath(tmp, fname);
- }
-
- flen = strlen(fname);
+ bnlen = strlen(base_name);
+ if (dir_name != NULL)
+ dnlen = strlen(dir_name);
+ if (real_dir_name != NULL)
+ rdnlen = strlen(real_dir_name);
if (chdir(path) != 0 || (dir = opendir(".")) == NULL)
return;
- if (!strchr(fname, '/'))
- base = 1;
- else
- base = 0;
-
while ((dentry = readdir(dir))) {
if (dentry->d_name[0] == '.')
continue;
@@ -70,20 +58,61 @@ void qfile(char *path, char *fullname)
snprintf(pkg, sizeof(pkg), "%s/%s", basename(path), dentry->d_name);
while ((fgets(buf, sizeof(buf), fp)) != NULL) {
contents_entry *e;
+ int path_ok = 0;
+ if (dir_name == NULL && real_dir_name == NULL)
+ path_ok = 1;
e = contents_parse_line(buf);
if (!e)
continue;
p = xstrdup(e->name);
- if (strncmp(base ? basename(p) : p, fname, flen) != 0
- || strlen(base ? basename(p) : p) != flen) {
+ q = basename(p);
+ if (strncmp(q, base_name, bnlen) != 0
+ || strlen(q) != bnlen) {
free(p);
continue;
}
+ free(p);
+
+ if (!path_ok) {
+ // check the full filepath...
+ p = xstrdup(e->name);
+ q = xstrdup(dirname(p));
+ free(p);
+ if (dnlen == strlen(q)
+ && strncmp(q, dir_name, dnlen) == 0)
+ // dir_name == dirname(CONTENTS)
+ path_ok = 1;
+ else if (rdnlen == strlen(q)
+ && strncmp(q, real_dir_name, rdnlen) == 0)
+ // real_dir_name == dirname(CONTENTS)
+ path_ok = 1;
+ else {
+ char rpath[_Q_PATH_MAX];
+ errno = 0;
+ realpath(q, rpath);
+ if (errno != 0) {
+ if (verbose) {
+ warn("Could not read real path of \"%s\": %s", q, strerror(errno));
+ warn("We'll never know whether it was a result for your query...");
+ }
+ } else if (dnlen == strlen(rpath)
+ && strncmp(rpath, dir_name, dnlen) == 0)
+ // dir_name == realpath(dirname(CONTENTS))
+ path_ok = 1;
+ else if (rdnlen == strlen(rpath)
+ && strncmp(rpath, real_dir_name, rdnlen) == 0)
+ // real_dir_name == realpath(dirname(CONTENTS))
+ path_ok = 1;
+ }
+ free(q);
+ }
+ if (!path_ok)
+ continue;
+
if ((atom = atom_explode(pkg)) == NULL) {
warn("invalid atom %s", pkg);
- free(p);
continue;
}
printf("%s%s/%s%s%s", BOLD, atom->CATEGORY, BLUE,
@@ -92,10 +121,9 @@ void qfile(char *path, char *fullname)
if (quiet)
puts("");
else
- printf(" (%s)\n", p);
+ printf(" (%s)\n", e->name);
atom_implode(atom);
- free(p);
found++;
}
fclose(fp);
@@ -110,6 +138,10 @@ int qfile_main(int argc, char **argv)
struct dirent *dentry;
int i;
char *p;
+ char ** basenames;
+ char ** dirnames;
+ char ** realdirnames;
+ char * pwd;
DBG("argc=%d argv[0]=%s argv[1]=%s",
argc, argv[0], argc > 1 ? argv[1] : "NULL?");
@@ -130,21 +162,90 @@ int qfile_main(int argc, char **argv)
if (chdir(portvdb) != 0 || (dir = opendir(".")) == NULL)
return EXIT_FAILURE;
- /* CONTENTS stores dir names w/out trailing / so clean up input */
- for (i = optind; i < argc; ++i) {
- p = argv[i] + strlen(argv[i]) - 1;
- if (*p == '/')
- *p = '\0';
+ // For each argument, we store its basename, its dirname,
+ // and the realpath of its dirname.
+ basenames = malloc((argc-optind) * sizeof(char*));
+ dirnames = malloc((argc-optind) * sizeof(char*));
+ realdirnames = malloc((argc-optind) * sizeof(char*));
+ if ((pwd = getenv("PWD")) != NULL) {
+ int pwdlen = strlen(pwd);
+ if ((pwdlen > 0) && (pwd[pwdlen-1] == '/'))
+ pwd[pwdlen-1] = '\0';
+ }
+ for (i = 0; i < (argc-optind); ++i) {
+ char tmppath[_Q_PATH_MAX];
+ char abspath[_Q_PATH_MAX];
+
+ basenames[i] = NULL;
+ dirnames[i] = NULL;
+ realdirnames[i] = NULL;
+
+ // Record basename, but if it is "." or ".."
+ strncpy(tmppath, basename(argv[i+optind]), _Q_PATH_MAX);
+ if ((strlen(tmppath) > 2) || strncmp(tmppath, "..", strlen(tmppath))) {
+ basenames[i] = xstrdup(tmppath);
+ // If there is no "/" in the argument, then it's over.
+ // (we are searching a simple file name)
+ if (strchr(argv[i+optind], '/') == NULL)
+ continue;
+ }
+
+ // Make sure we have an absolute path available
+ if (argv[i+optind][0] == '/')
+ strncpy(abspath, argv[i+optind], _Q_PATH_MAX);
+ else if (pwd != NULL)
+ snprintf(abspath, _Q_PATH_MAX, "%s/%s", pwd, argv[i+optind]);
+ else {
+ err("$PWD not found in environment.");
+ err("Skipping query item \"%s\".", argv[i+optind]);
+ continue;
+ }
+
+ if (basenames[i] != NULL) {
+ // Get both the dirname and its realpath
+ dirnames[i] = xstrdup(dirname(abspath));
+ errno = 0;
+ realpath(dirnames[i], tmppath);
+ if (errno != 0) {
+ if (verbose) {
+ warn("Could not read real path of \"%s\": %s", dirnames[i], strerror(errno));
+ warn("Results for query item \"%s\" may not be accurate.", argv[i+optind]);
+ }
+ } else if (strcmp(dirnames[i], tmppath))
+ realdirnames[i] = xstrdup(tmppath);
+ } else {
+ // No basename means we are looking for something like "/foo/bar/.."
+ // Dirname is meaningless here, we can only get realpath of the full
+ // path and then split it.
+ errno = 0;
+ realpath(tmppath, abspath);
+ if (errno != 0) {
+ err("Could not read real path of \"%s\": %s", tmppath, strerror(errno));
+ err("Skipping query item \"%s\".", argv[i+optind]);
+ continue;
+ }
+ basenames[i] = xstrdup(basename(tmppath));
+ realdirnames[i] = xstrdup(dirname(tmppath));
+ }
}
/* open /var/db/pkg */
while ((dentry = q_vdb_get_next_dir(dir))) {
xasprintf(&p, "%s%s/%s", portroot, portvdb, dentry->d_name);
- for (i = optind; i < argc; ++i)
- qfile(p, argv[i]);
+ for (i = 0; i < (argc-optind); ++i) {
+ if (basenames[i] != NULL)
+ qfile(p, basenames[i], dirnames[i], realdirnames[i]);
+ }
free(p);
}
+ for (i = 0; i < (argc-optind); ++i) {
+ if (basenames[i] != NULL) free(basenames[i]);
+ if (dirnames[i] != NULL) free(dirnames[i]);
+ if (realdirnames[i] != NULL) free(realdirnames[i]);
+ }
+ free(basenames); free(dirnames); free(realdirnames);
+
return (found ? EXIT_SUCCESS : EXIT_FAILURE);
}