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'); }
/** * save text file * * @NoAdminRequired * * @param string $path * @param string $filecontents * @param integer $mtime * @return DataResponse */ public function save($path, $filecontents, $mtime) { try { if ($path !== '' && (is_integer($mtime) && $mtime > 0)) { // Get file mtime $filemtime = $this->view->filemtime($path); if ($mtime !== $filemtime) { // Then the file has changed since opening $this->logger->error('File: ' . $path . ' modified since opening.', ['app' => 'files_texteditor']); return new DataResponse(['message' => $this->l->t('Cannot save file as it has been modified since opening')], Http::STATUS_BAD_REQUEST); } else { // File same as when opened, save file if ($this->view->isUpdatable($path)) { $filecontents = iconv(mb_detect_encoding($filecontents), "UTF-8", $filecontents); try { $this->view->file_put_contents($path, $filecontents); } catch (LockedException $e) { $message = (string) $this->l->t('The file is locked.'); return new DataResponse(['message' => $message], Http::STATUS_BAD_REQUEST); } catch (ForbiddenException $e) { return new DataResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST); } // Clear statcache clearstatcache(); // Get new mtime $newmtime = $this->view->filemtime($path); $newsize = $this->view->filesize($path); return new DataResponse(['mtime' => $newmtime, 'size' => $newsize], Http::STATUS_OK); } else { // Not writeable! $this->logger->error('User does not have permission to write to file: ' . $path, ['app' => 'files_texteditor']); return new DataResponse(['message' => $this->l->t('Insufficient permissions')], Http::STATUS_BAD_REQUEST); } } } else { if ($path === '') { $this->logger->error('No file path supplied'); return new DataResponse(['message' => $this->l->t('File path not supplied')], Http::STATUS_BAD_REQUEST); } else { $this->logger->error('No file mtime supplied', ['app' => 'files_texteditor']); return new DataResponse(['message' => $this->l->t('File mtime not supplied')], Http::STATUS_BAD_REQUEST); } } } catch (HintException $e) { $message = (string) $e->getHint(); return new DataResponse(['message' => $message], Http::STATUS_BAD_REQUEST); } catch (\Exception $e) { $message = (string) $this->l->t('An internal server error occurred.'); return new DataResponse(['message' => $message], Http::STATUS_BAD_REQUEST); } }
/** * Check if we need to re-bundle the certificates because one of the sources has updated * * @param string $uid (optional) user to get the certificate path for, use `null` to get the system path * @return bool */ private function needsRebundling($uid = '') { if ($uid === '') { $uid = $this->uid; } $sourceMTimes = [filemtime(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt')]; $targetBundle = $this->getCertificateBundle($uid); if (!$this->view->file_exists($targetBundle)) { return true; } if (!is_null($uid)) { // also depend on the system bundle $sourceBundles[] = $this->view->filemtime($this->getCertificateBundle(null)); } $sourceMTime = array_reduce($sourceMTimes, function ($max, $mtime) { return max($max, $mtime); }, 0); return $sourceMTime > $this->view->filemtime($targetBundle); }
public function show() { if ($this->useOriginal) { $fp = @$this->view->fopen($this->path, 'rb'); $mtime = $this->view->filemtime($this->path); $size = $this->view->filesize($this->path); $mime = $this->view->getMimetype($this->path); } else { $fp = @fopen($this->path, 'rb'); $mtime = filemtime($this->path); $size = filesize($this->path); $mime = \OC_Helper::getMimetype($this->path); } if ($fp) { \OCP\Response::enableCaching(); \OCP\Response::setLastModifiedHeader($mtime); header('Content-Length: ' . $size); header('Content-Type: ' . $mime); fpassthru($fp); } else { \OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND); } }
/** * @return int */ public function getMTime() { return $this->view->filemtime($this->path); }
/** * recursive copy to copy a whole directory * * @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 */ private static function copy_recursive($source, $destination, $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::copy_recursive($pathDir, $destination . '/' . $i['name'], $view); } else { $size += $view->filesize($pathDir); $result = $view->copy($pathDir, $destination . '/' . $i['name']); if (!$result) { throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException(); } $view->touch($destination . '/' . $i['name'], $view->filemtime($pathDir)); } } } else { $size += $view->filesize($source); $result = $view->copy($source, $destination); if (!$result) { throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException(); } $view->touch($destination, $view->filemtime($source)); } return $size; }
/** * 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 View('/' . $uid); $files_view = new View('/' . User::getUser() . '/files'); $versionCreated = false; //first create a new version $version = 'files_versions' . $filename . '.v' . $users_view->filemtime('files' . $filename); if (!$users_view->file_exists($version)) { $users_view->copy('files' . $filename, 'files_versions' . $filename . '.v' . $users_view->filemtime('files' . $filename)); $versionCreated = true; } $fileToRestore = 'files_versions' . $filename . '.v' . $revision; // Restore encrypted version of the old file for the newly restored file // This has to happen manually here since the file is manually copied below $oldVersion = $users_view->getFileInfo($fileToRestore)->getEncryptedVersion(); $newFileInfo = $files_view->getFileInfo($filename); $cache = $newFileInfo->getStorage()->getCache(); $cache->update($newFileInfo->getId(), ['encrypted' => $oldVersion, 'encryptedVersion' => $oldVersion]); // rollback if (self::copyFileContents($users_view, $fileToRestore, 'files' . $filename)) { $files_view->touch($file, $revision); Storage::scheduleExpire($uid, $file); \OC_Hook::emit('\\OCP\\Versions', 'rollback', array('path' => $filename, 'revision' => $revision)); return true; } else { if ($versionCreated) { self::deleteVersion($users_view, $version); } } } return false; }
public static function filemtime($path) { return self::$defaultInstance->filemtime($path); }