From 8575bb2cb9f57d2b7e6d9e9e48e7c85485a7c63b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 16 Jan 2015 13:32:42 +0100 Subject: [PATCH] Move cross storage copy logic to the storage --- lib/private/files/storage/common.php | 48 ++++++++++ lib/private/files/storage/wrapper/wrapper.php | 20 +++++ lib/private/files/view.php | 87 +++---------------- lib/public/files/storage.php | 16 ++++ 4 files changed, 97 insertions(+), 74 deletions(-) diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index ed85d3c07ccb..164225de3e88 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -525,4 +525,52 @@ public function setMountOptions(array $options) { public function getMountOption($name, $default = null) { return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; } + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @param bool $preserveMtime + * @return bool + */ + public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { + if ($sourceStorage->is_dir($sourceInternalPath)) { + $dh = $sourceStorage->opendir($sourceInternalPath); + $result = $this->mkdir($targetInternalPath); + if (is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if (!Filesystem::isIgnoredDir($file)) { + $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file); + } + } + } + } else { + $source = $sourceStorage->fopen($sourceInternalPath, 'r'); + $target = $this->fopen($targetInternalPath, 'w'); + list(, $result) = \OC_Helper::streamCopy($source, $target); + if ($preserveMtime) { + $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath)); + } + fclose($source); + fclose($target); + } + return $result; + } + + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + */ + public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + $result = $this->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true); + if ($result) { + if ($sourceStorage->is_dir($sourceInternalPath)) { + $sourceStorage->rmdir($sourceInternalPath); + } else { + $sourceStorage->unlink($sourceInternalPath); + } + } + return $result; + } } diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php index 6550313f710d..2552c926e021 100644 --- a/lib/private/files/storage/wrapper/wrapper.php +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -505,4 +505,24 @@ public function getDirectDownload($path) { public function verifyPath($path, $fileName) { $this->storage->verifyPath($path, $fileName); } + + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + */ + public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + } + + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + */ + public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 475a9d35af19..84164e2a2499 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -584,8 +584,6 @@ public function deleteAll($directory) { * @return bool|mixed */ public function rename($path1, $path2) { - $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; - $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); if ( @@ -620,7 +618,7 @@ public function rename($path1, $path2) { $mount1 = $this->getMount($path1); $mount2 = $this->getMount($path2); $storage1 = $mount1->getStorage(); - $storage2 = $mount1->getStorage(); + $storage2 = $mount2->getStorage(); $internalPath1 = $mount1->getInternalPath($absolutePath1); $internalPath2 = $mount2->getInternalPath($absolutePath2); @@ -642,34 +640,9 @@ public function rename($path1, $path2) { $result = false; } } else { - if ($this->is_dir($path1)) { - $result = $this->copy($path1, $path2, true); - if ($result === true) { - $result = $storage1->rmdir($internalPath1); - } - } else { - $source = $this->fopen($path1 . $postFix1, 'r'); - $target = $this->fopen($path2 . $postFix2, 'w'); - list(, $result) = \OC_Helper::streamCopy($source, $target); - if ($result !== false) { - $this->touch($path2, $this->filemtime($path1)); - } - - // close open handle - especially $source is necessary because unlink below will - // throw an exception on windows because the file is locked - fclose($source); - fclose($target); - - if ($result !== false) { - $result &= $storage1->unlink($internalPath1); - } else { - // delete partially written target file - $storage2->unlink($internalPath2); - // delete cache entry that was created by fopen - $storage2->getCache()->remove($internalPath2); - } - } + $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2); } + \OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2); if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { // if it was a rename from a part file to a regular file it was a write and not a rename operation $this->updater->update($path2); @@ -708,8 +681,6 @@ public function rename($path1, $path2) { * @return bool|mixed */ public function copy($path1, $path2, $preserveMtime = false) { - $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; - $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); if ( @@ -738,52 +709,20 @@ public function copy($path1, $path2, $preserveMtime = false) { $this->emit_file_hooks_pre($exists, $path2, $run); } if ($run) { - $mp1 = $this->getMountPoint($path1 . $postFix1); - $mp2 = $this->getMountPoint($path2 . $postFix2); - if ($mp1 == $mp2) { - list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); - list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); - if ($storage) { - $result = $storage->copy($internalPath1, $internalPath2); - if (!$result) { - // delete partially written target file - $storage->unlink($internalPath2); - $storage->getCache()->remove($internalPath2); - } + $mount1 = $this->getMount($path1); + $mount2 = $this->getMount($path2); + $storage1 = $mount1->getStorage(); + $internalPath1 = $mount1->getInternalPath($absolutePath1); + $storage2 = $mount2->getStorage(); + $internalPath2 = $mount2->getInternalPath($absolutePath2); + if ($mount1->getMountPoint() == $mount2->getMountPoint()) { + if ($storage1) { + $result = $storage1->copy($internalPath1, $internalPath2); } else { $result = false; } } else { - if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) { - $result = $this->mkdir($path2); - if ($preserveMtime) { - $this->touch($path2, $this->filemtime($path1)); - } - if (is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if (!Filesystem::isIgnoredDir($file)) { - if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file, $preserveMtime)) { - $result = false; - } - } - } - } - } else { - list($storage2, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); - $source = $this->fopen($path1 . $postFix1, 'r'); - $target = $this->fopen($path2 . $postFix2, 'w'); - list(, $result) = \OC_Helper::streamCopy($source, $target); - if($result && $preserveMtime) { - $this->touch($path2, $this->filemtime($path1)); - } - fclose($source); - fclose($target); - if (!$result) { - // delete partially written target file - $storage2->unlink($internalPath2); - $storage2->getCache()->remove($internalPath2); - } - } + $result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2); } $this->updater->update($path2); if ($this->shouldEmitHooks() && $result !== false) { diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index 8a20eff2d9ff..bac2c95ebced 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -358,4 +358,20 @@ public function getDirectDownload($path); * @throws InvalidPathException */ public function verifyPath($path, $fileName); + + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + */ + public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath); + + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + */ + public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath); }