mirror of
https://github.com/nextcloud/server.git
synced 2026-06-08 16:26:59 -04:00
Merge pull request #5701 from owncloud/sharing-updateownerfoldersizes
Fixed watcher to also update the owner's folder sizes
This commit is contained in:
commit
55331479cd
6 changed files with 341 additions and 114 deletions
|
|
@ -43,7 +43,7 @@ class Shared extends \OC\Files\Storage\Common {
|
|||
* @param string Shared target file path
|
||||
* @return Returns array with the keys path, permissions, and owner or false if not found
|
||||
*/
|
||||
private function getFile($target) {
|
||||
public function getFile($target) {
|
||||
if (!isset($this->files[$target])) {
|
||||
// Check for partial files
|
||||
if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
|
||||
|
|
@ -66,7 +66,7 @@ class Shared extends \OC\Files\Storage\Common {
|
|||
* @param string Shared target file path
|
||||
* @return string source file path or false if not found
|
||||
*/
|
||||
private function getSourcePath($target) {
|
||||
public function getSourcePath($target) {
|
||||
$source = $this->getFile($target);
|
||||
if ($source) {
|
||||
if (!isset($source['fullPath'])) {
|
||||
|
|
|
|||
|
|
@ -32,9 +32,32 @@ class Shared_Watcher extends Watcher {
|
|||
* @param string $path
|
||||
*/
|
||||
public function checkUpdate($path) {
|
||||
if ($path != '') {
|
||||
parent::checkUpdate($path);
|
||||
if ($path != '' && parent::checkUpdate($path)) {
|
||||
// since checkUpdate() has already updated the size of the subdirs,
|
||||
// only apply the update to the owner's parent dirs
|
||||
|
||||
// find last parent before reaching the shared storage root,
|
||||
// which is the actual shared dir from the owner
|
||||
$sepPos = strpos($path, '/');
|
||||
if ($sepPos > 0) {
|
||||
$baseDir = substr($path, 0, $sepPos);
|
||||
} else {
|
||||
$baseDir = $path;
|
||||
}
|
||||
|
||||
// find the path relative to the data dir
|
||||
$file = $this->storage->getFile($baseDir);
|
||||
$view = new \OC\Files\View('/' . $file['fileOwner']);
|
||||
|
||||
// find the owner's storage and path
|
||||
list($storage, $internalPath) = $view->resolvePath($file['path']);
|
||||
|
||||
// update the parent dirs' sizes in the owner's cache
|
||||
$storage->getCache()->correctFolderSize(dirname($internalPath));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,90 +20,33 @@
|
|||
*
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../../lib/base.php';
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
use OCA\Files\Share;
|
||||
|
||||
/**
|
||||
* Class Test_Files_Sharing_Api
|
||||
*/
|
||||
class Test_Files_Sharing_Api extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
const TEST_FILES_SHARING_API_USER1 = "test-share-user1";
|
||||
const TEST_FILES_SHARING_API_USER2 = "test-share-user2";
|
||||
const TEST_FILES_SHARING_API_USER3 = "test-share-user3";
|
||||
|
||||
public $stateFilesEncryption;
|
||||
public $filename;
|
||||
public $data;
|
||||
/**
|
||||
* @var OC_FilesystemView
|
||||
*/
|
||||
public $view;
|
||||
public $folder;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
// clear share hooks
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
\OC::registerShareHooks();
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
|
||||
|
||||
// create users
|
||||
self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1, true);
|
||||
self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, true);
|
||||
self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3, true);
|
||||
|
||||
}
|
||||
class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
|
||||
|
||||
function setUp() {
|
||||
|
||||
//login as user1
|
||||
\Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$this->data = 'foobar';
|
||||
$this->view = new \OC_FilesystemView('/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1 . '/files');
|
||||
parent::setUp();
|
||||
|
||||
$this->folder = '/folder_share_api_test';
|
||||
|
||||
$this->filename = 'share-api-test.txt';
|
||||
|
||||
// remember files_encryption state
|
||||
$this->stateFilesEncryption = \OC_App::isEnabled('files_encryption');
|
||||
|
||||
//we don't want to tests with app files_encryption enabled
|
||||
\OC_App::disable('files_encryption');
|
||||
|
||||
|
||||
$this->assertTrue(!\OC_App::isEnabled('files_encryption'));
|
||||
|
||||
// save file with content
|
||||
$this->view->file_put_contents($this->filename, $this->data);
|
||||
$this->view->mkdir($this->folder);
|
||||
$this->view->file_put_contents($this->folder.'/'.$this->filename, $this->data);
|
||||
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->deleteAll($this->folder);
|
||||
// reset app files_encryption
|
||||
if ($this->stateFilesEncryption) {
|
||||
\OC_App::enable('files_encryption');
|
||||
} else {
|
||||
\OC_App::disable('files_encryption');
|
||||
}
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
|
||||
// cleanup users
|
||||
\OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1);
|
||||
\OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
|
||||
\OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -548,50 +491,4 @@ class Test_Files_Sharing_Api extends \PHPUnit_Framework_TestCase {
|
|||
$this->assertTrue(empty($itemsAfterDelete));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user
|
||||
* @param bool $create
|
||||
* @param bool $password
|
||||
*/
|
||||
private static function loginHelper($user, $create = false, $password = false) {
|
||||
if ($create) {
|
||||
\OC_User::createUser($user, $user);
|
||||
}
|
||||
|
||||
if ($password === false) {
|
||||
$password = $user;
|
||||
}
|
||||
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_User::setUserId('');
|
||||
\OC\Files\Filesystem::tearDown();
|
||||
\OC_Util::setupFS($user);
|
||||
\OC_User::setUserId($user);
|
||||
|
||||
$params['uid'] = $user;
|
||||
$params['password'] = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get some information from a given share
|
||||
* @param int $shareID
|
||||
* @return array with: item_source, share_type, share_with, item_type, permissions
|
||||
*/
|
||||
private function getShareFromId($shareID) {
|
||||
$sql = 'SELECT `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?';
|
||||
$args = array($shareID);
|
||||
$query = \OCP\DB::prepare($sql);
|
||||
$result = $query->execute($args);
|
||||
|
||||
$share = Null;
|
||||
|
||||
if ($result && $result->numRows() > 0) {
|
||||
$share = $result->fetchRow();
|
||||
}
|
||||
|
||||
return $share;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
143
apps/files_sharing/tests/base.php
Normal file
143
apps/files_sharing/tests/base.php
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Bjoern Schiessle
|
||||
* @copyright 2013 Bjoern Schiessle <schiessle@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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../../lib/base.php';
|
||||
|
||||
use OCA\Files\Share;
|
||||
|
||||
/**
|
||||
* Class Test_Files_Sharing_Base
|
||||
*
|
||||
* Base class for sharing tests.
|
||||
*/
|
||||
abstract class Test_Files_Sharing_Base extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
const TEST_FILES_SHARING_API_USER1 = "test-share-user1";
|
||||
const TEST_FILES_SHARING_API_USER2 = "test-share-user2";
|
||||
const TEST_FILES_SHARING_API_USER3 = "test-share-user3";
|
||||
|
||||
public $stateFilesEncryption;
|
||||
public $filename;
|
||||
public $data;
|
||||
/**
|
||||
* @var OC_FilesystemView
|
||||
*/
|
||||
public $view;
|
||||
public $folder;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
// clear share hooks
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
\OC::registerShareHooks();
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
|
||||
|
||||
// create users
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1, true);
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2, true);
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER3, true);
|
||||
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
|
||||
//login as user1
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$this->data = 'foobar';
|
||||
$this->view = new \OC_FilesystemView('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
|
||||
// remember files_encryption state
|
||||
$this->stateFilesEncryption = \OC_App::isEnabled('files_encryption');
|
||||
|
||||
//we don't want to tests with app files_encryption enabled
|
||||
\OC_App::disable('files_encryption');
|
||||
|
||||
|
||||
$this->assertTrue(!\OC_App::isEnabled('files_encryption'));
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
// reset app files_encryption
|
||||
if ($this->stateFilesEncryption) {
|
||||
\OC_App::enable('files_encryption');
|
||||
} else {
|
||||
\OC_App::disable('files_encryption');
|
||||
}
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
|
||||
// cleanup users
|
||||
\OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER1);
|
||||
\OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER2);
|
||||
\OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user
|
||||
* @param bool $create
|
||||
* @param bool $password
|
||||
*/
|
||||
protected static function loginHelper($user, $create = false, $password = false) {
|
||||
if ($create) {
|
||||
\OC_User::createUser($user, $user);
|
||||
}
|
||||
|
||||
if ($password === false) {
|
||||
$password = $user;
|
||||
}
|
||||
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_User::setUserId('');
|
||||
\OC\Files\Filesystem::tearDown();
|
||||
\OC_Util::setupFS($user);
|
||||
\OC_User::setUserId($user);
|
||||
|
||||
$params['uid'] = $user;
|
||||
$params['password'] = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get some information from a given share
|
||||
* @param int $shareID
|
||||
* @return array with: item_source, share_type, share_with, item_type, permissions
|
||||
*/
|
||||
protected function getShareFromId($shareID) {
|
||||
$sql = 'SELECT `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?';
|
||||
$args = array($shareID);
|
||||
$query = \OCP\DB::prepare($sql);
|
||||
$result = $query->execute($args);
|
||||
|
||||
$share = Null;
|
||||
|
||||
if ($result && $result->numRows() > 0) {
|
||||
$share = $result->fetchRow();
|
||||
}
|
||||
|
||||
return $share;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
161
apps/files_sharing/tests/watcher.php
Normal file
161
apps/files_sharing/tests/watcher.php
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2013 Vincent Petry <pvince81@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/>.
|
||||
*
|
||||
*/
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
class Test_Files_Sharing_Watcher extends Test_Files_Sharing_Base {
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
// prepare user1's dir structure
|
||||
$textData = "dummy file data\n";
|
||||
$this->view->mkdir('container');
|
||||
$this->view->mkdir('container/shareddir');
|
||||
$this->view->mkdir('container/shareddir/subdir');
|
||||
|
||||
list($this->ownerStorage, $internalPath) = $this->view->resolvePath('');
|
||||
$this->ownerCache = $this->ownerStorage->getCache();
|
||||
$this->ownerStorage->getScanner()->scan('');
|
||||
|
||||
// share "shareddir" with user2
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, 31);
|
||||
|
||||
// login as user2
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
// retrieve the shared storage
|
||||
$secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
|
||||
list($this->sharedStorage, $internalPath) = $secondView->resolvePath('files/Shared/shareddir');
|
||||
$this->sharedCache = $this->sharedStorage->getCache();
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
$this->sharedCache->clear();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$this->view->deleteAll('container');
|
||||
|
||||
$this->ownerCache->clear();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that writing a file using the shared storage will propagate the file
|
||||
* size to the owner's parent folders.
|
||||
*/
|
||||
function testFolderSizePropagationToOwnerStorage() {
|
||||
$initialSizes = self::getOwnerDirSizes('files/container/shareddir');
|
||||
|
||||
$textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$dataLen = strlen($textData);
|
||||
$this->sharedCache->put('shareddir/bar.txt', array('storage_mtime' => 10));
|
||||
$this->sharedStorage->file_put_contents('shareddir/bar.txt', $textData);
|
||||
$this->sharedCache->put('shareddir', array('storage_mtime' => 10));
|
||||
|
||||
// run the propagation code
|
||||
$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir');
|
||||
|
||||
$this->assertTrue($result);
|
||||
|
||||
// the owner's parent dirs must have increase size
|
||||
$newSizes = self::getOwnerDirSizes('files/container/shareddir');
|
||||
$this->assertEquals($initialSizes[''] + $dataLen, $newSizes['']);
|
||||
$this->assertEquals($initialSizes['files'] + $dataLen, $newSizes['files']);
|
||||
$this->assertEquals($initialSizes['files/container'] + $dataLen, $newSizes['files/container']);
|
||||
$this->assertEquals($initialSizes['files/container/shareddir'] + $dataLen, $newSizes['files/container/shareddir']);
|
||||
|
||||
// no more updates
|
||||
$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir');
|
||||
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that writing a file using the shared storage will propagate the file
|
||||
* size to the owner's parent folders.
|
||||
*/
|
||||
function testSubFolderSizePropagationToOwnerStorage() {
|
||||
$initialSizes = self::getOwnerDirSizes('files/container/shareddir/subdir');
|
||||
|
||||
$textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$dataLen = strlen($textData);
|
||||
$this->sharedCache->put('shareddir/subdir/bar.txt', array('storage_mtime' => 10));
|
||||
$this->sharedStorage->file_put_contents('shareddir/subdir/bar.txt', $textData);
|
||||
$this->sharedCache->put('shareddir/subdir', array('storage_mtime' => 10));
|
||||
|
||||
// run the propagation code
|
||||
$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir/subdir');
|
||||
|
||||
$this->assertTrue($result);
|
||||
|
||||
// the owner's parent dirs must have increase size
|
||||
$newSizes = self::getOwnerDirSizes('files/container/shareddir/subdir');
|
||||
$this->assertEquals($initialSizes[''] + $dataLen, $newSizes['']);
|
||||
$this->assertEquals($initialSizes['files'] + $dataLen, $newSizes['files']);
|
||||
$this->assertEquals($initialSizes['files/container'] + $dataLen, $newSizes['files/container']);
|
||||
$this->assertEquals($initialSizes['files/container/shareddir'] + $dataLen, $newSizes['files/container/shareddir']);
|
||||
$this->assertEquals($initialSizes['files/container/shareddir/subdir'] + $dataLen, $newSizes['files/container/shareddir/subdir']);
|
||||
|
||||
// no more updates
|
||||
$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir/subdir');
|
||||
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
function testNoUpdateOnRoot() {
|
||||
// no updates when called for root path
|
||||
$result = $this->sharedStorage->getWatcher()->checkUpdate('');
|
||||
|
||||
$this->assertFalse($result);
|
||||
|
||||
// FIXME: for some reason when running this "naked" test,
|
||||
// there will be remaining nonsensical entries in the
|
||||
// database with a path "test-share-user1/container/..."
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sizes of the path and its parent dirs in a hash
|
||||
* where the key is the path and the value is the size.
|
||||
*/
|
||||
function getOwnerDirSizes($path) {
|
||||
$result = array();
|
||||
|
||||
while ($path != '' && $path != '' && $path != '.') {
|
||||
$cachedData = $this->ownerCache->get($path);
|
||||
$result[$path] = $cachedData['size'];
|
||||
$path = dirname($path);
|
||||
}
|
||||
$cachedData = $this->ownerCache->get('');
|
||||
$result[''] = $cachedData['size'];
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
9
lib/private/files/cache/watcher.php
vendored
9
lib/private/files/cache/watcher.php
vendored
|
|
@ -15,17 +15,17 @@ class Watcher {
|
|||
/**
|
||||
* @var \OC\Files\Storage\Storage $storage
|
||||
*/
|
||||
private $storage;
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* @var Cache $cache
|
||||
*/
|
||||
private $cache;
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var Scanner $scanner;
|
||||
*/
|
||||
private $scanner;
|
||||
protected $scanner;
|
||||
|
||||
/**
|
||||
* @param \OC\Files\Storage\Storage $storage
|
||||
|
|
@ -40,6 +40,7 @@ class Watcher {
|
|||
* check $path for updates
|
||||
*
|
||||
* @param string $path
|
||||
* @return boolean true if path was updated, false otherwise
|
||||
*/
|
||||
public function checkUpdate($path) {
|
||||
$cachedEntry = $this->cache->get($path);
|
||||
|
|
@ -53,7 +54,9 @@ class Watcher {
|
|||
$this->cleanFolder($path);
|
||||
}
|
||||
$this->cache->correctFolderSize($path);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue