-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proper copy/move between multiple local storages #13360
Changes from all commits
b302592
8575bb2
31e9470
d726db7
d16ee41
c4ec8fb
d26c6ca
4047739
0772e3b
d4c91dc
c29419e
0f21303
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -525,4 +525,59 @@ 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 ($result and ($file = readdir($dh)) !== false) { | ||
if (!Filesystem::isIgnoredDir($file)) { | ||
$result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file); | ||
} | ||
} | ||
} | ||
} else { | ||
$source = $sourceStorage->fopen($sourceInternalPath, 'r'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: will this go through the storage wrappers or bypass them ? When we had this on $view level the fopen() was done on the view. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will use the storage wrappers |
||
$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); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add |
||
return $result; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -322,7 +322,7 @@ public function hasUpdated($path, $time) { | |
* @param string $path | ||
* @return string | ||
*/ | ||
protected function getSourcePath($path) { | ||
public function getSourcePath($path) { | ||
$fullPath = $this->datadir . $path; | ||
return $fullPath; | ||
} | ||
|
@@ -353,5 +353,41 @@ public function getETag($path) { | |
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' => '/']); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add "getSourcePath()" to the Storage interface ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No, it only makes sense for some backends, and the Local and Shared versions both mean something different |
||
} 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')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this will also catch the Windows local storage, right ? |
||
/** | ||
* @var \OC\Files\Storage\Local $sourceStorage | ||
*/ | ||
$rootStorage = new Local(['datadir' => '/']); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. atm, this implementation is not used on windows There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't see a point in this PR that would cause this not being ran on windows?! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since Windows support is dropped for master => Not a problem anymore. |
||
return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm... what happens if $sourceStorage is a "local external storage mount" ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes |
||
} else { | ||
return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add PHPDoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still applies 🙈
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done