diff options
| -rw-r--r-- | generic/tclInt.h | 2 | ||||
| -rw-r--r-- | generic/tclPathObj.c | 48 | ||||
| -rw-r--r-- | generic/tclZipfs.c | 27 | ||||
| -rw-r--r-- | tests/zipfs.test | 53 |
4 files changed, 115 insertions, 15 deletions
diff --git a/generic/tclInt.h b/generic/tclInt.h index d5a8645..a336a53 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3477,7 +3477,7 @@ MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, Tcl_Size length); /* Tip 430 */ MODULE_SCOPE int TclZipfs_Init(Tcl_Interp *interp); - +MODULE_SCOPE int TclIsZipfsPath(const char *path); MODULE_SCOPE int *TclGetUnicodeFromObj(Tcl_Obj *, int *); MODULE_SCOPE Tcl_Obj *TclNewUnicodeObj(const int *, int); diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 1e8f994..0095469 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -143,9 +143,17 @@ TclFSNormalizeAbsolutePath( * directory separator - we can't use '..' to * remove the volume in a path. */ Tcl_Obj *retVal = NULL; + int zipVolumeLen; dirSep = TclGetString(pathPtr); - if (tclPlatform == TCL_PLATFORM_WINDOWS) { + zipVolumeLen = TclIsZipfsPath(dirSep); + if (zipVolumeLen) { + /* + * NOTE: file normalization for zipfs is very specific to + * format of zipfs volume being of the form //xxx:/ + */ + dirSep += zipVolumeLen-1; /* Start parse after : */ + } else if (tclPlatform == TCL_PLATFORM_WINDOWS) { if ( (dirSep[0] == '/' || dirSep[0] == '\\') && (dirSep[1] == '/' || dirSep[1] == '\\') && (dirSep[2] == '?') @@ -246,13 +254,17 @@ TclFSNormalizeAbsolutePath( Tcl_AppendToObj(retVal, dirSep, 1); } if (!first || (tclPlatform == TCL_PLATFORM_UNIX)) { - linkObj = Tcl_FSLink(retVal, NULL, 0); + if (zipVolumeLen) { + linkObj = NULL; + } else { + linkObj = Tcl_FSLink(retVal, NULL, 0); - /* Safety check in case driver caused sharing */ - if (Tcl_IsShared(retVal)) { - TclDecrRefCount(retVal); - retVal = Tcl_DuplicateObj(retVal); - Tcl_IncrRefCount(retVal); + /* Safety check in case driver caused sharing */ + if (Tcl_IsShared(retVal)) { + TclDecrRefCount(retVal); + retVal = Tcl_DuplicateObj(retVal); + Tcl_IncrRefCount(retVal); + } } if (linkObj != NULL) { @@ -322,10 +334,12 @@ TclFSNormalizeAbsolutePath( /* * Either way, we now remove the last path element (but - * not the first character of the path). + * not the first character of the path). In the case of + * zipfs, make sure not to go beyond the zipfs volume. */ - while (--curLen >= 0) { + int minLen = zipVolumeLen ? zipVolumeLen - 1 : 0; + while (--curLen >= minLen) { if (IsSeparatorOrNull(linkStr[curLen])) { if (curLen) { Tcl_SetObjLength(retVal, curLen); @@ -384,13 +398,21 @@ TclFSNormalizeAbsolutePath( /* * Ensure a windows drive like C:/ has a trailing separator. + * Likewise for zipfs volumes. */ - - if (tclPlatform == TCL_PLATFORM_WINDOWS) { + if (zipVolumeLen || (tclPlatform == TCL_PLATFORM_WINDOWS)) { + int needTrailingSlash = 0; int len; const char *path = TclGetStringFromObj(retVal, &len); - - if (len == 2 && path[0] != 0 && path[1] == ':') { + if (zipVolumeLen) { + if (len == (zipVolumeLen - 1)) + needTrailingSlash = 1; + } else { + if (len == 2 && path[0] != 0 && path[1] == ':') { + needTrailingSlash = 1; + } + } + if (needTrailingSlash) { if (Tcl_IsShared(retVal)) { TclDecrRefCount(retVal); retVal = Tcl_DuplicateObj(retVal); diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c index 47b294e..45a2041 100644 --- a/generic/tclZipfs.c +++ b/generic/tclZipfs.c @@ -69,7 +69,6 @@ } \ } while (0) - #ifdef HAVE_ZLIB #include "zlib.h" #include "crypt.h" @@ -451,6 +450,27 @@ static Tcl_ChannelType ZipChannelType = { #define ERROR_LENGTH ((size_t) -1) /* + *------------------------------------------------------------------------ + * + * TclIsZipfsPath -- + * + * Checks if the passed path has a zipfs volume prefix. + * + * Results: + * 0 if not a zipfs path + * else the length of the zipfs volume prefix + * + * Side effects: + * None. + * + *------------------------------------------------------------------------ + */ +int TclIsZipfsPath (const char *path) +{ + return strncmp(path, ZIPFS_VOLUME, ZIPFS_VOLUME_LEN) ? 0 : ZIPFS_VOLUME_LEN; +} + +/* *------------------------------------------------------------------------- * * ZipReadInt, ZipReadShort, ZipWriteInt, ZipWriteShort -- @@ -6142,6 +6162,11 @@ TclZipfs_TclLibrary(void) return NULL; } +int TclIsZipfsPath (const char *path) +{ + return 0; +} + #endif /* !HAVE_ZLIB */ /* diff --git a/tests/zipfs.test b/tests/zipfs.test index f5fb9f9..727adf0 100644 --- a/tests/zipfs.test +++ b/tests/zipfs.test @@ -1114,6 +1114,59 @@ namespace eval test_ns_zipfs { # # TODO - file copy, file rename etc. + # + # file normalize + proc testzipfsnormalize {id path result {dir {}}} { + if {$dir eq ""} { + test zipfs-file-normalize-$id "zipfs file normalize $id" -body { + file normalize $path + } -result $result + } else { + test zipfs-file-normalize-$id "zipfs file normalize $id" -setup { + set cwd [pwd] + mount [zippath test.zip] [zipfs root] + cd $dir + } -cleanup { + cd $cwd + cleanup + } -body { + file normalize $path + } -result $result + } + } + # The parsing requires all these cases for various code paths + # in particular, root, one below root and more than one below root + testzipfsnormalize dot-1 [zipfs root] [zipfs root] + testzipfsnormalize dot-2 [file join [zipfs root] .] [zipfs root] + testzipfsnormalize dot-3 [file join [zipfs root] . .] [zipfs root] + testzipfsnormalize dot-4 [file join [zipfs root] a .] [file join [zipfs root] a] + testzipfsnormalize dot-5 [file join [zipfs root] a . . .] [file join [zipfs root] a] + testzipfsnormalize dot-6 [file join [zipfs root] a b .] [file join [zipfs root] a b] + testzipfsnormalize dot-7 [file join [zipfs root] a b . .] [file join [zipfs root] a b] + + testzipfsnormalize dotdot-1 [file join [zipfs root] ..] [zipfs root] + testzipfsnormalize dotdot-2 [file join [zipfs root] .. ..] [zipfs root] + testzipfsnormalize dotdot-3 [file join [zipfs root] a ..] [zipfs root] + testzipfsnormalize dotdot-4 [file join [zipfs root] a .. .. ..] [zipfs root] + testzipfsnormalize dotdot-5 [file join [zipfs root] a b ..] [file join [zipfs root] a] + testzipfsnormalize dotdot-6 [file join [zipfs root] a b ..] [file join [zipfs root] a] + testzipfsnormalize dotdot-7 [file join [zipfs root] a b .. ..] [zipfs root] + testzipfsnormalize dotdot-8 [file join [zipfs root] a b .. .. .. ..] [zipfs root] + + testzipfsnormalize relative-1 a [file join [zipfs root] a] [zipfs root] + testzipfsnormalize relative-2 . [zipfs root] [zipfs root] + testzipfsnormalize relative-3 ./ [zipfs root] [zipfs root] + testzipfsnormalize relative-4 ./a [file join [zipfs root] a] [zipfs root] + testzipfsnormalize relative-5 ../ [file join [zipfs root]] [zipfs root] + testzipfsnormalize relative-6 ../a [file join [zipfs root] a] [zipfs root] + testzipfsnormalize relative-7 ../a/ [file join [zipfs root] a] [zipfs root] + testzipfsnormalize relative-8 ../.. [zipfs root] [zipfs root] + testzipfsnormalize relative-9 dir/a [file join [zipfs root] dir a] [zipfs root] + testzipfsnormalize relative-10 dir/dirb/.. [file join [zipfs root] dir] [zipfs root] + testzipfsnormalize relative-11 dir/../a [file join [zipfs root] a] [zipfs root] + testzipfsnormalize relative-12 dir/../a/ [file join [zipfs root] a] [zipfs root] + testzipfsnormalize relative-13 dir/../../../a [file join [zipfs root] a] [zipfs root] + testzipfsnormalize relative-14 a [file join [zipfs root] testdir a] [file join [zipfs root] testdir] # TODO - mkkey, mkimg, mkzip, lmkimg, lmkzip testnumargs "zipfs mkkey" "password" "" -constraints zipfs |
