Пример #1
0
 /**
  * Gets all versions of a note
  *
  * @NoAdminRequired
  * @NoCSRFRequired
  * @CORS
  *
  * @return array
  */
 public function getAllVersions()
 {
     $source = $this->request->getParam("file_name", "");
     list($uid, $filename) = Storage::getUidAndFilename($source);
     $versions = Storage::getVersions($uid, $filename, $source);
     $versionsResults = array();
     if (is_array($versions) && count($versions) > 0) {
         require_once __DIR__ . '/../3rdparty/finediff/finediff.php';
         $users_view = new View('/' . $uid);
         $currentData = $users_view->file_get_contents('files/' . $filename);
         //            $previousData = $currentData;
         //            $versions = array_reverse( $versions, true );
         foreach ($versions as $versionData) {
             // get timestamp of version
             $mtime = (int) $versionData["version"];
             // get filename of note version
             $versionFileName = 'files_versions/' . $filename . '.v' . $mtime;
             // load the data from the file
             $data = $users_view->file_get_contents($versionFileName);
             // calculate diff between versions
             $opcodes = \FineDiff::getDiffOpcodes($currentData, $data);
             $html = \FineDiff::renderDiffToHTMLFromOpcodes($currentData, $opcodes);
             $versionsResults[] = array("timestamp" => $mtime, "humanReadableTimestamp" => $versionData["humanReadableTimestamp"], "diffHtml" => $html, "data" => $data);
             //                $previousData = $data;
         }
         //            $versionsResults = array_reverse( $versionsResults );
     }
     return array("file_name" => $source, "versions" => $versionsResults);
 }
Пример #2
0
 public function handle()
 {
     $userManager = \OC::$server->getUserManager();
     if (!$userManager->userExists($this->user)) {
         // User has been deleted already
         return;
     }
     \OC_Util::setupFS($this->user);
     Storage::expire($this->fileName, $this->versionsSize, $this->neededSpace);
     \OC_Util::tearDownFS();
 }
Пример #3
0
 protected function run($argument)
 {
     $maxAge = $this->expiration->getMaxAgeAsTimestamp();
     if (!$maxAge) {
         return;
     }
     $this->userManager->callForAllUsers(function (IUser $user) {
         $uid = $user->getUID();
         if (!$this->setupFS($uid)) {
             return;
         }
         Storage::expireOlderThanMaxForUser($uid);
     });
 }
Пример #4
0
 protected function run($argument)
 {
     $maxAge = $this->expiration->getMaxAgeAsTimestamp();
     if (!$maxAge) {
         return;
     }
     $users = $this->userManager->search('');
     $isFSready = false;
     foreach ($users as $user) {
         $uid = $user->getUID();
         if (!$isFSready) {
             if (!$this->setupFS($uid)) {
                 continue;
             }
             $isFSready = true;
         }
         Storage::expireOlderThanMaxForUser($uid);
     }
     \OC_Util::tearDownFS();
 }
Пример #5
0
 /**
  * decrypt versions from given file
  * @param string $filelist list of decrypted files, relative to data/user/files
  * @return boolean
  */
 private function decryptVersions($filelist)
 {
     $successful = true;
     if (\OCP\App::isEnabled('files_versions')) {
         foreach ($filelist as $filename) {
             $versions = \OCA\Files_Versions\Storage::getVersions($this->userId, $filename);
             foreach ($versions as $version) {
                 $path = '/' . $this->userId . '/files_versions/' . $version['path'] . '.v' . $version['version'];
                 $encHandle = fopen('crypt://' . $path, 'rb');
                 if ($encHandle === false) {
                     \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $path . '", decryption failed!', \OCP\Util::FATAL);
                     $successful = false;
                     continue;
                 }
                 $plainHandle = $this->view->fopen($path . '.part', 'wb');
                 if ($plainHandle === false) {
                     \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $path . '.part", decryption failed!', \OCP\Util::FATAL);
                     $successful = false;
                     continue;
                 }
                 stream_copy_to_stream($encHandle, $plainHandle);
                 fclose($encHandle);
                 fclose($plainHandle);
                 $this->view->rename($path . '.part', $path);
             }
         }
     }
     return $successful;
 }
