Commit bbaf97ca authored by Thomas Müller's avatar Thomas Müller
Browse files

Merge pull request #14644 from owncloud/trash-expire-command

Expire files from the trash in the background
parents 69277736 4ffca58b
<?php
/**
* ownCloud - trash bin
*
* @author Robin Appelman
* @copyright 2015 Robin Appelman icewind@owncloud.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Files_Trashbin\Command;
use OC\Command\FileAccess;
use OCA\Files_Trashbin\Trashbin;
use OCP\Command\ICommand;
class Expire implements ICommand {
use FileAccess;
/**
* @var string
*/
private $user;
/**
* @var int
*/
private $trashBinSize;
/**
* @param string $user
* @param int $trashBinSize
*/
function __construct($user, $trashBinSize) {
$this->user = $user;
$this->trashBinSize = $trashBinSize;
}
public function handle() {
\OC_Util::tearDownFS();
\OC_Util::setupFS($this->user);
Trashbin::expire($this->trashBinSize, $this->user);
}
}
......@@ -23,6 +23,7 @@
namespace OCA\Files_Trashbin;
use OC\Files\Filesystem;
use OCA\Files_Trashbin\Command\Expire;
class Trashbin {
// how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
......@@ -211,13 +212,13 @@ class Trashbin {
}
$userTrashSize += $size;
$userTrashSize -= self::expire($userTrashSize, $user);
self::scheduleExpire($userTrashSize, $user);
// if owner !== user we also need to update the owners trash size
if ($owner !== $user) {
$ownerTrashSize = self::getTrashbinSize($owner);
$ownerTrashSize += $size;
$ownerTrashSize -= self::expire($ownerTrashSize, $owner);
self::scheduleExpire($ownerTrashSize, $owner);
}
return ($sizeOfAddedFiles === false) ? false : true;
......@@ -429,7 +430,7 @@ class Trashbin {
if ($view->is_dir('/files_trashbin/versions/' . $file)) {
$rootView->rename(\OC\Files\Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp)) {
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp, $user)) {
foreach ($versions as $v) {
if ($timestamp) {
$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
......@@ -533,8 +534,8 @@ class Trashbin {
$file = $filename;
}
$size += self::deleteVersions($view, $file, $filename, $timestamp);
$size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp);
$size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
$size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp, $user);
if ($view->is_dir('/files_trashbin/files/' . $file)) {
$size += self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin/files/' . $file));
......@@ -555,14 +556,13 @@ class Trashbin {
* @param $timestamp
* @return int
*/
private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp) {
private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
$size = 0;
if (\OCP\App::isEnabled('files_versions')) {
$user = \OCP\User::getUser();
if ($view->is_dir('files_trashbin/versions/' . $file)) {
$size += self::calculateSize(new \OC\Files\view('/' . $user . '/files_trashbin/versions/' . $file));
$view->unlink('files_trashbin/versions/' . $file);
} else if ($versions = self::getVersionsFromTrash($filename, $timestamp)) {
} else if ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
foreach ($versions as $v) {
if ($timestamp) {
$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
......@@ -584,10 +584,9 @@ class Trashbin {
* @param $timestamp
* @return int
*/
private static function deleteEncryptionKeys(\OC\Files\View $view, $file, $filename, $timestamp) {
private static function deleteEncryptionKeys(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
$size = 0;
if (\OCP\App::isEnabled('files_encryption')) {
$user = \OCP\User::getUser();
$keyfiles = \OC\Files\Filesystem::normalizePath('files_trashbin/keys/' . $filename);
......@@ -689,26 +688,18 @@ class Trashbin {
$freeSpace = self::calculateFreeSpace($size, $user);
if ($freeSpace < 0) {
self::expire($size, $user);
self::scheduleExpire($size, $user);
}
}
/**
* clean up the trash bin
*
* @param int $trashbinSize current size of the trash bin
* @param int $trashBinSize current size of the trash bin
* @param string $user
* @return int size of expired files
*/
private static function expire($trashbinSize, $user) {
// let the admin disable auto expire
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
if ($autoExpire === false) {
return 0;
}
$availableSpace = self::calculateFreeSpace($trashbinSize, $user);
public static function expire($trashBinSize, $user) {
$availableSpace = self::calculateFreeSpace($trashBinSize, $user);
$size = 0;
$retention_obligation = \OC_Config::getValue('trashbin_retention_obligation', self::DEFAULT_RETENTION_OBLIGATION);
......@@ -725,8 +716,18 @@ class Trashbin {
// delete files from trash until we meet the trash bin size limit again
$size += self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
}
return $size;
/**@param int $trashBinSize current size of the trash bin
* @param string $user
*/
private static function scheduleExpire($trashBinSize, $user) {
// let the admin disable auto expire
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
if ($autoExpire === false) {
return;
}
\OC::$server->getCommandBus()->push(new Expire($user, $trashBinSize));
}
/**
......@@ -827,8 +828,8 @@ class Trashbin {
* @param int $timestamp timestamp when the file was deleted
* @return array
*/
private static function getVersionsFromTrash($filename, $timestamp) {
$view = new \OC\Files\View('/' . \OCP\User::getUser() . '/files_trashbin/versions');
private static function getVersionsFromTrash($filename, $timestamp, $user) {
$view = new \OC\Files\View('/' . $user . '/files_trashbin/versions');
$versions = array();
//force rescan of versions, local storage may not have updated the cache
......
......@@ -210,6 +210,8 @@ class Test_Trashbin extends \Test\TestCase {
\OC\Files\Filesystem::unlink($folder . 'user1-4.txt');
$this->runCommands();
$filesInTrashUser2AfterDelete = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER2);
// user2-1.txt should have been expired
......
<?php
/**
* Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Command;
use OCP\Command\IBus;
use OCP\Command\ICommand;
class QueueBus implements IBus {
/**
* @var (ICommand|callable)[]
*/
private $queue;
/**
* Schedule a command to be fired
*
* @param \OCP\Command\ICommand | callable $command
*/
public function push($command) {
$this->queue[] = $command;
}
/**
* Require all commands using a trait to be run synchronous
*
* @param string $trait
*/
public function requireSync($trait) {
}
/**
* @param \OCP\Command\ICommand | callable $command
*/
private function runCommand($command) {
if ($command instanceof ICommand) {
$command->handle();
} else {
$command();
}
}
public function run() {
while ($command = array_shift($this->queue)) {
$this->runCommand($command);
}
}
}
......@@ -22,9 +22,23 @@
namespace Test;
use OC\Command\QueueBus;
use OCP\Security\ISecureRandom;
abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* @var \OC\Command\QueueBus
*/
private $commandBus;
protected function setUp() {
// overwrite the command bus with one we can run ourselves
$this->commandBus = new QueueBus();
\OC::$server->registerService('AsyncCommandBus', function(){
return $this->commandBus;
});
}
/**
* Returns a unique identifier as uniqid() is not reliable sometimes
*
......@@ -55,6 +69,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* Remove all entries from the files map table
*
* @param string $dataDir
*/
static protected function tearDownAfterClassCleanFileMapper($dataDir) {
......@@ -66,6 +81,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* Remove all entries from the storages table
*
* @throws \OC\DatabaseException
*/
static protected function tearDownAfterClassCleanStorages() {
......@@ -76,6 +92,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* Remove all entries from the filecache table
*
* @throws \OC\DatabaseException
*/
static protected function tearDownAfterClassCleanFileCache() {
......@@ -91,11 +108,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
*/
static protected function tearDownAfterClassCleanStrayDataFiles($dataDir) {
$knownEntries = array(
'owncloud.log' => true,
'owncloud.db' => true,
'.ocdata' => true,
'..' => true,
'.' => true,
'owncloud.log' => true,
'owncloud.db' => true,
'.ocdata' => true,
'..' => true,
'.' => true,
);
if ($dh = opendir($dataDir)) {
......@@ -122,8 +139,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
$path = $dir . '/' . $file;
if (is_dir($path)) {
self::tearDownAfterClassCleanStrayDataUnlinkDir($path);
}
else {
} else {
@unlink($path);
}
}
......@@ -169,4 +185,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
\OC_Util::tearDownFS();
\OC_User::setUserId('');
}
/**
* Run all commands pushed to the bus
*/
protected function runCommands() {
$this->commandBus->run();
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment