From 6455265a464952ed8409b54f3d8670424006e503 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 15 May 2012 21:51:59 +0200 Subject: [PATCH] Fixing Zip to properly extract empty folders. Additionally adding getContentList to IArchive and implementing it for Zip. Furthermore the API of Tar and Zip now also matches in the data-arrays. Fixes WoltLab/WCF#591 Closes WoltLab/WCF#592 --- .../files/lib/system/io/IArchive.class.php | 7 ++++ .../install/files/lib/system/io/Tar.class.php | 7 ++-- .../install/files/lib/system/io/Zip.class.php | 37 +++++++++++++++---- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/wcfsetup/install/files/lib/system/io/IArchive.class.php b/wcfsetup/install/files/lib/system/io/IArchive.class.php index 259db55537..10b2f4583c 100644 --- a/wcfsetup/install/files/lib/system/io/IArchive.class.php +++ b/wcfsetup/install/files/lib/system/io/IArchive.class.php @@ -12,6 +12,13 @@ namespace wcf\system\io; * @category Community Framework */ interface IArchive { + /** + * Returns the table of contents (TOC) list for this tar archive. + * + * @return array list of content + */ + public function getContentList(); + /** * Returns an associative array with information * about a specific file in the archive. diff --git a/wcfsetup/install/files/lib/system/io/Tar.class.php b/wcfsetup/install/files/lib/system/io/Tar.class.php index 99a8fa0f60..7210002e9c 100644 --- a/wcfsetup/install/files/lib/system/io/Tar.class.php +++ b/wcfsetup/install/files/lib/system/io/Tar.class.php @@ -218,9 +218,10 @@ class Tar implements IArchive { } $header = $this->getFileInfo($index); - // can not extract a folder - if ($header['type'] != 'file') { - return false; + FileUtil::makePath(dirname($destination)); + if ($header['type'] === 'folder') { + FileUtil::makePath($destination); + return; } // seek to offset diff --git a/wcfsetup/install/files/lib/system/io/Zip.class.php b/wcfsetup/install/files/lib/system/io/Zip.class.php index 59b9a4810c..112f5ebe3c 100644 --- a/wcfsetup/install/files/lib/system/io/Zip.class.php +++ b/wcfsetup/install/files/lib/system/io/Zip.class.php @@ -36,6 +36,16 @@ class Zip extends File implements IArchive { return false; } + /** + * @see wcf\system\io\IArchive::getContentList() + */ + public function getContentList() { + $this->jumpToCentralDirectory(); + $centralDirectory = $this->readCentralDirectory(); + + return $centralDirectory['files']; + } + /** * @see wcf\system\io\IArchive::getFileInfo() */ @@ -76,6 +86,7 @@ class Zip extends File implements IArchive { catch (SystemException $e) { return false; } + if ($file['header']['type'] === 'folder') return false; return $file['content']; } @@ -94,6 +105,11 @@ class Zip extends File implements IArchive { } FileUtil::makePath(dirname($destination)); + if ($file['header']['type'] === 'folder') { + FileUtil::makePath($destination); + return; + } + $targetFile = new File($destination); $targetFile->write($file['content'], strlen($file['content'])); $targetFile->close(); @@ -105,12 +121,12 @@ class Zip extends File implements IArchive { @$targetFile->chmod(0755); } - if ($file['header']['x-timestamp']) { - @$targetFile->touch($file['header']['x-timestamp']); + if ($file['header']['mtime']) { + @$targetFile->touch($file['header']['mtime']); } // check filesize - if (filesize($destination) != $file['header']['uncompressedSize']) { + if (filesize($destination) != $file['header']['size']) { throw new SystemException("Could not unzip file '".$file['header']['filename']."' to '".$destination."'. Maybe disk quota exceeded in folder '".dirname($destination)."'."); } @@ -158,9 +174,11 @@ class Zip extends File implements IArchive { $day = $data['mdate'] & 31 /* 5 bits */; $month = ($data['mdate'] >> 5) & 15 /* 4 bits */; $year = (($data['mdate'] >> 9) & 127 /* 7 bits */) + 1980; - $data['x-timestamp'] = mktime($hour, $minute, $second, $month, $day, $year); + $data['mtime'] = mktime($hour, $minute, $second, $month, $day, $year); - $data += unpack('Vcrc32/VcompressedSize/VuncompressedSize/vfilenameLength/vextraFieldLength/vfileCommentLength/vdiskNo/vinternalAttr/vexternalAttr', $this->read(26)); + $data += unpack('Vcrc32/VcompressedSize/Vsize/vfilenameLength/vextraFieldLength/vfileCommentLength/vdiskNo/vinternalAttr/vexternalAttr', $this->read(26)); + if ($data['compressedSize'] > 0) $data['type'] = 'file'; + else $data['type'] = 'folder'; $data['offset'] = $this->readAndUnpack(4, 'v'); $data['filename'] = $this->read($data['filenameLength']); @@ -267,7 +285,7 @@ class Zip extends File implements IArchive { $month = ($header['mdate'] >> 5) & 15 /* 4 bits */; $year = (($header['mdate'] >> 9) & 127 /* 7 bits */) + 1980; $header['x-timestamp'] = mktime($hour, $minute, $second, $month, $day, $year); - $header += unpack('Vcrc32/VcompressedSize/VuncompressedSize/vfilenameLength/vextraFieldLength', $this->read(16)); + $header += unpack('Vcrc32/VcompressedSize/Vsize/vfilenameLength/vextraFieldLength', $this->read(16)); // read filename $header['filename'] = $this->read($header['filenameLength']); @@ -276,7 +294,12 @@ class Zip extends File implements IArchive { else $header['extraField'] = ''; // read contents - $content = $this->read($header['compressedSize']); + $header['type'] = 'file'; + if ($header['compressedSize'] > 0) $content = $this->read($header['compressedSize']); + else { + $header['type'] = 'folder'; + $content = false; + } // uncompress file switch ($header['compression']) { -- 2.20.1