104
105 for (i = 0, p = names; i < nc; i++) {
106 if (!ix[i]) continue;
107 if (i > 0) {
108 p[-1] = '/';
109 }
110 if (p == ix[i]) {
111 p += strlen(p) + 1;
112 } else {
113 char *q = ix[i];
114 while ((*p++ = *q++));
115 }
116 }
117 *p = '\0';
118 }
119
120
121 /* Collapse "." and ".." names in the given path wherever possible.
122 A "." name may always be eliminated; a ".." name may be eliminated if it
123 follows a name that is neither "." nor "..". This is a syntactic operation
124 that performs no filesystem queries, so it should only be used to cleanup
125 after invoking the realpath() procedure. */
126
127 static void
128 collapse(char *path)
129 {
130 char *names = (path[0] == '/') ? path + 1 : path; /* Preserve first '/' */
131 int nc;
132 char **ix;
133 int i, j;
134 char *p, *q;
135
136 nc = collapsible(names);
137 if (nc < 2) return; /* Nothing to do */
138 ix = (char **)alloca(nc * sizeof(char *));
139 splitNames(names, ix);
140
141 for (i = 0; i < nc; i++) {
142 int dots = 0;
143
144 /* Find next occurrence of "." or ".." */
145 do {
165 ix[i] = 0;
166 }
167 else {
168 /* If there is a preceding name, remove both that name and this
169 instance of ".."; otherwise, leave the ".." as is */
170 for (j = i - 1; j >= 0; j--) {
171 if (ix[j]) break;
172 }
173 if (j < 0) continue;
174 ix[j] = 0;
175 ix[i] = 0;
176 }
177 /* i will be incremented at the top of the loop */
178 }
179
180 joinNames(names, nc, ix);
181 }
182
183
184 /* Convert a pathname to canonical form. The input path is assumed to contain
185 no duplicate slashes. On Solaris we can use realpath() to do most of the
186 work, though once that's done we still must collapse any remaining "." and
187 ".." names by hand. */
188
189 int
190 canonicalize(char *original, char *resolved, int len)
191 {
192 if (len < PATH_MAX) {
193 errno = EINVAL;
194 return -1;
195 }
196
197 if (strlen(original) > PATH_MAX) {
198 errno = ENAMETOOLONG;
199 return -1;
200 }
201
202 /* First try realpath() on the entire path */
203 if (realpath(original, resolved)) {
204 /* That worked, so return it */
205 collapse(resolved);
206 return 0;
207 }
208 else {
209 /* Something's bogus in the original path, so remove names from the end
210 until either some subpath works or we run out of names */
211 char *p, *end, *r = NULL;
212 char path[PATH_MAX + 1];
213
214 strncpy(path, original, sizeof(path));
215 if (path[PATH_MAX] != '\0') {
216 errno = ENAMETOOLONG;
217 return -1;
218 }
219 end = path + strlen(path);
220
221 for (p = end; p > path;) {
222
223 /* Skip last element */
224 while ((--p > path) && (*p != '/'));
225 if (p == path) break;
241 continue;
242 }
243 else {
244 return -1;
245 }
246 }
247
248 if (r != NULL) {
249 /* Append unresolved subpath to resolved subpath */
250 int rn = strlen(r);
251 if (rn + (int)strlen(p) >= len) {
252 /* Buffer overflow */
253 errno = ENAMETOOLONG;
254 return -1;
255 }
256 if ((rn > 0) && (r[rn - 1] == '/') && (*p == '/')) {
257 /* Avoid duplicate slashes */
258 p++;
259 }
260 strcpy(r + rn, p);
261 collapse(r);
262 return 0;
263 }
264 else {
265 /* Nothing resolved, so just return the original path */
266 strcpy(resolved, path);
267 collapse(resolved);
268 return 0;
269 }
270 }
271
272 }
|
104
105 for (i = 0, p = names; i < nc; i++) {
106 if (!ix[i]) continue;
107 if (i > 0) {
108 p[-1] = '/';
109 }
110 if (p == ix[i]) {
111 p += strlen(p) + 1;
112 } else {
113 char *q = ix[i];
114 while ((*p++ = *q++));
115 }
116 }
117 *p = '\0';
118 }
119
120
121 /* Collapse "." and ".." names in the given path wherever possible.
122 A "." name may always be eliminated; a ".." name may be eliminated if it
123 follows a name that is neither "." nor "..". This is a syntactic operation
124 that performs no filesystem queries, so it should only be used to clean up
125 after symlink resolution. */
126
127 static void
128 collapse(char *path)
129 {
130 char *names = (path[0] == '/') ? path + 1 : path; /* Preserve first '/' */
131 int nc;
132 char **ix;
133 int i, j;
134 char *p, *q;
135
136 nc = collapsible(names);
137 if (nc < 2) return; /* Nothing to do */
138 ix = (char **)alloca(nc * sizeof(char *));
139 splitNames(names, ix);
140
141 for (i = 0; i < nc; i++) {
142 int dots = 0;
143
144 /* Find next occurrence of "." or ".." */
145 do {
165 ix[i] = 0;
166 }
167 else {
168 /* If there is a preceding name, remove both that name and this
169 instance of ".."; otherwise, leave the ".." as is */
170 for (j = i - 1; j >= 0; j--) {
171 if (ix[j]) break;
172 }
173 if (j < 0) continue;
174 ix[j] = 0;
175 ix[i] = 0;
176 }
177 /* i will be incremented at the top of the loop */
178 }
179
180 joinNames(names, nc, ix);
181 }
182
183
184 /* Convert a pathname to canonical form. The input path is assumed to contain
185 no duplicate slashes. We can use realpath() to do most of the
186 work, though once that's done we still must collapse any remaining "." and
187 ".." names in the unresolved portion of the path by hand. */
188
189 int
190 canonicalize(char *original, char *resolved, int len)
191 {
192 if (len < PATH_MAX) {
193 errno = EINVAL;
194 return -1;
195 }
196
197 if (strlen(original) > PATH_MAX) {
198 errno = ENAMETOOLONG;
199 return -1;
200 }
201
202 /* First try realpath() on the entire path */
203 if (realpath(original, resolved)) {
204 /* That worked, so return it */
205 return 0;
206 }
207 else {
208 /* Something's bogus in the original path, so remove names from the end
209 until either some subpath works or we run out of names */
210 char *p, *end, *r = NULL;
211 char path[PATH_MAX + 1];
212
213 strncpy(path, original, sizeof(path));
214 if (path[PATH_MAX] != '\0') {
215 errno = ENAMETOOLONG;
216 return -1;
217 }
218 end = path + strlen(path);
219
220 for (p = end; p > path;) {
221
222 /* Skip last element */
223 while ((--p > path) && (*p != '/'));
224 if (p == path) break;
240 continue;
241 }
242 else {
243 return -1;
244 }
245 }
246
247 if (r != NULL) {
248 /* Append unresolved subpath to resolved subpath */
249 int rn = strlen(r);
250 if (rn + (int)strlen(p) >= len) {
251 /* Buffer overflow */
252 errno = ENAMETOOLONG;
253 return -1;
254 }
255 if ((rn > 0) && (r[rn - 1] == '/') && (*p == '/')) {
256 /* Avoid duplicate slashes */
257 p++;
258 }
259 strcpy(r + rn, p);
260 collapse(r + rn);
261 return 0;
262 }
263 else {
264 /* Nothing resolved, so just return the original path, collapsed */
265 strcpy(resolved, path);
266 collapse(resolved);
267 return 0;
268 }
269 }
270
271 }
|