From a7c51a9e790452db4a5d6bb8f38111f2f8e401bd Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 4 Dec 2008 17:43:53 +0000 Subject: * generic/tclIOUtil.c (Tcl_FSGetNormalizedPath): Added another flag value TCLPATH_NEEDNORM to mark those intreps which need more complete normalization attention for correct results. [Bug 2385549] --- ChangeLog | 6 ++++ generic/tclIOUtil.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7b38f39..e4c4c29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-12-04 Don Porter + + * generic/tclIOUtil.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 * generic/tclFileName.c (TclDoGlob): One of the 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; -- cgit v0.12