Fix version rollback to keep fileid
This commit is contained in:
parent
41d7870d7b
commit
2228faaa39
|
@ -262,11 +262,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');
|
||||
|
@ -282,12 +287,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::scheduleExpire($file);
|
||||
return true;
|
||||
|
||||
}else if ( $versionCreated ) {
|
||||
} else if ($versionCreated) {
|
||||
self::deleteVersion($users_view, $version);
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +299,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
|
||||
|
|
|
@ -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
|
||||
|
@ -420,6 +422,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
|
||||
|
|
Loading…
Reference in New Issue