diff --git a/src/zippy/tarballs_v1.nim b/src/zippy/tarballs_v1.nim index 08926a0..ab8db43 100644 --- a/src/zippy/tarballs_v1.nim +++ b/src/zippy/tarballs_v1.nim @@ -46,10 +46,10 @@ proc addDir*( tarball: Tarball, dir: string ) {.raises: [IOError, OSError, ZippyError].} = ## Recursively adds all of the files and directories inside dir to tarball. - if splitFile(dir).ext.len > 0: + if not dirExists(dir): raise newException( ZippyError, - "Error adding dir " & dir & " to tarball, appears to be a file?" + "Error adding dir " & dir & " to tarball, not a directory?" ) let (head, tail) = splitPath(dir) diff --git a/src/zippy/ziparchives_v1.nim b/src/zippy/ziparchives_v1.nim index 5780c74..a2c65cc 100644 --- a/src/zippy/ziparchives_v1.nim +++ b/src/zippy/ziparchives_v1.nim @@ -44,10 +44,10 @@ proc addDir*( archive: ZipArchive, dir: string ) {.raises: [IOError, OSError, ZippyError].} = ## Recursively adds all of the files and directories inside dir to archive. - if splitFile(dir).ext.len > 0: + if not dirExists(dir): raise newException( ZippyError, - "Error adding dir " & dir & " to archive, appears to be a file?" + "Error adding dir " & dir & " to archive, not a directory?" ) let (head, tail) = splitPath(dir) diff --git a/tests/all.nim b/tests/all.nim index 5346be2..3862a9f 100644 --- a/tests/all.nim +++ b/tests/all.nim @@ -1 +1 @@ -import test, test_known_bad, test_levels, test_tarballs_read, test_ziparchives_read, test_ziparchives_write +import test, test_known_bad, test_levels, test_tarballs_read, test_ziparchives_read, test_ziparchives_write, test_issue_97 diff --git a/tests/test_issue_97.nim b/tests/test_issue_97.nim new file mode 100644 index 0000000..57aff03 --- /dev/null +++ b/tests/test_issue_97.nim @@ -0,0 +1,50 @@ +import std/os, std/strutils, zippy/tarballs, zippy/ziparchives + +# https://github.com/guzba/zippy/issues/97 +# A directory whose name contains a period (e.g. `/etc/cron.d`) must not be +# mistaken for a file and rejected: addDir used the filename extension instead +# of checking the filesystem. + +proc containsFile(dir, name, contents: string): bool = + for path in walkDirRec(dir): + if path.extractFilename == name and readFile(path) == contents: + return true + false + +block: + let dir = getTempDir() / "zippy_dotted.d" + removeDir(dir) + createDir(dir) + writeFile(dir / "a.txt", "hello") + + # tarball + let tarPath = getTempDir() / "zippy_dotted.tar.gz" + createTarball(dir, tarPath) # must not raise + doAssert fileExists(tarPath) + let tarOut = getTempDir() / "zippy_dotted_tar_out" + removeDir(tarOut) + tarballs.extractAll(tarPath, tarOut) + doAssert containsFile(tarOut, "a.txt", "hello") + + # zip + let zipPath = getTempDir() / "zippy_dotted.zip" + createZipArchive(dir, zipPath) # must not raise + doAssert fileExists(zipPath) + let zipOut = getTempDir() / "zippy_dotted_zip_out" + removeDir(zipOut) + ziparchives.extractAll(zipPath, zipOut) + doAssert containsFile(zipOut, "a.txt", "hello") + + removeDir(dir) + removeFile(tarPath) + removeFile(zipPath) + removeDir(tarOut) + removeDir(zipOut) + +# A real file (or a nonexistent path) is still rejected. +block: + let file = getTempDir() / "zippy_not_a_dir.txt" + writeFile(file, "x") + doAssertRaises ZippyError: + createTarball(file, getTempDir() / "zippy_not_a_dir.tar.gz") + removeFile(file)