|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/port/path.c,v 1.56 2005/08/1219:43:32 momjian Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/port/path.c,v 1.57 2005/08/1221:07:53 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
|
225 | 225 | canonicalize_path(char*path)
|
226 | 226 | {
|
227 | 227 | char*p,*to_p;
|
| 228 | +char*spath; |
228 | 229 | boolwas_sep= false;
|
| 230 | +intpending_strips; |
229 | 231 |
|
230 | 232 | #ifdefWIN32
|
231 | 233 | /*
|
@@ -277,30 +279,89 @@ canonicalize_path(char *path)
|
277 | 279 |
|
278 | 280 | /*
|
279 | 281 | * Remove any trailing uses of "." and process ".." ourselves
|
| 282 | + * |
| 283 | + * Note that "/../.." should reduce to just "/", while "../.." has to |
| 284 | + * be kept as-is. In the latter case we put back mistakenly trimmed |
| 285 | + * ".." components below. Also note that we want a Windows drive spec |
| 286 | + * to be visible to trim_directory(), but it's not part of the logic |
| 287 | + * that's looking at the name components; hence distinction between |
| 288 | + * path and spath. |
280 | 289 | */
|
| 290 | +spath=skip_drive(path); |
| 291 | +pending_strips=0; |
281 | 292 | for (;;)
|
282 | 293 | {
|
283 |
| -intlen=strlen(path); |
| 294 | +intlen=strlen(spath); |
284 | 295 |
|
285 |
| -if (len>2&&strcmp(path+len-2,"/.")==0) |
| 296 | +if (len >=2&&strcmp(spath+len-2,"/.")==0) |
286 | 297 | trim_directory(path);
|
287 |
| -/* |
288 |
| - *Process only a single trailing "..", and only if ".." does |
289 |
| - *not preceed it. |
290 |
| - *So, we only deal with "/usr/local/..", not with "/usr/local/../..". |
291 |
| - *We don't handle the even more complex cases, like |
292 |
| - *"usr/local/../../..". |
293 |
| - */ |
294 |
| -elseif (len>3&&strcmp(path+len-3,"/..")==0&& |
295 |
| - (len!=5||strcmp(path,"../..")!=0)&& |
296 |
| - (len<6||strcmp(path+len-6,"/../..")!=0)) |
| 298 | +elseif (strcmp(spath,".")==0) |
| 299 | +{ |
| 300 | +/* Want to leave "." alone, but "./.." has to become ".." */ |
| 301 | +if (pending_strips>0) |
| 302 | +*spath='\0'; |
| 303 | +break; |
| 304 | +} |
| 305 | +elseif ((len >=3&&strcmp(spath+len-3,"/..")==0)|| |
| 306 | +strcmp(spath,"..")==0) |
| 307 | +{ |
| 308 | +trim_directory(path); |
| 309 | +pending_strips++; |
| 310 | +} |
| 311 | +elseif (pending_strips>0&&*spath!='\0') |
297 | 312 | {
|
| 313 | +/* trim a regular directory name cancelled by ".." */ |
298 | 314 | trim_directory(path);
|
299 |
| -trim_directory(path);/* remove directory above */ |
| 315 | +pending_strips--; |
| 316 | +/* foo/.. should become ".", not empty */ |
| 317 | +if (*spath=='\0') |
| 318 | +strcpy(spath,"."); |
300 | 319 | }
|
301 | 320 | else
|
302 | 321 | break;
|
303 | 322 | }
|
| 323 | + |
| 324 | +if (pending_strips>0) |
| 325 | +{ |
| 326 | +/* |
| 327 | + * We could only get here if path is now totally empty (other than |
| 328 | + * a possible drive specifier on Windows). |
| 329 | + * We have to put back one or more ".."'s that we took off. |
| 330 | + */ |
| 331 | +while (--pending_strips>0) |
| 332 | +strcat(path,"../"); |
| 333 | +strcat(path,".."); |
| 334 | +} |
| 335 | +} |
| 336 | + |
| 337 | +/* |
| 338 | + * Detect whether a path contains any parent-directory references ("..") |
| 339 | + * |
| 340 | + * The input *must* have been put through canonicalize_path previously. |
| 341 | + * |
| 342 | + * This is a bit tricky because we mustn't be fooled by "..a.." (legal) |
| 343 | + * nor "C:.." (legal on Unix but not Windows). |
| 344 | + */ |
| 345 | +bool |
| 346 | +path_contains_parent_reference(constchar*path) |
| 347 | +{ |
| 348 | +intpath_len; |
| 349 | + |
| 350 | +path=skip_drive(path);/* C: shouldn't affect our conclusion */ |
| 351 | + |
| 352 | +path_len=strlen(path); |
| 353 | + |
| 354 | +/* |
| 355 | + * ".." could be the whole path; otherwise, if it's present it must |
| 356 | + * be at the beginning, in the middle, or at the end. |
| 357 | + */ |
| 358 | +if (strcmp(path,"..")==0|| |
| 359 | +strncmp(path,"../",3)==0|| |
| 360 | +strstr(path,"/../")!=NULL|| |
| 361 | +(path_len >=3&&strcmp(path+path_len-3,"/..")==0)) |
| 362 | +return true; |
| 363 | + |
| 364 | +return false; |
304 | 365 | }
|
305 | 366 |
|
306 | 367 |
|
|