Пример #6
0
 /**
  * @param \OC\Files\View $view
  * @param string $path
  */
 private function createAndCheckVersions(\OC\Files\View $view, $path)
 {
     $view->file_put_contents($path, 'test file');
     $view->file_put_contents($path, 'version 1');
     $view->file_put_contents($path, 'version 2');
     $this->loginAsUser(self::TEST_VERSIONS_USER);
     // need to scan for the versions
     list($rootStorage, ) = $this->rootView->resolvePath(self::TEST_VERSIONS_USER . '/files_versions');
     $rootStorage->getScanner()->scan('files_versions');
     $versions = \OCA\Files_Versions\Storage::getVersions(self::TEST_VERSIONS_USER, '/' . $path);
     // note: we cannot predict how many versions are created due to
     // test run timing
     $this->assertGreaterThan(0, count($versions));
 }
Пример #7
0
 /**
  * Move file versions to trash so that they can be restored later
  *
  * @param string $file_path path to original file
  * @param string $filename of deleted file
  * @param integer $timestamp when the file was deleted
  *
  * @return int size of stored versions
  */
 private static function retainVersions($file_path, $filename, $timestamp)
 {
     $size = 0;
     if (\OCP\App::isEnabled('files_versions')) {
         // disable proxy to prevent recursive calls
         $proxyStatus = \OC_FileProxy::$enabled;
         \OC_FileProxy::$enabled = false;
         $user = \OCP\User::getUser();
         $rootView = new \OC\Files\View('/');
         list($owner, $ownerPath) = self::getUidAndFilename($file_path);
         if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
             $size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
             if ($owner !== $user) {
                 self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
             }
             $rootView->rename($owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
         } else {
             if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
                 foreach ($versions as $v) {
                     $size += $rootView->filesize($owner . '/files_versions' . $v['path'] . '.v' . $v['version']);
                     if ($owner !== $user) {
                         $rootView->copy($owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp);
                     }
                     $rootView->rename($owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $user . '/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
                 }
             }
         }
         // enable proxy
         \OC_FileProxy::$enabled = $proxyStatus;
     }
     return $size;
 }
Пример #8
0
 /**
  * Move file versions to trash so that they can be restored later
  *
  * @param string $file_path path to original file
  * @param string $filename of deleted file
  * @param string $owner owner user id
  * @param string $ownerPath path relative to the owner's home storage
  * @param integer $timestamp when the file was deleted
  *
  * @return int size of stored versions
  */
 private static function retainVersions($file_path, $filename, $owner, $ownerPath, $timestamp)
 {
     $size = 0;
     if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) {
         $user = \OCP\User::getUser();
         $rootView = new \OC\Files\View('/');
         if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
             $size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
             if ($owner !== $user) {
                 self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
             }
             self::move($rootView, $owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
         } else {
             if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
                 foreach ($versions as $v) {
                     $size += $rootView->filesize($owner . '/files_versions/' . $v['path'] . '.v' . $v['version']);
                     if ($owner !== $user) {
                         self::copy($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp);
                     }
                     self::move($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $user . '/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
                 }
             }
         }
     }
     return $size;
 }
Пример #9
0
 public function handle()
 {
     \OC_Util::setupFS($this->user);
     Storage::expire($this->fileName, $this->versionsSize, $this->neededSpace);
     \OC_Util::tearDownFS();
 }
