summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMorris Jobke <hey@morrisjobke.de>2015-04-14 14:35:08 +0200
committerMorris Jobke <hey@morrisjobke.de>2015-04-14 14:35:08 +0200
commit82cab257622759d1b64582f27de33a982c79c158 (patch)
treebcacfc55a044830e1a5529b9bece572bb6f180e8 /lib
parentffa115b51725c4774b49c2419f88cb91d726386b (diff)
parent0f21303b751291188733e24b5f213053ea96a368 (diff)
downloadnextcloud-server-82cab257622759d1b64582f27de33a982c79c158.tar.gz
nextcloud-server-82cab257622759d1b64582f27de33a982c79c158.zip
Merge pull request #13360 from owncloud/cross-storage-move
Proper copy/move between multiple local storages
Diffstat (limited to 'lib')
-rw-r--r--lib/private/files/storage/common.php55
-rw-r--r--lib/private/files/storage/local.php38
-rw-r--r--lib/private/files/storage/wrapper/quota.php39
-rw-r--r--lib/private/files/storage/wrapper/wrapper.php20
-rw-r--r--lib/private/files/view.php109
-rw-r--r--lib/public/files/storage.php16
6 files changed, 189 insertions, 88 deletions
diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php
index ed85d3c07cc..66ed713e22d 100644
--- a/lib/private/files/storage/common.php
+++ b/lib/private/files/storage/common.php
@@ -525,4 +525,59 @@ abstract class Common implements Storage {
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 ($result and ($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 ($result and $preserveMtime) {
+ $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
+ }
+ fclose($source);
+ fclose($target);
+
+ if (!$result) {
+ // delete partially written target file
+ $this->unlink($targetInternalPath);
+ // delete cache entry that was created by fopen
+ $this->getCache()->remove($targetInternalPath);
+ }
+ }
+ return (bool)$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)) {
+ $result &= $sourceStorage->rmdir($sourceInternalPath);
+ } else {
+ $result &= $sourceStorage->unlink($sourceInternalPath);
+ }
+ }
+ return $result;
+ }
}
diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php
index 6bd9b4401d6..175b33b0329 100644
--- a/lib/private/files/storage/local.php
+++ b/lib/private/files/storage/local.php
@@ -322,7 +322,7 @@ if (\OC_Util::runningOnWindows()) {
* @param string $path
* @return string
*/
- protected function getSourcePath($path) {
+ public function getSourcePath($path) {
$fullPath = $this->datadir . $path;
return $fullPath;
}
@@ -353,5 +353,41 @@ if (\OC_Util::runningOnWindows()) {
return parent::getETag($path);
}
}
+
+ /**
+ * @param \OCP\Files\Storage $sourceStorage
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @return bool
+ */
+ public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ if($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')){
+ /**
+ * @var \OC\Files\Storage\Local $sourceStorage
+ */
+ $rootStorage = new Local(['datadir' => '/']);
+ return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
+ } else {
+ return parent::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) {
+ if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) {
+ /**
+ * @var \OC\Files\Storage\Local $sourceStorage
+ */
+ $rootStorage = new Local(['datadir' => '/']);
+ return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
+ } else {
+ return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ }
+ }
}
}
diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php
index 3c0fda98dad..92d749a814f 100644
--- a/lib/private/files/storage/wrapper/quota.php
+++ b/lib/private/files/storage/wrapper/quota.php
@@ -55,9 +55,14 @@ class Quota extends Wrapper {
/**
* @param string $path
+ * @param \OC\Files\Storage\Storage $storage
*/
- protected function getSize($path) {
- $cache = $this->getCache();
+ protected function getSize($path, $storage = null) {
+ if (is_null($storage)) {
+ $cache = $this->getCache();
+ } else {
+ $cache = $storage->getCache();
+ }
$data = $cache->get($path);
if (is_array($data) and isset($data['size'])) {
return $data['size'];
@@ -141,4 +146,34 @@ class Quota extends Wrapper {
return $source;
}
}
+
+ /**
+ * @param \OCP\Files\Storage $sourceStorage
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @return bool
+ */
+ public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ $free = $this->free_space('');
+ if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
+ return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param \OCP\Files\Storage $sourceStorage
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @return bool
+ */
+ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ $free = $this->free_space('');
+ if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
+ return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ } else {
+ return false;
+ }
+ }
}
diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php
index 6550313f710..2552c926e02 100644
--- a/lib/private/files/storage/wrapper/wrapper.php
+++ b/lib/private/files/storage/wrapper/wrapper.php
@@ -505,4 +505,24 @@ class Wrapper implements \OC\Files\Storage\Storage {
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 be14521990a..3300998da35 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -584,8 +584,6 @@ class View {
* @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 (
@@ -617,58 +615,33 @@ class View {
if ($run) {
$this->verifyPath(dirname($path2), basename($path2));
- $mp1 = $this->getMountPoint($path1 . $postFix1);
- $mp2 = $this->getMountPoint($path2 . $postFix2);
$manager = Filesystem::getMountManager();
- $mount = $manager->find($absolutePath1 . $postFix1);
- $storage1 = $mount->getStorage();
- $internalPath1 = $mount->getInternalPath($absolutePath1 . $postFix1);
- list($storage2, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
- if ($internalPath1 === '' and $mount instanceof MoveableMount) {
+ $mount1 = $this->getMount($path1);
+ $mount2 = $this->getMount($path2);
+ $storage1 = $mount1->getStorage();
+ $storage2 = $mount2->getStorage();
+ $internalPath1 = $mount1->getInternalPath($absolutePath1);
+ $internalPath2 = $mount2->getInternalPath($absolutePath2);
+
+ if ($internalPath1 === '' and $mount1 instanceof MoveableMount) {
if ($this->isTargetAllowed($absolutePath2)) {
/**
- * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount
+ * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
*/
- $sourceMountPoint = $mount->getMountPoint();
- $result = $mount->moveMount($absolutePath2);
- $manager->moveMount($sourceMountPoint, $mount->getMountPoint());
+ $sourceMountPoint = $mount1->getMountPoint();
+ $result = $mount1->moveMount($absolutePath2);
+ $manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
} else {
$result = false;
}
- } elseif ($mp1 == $mp2) {
+ } elseif ($storage1 == $storage2) {
if ($storage1) {
$result = $storage1->rename($internalPath1, $internalPath2);
} else {
$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);
}
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
@@ -710,8 +683,6 @@ class View {
* @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 (
@@ -740,52 +711,20 @@ class View {
$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 8a20eff2d9f..bac2c95ebce 100644
--- a/lib/public/files/storage.php
+++ b/lib/public/files/storage.php
@@ -358,4 +358,20 @@ interface Storage {
* @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);
}