summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/tclIOUtil.c89
1 files changed, 78 insertions, 11 deletions
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c
index 0de5890..82aa209 100644
--- a/generic/tclIOUtil.c
+++ b/generic/tclIOUtil.c
@@ -17,7 +17,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIOUtil.c,v 1.77.2.38 2008/06/28 04:19:15 dgp Exp $
+ * RCS: @(#) $Id: tclIOUtil.c,v 1.77.2.39 2008/12/04 17:43:53 dgp Exp $
*/
#include "tclInt.h"
@@ -4683,6 +4683,7 @@ typedef struct FsPath {
#define TCLPATH_APPENDED 1
#define TCLPATH_RELATIVE 2
+#define TCLPATH_NEEDNORM 4
/*
*----------------------------------------------------------------------
@@ -5092,6 +5093,8 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len)
FsPath *fsPathPtr;
Tcl_Obj *objPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ CONST char *p;
+ int state = 0, count = 0;
objPtr = Tcl_NewObj();
fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
@@ -5124,6 +5127,45 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len)
objPtr->bytes = NULL;
objPtr->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(objPtr) |= 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(objPtr) |= TCLPATH_NEEDNORM;
+ }
+
return objPtr;
}
@@ -5592,16 +5634,36 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr)
break;
}
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.
- */
- TclFSNormalizeToUniquePath(interp, copy, cwdLen-1,
- (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL));
+
+ /* Normalize the combined string. */
+
+ if (PATHFLAGS(pathObjPtr) & 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] ...
+ */
+
+ 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) {
@@ -5626,6 +5688,11 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr)
Tcl_DecrRefCount(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(pathObjPtr) = 0;