Пример #10
0
 /**
  * Expire versions which exceed the quota
  *
  * @param string $filename
  * @return bool|int|null
  */
 public static function expire($filename)
 {
     $config = \OC::$server->getConfig();
     $expiration = self::getExpiration();
     if ($config->getSystemValue('files_versions', Storage::DEFAULTENABLED) == 'true' && $expiration->isEnabled()) {
         if (!Filesystem::file_exists($filename)) {
             return false;
         }
         list($uid, $filename) = self::getUidAndFilename($filename);
         if (empty($filename)) {
             // file maybe renamed or deleted
             return false;
         }
         $versionsFileview = new View('/' . $uid . '/files_versions');
         // get available disk space for user
         $user = \OC::$server->getUserManager()->get($uid);
         $softQuota = true;
         $quota = $user->getQuota();
         if ($quota === null || $quota === 'none') {
             $quota = Filesystem::free_space('/');
             $softQuota = false;
         } else {
             $quota = \OCP\Util::computerFileSize($quota);
         }
         // make sure that we have the current size of the version history
         $versionsSize = self::getVersionsSize($uid);
         // calculate available space for version history
         // subtract size of files and current versions size from quota
         if ($quota >= 0) {
             if ($softQuota) {
                 $files_view = new View('/' . $uid . '/files');
                 $rootInfo = $files_view->getFileInfo('/', false);
                 $free = $quota - $rootInfo['size'];
                 // remaining free space for user
                 if ($free > 0) {
                     $availableSpace = $free * self::DEFAULTMAXSIZE / 100 - $versionsSize;
                     // how much space can be used for versions
                 } else {
                     $availableSpace = $free - $versionsSize;
                 }
             } else {
                 $availableSpace = $quota;
             }
         } else {
             $availableSpace = PHP_INT_MAX;
         }
         $allVersions = Storage::getVersions($uid, $filename);
         $time = time();
         list($toDelete, $sizeOfDeletedVersions) = self::getExpireList($time, $allVersions, $availableSpace <= 0);
         $availableSpace = $availableSpace + $sizeOfDeletedVersions;
         $versionsSize = $versionsSize - $sizeOfDeletedVersions;
         // if still not enough free space we rearrange the versions from all files
         if ($availableSpace <= 0) {
             $result = Storage::getAllVersions($uid);
             $allVersions = $result['all'];
             foreach ($result['by_file'] as $versions) {
                 list($toDeleteNew, $size) = self::getExpireList($time, $versions, $availableSpace <= 0);
                 $toDelete = array_merge($toDelete, $toDeleteNew);
                 $sizeOfDeletedVersions += $size;
             }
             $availableSpace = $availableSpace + $sizeOfDeletedVersions;
             $versionsSize = $versionsSize - $sizeOfDeletedVersions;
         }
         foreach ($toDelete as $key => $path) {
             \OC_Hook::emit('\\OCP\\Versions', 'preDelete', array('path' => $path, 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED));
             self::deleteVersion($versionsFileview, $path);
             \OC_Hook::emit('\\OCP\\Versions', 'delete', array('path' => $path, 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED));
             unset($allVersions[$key]);
             // update array with the versions we keep
             \OCP\Util::writeLog('files_versions', "Expire: " . $path, \OCP\Util::DEBUG);
         }
         // Check if enough space is available after versions are rearranged.
         // If not we delete the oldest versions until we meet the size limit for versions,
         // but always keep the two latest versions
         $numOfVersions = count($allVersions) - 2;
         $i = 0;
         // sort oldest first and make sure that we start at the first element
         ksort($allVersions);
         reset($allVersions);
         while ($availableSpace < 0 && $i < $numOfVersions) {
             $version = current($allVersions);
             \OC_Hook::emit('\\OCP\\Versions', 'preDelete', array('path' => $version['path'] . '.v' . $version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED));
             self::deleteVersion($versionsFileview, $version['path'] . '.v' . $version['version']);
             \OC_Hook::emit('\\OCP\\Versions', 'delete', array('path' => $version['path'] . '.v' . $version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED));
             \OCP\Util::writeLog('files_versions', 'running out of space! Delete oldest version: ' . $version['path'] . '.v' . $version['version'], \OCP\Util::DEBUG);
             $versionsSize -= $version['size'];
             $availableSpace += $version['size'];
             next($allVersions);
             $i++;
         }
         return $versionsSize;
         // finally return the new size of the version history
     }
     return false;
 }
Пример #11
0
 /**
  * test if we find all versions and if the versions array contain
  * the correct 'path' and 'name'
  */
 public function testGetVersions()
 {
     $t1 = time();
     // second version is two weeks older, this way we make sure that no
     // version will be expired
     $t2 = $t1 - 60 * 60 * 24 * 14;
     // create some versions
     $v1 = self::USERS_VERSIONS_ROOT . '/subfolder/test.txt.v' . $t1;
     $v2 = self::USERS_VERSIONS_ROOT . '/subfolder/test.txt.v' . $t2;
     $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/subfolder/');
     $this->rootView->file_put_contents($v1, 'version1');
     $this->rootView->file_put_contents($v2, 'version2');
     // execute copy hook of versions app
     $versions = \OCA\Files_Versions\Storage::getVersions(self::TEST_VERSIONS_USER, '/subfolder/test.txt');
     $this->assertSame(2, count($versions));
     foreach ($versions as $version) {
         $this->assertSame('/subfolder/test.txt', $version['path']);
         $this->assertSame('test.txt', $version['name']);
     }
     //cleanup
     $this->rootView->deleteAll(self::USERS_VERSIONS_ROOT . '/subfolder');
 }
