Skip to content

Commit

Permalink
Merge pull request #15486 from owncloud/versions-rollbackkeepfileid
Browse files Browse the repository at this point in the history
Keep fileid when restoring version, using stream copy
  • Loading branch information
MorrisJobke committed May 3, 2015
2 parents 6bd8619 + 972e189 commit 7a3b74a
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 4 deletions.
29 changes: 25 additions & 4 deletions apps/files_versions/lib/storage.php
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,16 @@ public static function renameOrCopy($old_path, $new_path, $operation) {
}

/**
* 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');
Expand All @@ -282,19 +287,35 @@ public static function rollback($file, $revision) {
}

// 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::scheduleExpire($file);
return true;

}else if ( $versionCreated ) {
} else if ($versionCreated) {
self::deleteVersion($users_view, $version);
}
}
return false;

}

/**
* 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);

$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);

return ($result !== false);
}

/**
* get a list of all available versions of a file in descending chronological order
Expand Down
96 changes: 96 additions & 0 deletions apps/files_versions/tests/versions.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

require_once __DIR__ . '/../appinfo/app.php';

use OC\Files\Storage\Temporary;

/**
* Class Test_Files_versions
* this class provide basic files versions test
Expand Down Expand Up @@ -420,6 +422,100 @@ public function testGetVersions() {
$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
Expand Down

0 comments on commit 7a3b74a

Please sign in to comment.