1 |
commit: b9eca954b9f0518916f390039b43eff46f0ee67e |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sat Oct 12 12:43:19 2019 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat Oct 12 12:43:19 2019 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=b9eca954 |
7 |
|
8 |
qfile: fix matching of full paths, bug #697094 |
9 |
|
10 |
- properly handle trailing slashes, this is necessary because we use a |
11 |
custom basename that doesn't strip it |
12 |
- fix bug in creating realpath of dirname, resulting in one path |
13 |
component short |
14 |
- cleanup some match conditions |
15 |
|
16 |
Bug: https://bugs.gentoo.org/697094 |
17 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
18 |
|
19 |
qfile.c | 72 ++++++++++++++++++++++++++++++++--------------------------------- |
20 |
1 file changed, 36 insertions(+), 36 deletions(-) |
21 |
|
22 |
diff --git a/qfile.c b/qfile.c |
23 |
index 63b47da..8fa6eb4 100644 |
24 |
--- a/qfile.c |
25 |
+++ b/qfile.c |
26 |
@@ -171,6 +171,7 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) |
27 |
short *non_orphans = args->non_orphans; |
28 |
int *results = args->results; |
29 |
int found = 0; |
30 |
+ size_t len; |
31 |
|
32 |
/* If exclude_pkg is not NULL, check it. We are looking for files |
33 |
* collisions, and must exclude one package. */ |
34 |
@@ -223,23 +224,22 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) |
35 |
if (non_orphans != NULL && non_orphans[i]) |
36 |
continue; |
37 |
|
38 |
- /* For optimization of qfile(), we also give it an array of |
39 |
- * the first char of each basename. This way we avoid |
40 |
- * numerous strcmp() calls. */ |
41 |
+ /* Try to avoid numerous strcmp() calls. */ |
42 |
if (base[0] != base_names[i][0] || strcmp(base, base_names[i]) != 0) |
43 |
continue; |
44 |
|
45 |
path_ok = false; |
46 |
|
47 |
- if (dir_names[i] && |
48 |
- strncmp(e->name, dir_names[i], dirname_len) == 0 && |
49 |
- dir_names[i][dirname_len] == '\0') |
50 |
+ if (dir_names[i] && (len = strlen(dir_names[i])) > 0 && |
51 |
+ len == dirname_len && |
52 |
+ memcmp(e->name, dir_names[i], len) == 0) |
53 |
{ |
54 |
/* dir_name == dirname(CONTENTS) */ |
55 |
path_ok = true; |
56 |
} else if (real_dir_names[i] && |
57 |
- strncmp(e->name, real_dir_names[i], dirname_len) == 0 && |
58 |
- real_dir_names[i][dirname_len] == '\0') |
59 |
+ (len = strlen(real_dir_names[i])) > 0 && |
60 |
+ len == dirname_len && |
61 |
+ memcmp(e->name, real_dir_names[i], len) == 0) |
62 |
{ |
63 |
/* real_dir_name == dirname(CONTENTS) */ |
64 |
path_ok = true; |
65 |
@@ -276,19 +276,19 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) |
66 |
} |
67 |
} |
68 |
|
69 |
- if (!path_ok && state->basename) { |
70 |
+ if (!path_ok && state->basename) |
71 |
path_ok = true; |
72 |
- } |
73 |
|
74 |
if (!path_ok && state->pwd && dir_names[i] == NULL) { |
75 |
/* try to match file in current directory */ |
76 |
- if (strncmp(e->name, state->pwd, dirname_len) == 0 && |
77 |
- state->pwd[dirname_len] == '\0') |
78 |
+ if ((len = strlen(state->pwd)) > 0 && |
79 |
+ len == dirname_len && |
80 |
+ memcmp(e->name, state->pwd, len) == 0) |
81 |
path_ok = true; |
82 |
} |
83 |
|
84 |
if (!path_ok && dir_names[i] == NULL && real_dir_names[i] == NULL) { |
85 |
- /* try basename match */ |
86 |
+ /* basename match */ |
87 |
if (e->type != CONTENTS_DIR) |
88 |
path_ok = true; |
89 |
} |
90 |
@@ -357,7 +357,7 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st |
91 |
char **realdirnames = NULL; |
92 |
int *results = NULL; |
93 |
char tmppath[_Q_PATH_MAX]; |
94 |
- char abspath[_Q_PATH_MAX]; |
95 |
+ char abspath[_Q_PATH_MAX * 2]; |
96 |
|
97 |
/* For each argument, we store its basename, its absolute dirname, |
98 |
* and the realpath of its dirname. Dirnames and their realpaths |
99 |
@@ -370,11 +370,15 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st |
100 |
results = xcalloc(argc, sizeof(int)); |
101 |
|
102 |
for (i = 0; i < argc; ++i) { |
103 |
- /* Record basename, but if it is ".", ".." or "/" */ |
104 |
- /* copy so that "argv" can be "const" */ |
105 |
- snprintf(tmppath, sizeof(tmppath), "%s", argv[i]); |
106 |
+ /* copy so that "argv" can be "const", but skip trailing / |
107 |
+ * because our basename doesn't modify its input */ |
108 |
+ len = strlen(argv[i]); |
109 |
+ if (len > 1 && argv[i][len - 1] == '/') |
110 |
+ len--; |
111 |
+ snprintf(tmppath, sizeof(tmppath), "%.*s", (int)len, argv[i]); |
112 |
p = basename(tmppath); |
113 |
- len = strlen(p); |
114 |
+ |
115 |
+ /* record basename, but if it is ".", ".." or "/" */ |
116 |
if ((len > 2) || |
117 |
(strncmp(tmppath, "..", len) != 0 && |
118 |
strncmp(tmppath, "/", len) != 0)) |
119 |
@@ -388,15 +392,15 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st |
120 |
|
121 |
/* Make sure we have an absolute path available (with |
122 |
* "realpath(ROOT)" prefix) */ |
123 |
- if (argv[i][0] == '/') { |
124 |
+ if (tmppath[0] == '/') { |
125 |
snprintf(abspath, sizeof(abspath), "%s%s", |
126 |
- state->assume_root_prefix ? "" : real_root, argv[i]); |
127 |
+ state->assume_root_prefix ? "" : real_root, tmppath); |
128 |
} else if (pwd) { |
129 |
if (state->assume_root_prefix) |
130 |
- snprintf(abspath, sizeof(abspath), "%s/%s", pwd, argv[i]); |
131 |
+ snprintf(abspath, sizeof(abspath), "%s/%s", pwd, tmppath); |
132 |
else |
133 |
snprintf(abspath, sizeof(abspath), "%s%s/%s", |
134 |
- real_root, pwd, argv[i]); |
135 |
+ real_root, pwd, tmppath); |
136 |
} else { |
137 |
warn("$PWD was not found in environment, " |
138 |
"or is not an absolute path"); |
139 |
@@ -424,11 +428,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st |
140 |
tmppath, abspath); |
141 |
goto skip_query_item; |
142 |
} |
143 |
- snprintf(tmppath, sizeof(tmppath), "%s%s", |
144 |
- dirname(abspath), |
145 |
- abspath[real_root_len] == '\0' ? "/" : ""); |
146 |
- if (strcmp(dirnames[i], tmppath + real_root_len)) |
147 |
- realdirnames[i] = xstrdup(tmppath + real_root_len); |
148 |
+ if (strcmp(dirnames[i], abspath + real_root_len)) |
149 |
+ realdirnames[i] = xstrdup(abspath + real_root_len); |
150 |
} else { |
151 |
/* No basename means we are looking for something like "/foo/bar/.." |
152 |
* Dirname is meaningless here, we can only get realpath of the full |
153 |
@@ -442,8 +443,7 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st |
154 |
abspath, tmppath); |
155 |
goto skip_query_item; |
156 |
} |
157 |
- snprintf(abspath, sizeof(abspath), "%s", tmppath); |
158 |
- basenames[i] = xstrdup(basename(abspath)); |
159 |
+ basenames[i] = xstrdup(basename(tmppath)); |
160 |
snprintf(abspath, sizeof(abspath), "%s%s", |
161 |
dirname(tmppath), |
162 |
tmppath[real_root_len] == '\0' ? "/" : ""); |
163 |
@@ -451,13 +451,13 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st |
164 |
} |
165 |
continue; |
166 |
|
167 |
- skip_query_item: |
168 |
- --nb_of_queries; |
169 |
- warn("Skipping query item \"%s\".", argv[i]); |
170 |
- free(basenames[i]); |
171 |
- free(dirnames[i]); |
172 |
- free(realdirnames[i]); |
173 |
- basenames[i] = dirnames[i] = realdirnames[i] = NULL; |
174 |
+ skip_query_item: |
175 |
+ --nb_of_queries; |
176 |
+ warn("Skipping query item \"%s\".", argv[i]); |
177 |
+ free(basenames[i]); |
178 |
+ free(dirnames[i]); |
179 |
+ free(realdirnames[i]); |
180 |
+ basenames[i] = dirnames[i] = realdirnames[i] = NULL; |
181 |
} |
182 |
|
183 |
args->basenames = basenames; |