diff options
| -rw-r--r-- | generic/tclPathObj.c | 81 | ||||
| -rw-r--r-- | tests/cmdAH.test | 7 | ||||
| -rw-r--r-- | tests/winFile.test | 6 | ||||
| -rw-r--r-- | tests/winPipe.test | 8 | ||||
| -rw-r--r-- | win/tclWinTest.c | 15 |
5 files changed, 71 insertions, 46 deletions
diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 87ddfb7..d8be51a 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -29,6 +29,9 @@ static int IsSeparatorOrNull(int ch); static Tcl_Obj * GetExtension(Tcl_Obj *pathPtr); static int MakePathFromNormalized(Tcl_Interp *interp, Tcl_Obj *pathPtr); +static Tcl_Obj * TclJoinPath(int elements, Tcl_Obj * const objv[], + int forceRelative); + /* * Define the 'path' object type, which Tcl uses to represent file paths @@ -821,15 +824,13 @@ GetExtension( *--------------------------------------------------------------------------- */ -Tcl_Obj * TclJoinPath(int elements, Tcl_Obj * const objv[]); - Tcl_Obj * Tcl_FSJoinPath( Tcl_Obj *listObj, /* Path elements to join, may have a zero * reference count. */ int elements) /* Number of elements to use (-1 = all) */ { - Tcl_Obj *copy, *res; + Tcl_Obj *res; int objc; Tcl_Obj **objv; @@ -838,17 +839,17 @@ Tcl_FSJoinPath( } elements = ((elements >= 0) && (elements <= objc)) ? elements : objc; - copy = TclListObjCopy(NULL, listObj); Tcl_ListObjGetElements(NULL, listObj, &objc, &objv); - res = TclJoinPath(elements, objv); - Tcl_DecrRefCount(copy); + res = TclJoinPath(elements, objv, 0); return res; } -Tcl_Obj * +static Tcl_Obj * TclJoinPath( - int elements, - Tcl_Obj * const objv[]) + int elements, /* Number of elements to use (-1 = all) */ + Tcl_Obj * const objv[], /* Path elements to join */ + int forceRelative) /* If non-zero, assume all more paths are + * relative (e. g. simple normalization) */ { Tcl_Obj *res = NULL; /* Resulting path object (container of join) */ Tcl_Obj *elt; /* Path part (result if returns part of path) */ @@ -875,13 +876,14 @@ TclJoinPath( * to be an absolute path. Added a check for that elt is absolute. */ - if ((i == (elements-2)) && (i == 0) + if ((i == 0) && (elements == 2) && (elt->typePtr == &tclFsPathType) && !((elt->bytes != NULL) && (elt->bytes[0] == '\0')) && TclGetPathType(elt, NULL, NULL, NULL) == TCL_PATH_ABSOLUTE) { Tcl_Obj *tailObj = objv[i+1]; - - type = TclGetPathType(tailObj, NULL, NULL, NULL); + /* if forceRelative - second path is relative */ + type = forceRelative ? TCL_PATH_RELATIVE : + TclGetPathType(tailObj, NULL, NULL, NULL); if (type == TCL_PATH_RELATIVE) { const char *str; int len; @@ -953,7 +955,9 @@ TclJoinPath( } strElt = Tcl_GetStringFromObj(elt, &strEltLen); driveNameLength = 0; - type = TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName); + /* if forceRelative - all paths excepting first one are relative */ + type = (forceRelative && (i > 0)) ? TCL_PATH_RELATIVE : + TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName); if (type != TCL_PATH_RELATIVE) { /* * Zero out the current result. @@ -2413,37 +2417,30 @@ SetFsPathFromAny( * Handle tilde substitutions, if needed. */ - if (name[0] == '~') { + if (len && name[0] == '~') { char *expandedUser; Tcl_DString temp; int split; char separator = '/'; + /* + * We have multiple cases '~/foo/bar...', '~user/foo/bar...', etc. + * split becomes value 1 for '~/...' as well as for '~'. + */ split = FindSplitPos(name, separator); - if (split != len) { - /* - * We have multiple pieces '~user/foo/bar...' - */ - - name[split] = '\0'; - } /* * Do some tilde substitution. */ - if (name[1] == '\0') { + if (split == 1) { /* - * We have just '~' + * We have just '~' (or '~/...') */ const char *dir; Tcl_DString dirString; - if (split != len) { - name[split] = separator; - } - dir = TclGetEnv("HOME", &dirString); if (dir == NULL) { if (interp) { @@ -2461,22 +2458,24 @@ SetFsPathFromAny( * We have a user name '~user' */ + Tcl_DString userName; + + Tcl_DStringInit(&userName); + Tcl_DStringAppend(&userName, name+1, split-1); + expandedUser = Tcl_DStringValue(&userName); + Tcl_DStringInit(&temp); - if (TclpGetUserHome(name+1, &temp) == NULL) { + if (TclpGetUserHome(expandedUser, &temp) == NULL) { if (interp != NULL) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "user \"", name+1, + Tcl_AppendResult(interp, "user \"", expandedUser, "\" doesn't exist", NULL); } + Tcl_DStringFree(&userName); Tcl_DStringFree(&temp); - if (split != len) { - name[split] = separator; - } return TCL_ERROR; } - if (split != len) { - name[split] = separator; - } + Tcl_DStringFree(&userName); } expandedUser = Tcl_DStringValue(&temp); @@ -2514,14 +2513,18 @@ SetFsPathFromAny( pair[0] = transPtr; pair[1] = Tcl_NewStringObj(name+split+1, -1); - transPtr = TclJoinPath(2, pair); - TclDecrRefCount(pair[0]); - TclDecrRefCount(pair[1]); + transPtr = TclJoinPath(2, pair, 1); + if (transPtr != pair[0]) { + TclDecrRefCount(pair[0]); + } + if (transPtr != pair[1]) { + TclDecrRefCount(pair[1]); + } } } Tcl_DStringFree(&temp); } else { - transPtr = TclJoinPath(1, &pathPtr); + transPtr = TclJoinPath(1, &pathPtr, 1); } /* diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 6cc8c0f..516505c 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -541,6 +541,13 @@ test cmdAH-9.51 {Tcl_FileObjCmd: tail} testsetplatform { testsetplatform windows file tail {foo\bar} } bar +test cmdAH-9.52 {Tcl_FileObjCmd: tail / normalize, bug 7a9dc52b29} { + list \ + [file tail {~/~foo}] \ + [file tail {~/test/~foo}] \ + [file tail [file normalize {~/~foo}]] \ + [file tail [file normalize {~/test/~foo}]] +} [lrepeat 4 ./~foo] # rootname diff --git a/tests/winFile.test b/tests/winFile.test index bfba9cf..d586e06 100644 --- a/tests/winFile.test +++ b/tests/winFile.test @@ -60,13 +60,15 @@ test winFile-1.4 {TclpGetUserHome} {win nt nonPortable} { test winFile-2.1 {TclpMatchFiles: case sensitivity} {win} { makeFile {} GlobCapS - set result [list [glob -nocomplain GlobC*] [glob -nocomplain globc*]] + set args [list -nocomplain -tails -directory [temporaryDirectory]] + set result [list [glob {*}$args GlobC*] [glob {*}$args globc*]] removeFile GlobCapS set result } {GlobCapS GlobCapS} test winFile-2.2 {TclpMatchFiles: case sensitivity} {win} { makeFile {} globlower - set result [list [glob -nocomplain globl*] [glob -nocomplain gLOBl*]] + set args [list -nocomplain -tails -directory [temporaryDirectory]] + set result [list [glob {*}$args globl*] [glob {*}$args gLOBl*]] removeFile globlower set result } {globlower globlower} diff --git a/tests/winPipe.test b/tests/winPipe.test index 6a02147..70d4843 100644 --- a/tests/winPipe.test +++ b/tests/winPipe.test @@ -17,9 +17,13 @@ namespace import -force ::tcltest::* unset -nocomplain path -set bindir [file join [pwd] [file dirname [info nameofexecutable]]] +set org_pwd [pwd] +set bindir [file join $org_pwd [file dirname [info nameofexecutable]]] set cat32 [file join $bindir cat32.exe] +# several test-cases here expect current directory == [temporaryDirectory]: +cd [temporaryDirectory] + testConstraint exec [llength [info commands exec]] testConstraint testexcept [llength [info commands testexcept]] testConstraint cat32 [file exists $cat32] @@ -600,4 +604,6 @@ if {[catch {set env(TEMP) $env_temp}]} { file delete big little stdout stderr nothing echoArgs.tcl echoArgs.bat file delete -force [file join [temporaryDirectory] test(Dir)Check] ::tcltest::cleanupTests +# back to original directory: +cd $org_pwd; unset org_pwd return diff --git a/win/tclWinTest.c b/win/tclWinTest.c index 73f4e45..7f49b63 100644 --- a/win/tclWinTest.c +++ b/win/tclWinTest.c @@ -420,9 +420,11 @@ TestplatformChmod( static const SECURITY_INFORMATION infoBits = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; + /* don't deny DELETE mask (reset writable only, allow test-cases cleanup) */ static const DWORD readOnlyMask = FILE_DELETE_CHILD | FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA | FILE_APPEND_DATA - | FILE_WRITE_DATA | DELETE; + | FILE_WRITE_DATA + /* | DELETE */; /* * References to security functions (only available on NT and later). @@ -466,7 +468,10 @@ TestplatformChmod( TCL_DECLARE_MUTEX(initializeMutex) Tcl_MutexLock(&initializeMutex); if (!initialized) { - HMODULE handle = GetModuleHandle(TEXT("ADVAPI")); + HMODULE handle = GetModuleHandle(TEXT("ADVAPI32")); + if (handle == NULL) { + handle = GetModuleHandle(TEXT("ADVAPI")); + } if (handle != NULL) { setNamedSecurityInfoProc = (setNamedSecurityInfoADef) @@ -661,11 +666,13 @@ TestplatformChmod( } /* - * Apply the new ACL. + * Apply the new ACL. Note PROTECTED_DACL_SECURITY_INFORMATION can be used + * to remove inherited ACL (we need to overwrite the default ACL's in this case) */ if (set_readOnly == acl_readOnly_found || setNamedSecurityInfoProc( - (LPSTR) nativePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, + (LPSTR) nativePath, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION /*| PROTECTED_DACL_SECURITY_INFORMATION*/, NULL, NULL, newAcl, NULL) == ERROR_SUCCESS) { res = 0; } |
