diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | generic/tclPathObj.c | 89 |
2 files changed, 82 insertions, 13 deletions
@@ -1,3 +1,9 @@ +2008-12-04 Don Porter <dgp@users.sourceforge.net> + + * generic/tclPathObj.c (Tcl_FSGetNormalizedPath): Added another + flag value TCLPATH_NEEDNORM to mark those intreps which need more + complete normalization attention for correct results. [Bug 2385549] + 2008-12-03 Don Porter <dgp@users.sourceforge.net> * generic/tclFileName.c (DoGlob): One of the diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index cdf6e2b..dee1745 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPathObj.c,v 1.66.2.4 2008/06/29 19:08:36 dgp Exp $ + * RCS: @(#) $Id: tclPathObj.c,v 1.66.2.5 2008/12/04 17:45:02 dgp Exp $ */ #include "tclInt.h" @@ -103,6 +103,7 @@ typedef struct FsPath { */ #define TCLPATH_APPENDED 1 +#define TCLPATH_NEEDNORM 4 /* * Define some macros to give us convenient access to path-object specific @@ -1246,6 +1247,8 @@ TclNewFSPathObj( FsPath *fsPathPtr; Tcl_Obj *pathPtr; ThreadSpecificData *tsdPtr; + const char *p; + int state = 0, count = 0; tsdPtr = TCL_TSD_INIT(&tclFsDataKey); @@ -1271,6 +1274,45 @@ TclNewFSPathObj( pathPtr->bytes = NULL; pathPtr->length = 0; + /* + * Look for path components made up of only "." + * This is overly conservative analysis to keep simple. It may + * mark some things as needing more aggressive normalization + * that don't actually need it. No harm done. + */ + for (p = addStrRep; len > 0; p++, len--) { + switch (state) { + case 0: /* So far only "." since last dirsep or start */ + switch (*p) { + case '.': + count++; + break; + case '/': + case '\\': + case ':': + if (count) { + PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM; + len = 0; + } + break; + default: + count = 0; + state = 1; + } + case 1: /* Scanning for next dirsep */ + switch (*p) { + case '/': + case '\\': + case ':': + state = 0; + break; + } + } + } + if (len == 0 && count) { + PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM; + } + return pathPtr; } @@ -1756,20 +1798,36 @@ Tcl_FSGetNormalizedPath( } Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); - /* - * Normalize the combined string, but only starting after the end of - * the previously normalized 'dir'. This should be much faster! We use - * 'cwdLen-1' so that we are already pointing at the dir-separator - * that we know about. The normalization code will actually start off - * directly after that separator. - */ + /* Normalize the combined string. */ - TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, - (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); + if (PATHFLAGS(pathPtr) & TCLPATH_NEEDNORM) { + /* + * If the "tail" part has components (like /../) that cause + * the combined path to need more complete normalizing, + * call on the more powerful routine to accomplish that so + * we avoid [Bug 2385549] ... + */ - /* - * Now we need to construct the new path object - */ + Tcl_Obj *newCopy = TclFSNormalizeAbsolutePath(interp, copy, NULL); + Tcl_DecrRefCount(copy); + copy = newCopy; + } else { + /* + * ... but in most cases where we join a trouble free tail + * to a normalized head, we can more efficiently normalize the + * combined path by passing over only the unnormalized tail + * portion. When this is sufficient, prior developers claim + * this should be much faster. We use 'cwdLen-1' so that we are + * already pointing at the dir-separator that we know about. + * The normalization code will actually start off directly + * after that separator. + */ + + TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, + (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); + } + + /* Now we need to construct the new path object. */ if (pathType == TCL_PATH_RELATIVE) { Tcl_Obj *origDir = fsPathPtr->cwdPtr; @@ -1810,6 +1868,11 @@ Tcl_FSGetNormalizedPath( TclDecrRefCount(dir); } if (clientData != NULL) { + /* + * This may be unnecessary. It appears that the + * TclFSNormalizeToUniquePath call above should have already + * set this up. Not changing out of fear of the unknown. + */ fsPathPtr->nativePathPtr = clientData; } PATHFLAGS(pathPtr) = 0; |