]> source.dussan.org Git - nextcloud-server.git/commitdiff
Call final unlink in trash wrapper's storage
authorVincent Petry <pvince81@owncloud.com>
Wed, 21 Jan 2015 15:29:52 +0000 (16:29 +0100)
committerVincent Petry <pvince81@owncloud.com>
Fri, 23 Jan 2015 11:20:54 +0000 (12:20 +0100)
In the case of cross-storage delete, the files are copied to the trash,
then deleted. The final delete on the source storage would still reach
the trash wrapper.

This fix makes forwards that second call to the wrapped storage to make
the final delete work.

It fixes the issue with remote shares, local shares and external
storage.

Also, it uses a new function "renameRecursive" that renames the files
and preserves the mtimes (like "copy_recursive" did in the past))

apps/files_encryption/tests/trashbin.php
apps/files_trashbin/lib/storage.php
apps/files_trashbin/lib/trashbin.php
apps/files_trashbin/tests/storage.php [new file with mode: 0644]

index b759c8e32fd1dd55cf08aff0f588efaac8544cda..2704a9752cc588ec6e0a60de4f7af4a27c98f1f9 100755 (executable)
@@ -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();
        }
 
index aa5d48b5fbe2da4e11fe50461b84e517cc6df636..5036a260d0cce86a8f639277e05366d7e66077b0 100644 (file)
@@ -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);
                        }
index f5cebea6b789a0d18d3eebb4dfd5a71a517c77ce..1833936ea261797332f58efc292bf51baeb2f8f1 100644 (file)
@@ -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)) {
@@ -806,6 +805,46 @@ class Trashbin {
                return $size;
        }
 
+       /**
+        * 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
         *
diff --git a/apps/files_trashbin/tests/storage.php b/apps/files_trashbin/tests/storage.php
new file mode 100644 (file)
index 0000000..c340b9d
--- /dev/null
@@ -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, '.')));
+       }
+}