diff options
-rwxr-xr-x | apps/files_encryption/tests/trashbin.php | 2 | ||||
-rw-r--r-- | apps/files_trashbin/lib/storage.php | 3 | ||||
-rw-r--r-- | apps/files_trashbin/lib/trashbin.php | 43 | ||||
-rw-r--r-- | apps/files_trashbin/tests/storage.php | 132 |
4 files changed, 178 insertions, 2 deletions
diff --git a/apps/files_encryption/tests/trashbin.php b/apps/files_encryption/tests/trashbin.php index b759c8e32fd..2704a9752cc 100755 --- a/apps/files_encryption/tests/trashbin.php +++ b/apps/files_encryption/tests/trashbin.php @@ -93,6 +93,8 @@ class Trashbin extends TestCase { // cleanup test user \OC_User::deleteUser(self::TEST_ENCRYPTION_TRASHBIN_USER1); + \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); + parent::tearDownAfterClass(); } diff --git a/apps/files_trashbin/lib/storage.php b/apps/files_trashbin/lib/storage.php index aa5d48b5fbe..5036a260d0c 100644 --- a/apps/files_trashbin/lib/storage.php +++ b/apps/files_trashbin/lib/storage.php @@ -46,6 +46,9 @@ class Storage extends Wrapper { if (count($parts) > 3 && $parts[2] === 'files') { $filesPath = implode('/', array_slice($parts, 3)); $result = \OCA\Files_Trashbin\Trashbin::move2trash($filesPath); + // in cross-storage cases the file will be copied + // but not deleted, so we delete it here + $this->storage->unlink($path); } else { $result = $this->storage->unlink($path); } diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php index f5cebea6b78..1833936ea26 100644 --- a/apps/files_trashbin/lib/trashbin.php +++ b/apps/files_trashbin/lib/trashbin.php @@ -166,8 +166,7 @@ class Trashbin { \OC_FileProxy::$enabled = false; $trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp; try { - $sizeOfAddedFiles = $view->filesize('/files/' . $file_path); - $view->rename('/files/' . $file_path, $trashPath); + $sizeOfAddedFiles = self::renameRecursive('/files/'.$file_path, $trashPath, $view); } catch (\OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e) { $sizeOfAddedFiles = false; if ($view->file_exists($trashPath)) { @@ -807,6 +806,46 @@ class Trashbin { } /** + * recursive rename a whole directory and preserve timestamps + * + * @param string $source source path, relative to the users files directory + * @param string $destination destination path relative to the users root directoy + * @param \OC\Files\View $view file view for the users root directory + * @return int + * @throws Exceptions\CopyRecursiveException + */ + private static function renameRecursive($source, $destination, \OC\Files\View $view) { + $size = 0; + if ($view->is_dir($source)) { + $view->mkdir($destination); + $view->touch($destination, $view->filemtime($source)); + foreach ($view->getDirectoryContent($source) as $i) { + $pathDir = $source . '/' . $i['name']; + if ($view->is_dir($pathDir)) { + $size += self::renameRecursive($pathDir, $destination . '/' . $i['name'], $view); + } else { + $size += $view->filesize($pathDir); + $mtime = $view->filemtime($pathDir); + $result = $view->rename($pathDir, $destination . '/' . $i['name']); + if (!$result) { + throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException(); + } + $view->touch($destination . '/' . $i['name'], $mtime); + } + } + } else { + $size += $view->filesize($source); + $mtime = $view->filemtime($source); + $result = $view->rename($source, $destination); + if (!$result) { + throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException(); + } + $view->touch($destination, $mtime); + } + return $size; + } + + /** * find all versions which belong to the file we want to restore * * @param string $filename name of the file which should be restored diff --git a/apps/files_trashbin/tests/storage.php b/apps/files_trashbin/tests/storage.php new file mode 100644 index 00000000000..c340b9d2362 --- /dev/null +++ b/apps/files_trashbin/tests/storage.php @@ -0,0 +1,132 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\Files_trashbin\Tests\Storage; + +use OC\Files\Storage\Home; +use OC\Files\Storage\Temporary; +use OC\Files\Mount\MountPoint; +use OC\Files\Filesystem; + +class Storage extends \Test\TestCase { + /** + * @var \OCA\Files_trashbin\Storage + */ + private $wrapper; + + /** + * @var \OCP\Files\Storage + */ + private $storage; + + /** + * @var string + */ + private $user; + + /** + * @var \OC\Files\Storage\Storage + **/ + private $originalStorage; + + /** + * @var \OC\Files\View + */ + private $userView; + + protected function setUp() { + parent::setUp(); + + $this->user = $this->getUniqueId('user'); + \OC_User::createUser($this->user, $this->user); + + // this will setup the FS + $this->loginAsUser($this->user); + + $this->originalStorage = \OC\Files\Filesystem::getStorage('/'); + + $mockUser = $this->getMock('\OCP\IUser'); + $mockUser->expects($this->any()) + ->method('getHome') + ->will($this->returnValue($this->originalStorage->getLocalFolder($this->user))); + $mockUser->expects($this->any()) + ->method('getUID') + ->will($this->returnValue($this->user)); + + // use temp as root storage so we can wrap it for testing + $this->storage = new Home( + array('user' => $mockUser) + ); + $this->wrapper = new \OCA\Files_Trashbin\Storage( + array( + 'storage' => $this->storage, + 'mountPoint' => $this->user, + ) + ); + + // make room for a new root + Filesystem::clearMounts(); + $rootMount = new MountPoint($this->originalStorage, ''); + Filesystem::getMountManager()->addMount($rootMount); + $homeMount = new MountPoint($this->wrapper, $this->user); + Filesystem::getMountManager()->addMount($homeMount); + + $this->userView = new \OC\Files\View('/' . $this->user . '/files/'); + $this->userView->file_put_contents('test.txt', 'foo'); + } + + protected function tearDown() { + \OC\Files\Filesystem::mount($this->originalStorage, array(), '/'); + $this->logout(); + parent::tearDown(); + } + + public function testSingleStorageDelete() { + $this->assertTrue($this->storage->file_exists('files/test.txt')); + $this->userView->unlink('test.txt'); + $this->storage->getScanner()->scan(''); + $this->assertFalse($this->userView->getFileInfo('test.txt')); + $this->assertFalse($this->storage->file_exists('files/test.txt')); + + // check if file is in trashbin + $rootView = new \OC\Files\View('/'); + $results = $rootView->getDirectoryContent($this->user . '/files_trashbin/files/'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('test.txt', substr($name, 0, strrpos($name, '.'))); + } + + public function testCrossStorageDelete() { + $storage2 = new Temporary(array()); + $wrapper2 = new \OCA\Files_Trashbin\Storage( + array( + 'storage' => $storage2, + 'mountPoint' => $this->user . '/files/substorage', + ) + ); + + $mount = new MountPoint($wrapper2, $this->user . '/files/substorage'); + Filesystem::getMountManager()->addMount($mount); + + $this->userView->file_put_contents('substorage/subfile.txt', 'foo'); + $storage2->getScanner()->scan(''); + $this->assertTrue($storage2->file_exists('subfile.txt')); + $this->userView->unlink('substorage/subfile.txt'); + + $storage2->getScanner()->scan(''); + $this->assertFalse($this->userView->getFileInfo('substorage/subfile.txt')); + $this->assertFalse($storage2->file_exists('subfile.txt')); + + // check if file is in trashbin + $rootView = new \OC\Files\View('/'); + $results = $rootView->getDirectoryContent($this->user . '/files_trashbin/files'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('subfile.txt', substr($name, 0, strrpos($name, '.'))); + } +} |