From 149792abe629c3105c7966ffb14c7514d4bcb3c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 28 Sep 2015 13:14:32 +0200 Subject: [PATCH 1/6] Clean PHPDoc --- lib/private/streamer.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/private/streamer.php b/lib/private/streamer.php index 6f0a70e2388..b6e6892b6c7 100644 --- a/lib/private/streamer.php +++ b/lib/private/streamer.php @@ -89,9 +89,9 @@ class Streamer { /** * Add a file to the archive at the specified location and file name. * - * @param string $stream Stream to read data from - * @param string $internalName Filepath and name to be used in the archive. - * @param int $size Filesize + * @param string $stream Stream to read data from + * @param string $internalName Filepath and name to be used in the archive. + * @param int $size Filesize * @return bool $success */ public function addFileFromStream($stream, $internalName, $size){ @@ -101,17 +101,17 @@ class Streamer { return $this->streamerInstance->addFileFromStream($stream, $internalName, $size); } } - + /** * Add an empty directory entry to the archive. * - * @param string $directoryPath Directory Path and name to be added to the archive. + * @param string $dirName Directory Path and name to be added to the archive. * @return bool $success */ public function addEmptyDir($dirName){ return $this->streamerInstance->addEmptyDir($dirName); } - + /** * Close the archive. * A closed archive can no longer have new files added to it. After From b5dce05cb6856cfd99bded35ca87b4a8c12813bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 28 Sep 2015 13:14:51 +0200 Subject: [PATCH 2/6] Lock files which are zipped --- lib/private/files.php | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/private/files.php b/lib/private/files.php index 86ebf40cc57..5befda3bad5 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -40,7 +40,6 @@ * */ -use OC\Lock\NoopLockingProvider; use OC\Streamer; use OCP\Lock\ILockingProvider; @@ -63,10 +62,11 @@ class OC_Files { OC_Response::setContentDispositionHeader($name, 'attachment'); header('Content-Transfer-Encoding: binary'); OC_Response::disableCaching(); - $filesize = \OC\Files\Filesystem::filesize($filename); - header('Content-Type: '.\OC_Helper::getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename))); - if ($filesize > -1) { - OC_Response::setContentLengthHeader($filesize); + $fileSize = \OC\Files\Filesystem::filesize($filename); + $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename)); + header('Content-Type: '.$type); + if ($fileSize > -1) { + OC_Response::setContentLengthHeader($fileSize); } } @@ -122,7 +122,17 @@ class OC_Files { if ($getType === self::FILE) { $view->lockFile($filename, ILockingProvider::LOCK_SHARED); } - + if ($getType === self::ZIP_FILES) { + foreach ($files as $file) { + $file = $dir . '/' . $file; + $view->lockFile($file, ILockingProvider::LOCK_SHARED); + } + } + if ($getType === self::ZIP_DIR) { + $file = $dir . '/' . $files; + $view->lockFile($file, ILockingProvider::LOCK_SHARED); + } + if ($streamer) { $streamer->sendHeaders($name); } elseif (\OC\Files\Filesystem::isReadable($filename)) { @@ -166,6 +176,16 @@ class OC_Files { if ($getType === self::FILE) { $view->unlockFile($filename, ILockingProvider::LOCK_SHARED); } + if ($getType === self::ZIP_FILES) { + foreach ($files as $file) { + $file = $dir . '/' . $file; + $view->unlockFile($file, ILockingProvider::LOCK_SHARED); + } + } + if ($getType === self::ZIP_DIR) { + $file = $dir . '/' . $files; + $view->unlockFile($file, ILockingProvider::LOCK_SHARED); + } } catch (\OCP\Lock\LockedException $ex) { $l = \OC::$server->getL10N('core'); $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; From def8e0c12a263e16ec7245c5be47b6aed10f7a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 2 Oct 2015 17:40:45 +0200 Subject: [PATCH 3/6] log the exception during zip creation --- lib/private/files.php | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/lib/private/files.php b/lib/private/files.php index 5befda3bad5..4783a617065 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -173,24 +173,14 @@ class OC_Files { } else { \OC\Files\Filesystem::readfile($filename); } - if ($getType === self::FILE) { - $view->unlockFile($filename, ILockingProvider::LOCK_SHARED); - } - if ($getType === self::ZIP_FILES) { - foreach ($files as $file) { - $file = $dir . '/' . $file; - $view->unlockFile($file, ILockingProvider::LOCK_SHARED); - } - } - if ($getType === self::ZIP_DIR) { - $file = $dir . '/' . $files; - $view->unlockFile($file, ILockingProvider::LOCK_SHARED); - } + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); } catch (\OCP\Lock\LockedException $ex) { + OC::$server->getLogger()->logException($ex); $l = \OC::$server->getL10N('core'); $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint); } catch (\Exception $ex) { + OC::$server->getLogger()->logException($ex); $l = \OC::$server->getL10N('core'); $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; \OC_Template::printErrorPage($l->t('Can\'t read file'), $hint); @@ -278,4 +268,27 @@ class OC_Files { } return false; } + + /** + * @param $dir + * @param $files + * @param $getType + * @param $view + * @param $filename + */ + private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) { + if ($getType === self::FILE) { + $view->unlockFile($filename, ILockingProvider::LOCK_SHARED); + } + if ($getType === self::ZIP_FILES) { + foreach ($files as $file) { + $file = $dir . '/' . $file; + $view->unlockFile($file, ILockingProvider::LOCK_SHARED); + } + } + if ($getType === self::ZIP_DIR) { + $file = $dir . '/' . $files; + $view->unlockFile($file, ILockingProvider::LOCK_SHARED); + } + } } From 3bf818450a826d296b8e56ab41f91b3f9f8112f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 2 Oct 2015 17:42:18 +0200 Subject: [PATCH 4/6] release locks in case of exception --- lib/private/files.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/private/files.php b/lib/private/files.php index 4783a617065..af3a8ac574d 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -175,11 +175,13 @@ class OC_Files { } self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); } catch (\OCP\Lock\LockedException $ex) { + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); OC::$server->getLogger()->logException($ex); $l = \OC::$server->getL10N('core'); $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint); } catch (\Exception $ex) { + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); OC::$server->getLogger()->logException($ex); $l = \OC::$server->getL10N('core'); $hint = method_exists($ex, 'getHint') ? $ex->getHint() : ''; From 57f841da2c414209ad9d4ae5a1cd0ac5ba604b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 5 Oct 2015 17:31:37 +0200 Subject: [PATCH 5/6] Recursively lock folder contents --- lib/private/files.php | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/private/files.php b/lib/private/files.php index af3a8ac574d..099602d56b0 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -40,6 +40,7 @@ * */ +use OC\Files\View; use OC\Streamer; use OCP\Lock\ILockingProvider; @@ -123,14 +124,10 @@ class OC_Files { $view->lockFile($filename, ILockingProvider::LOCK_SHARED); } if ($getType === self::ZIP_FILES) { - foreach ($files as $file) { - $file = $dir . '/' . $file; - $view->lockFile($file, ILockingProvider::LOCK_SHARED); - } + self::lockFiles($view, $dir, $files); } if ($getType === self::ZIP_DIR) { - $file = $dir . '/' . $files; - $view->lockFile($file, ILockingProvider::LOCK_SHARED); + self::lockFiles($view, $dir, $files); } if ($streamer) { @@ -189,6 +186,30 @@ class OC_Files { } } + /** + * @param View $view + * @param $dir + * @param string[]|string $files + */ + public static function lockFiles($view, $dir, $files) { + if (!is_array($files)) { + $file = $dir . '/' . $files; + $files = [$file]; + } + foreach ($files as $file) { + $file = $dir . '/' . $file; + $view->lockFile($file, ILockingProvider::LOCK_SHARED); + if ($view->is_dir($file)) { + $contents = $view->getDirectoryContent($file); + $contents = array_map(function($fileInfo) use ($file) { + /** @var \OCP\Files\FileInfo $fileInfo */ + return $file . '/' . $fileInfo->getName(); + }, $contents); + self::lockFiles($view, $dir, $contents); + } + } + } + /** * set the maximum upload size limit for apache hosts using .htaccess * From be46cd6737f7b4414d4583d0096d90b73929ce3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 5 Oct 2015 17:47:15 +0200 Subject: [PATCH 6/6] Refactor single file download into it's own method --- lib/private/files.php | 147 ++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 76 deletions(-) diff --git a/lib/private/files.php b/lib/private/files.php index 099602d56b0..e49e0ffdbc2 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -79,97 +79,65 @@ class OC_Files { * @param boolean $onlyHeader ; boolean to only send header of the request */ public static function get($dir, $files, $onlyHeader = false) { + $view = \OC\Files\Filesystem::getView(); + $getType = self::FILE; + $filename = $dir; + try { - if (is_array($files) && count($files) === 1) { - $files = $files[0]; - } - - if (is_array($files)) { - $getType = self::ZIP_FILES; - $basename = basename($dir); - if ($basename) { - $name = $basename; - } else { - $name = 'download'; + if (is_array($files) && count($files) === 1) { + $files = $files[0]; + $filename = $dir . '/' . $files; + if (!$view->is_dir($files)) { + self::getSingleFile($view, $dir, $files, $onlyHeader); + return; + } } - $filename = $dir . '/' . $name; - } else { - $filename = $dir . '/' . $files; - if (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) { + $name = 'download'; + if (is_array($files)) { + $getType = self::ZIP_FILES; + $basename = basename($dir); + if ($basename) { + $name = $basename; + } + + $filename = $dir . '/' . $name; + } else { + $filename = $dir . '/' . $files; $getType = self::ZIP_DIR; // downloading root ? - if ($files === '') { - $name = 'download'; - } else { + if ($files !== '') { $name = $files; } - - } else { - $getType = self::FILE; - $name = $files; } - } - if ($getType === self::FILE) { - $streamer = false; - } else { $streamer = new Streamer(); - } - OC_Util::obEnd(); + OC_Util::obEnd(); - try { - if ($getType === self::FILE) { - $view->lockFile($filename, ILockingProvider::LOCK_SHARED); - } + self::lockFiles($view, $dir, $files); + + $streamer->sendHeaders($name); + $executionTime = intval(ini_get('max_execution_time')); + set_time_limit(0); if ($getType === self::ZIP_FILES) { - self::lockFiles($view, $dir, $files); - } - if ($getType === self::ZIP_DIR) { - self::lockFiles($view, $dir, $files); - } - - if ($streamer) { - $streamer->sendHeaders($name); - } elseif (\OC\Files\Filesystem::isReadable($filename)) { - self::sendHeaders($filename, $name); - } elseif (!\OC\Files\Filesystem::file_exists($filename)) { - header("HTTP/1.0 404 Not Found"); - $tmpl = new OC_Template('', '404', 'guest'); - $tmpl->printPage(); - exit(); - } else { - header("HTTP/1.0 403 Forbidden"); - die('403 Forbidden'); - } - if ($onlyHeader) { - return; - } - if ($streamer) { - $executionTime = intval(ini_get('max_execution_time')); - set_time_limit(0); - if ($getType === self::ZIP_FILES) { - foreach ($files as $file) { - $file = $dir . '/' . $file; - if (\OC\Files\Filesystem::is_file($file)) { - $fileSize = \OC\Files\Filesystem::filesize($file); - $fh = \OC\Files\Filesystem::fopen($file, 'r'); - $streamer->addFileFromStream($fh, basename($file), $fileSize); - fclose($fh); - } elseif (\OC\Files\Filesystem::is_dir($file)) { - $streamer->addDirRecursive($file); - } + foreach ($files as $file) { + $file = $dir . '/' . $file; + if (\OC\Files\Filesystem::is_file($file)) { + $fileSize = \OC\Files\Filesystem::filesize($file); + $fh = \OC\Files\Filesystem::fopen($file, 'r'); + $streamer->addFileFromStream($fh, basename($file), $fileSize); + fclose($fh); + } elseif (\OC\Files\Filesystem::is_dir($file)) { + $streamer->addDirRecursive($file); } - } elseif ($getType === self::ZIP_DIR) { - $file = $dir . '/' . $files; - $streamer->addDirRecursive($file); } - $streamer->finalize(); - set_time_limit($executionTime); - } else { - \OC\Files\Filesystem::readfile($filename); + } elseif ($getType === self::ZIP_DIR) { + $file = $dir . '/' . $files; + $streamer->addDirRecursive($file); } + $streamer->finalize(); + set_time_limit($executionTime); self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); } catch (\OCP\Lock\LockedException $ex) { self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); @@ -186,6 +154,32 @@ class OC_Files { } } + /** + * @param View $view + * @param string $name + */ + private static function getSingleFile($view, $dir, $name, $onlyHeader) { + $filename = $dir . '/' . $name; + OC_Util::obEnd(); + $view->lockFile($filename, ILockingProvider::LOCK_SHARED); + + if (\OC\Files\Filesystem::isReadable($filename)) { + self::sendHeaders($filename, $name); + } elseif (!\OC\Files\Filesystem::file_exists($filename)) { + header("HTTP/1.0 404 Not Found"); + $tmpl = new OC_Template('', '404', 'guest'); + $tmpl->printPage(); + exit(); + } else { + header("HTTP/1.0 403 Forbidden"); + die('403 Forbidden'); + } + if ($onlyHeader) { + return; + } + $view->readfile($filename); + } + /** * @param View $view * @param $dir @@ -296,7 +290,7 @@ class OC_Files { * @param $dir * @param $files * @param $getType - * @param $view + * @param View $view * @param $filename */ private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) { @@ -314,4 +308,5 @@ class OC_Files { $view->unlockFile($file, ILockingProvider::LOCK_SHARED); } } + }