[Pkg-owncloud-commits] [owncloud] 02/58: Fix version rollback to keep fileid

David Prévot taffit at moszumanska.debian.org
Tue Aug 11 15:58:02 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to annotated tag v8.0.6
in repository owncloud.

commit 2972585ba14ca243f18d02bd9f23ebbcf86af496
Author: Vincent Petry <pvince81 at owncloud.com>
Date:   Wed Apr 8 17:56:20 2015 +0200

    Fix version rollback to keep fileid
---
 apps/files_versions/lib/storage.php    | 42 +++++++++++++--
 apps/files_versions/tests/versions.php | 96 ++++++++++++++++++++++++++++++++++
 2 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/apps/files_versions/lib/storage.php b/apps/files_versions/lib/storage.php
index 60a4c46..11e693b 100644
--- a/apps/files_versions/lib/storage.php
+++ b/apps/files_versions/lib/storage.php
@@ -243,11 +243,16 @@ class Storage {
 	}
 
 	/**
-	 * rollback to an old version of a file.
+	 * Rollback to an old version of a file.
+	 *
+	 * @param string $file file name
+	 * @param int $revision revision timestamp
 	 */
 	public static function rollback($file, $revision) {
 
 		if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
+			// add expected leading slash
+			$file = '/' . ltrim($file, '/');
 			list($uid, $filename) = self::getUidAndFilename($file);
 			$users_view = new \OC\Files\View('/'.$uid);
 			$files_view = new \OC\Files\View('/'.\OCP\User::getUser().'/files');
@@ -270,12 +275,11 @@ class Storage {
 			}
 
 			// rollback
-			if( @$users_view->rename('files_versions'.$filename.'.v'.$revision, 'files'.$filename) ) {
+			if (self::copyFileContents($users_view, 'files_versions' . $filename . '.v' . $revision, 'files' . $filename)) {
 				$files_view->touch($file, $revision);
 				Storage::expire($file);
 				return true;
-
-			}else if ( $versionCreated ) {
+			} else if ($versionCreated) {
 				self::deleteVersion($users_view, $version);
 			}
 		}
@@ -283,6 +287,36 @@ class Storage {
 
 	}
 
+	/**
+	 * Stream copy file contents from $path1 to $path2
+	 *
+	 * @param \OC\Files\View $view view to use for copying
+	 * @param string $path1 source file to copy
+	 * @param string $path2 target file
+	 *
+	 * @return bool true for success, false otherwise
+	 */
+	private static function copyFileContents($view, $path1, $path2) {
+		list($storage1, $internalPath1) = $view->resolvePath($path1);
+		list($storage2, $internalPath2) = $view->resolvePath($path2);
+
+		if ($storage1 === $storage2) {
+			return $storage1->rename($internalPath1, $internalPath2);
+		}
+		$source = $storage1->fopen($internalPath1, 'r');
+		$target = $storage2->fopen($internalPath2, 'w');
+		// FIXME: might need to use part file to avoid concurrent writes
+		// (this would be an issue anyway when renaming/restoring cross-storage)
+		list(, $result) = \OC_Helper::streamCopy($source, $target);
+		fclose($source);
+		fclose($target);
+
+		if ($result !== false) {
+			$storage1->unlink($internalPath1);
+		}
+
+		return ($result !== false);
+	}
 
 	/**
 	 * get a list of all available versions of a file in descending chronological order
diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php
index cf0ffb3..f0a408b 100644
--- a/apps/files_versions/tests/versions.php
+++ b/apps/files_versions/tests/versions.php
@@ -22,6 +22,8 @@
 
 require_once __DIR__ . '/../appinfo/app.php';
 
+use OC\Files\Storage\Temporary;
+
 /**
  * Class Test_Files_versions
  * this class provide basic files versions test
@@ -406,6 +408,100 @@ class Test_Files_Versioning extends \Test\TestCase {
 		$this->rootView->deleteAll(self::USERS_VERSIONS_ROOT . '/subfolder');
 	}
 
+	public function testRestoreSameStorage() {
+		\OC\Files\Filesystem::mkdir('sub');
+		$this->doTestRestore();
+	}
+
+	public function testRestoreCrossStorage() {
+		$storage2 = new Temporary(array());
+		\OC\Files\Filesystem::mount($storage2, array(), self::TEST_VERSIONS_USER . '/files/sub');
+
+		$this->doTestRestore();
+	}
+
+	private function doTestRestore() {
+		$filePath = self::TEST_VERSIONS_USER . '/files/sub/test.txt';
+		$this->rootView->file_put_contents($filePath, 'test file');
+
+		$t0 = $this->rootView->filemtime($filePath);
+
+		// not exactly the same timestamp as the file
+		$t1 = time() - 60;
+		// second version is two weeks older
+		$t2 = $t1 - 60 * 60 * 24 * 14;
+
+		// create some versions
+		$v1 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t1;
+		$v2 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t2;
+
+		$this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/sub');
+		$this->rootView->file_put_contents($v1, 'version1');
+		$this->rootView->file_put_contents($v2, 'version2');
+
+		$oldVersions = \OCA\Files_Versions\Storage::getVersions(
+			self::TEST_VERSIONS_USER, '/sub/test.txt'
+		);
+
+		$this->assertCount(2, $oldVersions);
+
+		$this->assertEquals('test file', $this->rootView->file_get_contents($filePath));
+		$info1 = $this->rootView->getFileInfo($filePath);
+
+		\OCA\Files_Versions\Storage::rollback('sub/test.txt', $t2);
+
+		$this->assertEquals('version2', $this->rootView->file_get_contents($filePath));
+		$info2 = $this->rootView->getFileInfo($filePath);
+
+		$this->assertNotEquals(
+			$info2['etag'],
+			$info1['etag'],
+			'Etag must change after rolling back version'
+		);
+		$this->assertEquals(
+			$info2['fileid'],
+			$info1['fileid'],
+			'File id must not change after rolling back version'
+		);
+		$this->assertEquals(
+			$info2['mtime'],
+			$t2,
+			'Restored file has mtime from version'
+		);
+
+		$newVersions = \OCA\Files_Versions\Storage::getVersions(
+			self::TEST_VERSIONS_USER, '/sub/test.txt'
+		);
+
+		$this->assertTrue(
+			$this->rootView->file_exists(self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t0),
+			'A version file was created for the file before restoration'
+		);
+		$this->assertTrue(
+			$this->rootView->file_exists($v1),
+			'Untouched version file is still there'
+		);
+		$this->assertFalse(
+			$this->rootView->file_exists($v2),
+			'Restored version file gone from files_version folder'
+		);
+
+		$this->assertCount(2, $newVersions, 'Additional version created');
+
+		$this->assertTrue(
+			isset($newVersions[$t0 . '#' . 'test.txt']),
+			'A version was created for the file before restoration'
+		);
+		$this->assertTrue(
+			isset($newVersions[$t1 . '#' . 'test.txt']),
+			'Untouched version is still there'
+		);
+		$this->assertFalse(
+			isset($newVersions[$t2 . '#' . 'test.txt']),
+			'Restored version is not in the list any more'
+		);
+	}
+
 	/**
 	 * @param string $user
 	 * @param bool $create

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud.git



More information about the Pkg-owncloud-commits mailing list