summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclFileName.c8
-rw-r--r--generic/tclZipfs.c36
-rw-r--r--tests/zipfs.test46
3 files changed, 74 insertions, 16 deletions
diff --git a/generic/tclFileName.c b/generic/tclFileName.c
index ac0dfa3..f23b468 100644
--- a/generic/tclFileName.c
+++ b/generic/tclFileName.c
@@ -1399,11 +1399,15 @@ Tcl_GlobObjCmd(
* We must ensure that we haven't cut off too much, and turned
* a valid path like '/' or 'C:/' into an incorrect path like
* '' or 'C:'. The way we do this is to add a separator if
- * there are none presently in the prefix.
+ * there are none presently in the prefix. Similar treatment
+ * for the zipfs volume.
*/
- if (strpbrk(Tcl_GetString(pathOrDir), "\\/") == NULL) {
+ const char *temp = Tcl_GetString(pathOrDir);
+ if (strpbrk(temp, "\\/") == NULL) {
Tcl_AppendToObj(pathOrDir, last-1, 1);
+ } else if (!strcmp(temp, "//zipfs:")) {
+ Tcl_AppendToObj(pathOrDir, "/", 1);
}
}
diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c
index 103c246..ffa46d6 100644
--- a/generic/tclZipfs.c
+++ b/generic/tclZipfs.c
@@ -5551,6 +5551,10 @@ ZipFSMatchInDirectoryProc(
memcpy(pat + len, pattern, l + 1);
scnt = CountSlashes(pat);
+ Tcl_HashTable duplicates;
+ int notDuplicate;
+ Tcl_InitHashTable(&duplicates, TCL_STRING_KEYS);
+
if (foundInHash) {
for (hPtr = Tcl_FirstHashEntry(&ZipFS.fileHash, &search); hPtr;
hPtr = Tcl_NextHashEntry(&search)) {
@@ -5563,26 +5567,46 @@ ZipFSMatchInDirectoryProc(
if ((z->depth == scnt) &&
((z->flags & ZE_F_VOLUME) == 0) /* Bug 14db54d81e */
&& Tcl_StringCaseMatch(z->name, pat, 0)) {
+ Tcl_CreateHashEntry(&duplicates, z->name + strip, &notDuplicate);
+ assert(notDuplicate);
AppendWithPrefix(result, prefixBuf, z->name + strip, -1);
}
}
- } else if (dirOnly) {
- /* Not found in hash. May be a path that is the ancestor of a mount */
+ }
+ if (dirOnly) {
+ /*
+ * Not found in hash. May be a path that is the ancestor of a mount.
+ * e.g. glob //zipfs:/a/* with mount at //zipfs:/a/b/c. Also have
+ * to be careful about duplicates, such as when another mount is
+ * //zipfs:/a/b/d
+ */
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
+ Tcl_DString ds;
+ Tcl_DStringInit(&ds);
for (hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search); hPtr;
hPtr = Tcl_NextHashEntry(&search)) {
ZipFile *zf = (ZipFile *)Tcl_GetHashValue(hPtr);
if (Tcl_StringCaseMatch(zf->mountPoint, pat, 0)) {
const char *tail = zf->mountPoint + len;
+ if (*tail == '\0')
+ continue;
const char *end = strchr(tail, '/');
- AppendWithPrefix(result,
- prefixBuf,
- zf->mountPoint + strip,
- end ? (int)(end - zf->mountPoint) : -1);
+ Tcl_DStringAppend(&ds,
+ zf->mountPoint + strip,
+ end ? (Tcl_Size)(end - zf->mountPoint) : -1);
+ const char *matchedPath = Tcl_DStringValue(&ds);
+ Tcl_HashEntry *dupTableEntry =
+ Tcl_CreateHashEntry(&duplicates, matchedPath, &notDuplicate);
+ if (notDuplicate) {
+ AppendWithPrefix(
+ result, prefixBuf, matchedPath, Tcl_DStringLength(&ds));
+ }
+ Tcl_DStringFree(&ds);
}
}
}
+ Tcl_DeleteHashTable(&duplicates);
ckfree(pat);
end:
diff --git a/tests/zipfs.test b/tests/zipfs.test
index dbcf093..75a1651 100644
--- a/tests/zipfs.test
+++ b/tests/zipfs.test
@@ -412,7 +412,7 @@ namespace eval test_ns_zipfs {
# list of paths -> list of paths under [zipfs root]
proc zipfspaths {args} {
- return [lmap path $args {file join [zipfs root] $path}]
+ return [lsort [lmap path $args {file join [zipfs root] $path}]]
}
proc cleanup {} {
@@ -706,7 +706,7 @@ namespace eval test_ns_zipfs {
testzipfslist no-pattern-mount-on-empty "" {test.zip {}} {{} test testdir testdir/test2} -constraints !zipfslib
testzipfslist no-pattern-mount-on-root "" [list test.zip [zipfs root]] {{} test testdir testdir/test2} -constraints !zipfslib
testzipfslist no-pattern-mount-on-slash "" [list test.zip /] {{} test testdir testdir/test2} -constraints !zipfslib
- testzipfslist no-pattern-mount-on-level3 "" [list test.zip testmt/a/b] {{} testmt testmt/a testmt/a/b testmt/a/b/test testmt/a/b/testdir testmt/a/b/testdir/test2} -constraints {knownBug !zipfslib}
+ testzipfslist no-pattern-mount-on-mezzo "" [list test.zip testmt/a/b] {{} testmt testmt/a testmt/a/b testmt/a/b/test testmt/a/b/testdir testmt/a/b/testdir/test2} -constraints {knownBug !zipfslib}
testzipfslist no-pattern-multiple "" {test.zip testmountA test.zip testmountB/subdir} {
testmountA testmountA/test testmountA/testdir testmountA/testdir/test2
testmountB/subdir testmountB/subdir/test testmountB/subdir/testdir testmountB/subdir/testdir/test2
@@ -745,8 +745,8 @@ namespace eval test_ns_zipfs {
testzipfsexists dir [file join $defaultMountPoint testdir] 1
testzipfsexists mountpoint $defaultMountPoint 1
testzipfsexists root [zipfs root] 1 $defaultMountPoint
- testzipfsexists level3 [file join $defaultMountPoint a b] 1 [file join $defaultMountPoint a b c]
- testzipfsexists level3-enoent [file join $defaultMountPoint a c] 0 [file join $defaultMountPoint a b c]
+ testzipfsexists mezzo [file join $defaultMountPoint a b] 1 [file join $defaultMountPoint a b c]
+ testzipfsexists mezzo-enoent [file join $defaultMountPoint a c] 0 [file join $defaultMountPoint a b c]
#
# zipfs find
@@ -804,13 +804,13 @@ namespace eval test_ns_zipfs {
# bug-6183f535c8
testzipfsfind root-path [zipfs root] {
test.zip {} test.zip testmountB/subdir
- } [zipfspaths test testdir testdir/test2] -constraints !zipfslib
+ } [zipfspaths test testdir testdir/test2 testmountB testmountB/subdir testmountB/subdir/test testmountB/subdir/testdir testmountB/subdir/testdir/test2] -constraints !zipfslib
- testzipfsfind level3 [file join [zipfs root] testmt a] {
+ testzipfsfind mezzo [file join [zipfs root] testmt a] {
test.zip testmt/a/b
} [zipfspaths testmt/a/b testmt/a/b/test testmt/a/b/testdir testmt/a/b/testdir/test2]
- testzipfsfind level3-root [zipfs root] {
+ testzipfsfind mezzo-root [zipfs root] {
test.zip testmt/a/b
} [zipfspaths testmt testmt/a testmt/a/b testmt/a/b/test testmt/a/b/testdir testmt/a/b/testdir/test2] \
-constraints bug-9e039ee0b9
@@ -888,7 +888,7 @@ namespace eval test_ns_zipfs {
zipfs info $defaultMountPoint
} -result [list [zippath junk-at-start.zip] 0 0 4]
- test zipfs-info-level3 "zipfs info on mount point - verify correct offset of zip content" -setup {
+ test zipfs-info-mezzo "zipfs info on mount point - verify correct offset of zip content" -setup {
# zip starts at offset 4
mount [zippath junk-at-start.zip] /testmt/a/b
} -cleanup {
@@ -1368,6 +1368,36 @@ namespace eval test_ns_zipfs {
#
# glob of zipfs file
+ proc xxx {id mounts cmdopts resultpaths args} {
+ set setup {
+ foreach {zippath mountpoint} $mounts {
+ zipfs mount [zippath $zippath] [file join [zipfs root] $mountpoint]
+ }
+ }
+ if {[dict exists $args -setup]} {
+ append setup \n[dict get $args -setup]
+ dict unset args -setup
+ }
+ set cleanup cleanup
+ if {[dict exists $args -cleanup]} {
+ set cleanup "[dict get $args -cleanup]\n$cleanup"
+ dict unset args -cleanup
+ }
+ set resultpaths [lsort $resultpaths]
+ test zipfs-xxx-$id "zipfs glob $id $cmdopts" -body {
+ lsort [glob {*}$cmdopts]
+ } -setup $setup -cleanup $cleanup -result $resultpaths {*}$args
+ }
+ xxx root {test.zip /} [list [zipfs root]*] [zipfspaths test testdir]
+ xxx root-pat {test.zip /} [list [zipfs root]*d*] [zipfspaths testdir]
+ xxx root-deep {test.zip /} [list [zipfs root]*/*] [zipfspaths testdir/test2]
+ xxx root-dir {test.zip /} [list -dir [zipfs root] *] [zipfspaths test testdir]
+ xxx root-dir-tails {test.zip /} [list -tails -dir [zipfs root] *] [list test testdir]
+ xxx root-type-d {test.zip /} [list -type d [zipfs root]*] [zipfspaths testdir]
+ xxx root-type-f {test.zip /} [list -type f [zipfs root]*] [zipfspaths test]
+ xxx root-path {test.zip /} [list -path [zipfs root]t *d*] [zipfspaths testdir]
+
+
proc testzipfsglob {id mountpoint pat result {globopt {}} args} {
test zipfs-glob-$id "zipfs glob $id" -setup {
mount [zippath test.zip] $mountpoint