Пример #12
0
 function testDownloadVersions()
 {
     // login as admin
     self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1);
     $rootView = new \OC\Files\View();
     // save file twice to create a new version
     \OC\Files\Filesystem::file_put_contents($this->filename, "revision1");
     \OCA\Files_Versions\Storage::store($this->filename);
     \OC\Files\Filesystem::file_put_contents($this->filename, "revision2");
     // check if the owner can retrieve the correct version
     $versions = \OCA\Files_Versions\Storage::getVersions(self::TEST_ENCRYPTION_SHARE_USER1, $this->filename);
     $this->assertSame(1, count($versions));
     $version = reset($versions);
     $versionUser1 = $rootView->file_get_contents('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_versions/' . $this->filename . '.v' . $version['version']);
     $this->assertSame('revision1', $versionUser1);
     // share the file
     $fileInfo = \OC\Files\Filesystem::getFileInfo($this->filename);
     $this->assertInstanceOf('\\OC\\Files\\FileInfo', $fileInfo);
     $this->assertTrue(\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_SHARE_USER2, \OCP\Constants::PERMISSION_ALL));
     // try to download the version as user2
     self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER2);
     $versionUser2 = $rootView->file_get_contents('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_versions/' . $this->filename . '.v' . $version['version']);
     $this->assertSame('revision1', $versionUser2);
     //cleanup
     self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1);
     \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_SHARE_USER2);
     \OC\Files\Filesystem::unlink($this->filename);
 }
Пример #13
0
}
$file = array_key_exists('file', $_GET) ? (string) urldecode($_GET['file']) : '';
$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : 44;
$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : 44;
$version = array_key_exists('version', $_GET) ? $_GET['version'] : '';
$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
if ($file === '' && $version === '') {
    \OC_Response::setStatus(400);
    //400 Bad Request
    \OC_Log::write('versions-preview', 'No file parameter was passed', \OC_Log::DEBUG);
    exit;
}
if ($maxX === 0 || $maxY === 0) {
    \OC_Response::setStatus(400);
    //400 Bad Request
    \OC_Log::write('versions-preview', 'x and/or y set to 0', \OC_Log::DEBUG);
    exit;
}
try {
    list($user, $file) = \OCA\Files_Versions\Storage::getUidAndFilename($file);
    $preview = new \OC\Preview($user, 'files_versions', $file . '.v' . $version);
    $mimetype = \OC_Helper::getFileNameMimeType($file);
    $preview->setMimetype($mimetype);
    $preview->setMaxX($maxX);
    $preview->setMaxY($maxY);
    $preview->setScalingUp($scalingUp);
    $preview->showPreview();
} catch (\Exception $e) {
    \OC_Response::setStatus(500);
    \OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
}
Пример #14
0
 /**
  * @NoAdminRequired
  * @NoCSRFRequired
  * @PublicPage
  * Given an access token and a fileId, returns the contents of the file.
  * Expects a valid token in access_token parameter.
  */
 public function wopiGetFile($fileId)
 {
     $token = $this->request->getParam('access_token');
     $arr = explode('_', $fileId, 2);
     $version = '0';
     if (count($arr) == 2) {
         $fileId = $arr[0];
         $version = $arr[1];
     }
     \OC::$server->getLogger()->debug('Getting contents of file {fileId}, version {version} by token {token}.', ['app' => $this->appName, 'fileId' => $fileId, 'version' => $version, 'token' => $token]);
     $row = new Db\Wopi();
     $row->loadBy('token', $token);
     //TODO: Support X-WOPIMaxExpectedSize header.
     $res = $row->getPathForToken($fileId, $version, $token);
     $ownerid = $res['owner'];
     // Login the user to see his mount locations
     $this->loginUser($ownerid);
     $filename = '';
     // If some previous version is requested, fetch it from Files_Version app
     if ($version !== '0') {
         \OCP\JSON::checkAppEnabled('files_versions');
         // Setup the FS
         \OC_Util::tearDownFS();
         \OC_Util::setupFS($ownerid, '/' . $ownerid . '/files');
         list($ownerid, $filename) = \OCA\Files_Versions\Storage::getUidAndFilename($res['path']);
         $filename = '/files_versions/' . $filename . '.v' . $version;
         \OC_Util::tearDownFS();
     } else {
         $filename = '/files' . $res['path'];
     }
     // Close the session created for user login
     \OC::$server->getSession()->close();
     return new DownloadResponse($this->request, $ownerid, $filename);
 }