From d900f4d589fe63fad662b5a810f83f692c68a905 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 29 Sep 2021 12:09:13 +0200 Subject: [PATCH] Fix #77978: Dirname ending in colon unzips to wrong dir When making the relative path, we must not stop on a `:\` sequence in the middle of the filename. This is only significant on Windows as it may indicate an absolute filename, but this is already checked at the beginning of the function. Note that the bug and this patch affects all systems. However, on Windows the file is no longer extracted at all, since Windows NTSF does not allow filenames containing colons; this should likely be tackled along with other unsupported characters (such as trailing dots) by replacing these with an underscore (this is what Window's built-in extractor and 7-zip do). --- ext/zip/php_zip.c | 4 ++-- ext/zip/tests/bug77978.phpt | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 ext/zip/tests/bug77978.phpt diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 57aa4df34f9e3..9b73e3fed03d2 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -117,8 +117,8 @@ static char * php_zip_make_relative_path(char *path, size_t path_len) /* {{{ */ return path; } - if (i >= 2 && (path[i -1] == '.' || path[i -1] == ':')) { - /* i is the position of . or :, add 1 for / */ + if (i >= 2 && path[i -1] == '.') { + /* i is the position of ., add 1 for / */ path_begin = path + i + 1; break; } diff --git a/ext/zip/tests/bug77978.phpt b/ext/zip/tests/bug77978.phpt new file mode 100644 index 0000000000000..2f3c22f4213a2 --- /dev/null +++ b/ext/zip/tests/bug77978.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bug #77978 (Dirname ending in colon unzips to wrong dir) +--SKIPIF-- + +--FILE-- +open($file, ZipArchive::CREATE|ZipArchive::OVERWRITE); +$zip->addFromString("dir/test:/filename.txt", "contents"); +$zip->close(); + +$zip->open($file); +// Windows won't extract filenames with colons; we suppress the warning +@$zip->extractTo($target, "dir/test:/filename.txt"); +$zip->close(); + +var_dump(!file_exists("$target/filename.txt")); +var_dump(PHP_OS_FAMILY === "Windows" || file_exists("$target/dir/test:/filename.txt")); +?> +--EXPECT-- +bool(true) +bool(true) +--CLEAN-- +