Merge pull request #31431 from nextcloud/fs-setup-manager

Unify/cleanup filesystem setup
This commit is contained in:
Robin Appelman 2022-03-08 14:50:25 +00:00 committed by GitHub
commit e8872f01ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 765 additions and 523 deletions

View file

@ -34,6 +34,7 @@ use OC\Files\Storage\Temporary;
use OC\Files\View;
use OCA\DAV\Connector\Sabre\Directory;
use OCA\DAV\Connector\Sabre\ObjectTree;
use OCP\Files\Mount\IMountManager;
/**
* Class ObjectTreeTest
@ -266,7 +267,7 @@ class ObjectTreeTest extends \Test\TestCase {
];
}
public function testGetNodeForPathInvalidPath() {
$this->expectException(\OCA\DAV\Connector\Sabre\Exception\InvalidPath::class);
@ -287,8 +288,7 @@ class ObjectTreeTest extends \Test\TestCase {
$rootNode = $this->getMockBuilder(Directory::class)
->disableOriginalConstructor()
->getMock();
$mountManager = $this->getMockBuilder(Manager::class)
->getMock();
$mountManager = $this->createMock(IMountManager::class);
$tree = new \OCA\DAV\Connector\Sabre\ObjectTree();
$tree->init($rootNode, $view, $mountManager);
@ -314,8 +314,7 @@ class ObjectTreeTest extends \Test\TestCase {
$rootNode = $this->getMockBuilder(Directory::class)
->disableOriginalConstructor()
->getMock();
$mountManager = $this->getMockBuilder(Manager::class)
->getMock();
$mountManager = $this->createMock(IMountManager::class);
$tree = new \OCA\DAV\Connector\Sabre\ObjectTree();
$tree->init($rootNode, $view, $mountManager);

View file

@ -25,8 +25,13 @@
namespace OCA\Files_External\Tests;
use OC\Files\Mount\Manager;
use OC\Files\SetupManagerFactory;
use OCA\Files_External\Lib\PersonalMount;
use OCA\Files_External\Lib\StorageConfig;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IMountProviderCollection;
use OCP\IUserManager;
use Test\TestCase;
class PersonalMountTest extends TestCase {
@ -47,7 +52,7 @@ class PersonalMountTest extends TestCase {
$mount = new PersonalMount($storageService, $storageConfig, 10, $storage, '/foo');
$mountManager = new Manager();
$mountManager = new Manager($this->createMock(SetupManagerFactory::class));
$mountManager->addMount($mount);
$this->assertEquals([$mount], $mountManager->findByStorageId('dummy'));

View file

@ -43,6 +43,7 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Files;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorageFactory;
use OCP\Http\Client\IClientService;
use OCP\IDBConnection;
@ -599,8 +600,9 @@ class Manager {
}
public function removeShare($mountPoint): bool {
$mountPointObj = $this->mountManager->find($mountPoint);
if ($mountPointObj === null) {
try {
$mountPointObj = $this->mountManager->find($mountPoint);
} catch (NotFoundException $e) {
$this->logger->error('Mount point to remove share not found', ['mountPoint' => $mountPoint]);
return false;
}

View file

@ -26,6 +26,7 @@
*/
namespace OCA\Files_Sharing;
use OC\Files\Mount\MountPoint;
use OCP\Constants;
use OCP\Share\IShare;
@ -105,6 +106,7 @@ class Updater {
$mountManager = \OC\Files\Filesystem::getMountManager();
$mountedShares = $mountManager->findIn('/' . \OC_User::getUser() . '/files/' . $oldPath);
foreach ($mountedShares as $mount) {
/** @var MountPoint $mount */
if ($mount->getStorage()->instanceOfStorage(ISharedStorage::class)) {
$mountPoint = $mount->getMountPoint();
$target = str_replace($absOldPath, $absNewPath, $mountPoint);

View file

@ -31,14 +31,19 @@
namespace OCA\Files_Sharing\Tests\External;
use OC\Federation\CloudIdManager;
use OC\Files\SetupManager;
use OC\Files\SetupManagerFactory;
use OC\Files\Storage\StorageFactory;
use OCA\Files_Sharing\External\Manager;
use OCA\Files_Sharing\External\MountProvider;
use OCA\Files_Sharing\Tests\TestCase;
use OCP\Contacts\IManager;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\NotFoundException;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
use OCP\IGroup;
@ -102,9 +107,8 @@ class ManagerTest extends TestCase {
parent::setUp();
$this->uid = $this->getUniqueID('user');
$this->createUser($this->uid, '');
$this->user = \OC::$server->getUserManager()->get($this->uid);
$this->mountManager = new \OC\Files\Mount\Manager();
$this->user = $this->createUser($this->uid, '');
$this->mountManager = new \OC\Files\Mount\Manager($this->createMock(SetupManagerFactory::class));
$this->clientService = $this->getMockBuilder(IClientService::class)
->disableOriginalConstructor()->getMock();
$this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class);
@ -740,12 +744,12 @@ class ManagerTest extends TestCase {
private function assertNotMount($mountPoint) {
$mountPoint = rtrim($mountPoint, '/');
$mount = $this->mountManager->find($this->getFullPath($mountPoint));
if ($mount) {
try {
$mount = $this->mountManager->find($this->getFullPath($mountPoint));
$this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount);
$this->assertNotEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/'));
} else {
$this->assertNull($mount);
} catch (NotFoundException $e) {
}
}

View file

@ -271,6 +271,7 @@ return array(
'OCP\\Files\\Events\\Node\\BeforeNodeRenamedEvent' => $baseDir . '/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php',
'OCP\\Files\\Events\\Node\\BeforeNodeTouchedEvent' => $baseDir . '/lib/public/Files/Events/Node/BeforeNodeTouchedEvent.php',
'OCP\\Files\\Events\\Node\\BeforeNodeWrittenEvent' => $baseDir . '/lib/public/Files/Events/Node/BeforeNodeWrittenEvent.php',
'OCP\\Files\\Events\\Node\\FilesystemTornDownEvent' => $baseDir . '/lib/public/Files/Events/Node/FilesystemTornDownEvent.php',
'OCP\\Files\\Events\\Node\\NodeCopiedEvent' => $baseDir . '/lib/public/Files/Events/Node/NodeCopiedEvent.php',
'OCP\\Files\\Events\\Node\\NodeCreatedEvent' => $baseDir . '/lib/public/Files/Events/Node/NodeCreatedEvent.php',
'OCP\\Files\\Events\\Node\\NodeDeletedEvent' => $baseDir . '/lib/public/Files/Events/Node/NodeDeletedEvent.php',
@ -1162,6 +1163,8 @@ return array(
'OC\\Files\\Search\\SearchComparison' => $baseDir . '/lib/private/Files/Search/SearchComparison.php',
'OC\\Files\\Search\\SearchOrder' => $baseDir . '/lib/private/Files/Search/SearchOrder.php',
'OC\\Files\\Search\\SearchQuery' => $baseDir . '/lib/private/Files/Search/SearchQuery.php',
'OC\\Files\\SetupManager' => $baseDir . '/lib/private/Files/SetupManager.php',
'OC\\Files\\SetupManagerFactory' => $baseDir . '/lib/private/Files/SetupManagerFactory.php',
'OC\\Files\\SimpleFS\\NewSimpleFile' => $baseDir . '/lib/private/Files/SimpleFS/NewSimpleFile.php',
'OC\\Files\\SimpleFS\\SimpleFile' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFile.php',
'OC\\Files\\SimpleFS\\SimpleFolder' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFolder.php',

View file

@ -300,6 +300,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Files\\Events\\Node\\BeforeNodeRenamedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php',
'OCP\\Files\\Events\\Node\\BeforeNodeTouchedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/BeforeNodeTouchedEvent.php',
'OCP\\Files\\Events\\Node\\BeforeNodeWrittenEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/BeforeNodeWrittenEvent.php',
'OCP\\Files\\Events\\Node\\FilesystemTornDownEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/FilesystemTornDownEvent.php',
'OCP\\Files\\Events\\Node\\NodeCopiedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/NodeCopiedEvent.php',
'OCP\\Files\\Events\\Node\\NodeCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/NodeCreatedEvent.php',
'OCP\\Files\\Events\\Node\\NodeDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/NodeDeletedEvent.php',
@ -1191,6 +1192,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Files\\Search\\SearchComparison' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchComparison.php',
'OC\\Files\\Search\\SearchOrder' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchOrder.php',
'OC\\Files\\Search\\SearchQuery' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchQuery.php',
'OC\\Files\\SetupManager' => __DIR__ . '/../../..' . '/lib/private/Files/SetupManager.php',
'OC\\Files\\SetupManagerFactory' => __DIR__ . '/../../..' . '/lib/private/Files/SetupManagerFactory.php',
'OC\\Files\\SimpleFS\\NewSimpleFile' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/NewSimpleFile.php',
'OC\\Files\\SimpleFS\\SimpleFile' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFile.php',
'OC\\Files\\SimpleFS\\SimpleFolder' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFolder.php',

View file

@ -27,30 +27,42 @@ use OCP\ICache;
* In-memory cache with a capacity limit to keep memory usage in check
*
* Uses a simple FIFO expiry mechanism
* @template T
*/
class CappedMemoryCache implements ICache, \ArrayAccess {
private $capacity;
/** @var T[] */
private $cache = [];
public function __construct($capacity = 512) {
$this->capacity = $capacity;
}
public function hasKey($key) {
public function hasKey($key): bool {
return isset($this->cache[$key]);
}
/**
* @return ?T
*/
public function get($key) {
return isset($this->cache[$key]) ? $this->cache[$key] : null;
return $this->cache[$key] ?? null;
}
public function set($key, $value, $ttl = 0) {
/**
* @param string $key
* @param T $value
* @param int $ttl
* @return bool
*/
public function set($key, $value, $ttl = 0): bool {
if (is_null($key)) {
$this->cache[] = $value;
} else {
$this->cache[$key] = $value;
}
$this->garbageCollect();
return true;
}
public function remove($key) {
@ -68,13 +80,18 @@ class CappedMemoryCache implements ICache, \ArrayAccess {
}
/**
* @return mixed
* @return T
*/
#[\ReturnTypeWillChange]
public function &offsetGet($offset) {
return $this->cache[$offset];
}
/**
* @param string $key
* @param T $value
* @return void
*/
public function offsetSet($offset, $value): void {
$this->set($offset, $value);
}
@ -83,6 +100,9 @@ class CappedMemoryCache implements ICache, \ArrayAccess {
$this->remove($offset);
}
/**
* @return T[]
*/
public function getData() {
return $this->cache;
}

View file

@ -27,8 +27,7 @@ use OCP\Files\Config\ICachedMountFileInfo;
use OCP\IUser;
class CachedMountFileInfo extends CachedMountInfo implements ICachedMountFileInfo {
/** @var string */
private $internalPath;
private string $internalPath;
public function __construct(
IUser $user,

View file

@ -28,38 +28,13 @@ use OCP\Files\Node;
use OCP\IUser;
class CachedMountInfo implements ICachedMountInfo {
/**
* @var IUser
*/
protected $user;
/**
* @var int
*/
protected $storageId;
/**
* @var int
*/
protected $rootId;
/**
* @var string
*/
protected $mountPoint;
/**
* @var int|null
*/
protected $mountId;
/**
* @var string
*/
protected $rootInternalPath;
/** @var string */
protected $mountProvider;
protected IUser $user;
protected int $storageId;
protected int $rootId;
protected string $mountPoint;
protected ?int $mountId;
protected string $rootInternalPath;
protected string $mountProvider;
/**
* CachedMountInfo constructor.
@ -95,28 +70,28 @@ class CachedMountInfo implements ICachedMountInfo {
/**
* @return IUser
*/
public function getUser() {
public function getUser(): IUser {
return $this->user;
}
/**
* @return int the numeric storage id of the mount
*/
public function getStorageId() {
public function getStorageId(): int {
return $this->storageId;
}
/**
* @return int the fileid of the root of the mount
*/
public function getRootId() {
public function getRootId(): int {
return $this->rootId;
}
/**
* @return Node the root node of the mount
* @return Node|null the root node of the mount
*/
public function getMountPointNode() {
public function getMountPointNode(): ?Node {
// TODO injection etc
Filesystem::initMountPoints($this->getUser()->getUID());
$userNode = \OC::$server->getUserFolder($this->getUser()->getUID());
@ -131,7 +106,7 @@ class CachedMountInfo implements ICachedMountInfo {
/**
* @return string the mount point of the mount for the user
*/
public function getMountPoint() {
public function getMountPoint(): string {
return $this->mountPoint;
}
@ -141,7 +116,7 @@ class CachedMountInfo implements ICachedMountInfo {
* @return int|null mount id or null if not applicable
* @since 9.1.0
*/
public function getMountId() {
public function getMountId(): ?int {
return $this->mountId;
}
@ -150,7 +125,7 @@ class CachedMountInfo implements ICachedMountInfo {
*
* @return string
*/
public function getRootInternalPath() {
public function getRootInternalPath(): string {
return $this->rootInternalPath;
}

View file

@ -25,8 +25,7 @@ use OCP\Files\Mount\IMountPoint;
use OCP\IUser;
class LazyStorageMountInfo extends CachedMountInfo {
/** @var IMountPoint */
private $mount;
private IMountPoint $mount;
/**
* CachedMountInfo constructor.
@ -37,12 +36,15 @@ class LazyStorageMountInfo extends CachedMountInfo {
public function __construct(IUser $user, IMountPoint $mount) {
$this->user = $user;
$this->mount = $mount;
$this->rootId = 0;
$this->storageId = 0;
$this->mountPoint = '';
}
/**
* @return int the numeric storage id of the mount
*/
public function getStorageId() {
public function getStorageId(): int {
if (!$this->storageId) {
$this->storageId = $this->mount->getNumericStorageId();
}
@ -52,7 +54,7 @@ class LazyStorageMountInfo extends CachedMountInfo {
/**
* @return int the fileid of the root of the mount
*/
public function getRootId() {
public function getRootId(): int {
if (!$this->rootId) {
$this->rootId = $this->mount->getStorageRootId();
}
@ -62,14 +64,14 @@ class LazyStorageMountInfo extends CachedMountInfo {
/**
* @return string the mount point of the mount for the user
*/
public function getMountPoint() {
public function getMountPoint(): string {
if (!$this->mountPoint) {
$this->mountPoint = $this->mount->getMountPoint();
}
return parent::getMountPoint();
}
public function getMountId() {
public function getMountId(): ?int {
return $this->mount->getMountId();
}
@ -78,7 +80,7 @@ class LazyStorageMountInfo extends CachedMountInfo {
*
* @return string
*/
public function getRootInternalPath() {
public function getRootInternalPath(): string {
return $this->mount->getInternalPath($this->mount->getMountPoint());
}

View file

@ -183,16 +183,6 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
$this->emit('\OC\Files\Config', 'registerHomeMountProvider', [$provider]);
}
/**
* Cache mounts for user
*
* @param IUser $user
* @param IMountPoint[] $mountPoints
*/
public function registerMounts(IUser $user, array $mountPoints) {
$this->mountCache->registerMounts($user, $mountPoints);
}
/**
* Get the mount cache which can be used to search for mounts without setting up the filesystem
*
@ -222,4 +212,10 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
}, []);
return $mounts;
}
public function clearProviders() {
$this->providers = [];
$this->homeProviders = [];
$this->rootProviders = [];
}
}

View file

@ -38,13 +38,12 @@
namespace OC\Files;
use OC\Cache\CappedMemoryCache;
use OC\Files\Config\MountProviderCollection;
use OC\Files\Mount\MountPoint;
use OC\Lockdown\Filesystem\NullStorage;
use OCP\Files\Config\IMountProvider;
use OC\User\NoUserException;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Events\Node\FilesystemTornDownEvent;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorageFactory;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
@ -259,11 +258,7 @@ class Filesystem {
\OC_Util::setupFS();
}
$mount = self::$mounts->find($path);
if ($mount) {
return $mount->getMountPoint();
} else {
return '';
}
return $mount->getMountPoint();
}
/**
@ -319,11 +314,7 @@ class Filesystem {
*/
public static function resolvePath($path) {
$mount = self::getMountManager()->find($path);
if ($mount) {
return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
} else {
return [null, null];
}
return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
}
public static function init($user, $root) {
@ -332,6 +323,13 @@ class Filesystem {
}
self::getLoader();
self::$defaultInstance = new View($root);
/** @var IEventDispatcher $eventDispatcher */
$eventDispatcher = \OC::$server->get(IEventDispatcher::class);
$eventDispatcher->addListener(FilesystemTornDownEvent::class, function () {
self::$defaultInstance = null;
self::$usersSetup = [];
self::$loaded = false;
});
if (!self::$mounts) {
self::$mounts = \OC::$server->getMountManager();
@ -358,106 +356,16 @@ class Filesystem {
* @throws \OC\User\NoUserException if the user is not available
*/
public static function initMountPoints($user = '') {
$userManager = \OC::$server->getUserManager();
if (is_string($user)) {
if ($user === '') {
$user = \OC_User::getUser();
}
/** @var IUserManager $userManager */
$userManager = \OC::$server->get(IUserManager::class);
$userObject = $userManager->get($user);
} elseif ($user instanceof IUser) {
$userObject = $user;
$user = $userObject->getUID();
$userObject = ($user instanceof IUser) ? $user : $userManager->get($user);
if ($userObject) {
/** @var SetupManager $setupManager */
$setupManager = \OC::$server->get(SetupManager::class);
$setupManager->setupForUser($userObject);
} else {
$userObject = null;
}
if ($userObject === null || $user === false || $user === '') {
throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
}
if (isset(self::$usersSetup[$user])) {
return;
}
self::$usersSetup[$user] = true;
if (is_null($userObject)) {
\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR);
// reset flag, this will make it possible to rethrow the exception if called again
unset(self::$usersSetup[$user]);
throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
}
$realUid = $userObject->getUID();
// workaround in case of different casings
if ($user !== $realUid) {
$stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
\OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN);
$user = $realUid;
// again with the correct casing
if (isset(self::$usersSetup[$user])) {
return;
}
self::$usersSetup[$user] = true;
}
if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
$mountConfigManager = \OC::$server->getMountProviderCollection();
// home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
$homeMount = $mountConfigManager->getHomeMountForUser($userObject);
self::getMountManager()->addMount($homeMount);
if ($homeMount->getStorageRootId() === -1) {
$homeMount->getStorage()->mkdir('');
$homeMount->getStorage()->getScanner()->scan('');
}
\OC\Files\Filesystem::getStorage($user);
// Chance to mount for other storages
if ($userObject) {
$mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
$mounts[] = $homeMount;
$mountConfigManager->registerMounts($userObject, $mounts);
}
self::listenForNewMountProviders($mountConfigManager, $userManager);
} else {
self::getMountManager()->addMount(new MountPoint(
new NullStorage([]),
'/' . $user
));
self::getMountManager()->addMount(new MountPoint(
new NullStorage([]),
'/' . $user . '/files'
));
}
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]);
}
/**
* Get mounts from mount providers that are registered after setup
*
* @param MountProviderCollection $mountConfigManager
* @param IUserManager $userManager
*/
private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
if (!self::$listeningForProviders) {
self::$listeningForProviders = true;
$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
foreach (Filesystem::$usersSetup as $user => $setup) {
$userObject = $userManager->get($user);
if ($userObject) {
$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
array_walk($mounts, [self::$mounts, 'addMount']);
}
}
});
throw new NoUserException();
}
}
@ -474,8 +382,7 @@ class Filesystem {
* tear down the filesystem, removing all storage providers
*/
public static function tearDown() {
self::clearMounts();
self::$defaultInstance = null;
\OC_Util::tearDownFS();
}
/**
@ -492,16 +399,6 @@ class Filesystem {
return self::$defaultInstance->getRoot();
}
/**
* clear all mounts and storage backends
*/
public static function clearMounts() {
if (self::$mounts) {
self::$usersSetup = [];
self::$mounts->clear();
}
}
/**
* mount an \OC\Files\Storage\Storage in our virtual filesystem
*

View file

@ -26,26 +26,30 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OC\Files\Mount;
use OC\Cache\CappedMemoryCache;
use OC\Files\Filesystem;
use OC\Files\SetupManager;
use OC\Files\SetupManagerFactory;
use OCP\Files\Mount\IMountManager;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
class Manager implements IMountManager {
/** @var MountPoint[] */
private $mounts = [];
private array $mounts = [];
/** @var CappedMemoryCache<IMountPoint> */
private CappedMemoryCache $pathCache;
/** @var CappedMemoryCache<IMountPoint[]> */
private CappedMemoryCache $inPathCache;
private SetupManager $setupManager;
/** @var CappedMemoryCache */
private $pathCache;
/** @var CappedMemoryCache */
private $inPathCache;
public function __construct() {
public function __construct(SetupManagerFactory $setupManagerFactory) {
$this->pathCache = new CappedMemoryCache();
$this->inPathCache = new CappedMemoryCache();
$this->setupManager = $setupManagerFactory->create($this);
}
/**
@ -81,26 +85,14 @@ class Manager implements IMountManager {
$this->inPathCache->clear();
}
private function setupForFind(string $path) {
if (strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0) {
// for appdata, we only setup the root bits, not the user bits
\OC_Util::setupRootFS();
} elseif (strpos($path, '/files_external/uploads/') === 0) {
// for OC\Security\CertificateManager, we only setup the root bits, not the user bits
\OC_Util::setupRootFS();
} else {
\OC_Util::setupFS();
}
}
/**
* Find the mount for $path
*
* @param string $path
* @return MountPoint|null
* @return IMountPoint
*/
public function find(string $path) {
$this->setupForFind($path);
public function find(string $path): IMountPoint {
$this->setupManager->setupForPath($path);
$path = Filesystem::normalizePath($path);
if (isset($this->pathCache[$path])) {
@ -113,10 +105,8 @@ class Manager implements IMountManager {
if (isset($this->mounts[$mountPoint])) {
$this->pathCache[$path] = $this->mounts[$mountPoint];
return $this->mounts[$mountPoint];
}
if ($current === '') {
return null;
} elseif ($current === '') {
break;
}
$current = dirname($current);
@ -124,16 +114,18 @@ class Manager implements IMountManager {
$current = '';
}
}
throw new NotFoundException("No mount for path " . $path . " existing mounts: " . implode(",", array_keys($this->mounts)));
}
/**
* Find all mounts in $path
*
* @param string $path
* @return MountPoint[]
* @return IMountPoint[]
*/
public function findIn(string $path): array {
$this->setupForFind($path);
$this->setupManager->setupForPath($path);
$path = $this->formatPath($path);
if (isset($this->inPathCache[$path])) {
@ -163,7 +155,7 @@ class Manager implements IMountManager {
* Find mounts by storage id
*
* @param string $id
* @return MountPoint[]
* @return IMountPoint[]
*/
public function findByStorageId(string $id): array {
\OC_Util::setupFS();
@ -180,7 +172,7 @@ class Manager implements IMountManager {
}
/**
* @return MountPoint[]
* @return IMountPoint[]
*/
public function getAll(): array {
return $this->mounts;
@ -190,7 +182,7 @@ class Manager implements IMountManager {
* Find mounts by numeric storage id
*
* @param int $id
* @return MountPoint[]
* @return IMountPoint[]
*/
public function findByNumericId(int $id): array {
$storageId = \OC\Files\Cache\Storage::getStorageId($id);
@ -208,4 +200,8 @@ class Manager implements IMountManager {
}
return $path;
}
public function getSetupManager(): SetupManager {
return $this->setupManager;
}
}

View file

@ -35,13 +35,17 @@ namespace OC\Files\Node;
use OC\Cache\CappedMemoryCache;
use OC\Files\Mount\Manager;
use OC\Files\Mount\MountPoint;
use OC\Files\View;
use OC\Hooks\PublicEmitter;
use OC\User\NoUserException;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Events\Node\FilesystemTornDownEvent;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
/**
@ -64,35 +68,32 @@ use OCP\IUserManager;
* @package OC\Files\Node
*/
class Root extends Folder implements IRootFolder {
/** @var Manager */
private $mountManager;
/** @var PublicEmitter */
private $emitter;
/** @var null|\OC\User\User */
private $user;
/** @var CappedMemoryCache */
private $userFolderCache;
/** @var IUserMountCache */
private $userMountCache;
/** @var ILogger */
private $logger;
/** @var IUserManager */
private $userManager;
private Manager $mountManager;
private PublicEmitter $emitter;
private ?IUser $user;
private CappedMemoryCache $userFolderCache;
private IUserMountCache $userMountCache;
private ILogger $logger;
private IUserManager $userManager;
private IEventDispatcher $eventDispatcher;
/**
* @param \OC\Files\Mount\Manager $manager
* @param \OC\Files\View $view
* @param \OC\User\User|null $user
* @param Manager $manager
* @param View $view
* @param IUser|null $user
* @param IUserMountCache $userMountCache
* @param ILogger $logger
* @param IUserManager $userManager
*/
public function __construct($manager,
public function __construct(
$manager,
$view,
$user,
IUserMountCache $userMountCache,
ILogger $logger,
IUserManager $userManager) {
IUserMountCache $userMountCache,
ILogger $logger,
IUserManager $userManager,
IEventDispatcher $eventDispatcher
) {
parent::__construct($this, $view, '');
$this->mountManager = $manager;
$this->user = $user;
@ -101,6 +102,9 @@ class Root extends Folder implements IRootFolder {
$this->userMountCache = $userMountCache;
$this->logger = $logger;
$this->userManager = $userManager;
$eventDispatcher->addListener(FilesystemTornDownEvent::class, function () {
$this->userFolderCache = new CappedMemoryCache();
});
}
/**
@ -267,21 +271,21 @@ class Root extends Folder implements IRootFolder {
* @return int
*/
public function getId() {
return null;
return 0;
}
/**
* @return array
*/
public function stat() {
return null;
return [];
}
/**
* @return int
*/
public function getMTime() {
return null;
return 0;
}
/**
@ -289,14 +293,14 @@ class Root extends Folder implements IRootFolder {
* @return int
*/
public function getSize($includeMounts = true) {
return null;
return 0;
}
/**
* @return string
*/
public function getEtag() {
return null;
return '';
}
/**
@ -393,10 +397,6 @@ class Root extends Folder implements IRootFolder {
return $this->userFolderCache->get($userId);
}
public function clearCache() {
$this->userFolderCache = new CappedMemoryCache();
}
public function getUserMountCache() {
return $this->userMountCache;
}

View file

@ -0,0 +1,283 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Files;
use OC\Files\Config\MountProviderCollection;
use OC\Files\Mount\MountPoint;
use OC\Files\ObjectStore\HomeObjectStoreStorage;
use OC\Files\Storage\Common;
use OC\Files\Storage\Home;
use OC\Files\Storage\Storage;
use OC\Files\Storage\Wrapper\Availability;
use OC\Files\Storage\Wrapper\Encoding;
use OC\Files\Storage\Wrapper\PermissionsMask;
use OC\Files\Storage\Wrapper\Quota;
use OC\Lockdown\Filesystem\NullStorage;
use OC_App;
use OC_Hook;
use OC_Util;
use OCP\Constants;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Events\Node\FilesystemTornDownEvent;
use OCP\Files\Mount\IMountManager;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorage;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Lockdown\ILockdownManager;
class SetupManager {
private bool $rootSetup = false;
private IEventLogger $eventLogger;
private MountProviderCollection $mountProviderCollection;
private IMountManager $mountManager;
private IUserManager $userManager;
private array $setupUsers = [];
private IEventDispatcher $eventDispatcher;
private IUserMountCache $userMountCache;
private ILockdownManager $lockdownManager;
private bool $listeningForProviders;
public function __construct(
IEventLogger $eventLogger,
MountProviderCollection $mountProviderCollection,
IMountManager $mountManager,
IUserManager $userManager,
IEventDispatcher $eventDispatcher,
IUserMountCache $userMountCache,
ILockdownManager $lockdownManager
) {
$this->eventLogger = $eventLogger;
$this->mountProviderCollection = $mountProviderCollection;
$this->mountManager = $mountManager;
$this->userManager = $userManager;
$this->eventDispatcher = $eventDispatcher;
$this->userMountCache = $userMountCache;
$this->lockdownManager = $lockdownManager;
$this->listeningForProviders = false;
}
private function setupBuiltinWrappers() {
Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
if ($storage->instanceOfStorage(Common::class)) {
$storage->setMountOptions($mount->getOptions());
}
return $storage;
});
Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
if (!$mount->getOption('enable_sharing', true)) {
return new PermissionsMask([
'storage' => $storage,
'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
]);
}
return $storage;
});
// install storage availability wrapper, before most other wrappers
Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage) {
if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
return new Availability(['storage' => $storage]);
}
return $storage;
});
Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
return new Encoding(['storage' => $storage]);
}
return $storage;
});
Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
// set up quota for home storages, even for other users
// which can happen when using sharing
/**
* @var Storage $storage
*/
if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) {
if (is_object($storage->getUser())) {
$quota = OC_Util::getUserQuota($storage->getUser());
if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
return new Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']);
}
}
}
return $storage;
});
Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
/*
* Do not allow any operations that modify the storage
*/
if ($mount->getOption('readonly', false)) {
return new PermissionsMask([
'storage' => $storage,
'mask' => Constants::PERMISSION_ALL & ~(
Constants::PERMISSION_UPDATE |
Constants::PERMISSION_CREATE |
Constants::PERMISSION_DELETE
),
]);
}
return $storage;
});
}
/**
* Setup the full filesystem for the specified user
*/
public function setupForUser(IUser $user): void {
$this->setupRoot();
if (in_array($user->getUID(), $this->setupUsers, true)) {
return;
}
$this->setupUsers[] = $user->getUID();
$this->eventLogger->start('setup_fs', 'Setup filesystem');
$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user->getUID()]);
Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
$userDir = '/' . $user->getUID() . '/files';
Filesystem::init($user, $userDir);
if ($this->lockdownManager->canAccessFilesystem()) {
// home mounts are handled separate since we need to ensure this is mounted before we call the other mount providers
$homeMount = $this->mountProviderCollection->getHomeMountForUser($user);
$this->mountManager->addMount($homeMount);
if ($homeMount->getStorageRootId() === -1) {
$homeMount->getStorage()->mkdir('');
$homeMount->getStorage()->getScanner()->scan('');
}
// Chance to mount for other storages
$mounts = $this->mountProviderCollection->addMountForUser($user, $this->mountManager);
$mounts[] = $homeMount;
$this->userMountCache->registerMounts($user, $mounts);
$this->listenForNewMountProviders();
} else {
$this->mountManager->addMount(new MountPoint(
new NullStorage([]),
'/' . $user->getUID()
));
$this->mountManager->addMount(new MountPoint(
new NullStorage([]),
'/' . $user->getUID() . '/files'
));
}
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
$this->eventLogger->end('setup_fs');
}
/**
* Set up the root filesystem
*/
public function setupRoot(): void {
//setting up the filesystem twice can only lead to trouble
if ($this->rootSetup) {
return;
}
$this->rootSetup = true;
$this->eventLogger->start('setup_root_fs', 'Setup root filesystem');
// load all filesystem apps before, so no setup-hook gets lost
OC_App::loadApps(['filesystem']);
$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
$this->setupBuiltinWrappers();
Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
$rootMounts = $this->mountProviderCollection->getRootMounts();
foreach ($rootMounts as $rootMountProvider) {
$this->mountManager->addMount($rootMountProvider);
}
$this->eventLogger->end('setup_root_fs');
}
/**
* Set up the filesystem for the specified path
*/
public function setupForPath(string $path): void {
if (substr_count($path, '/') < 2 || strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0 || strpos($path, '/files_external/') === 0) {
$this->setupRoot();
return;
} else {
[, $userId] = explode('/', $path);
}
$user = $this->userManager->get($userId);
if (!$user) {
$this->setupRoot();
return;
}
$this->setupForUser($user);
}
public function tearDown() {
$this->setupUsers = [];
$this->rootSetup = false;
$this->mountManager->clear();
$this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
}
/**
* Get mounts from mount providers that are registered after setup
*/
private function listenForNewMountProviders() {
if (!$this->listeningForProviders) {
$this->listeningForProviders = true;
$this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) {
foreach ($this->setupUsers as $userId) {
$user = $this->userManager->get($userId);
if ($user) {
$mounts = $provider->getMountsForUser($user, Filesystem::getLoader());
array_walk($mounts, [$this->mountManager, 'addMount']);
}
}
});
}
}
}

View file

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Files;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Mount\IMountManager;
use OCP\IUserManager;
use OCP\Lockdown\ILockdownManager;
class SetupManagerFactory {
private IEventLogger $eventLogger;
private IMountProviderCollection $mountProviderCollection;
private IUserManager $userManager;
private IEventDispatcher $eventDispatcher;
private IUserMountCache $userMountCache;
private ILockdownManager $lockdownManager;
private ?SetupManager $setupManager;
public function __construct(
IEventLogger $eventLogger,
IMountProviderCollection $mountProviderCollection,
IUserManager $userManager,
IEventDispatcher $eventDispatcher,
IUserMountCache $userMountCache,
ILockdownManager $lockdownManager
) {
$this->eventLogger = $eventLogger;
$this->mountProviderCollection = $mountProviderCollection;
$this->userManager = $userManager;
$this->eventDispatcher = $eventDispatcher;
$this->userMountCache = $userMountCache;
$this->lockdownManager = $lockdownManager;
$this->setupManager = null;
}
public function create(IMountManager $mountManager): SetupManager {
if (!$this->setupManager) {
$this->setupManager = new SetupManager($this->eventLogger, $this->mountProviderCollection, $mountManager, $this->userManager, $this->eventDispatcher, $this->userMountCache, $this->lockdownManager);
}
return $this->setupManager;
}
}

View file

@ -274,7 +274,7 @@ class View {
/**
* remove mount point
*
* @param \OC\Files\Mount\MoveableMount $mount
* @param IMountPoint $mount
* @param string $path relative to data/
* @return boolean
*/
@ -719,7 +719,7 @@ class View {
$postFix = (substr($path, -1) === '/') ? '/' : '';
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
if ($mount and $mount->getInternalPath($absolutePath) === '') {
if ($mount->getInternalPath($absolutePath) === '') {
return $this->removeMount($mount, $absolutePath);
}
if ($this->is_dir($path)) {
@ -1383,10 +1383,6 @@ class View {
$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
$mount = Filesystem::getMountManager()->find($path);
if (!$mount) {
\OC::$server->getLogger()->warning('Mountpoint not found for path: ' . $path);
return false;
}
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($path);
if ($storage) {
@ -1488,7 +1484,7 @@ class View {
$rootEntry = $subCache->get('');
if (!$rootEntry) {
$subScanner = $subStorage->getScanner('');
$subScanner = $subStorage->getScanner();
try {
$subScanner->scanFile('');
} catch (\OCP\Files\StorageNotAvailableException $e) {
@ -1739,12 +1735,13 @@ class View {
$manager = Filesystem::getMountManager();
$mounts = $manager->findIn($this->fakeRoot);
$mounts[] = $manager->find($this->fakeRoot);
// reverse the array so we start with the storage this view is in
$mounts = array_filter($mounts);
// reverse the array, so we start with the storage this view is in
// which is the most likely to contain the file we're looking for
$mounts = array_reverse($mounts);
// put non shared mounts in front of the shared mount
// this prevent unneeded recursion into shares
// put non-shared mounts in front of the shared mount
// this prevents unneeded recursion into shares
usort($mounts, function (IMountPoint $a, IMountPoint $b) {
return $a instanceof SharedMount && (!$b instanceof SharedMount) ? 1 : -1;
});
@ -1915,14 +1912,10 @@ class View {
* @param string $absolutePath absolute path
* @param bool $useParentMount true to return parent mount instead of whatever
* is mounted directly on the given path, false otherwise
* @return \OC\Files\Mount\MountPoint mount point for which to apply locks
* @return IMountPoint mount point for which to apply locks
*/
private function getMountForLock($absolutePath, $useParentMount = false) {
$results = [];
$mount = Filesystem::getMountManager()->find($absolutePath);
if (!$mount) {
return $results;
}
if ($useParentMount) {
// find out if something is mounted directly on the path

View file

@ -95,6 +95,7 @@ use OC\Files\Mount\RootMountProvider;
use OC\Files\Node\HookConnector;
use OC\Files\Node\LazyRoot;
use OC\Files\Node\Root;
use OC\Files\SetupManager;
use OC\Files\Storage\StorageFactory;
use OC\Files\Template\TemplateManager;
use OC\Files\Type\Loader;
@ -216,6 +217,7 @@ use OCP\L10N\IFactory;
use OCP\LDAP\ILDAPProvider;
use OCP\LDAP\ILDAPProviderFactory;
use OCP\Lock\ILockingProvider;
use OCP\Lockdown\ILockdownManager;
use OCP\Log\ILogFactory;
use OCP\Mail\IMailer;
use OCP\Remote\Api\IApiFactory;
@ -423,7 +425,8 @@ class Server extends ServerContainer implements IServerContainer {
null,
$c->get(IUserMountCache::class),
$this->get(ILogger::class),
$this->get(IUserManager::class)
$this->get(IUserManager::class),
$this->get(IEventDispatcher::class),
);
$previewConnector = new \OC\Preview\WatcherConnector(
@ -1091,6 +1094,11 @@ class Server extends ServerContainer implements IServerContainer {
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('LockingProvider', ILockingProvider::class);
$this->registerAlias(ILockdownManager::class, 'LockdownManager');
$this->registerService(SetupManager::class, function ($c) {
// create the setupmanager through the mount manager to resolve the cyclic dependency
return $c->get(\OC\Files\Mount\Manager::class)->getSetupManager();
});
$this->registerAlias(IMountManager::class, \OC\Files\Mount\Manager::class);
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('MountManager', IMountManager::class);

View file

@ -66,6 +66,7 @@
use bantu\IniGetWrapper\IniGetWrapper;
use OC\AppFramework\Http\Request;
use OC\Files\SetupManager;
use OCP\Files\Template\ITemplateManager;
use OCP\IConfig;
use OCP\IGroupManager;
@ -78,8 +79,6 @@ class OC_Util {
public static $scripts = [];
public static $styles = [];
public static $headers = [];
private static $rootFsSetup = false;
private static $fsSetup = false;
/** @var array Local cache of version.php */
private static $versionCache = null;
@ -88,122 +87,6 @@ class OC_Util {
return \OC::$server->getAppManager();
}
/**
* Can be set up
*
* @param string $user
* @return boolean
* @description configure the initial filesystem based on the configuration
* @suppress PhanDeprecatedFunction
* @suppress PhanAccessMethodInternal
*/
public static function setupRootFS(string $user = '') {
//setting up the filesystem twice can only lead to trouble
if (self::$rootFsSetup) {
return false;
}
\OC::$server->getEventLogger()->start('setup_root_fs', 'Setup root filesystem');
// load all filesystem apps before, so no setup-hook gets lost
OC_App::loadApps(['filesystem']);
self::$rootFsSetup = true;
\OC\Files\Filesystem::initMountManager();
$prevLogging = \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
\OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
/** @var \OC\Files\Storage\Common $storage */
$storage->setMountOptions($mount->getOptions());
}
return $storage;
});
\OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
if (!$mount->getOption('enable_sharing', true)) {
return new \OC\Files\Storage\Wrapper\PermissionsMask([
'storage' => $storage,
'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
]);
}
return $storage;
});
// install storage availability wrapper, before most other wrappers
\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
}
return $storage;
});
\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
}
return $storage;
});
\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
// set up quota for home storages, even for other users
// which can happen when using sharing
/**
* @var \OC\Files\Storage\Storage $storage
*/
if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
) {
/** @var \OC\Files\Storage\Home $storage */
if (is_object($storage->getUser())) {
$quota = OC_Util::getUserQuota($storage->getUser());
if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
return new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']);
}
}
}
return $storage;
});
\OC\Files\Filesystem::addStorageWrapper('readonly', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
/*
* Do not allow any operations that modify the storage
*/
if ($mount->getOption('readonly', false)) {
return new \OC\Files\Storage\Wrapper\PermissionsMask([
'storage' => $storage,
'mask' => \OCP\Constants::PERMISSION_ALL & ~(
\OCP\Constants::PERMISSION_UPDATE |
\OCP\Constants::PERMISSION_CREATE |
\OCP\Constants::PERMISSION_DELETE
),
]);
}
return $storage;
});
OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user]);
\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
/** @var \OCP\Files\Config\IMountProviderCollection $mountProviderCollection */
$mountProviderCollection = \OC::$server->query(\OCP\Files\Config\IMountProviderCollection::class);
$rootMountProviders = $mountProviderCollection->getRootMounts();
/** @var \OC\Files\Mount\Manager $mountManager */
$mountManager = \OC\Files\Filesystem::getMountManager();
foreach ($rootMountProviders as $rootMountProvider) {
$mountManager->addMount($rootMountProvider);
}
\OC::$server->getEventLogger()->end('setup_root_fs');
return true;
}
/**
* Setup the file system
*
@ -214,14 +97,6 @@ class OC_Util {
* @suppress PhanAccessMethodInternal
*/
public static function setupFS(?string $user = '') {
self::setupRootFS($user ?? '');
if (self::$fsSetup) {
return false;
}
\OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
// If we are not forced to load a specific user we load the one that is logged in
if ($user === '') {
$userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser();
@ -229,18 +104,14 @@ class OC_Util {
$userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user);
}
//if we aren't logged in, or the user doesn't exist, there is no use to set up the filesystem
/** @var SetupManager $setupManager */
$setupManager = \OC::$server->get(SetupManager::class);
if ($userObject) {
self::$fsSetup = true;
$userDir = '/' . $userObject->getUID() . '/files';
//jail the user into his "home" directory
\OC\Files\Filesystem::init($userObject, $userDir);
OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $userObject->getUID(), 'user_dir' => $userDir]);
$setupManager->setupForUser($userObject);
} else {
$setupManager->setupRoot();
}
\OC::$server->getEventLogger()->end('setup_fs');
return true;
}
@ -394,10 +265,9 @@ class OC_Util {
* @suppress PhanUndeclaredMethod
*/
public static function tearDownFS() {
\OC\Files\Filesystem::tearDown();
\OC::$server->getRootFolder()->clearCache();
self::$fsSetup = false;
self::$rootFsSetup = false;
/** @var SetupManager $setupManager */
$setupManager = \OC::$server->get(SetupManager::class);
$setupManager->tearDown();
}
/**

View file

@ -34,11 +34,11 @@ interface ICachedMountFileInfo extends ICachedMountInfo {
* @return string
* @since 13.0.0
*/
public function getInternalPath();
public function getInternalPath(): string;
/**
* @return string
* @since 13.0.0
*/
public function getPath();
public function getPath(): string;
}

View file

@ -35,31 +35,31 @@ interface ICachedMountInfo {
* @return IUser
* @since 9.0.0
*/
public function getUser();
public function getUser(): IUser;
/**
* @return int the numeric storage id of the mount
* @since 9.0.0
*/
public function getStorageId();
public function getStorageId(): int;
/**
* @return int the fileid of the root of the mount
* @since 9.0.0
*/
public function getRootId();
public function getRootId(): int;
/**
* @return Node the root node of the mount
* @return Node|null the root node of the mount
* @since 9.0.0
*/
public function getMountPointNode();
public function getMountPointNode(): ?Node;
/**
* @return string the mount point of the mount for the user
* @since 9.0.0
*/
public function getMountPoint();
public function getMountPoint(): string;
/**
* Get the id of the configured mount
@ -67,7 +67,7 @@ interface ICachedMountInfo {
* @return int|null mount id or null if not applicable
* @since 9.1.0
*/
public function getMountId();
public function getMountId(): ?int;
/**
* Get the internal path (within the storage) of the root of the mount
@ -75,7 +75,7 @@ interface ICachedMountInfo {
* @return string
* @since 11.0.0
*/
public function getRootInternalPath();
public function getRootInternalPath(): string;
/**
* Get the class of the mount provider that this mount originates from

View file

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Files\Events\Node;
use OCP\EventDispatcher\Event;
/**
* Event fired after the filesystem has been torn down
*
* @since 24.0.0
*/
class FilesystemTornDownEvent extends Event {
}

View file

@ -37,7 +37,7 @@ interface IMountManager {
/**
* Add a new mount
*
* @param \OCP\Files\Mount\IMountPoint $mount
* @param IMountPoint $mount
* @since 8.2.0
*/
public function addMount(IMountPoint $mount);
@ -63,16 +63,16 @@ interface IMountManager {
* Find the mount for $path
*
* @param string $path
* @return \OCP\Files\Mount\IMountPoint|null
* @return IMountPoint
* @since 8.2.0
*/
public function find(string $path);
public function find(string $path): ?IMountPoint;
/**
* Find all mounts in $path
*
* @param string $path
* @return \OCP\Files\Mount\IMountPoint[]
* @return IMountPoint[]
* @since 8.2.0
*/
public function findIn(string $path): array;
@ -88,13 +88,13 @@ interface IMountManager {
* Find mounts by storage id
*
* @param string $id
* @return \OCP\Files\Mount\IMountPoint[]
* @return IMountPoint[]
* @since 8.2.0
*/
public function findByStorageId(string $id): array;
/**
* @return \OCP\Files\Mount\IMountPoint[]
* @return IMountPoint[]
* @since 8.2.0
*/
public function getAll(): array;
@ -103,7 +103,7 @@ interface IMountManager {
* Find mounts by numeric storage id
*
* @param int $id
* @return \OCP\Files\Mount\IMountPoint[]
* @return IMountPoint[]
* @since 8.2.0
*/
public function findByNumericId(int $id): array;

View file

@ -23,6 +23,7 @@
namespace Test\Cache;
use OC\Files\Storage\Local;
use OCP\Files\Mount\IMountManager;
use Test\Traits\UserTrait;
/**
@ -68,15 +69,12 @@ class FileCacheTest extends TestCache {
//clear all proxies and hooks so we can do clean testing
\OC_Hook::clear('OC_Filesystem');
//set up temporary storage
$this->storage = \OC\Files\Filesystem::getStorage('/');
\OC\Files\Filesystem::clearMounts();
/** @var IMountManager $manager */
$manager = \OC::$server->get(IMountManager::class);
$manager->removeMount('/test');
$storage = new \OC\Files\Storage\Temporary([]);
\OC\Files\Filesystem::mount($storage, [], '/');
$datadir = str_replace('local::', '', $storage->getId());
$config = \OC::$server->getConfig();
$this->datadir = $config->getSystemValue('cachedirectory', \OC::$SERVERROOT.'/data/cache');
$config->setSystemValue('cachedirectory', $datadir);
\OC\Files\Filesystem::mount($storage, [], '/test/cache');
//set up the users dir
$this->rootView = new \OC\Files\View('');
@ -94,17 +92,12 @@ class FileCacheTest extends TestCache {
}
\OC_User::setUserId($this->user);
\OC::$server->getConfig()->setSystemValue('cachedirectory', $this->datadir);
if ($this->instance) {
$this->instance->clear();
$this->instance = null;
}
// Restore the original mount point
\OC\Files\Filesystem::clearMounts();
\OC\Files\Filesystem::mount($this->storage, [], '/');
parent::tearDown();
}

View file

@ -10,6 +10,7 @@ namespace Test\Files\Cache;
use OC\Files\Filesystem as Filesystem;
use OC\Files\View;
use OCP\Files\Mount\IMountManager;
/**
* Class UpdaterLegacyTest
@ -61,7 +62,10 @@ class UpdaterLegacyTest extends \Test\TestCase {
Filesystem::init(self::$user, '/' . self::$user . '/files');
Filesystem::clearMounts();
/** @var IMountManager $manager */
$manager = \OC::$server->get(IMountManager::class);
$manager->removeMount('/' . self::$user);
Filesystem::mount($this->storage, [], '/' . self::$user . '/files');
\OC_Hook::clear('OC_Filesystem');

View file

@ -50,8 +50,6 @@ class UpdaterTest extends \Test\TestCase {
}
protected function tearDown(): void {
Filesystem::clearMounts();
$this->logout();
parent::tearDown();
}

View file

@ -45,6 +45,8 @@ class UserMountCacheTest extends TestCase {
private $fileIds = [];
protected function setUp(): void {
parent::setUp();
$this->fileIds = [];
$this->connection = \OC::$server->getDatabaseConnection();
$config = $this->getMockBuilder(IConfig::class)

View file

@ -8,6 +8,7 @@
namespace Test\Files\Mount;
use OC\Files\SetupManagerFactory;
use OC\Files\Storage\Temporary;
class LongId extends Temporary {
@ -24,12 +25,10 @@ class ManagerTest extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
$this->manager = new \OC\Files\Mount\Manager();
$this->manager = new \OC\Files\Mount\Manager($this->createMock(SetupManagerFactory::class));
}
public function testFind() {
$this->assertNull($this->manager->find('/'));
$rootMount = new \OC\Files\Mount\MountPoint(new Temporary([]), '/');
$this->manager->addMount($rootMount);
$this->assertEquals($rootMount, $this->manager->find('/'));

View file

@ -35,7 +35,7 @@ class FileTest extends NodeTest {
public function testGetContent() {
/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
$root = $this->getMockBuilder('\OC\Files\Node\Root')
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$hook = function ($file) {
@ -65,7 +65,7 @@ class FileTest extends NodeTest {
/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
$root = $this->getMockBuilder('\OC\Files\Node\Root')
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
@ -84,7 +84,7 @@ class FileTest extends NodeTest {
public function testPutContent() {
/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
$root = $this->getMockBuilder('\OC\Files\Node\Root')
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
@ -111,7 +111,7 @@ class FileTest extends NodeTest {
/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
$root = $this->getMockBuilder('\OC\Files\Node\Root')
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$this->view->expects($this->once())
@ -126,7 +126,7 @@ class FileTest extends NodeTest {
public function testGetMimeType() {
/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
$root = $this->getMockBuilder('\OC\Files\Node\Root')
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$this->view->expects($this->once())
@ -149,7 +149,8 @@ class FileTest extends NodeTest {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$hook = function ($file) {
@ -184,7 +185,8 @@ class FileTest extends NodeTest {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$hooksCalled = 0;
$hook = function ($file) use (&$hooksCalled) {
@ -223,7 +225,8 @@ class FileTest extends NodeTest {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$hook = function ($file) {
throw new \Exception('Hooks are not supposed to be called');
@ -248,7 +251,8 @@ class FileTest extends NodeTest {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$hook = function () {
throw new \Exception('Hooks are not supposed to be called');
@ -273,7 +277,8 @@ class FileTest extends NodeTest {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$hook = function () {
throw new \Exception('Hooks are not supposed to be called');

View file

@ -61,7 +61,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -93,7 +93,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -113,7 +113,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -136,7 +136,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -157,7 +157,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -187,7 +187,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->method('getUser')
->willReturn($this->user);
@ -207,7 +207,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -237,7 +237,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->method('getUser')
->willReturn($this->user);
@ -257,7 +257,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->method('getUser')
->willReturn($this->user);
@ -277,7 +277,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->method('getUser')
->willReturn($this->user);
@ -321,7 +321,7 @@ class FolderTest extends NodeTest {
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setMethods(['getUser', 'getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -364,7 +364,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->method('getUser')
->willReturn($this->user);
@ -407,7 +407,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')
@ -479,7 +479,7 @@ class FolderTest extends NodeTest {
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setMethods(['getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$storage = $this->createMock(\OC\Files\Storage\Storage::class);
$mount = new MountPoint($storage, '/bar');
@ -530,7 +530,7 @@ class FolderTest extends NodeTest {
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setMethods(['getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$storage = $this->createMock(\OC\Files\Storage\Storage::class);
$mount = new MountPoint($storage, '/bar');
@ -577,7 +577,7 @@ class FolderTest extends NodeTest {
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setMethods(['getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$storage = $this->createMock(\OC\Files\Storage\Storage::class);
$mount = new MountPoint($storage, '/bar');
@ -627,7 +627,7 @@ class FolderTest extends NodeTest {
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setMethods(['getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$storage = $this->createMock(\OC\Files\Storage\Storage::class);
$mount1 = new MountPoint($storage, '/bar');
@ -697,7 +697,7 @@ class FolderTest extends NodeTest {
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setMethods(['getUser', 'getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$view->expects($this->any())
@ -725,7 +725,7 @@ class FolderTest extends NodeTest {
/** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */
$root = $this->getMockBuilder(Root::class)
->setMethods(['getUser', 'getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
/** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */
$folderInfo = $this->getMockBuilder(FileInfo::class)
@ -793,7 +793,7 @@ class FolderTest extends NodeTest {
/** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */
$root = $this->getMockBuilder(Root::class)
->setMethods(['getUser', 'getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
/** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */
$folderInfo = $this->getMockBuilder(FileInfo::class)
@ -860,7 +860,7 @@ class FolderTest extends NodeTest {
/** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */
$root = $this->getMockBuilder(Root::class)
->setMethods(['getUser', 'getMountsIn', 'getMount'])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
/** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */
$folderInfo = $this->getMockBuilder(FileInfo::class)
@ -947,7 +947,7 @@ class FolderTest extends NodeTest {
*/
$view = $this->createMock(View::class);
$root = $this->getMockBuilder(Root::class)
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->getMock();
$root->expects($this->any())
->method('getUser')

View file

@ -78,7 +78,8 @@ class HookConnectorTest extends TestCase {
\OC::$server->getUserManager()->get($this->userId),
\OC::$server->getUserMountCache(),
$this->createMock(ILogger::class),
$this->createMock(IUserManager::class)
$this->createMock(IUserManager::class),
$this->createMock(IEventDispatcher::class)
);
$this->legacyDispatcher = \OC::$server->getEventDispatcher();
$this->eventDispatcher = \OC::$server->query(IEventDispatcher::class);

View file

@ -11,9 +11,11 @@ namespace Test\Files\Node;
use OC\Files\Node\Root;
use OC\Files\Storage\Temporary;
use OC\Files\View;
use OC\User\User;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Mount\IMountManager;
use OCP\ILogger;
use OCP\IUserManager;
use Test\Traits\UserTrait;
/**
* Class IntegrationTest
@ -23,6 +25,8 @@ use OCP\IUserManager;
* @package Test\Files\Node
*/
class IntegrationTest extends \Test\TestCase {
use UserTrait;
/**
* @var \OC\Files\Node\Root $root
*/
@ -41,11 +45,12 @@ class IntegrationTest extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
$manager = \OC\Files\Filesystem::getMountManager();
/** @var IMountManager $manager */
$manager = \OC::$server->get(IMountManager::class);
\OC_Hook::clear('OC_Filesystem');
$user = new User($this->getUniqueID('user'), new \Test\Util\User\Dummy, \OC::$server->getEventDispatcher());
$user = $this->createUser($this->getUniqueID('user'), '');
$this->loginAsUser($user->getUID());
$this->view = new View();
@ -55,7 +60,8 @@ class IntegrationTest extends \Test\TestCase {
$user,
\OC::$server->getUserMountCache(),
$this->createMock(ILogger::class),
$this->createMock(IUserManager::class)
$this->createMock(IUserManager::class),
$this->createMock(IEventDispatcher::class)
);
$storage = new Temporary([]);
$subStorage = new Temporary([]);
@ -63,6 +69,7 @@ class IntegrationTest extends \Test\TestCase {
$this->storages[] = $subStorage;
$this->root->mount($storage, '/');
$this->root->mount($subStorage, '/substorage/');
$manager->removeMount('/' . $user->getUID());
}
protected function tearDown(): void {

View file

@ -11,6 +11,7 @@ namespace Test\Files\Node;
use OC\Files\FileInfo;
use OC\Files\Mount\Manager;
use OC\Files\View;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
@ -39,6 +40,8 @@ abstract class NodeTest extends \Test\TestCase {
protected $logger;
/** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
protected $userManager;
/** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
protected $eventDispatcher;
protected function setUp(): void {
parent::setUp();
@ -55,8 +58,9 @@ abstract class NodeTest extends \Test\TestCase {
->getMock();
$this->logger = $this->createMock(ILogger::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
$this->root = $this->getMockBuilder('\OC\Files\Node\Root')
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->eventDispatcher])
->getMock();
}
@ -151,7 +155,8 @@ abstract class NodeTest extends \Test\TestCase {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$root->listen('\OC\Files', 'preDelete', $preListener);
@ -409,7 +414,8 @@ abstract class NodeTest extends \Test\TestCase {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$root->listen('\OC\Files', 'preTouch', $preListener);
$root->listen('\OC\Files', 'postTouch', $postListener);
@ -592,7 +598,7 @@ abstract class NodeTest extends \Test\TestCase {
public function testMoveCopyHooks($operationMethod, $viewMethod, $preHookName, $postHookName) {
/** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject $root */
$root = $this->getMockBuilder('\OC\Files\Node\Root')
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager])
->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher])
->setMethods(['get'])
->getMock();

View file

@ -13,6 +13,7 @@ use OC\Files\FileInfo;
use OC\Files\Mount\Manager;
use OC\Files\Node\Folder;
use OC\Files\View;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
@ -33,6 +34,8 @@ class RootTest extends \Test\TestCase {
private $logger;
/** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
private $userManager;
/** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
private $eventDispatcher;
protected function setUp(): void {
parent::setUp();
@ -46,6 +49,7 @@ class RootTest extends \Test\TestCase {
->getMock();
$this->logger = $this->createMock(ILogger::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
}
protected function getFileInfo($data) {
@ -71,7 +75,8 @@ class RootTest extends \Test\TestCase {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$view->expects($this->once())
@ -107,7 +112,8 @@ class RootTest extends \Test\TestCase {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$view->expects($this->once())
@ -135,7 +141,8 @@ class RootTest extends \Test\TestCase {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$root->get('/../foo');
@ -157,7 +164,8 @@ class RootTest extends \Test\TestCase {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$root->get('/bar/foo');
@ -170,7 +178,8 @@ class RootTest extends \Test\TestCase {
$this->user,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$user = $this->createMock(IUser::class);
$user
@ -210,7 +219,8 @@ class RootTest extends \Test\TestCase {
null,
$this->userMountCache,
$this->logger,
$this->userManager
$this->userManager,
$this->eventDispatcher
);
$this->userManager
->expects($this->once())

View file

@ -30,7 +30,7 @@ class PathVerificationTest extends \Test\TestCase {
$this->view = new View();
}
public function testPathVerificationFileNameTooLong() {
$this->expectException(\OCP\Files\InvalidPathException::class);
$this->expectExceptionMessage('File name is too long');

View file

@ -11,6 +11,7 @@ use OC\Cache\CappedMemoryCache;
use OC\Files\Cache\Watcher;
use OC\Files\Filesystem;
use OC\Files\Mount\MountPoint;
use OC\Files\SetupManager;
use OC\Files\Storage\Common;
use OC\Files\Storage\Storage;
use OC\Files\Storage\Temporary;
@ -19,6 +20,7 @@ use OCP\Constants;
use OCP\Files\Config\IMountProvider;
use OCP\Files\FileInfo;
use OCP\Files\GenericFileException;
use OCP\Files\Mount\IMountManager;
use OCP\Files\Storage\IStorage;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
@ -104,9 +106,10 @@ class ViewTest extends \Test\TestCase {
$this->groupObject->addUser($this->userObject);
self::loginAsUser($this->user);
// clear mounts but somehow keep the root storage
// that was initialized above...
Filesystem::clearMounts();
/** @var IMountManager $manager */
$manager = \OC::$server->get(IMountManager::class);
$manager->removeMount('/test');
$this->tempStorage = null;
}
@ -125,6 +128,10 @@ class ViewTest extends \Test\TestCase {
self::logout();
/** @var SetupManager $setupManager */
$setupManager = \OC::$server->get(SetupManager::class);
$setupManager->setupRoot();
$this->userObject->delete();
$this->groupObject->delete();
@ -224,12 +231,14 @@ class ViewTest extends \Test\TestCase {
$storage1 = $this->getTestStorage();
$storage2 = $this->getTestStorage();
$storage3 = $this->getTestStorage();
Filesystem::mount($storage1, [], '/');
Filesystem::mount($storage2, [], '/substorage');
Filesystem::mount($storage3, [], '/folder/anotherstorage');
$rootView = new View('');
$cachedData = $rootView->getFileInfo('/foo.txt');
/** @var int $id1 */
$id1 = $cachedData['fileid'];
@ -316,7 +325,6 @@ class ViewTest extends \Test\TestCase {
public function testCacheIncompleteFolder() {
$storage1 = $this->getTestStorage(false);
Filesystem::clearMounts();
Filesystem::mount($storage1, [], '/incomplete');
$rootView = new View('/incomplete');

View file

@ -9,6 +9,8 @@
namespace Test;
use OC\Files\Storage\Temporary;
use OCP\Files\Mount\IMountManager;
use Test\Traits\UserTrait;
/**
* Test the storage functions of OC_Helper
@ -16,6 +18,8 @@ use OC\Files\Storage\Temporary;
* @group DB
*/
class HelperStorageTest extends \Test\TestCase {
use UserTrait;
/** @var string */
private $user;
/** @var \OC\Files\Storage\Storage */
@ -27,14 +31,15 @@ class HelperStorageTest extends \Test\TestCase {
parent::setUp();
$this->user = $this->getUniqueID('user_');
\OC_User::useBackend('dummy');
\OC::$server->getUserManager()->createUser($this->user, $this->user);
$this->createUser($this->user, $this->user);
$this->storage = \OC\Files\Filesystem::getStorage('/');
\OC\Files\Filesystem::tearDown();
\OC_User::setUserId($this->user);
\OC\Files\Filesystem::init($this->user, '/' . $this->user . '/files');
\OC\Files\Filesystem::clearMounts();
/** @var IMountManager $manager */
$manager = \OC::$server->get(IMountManager::class);
$manager->removeMount('/' . $this->user);
$this->storageMock = null;
}
@ -47,13 +52,8 @@ class HelperStorageTest extends \Test\TestCase {
$this->storageMock = null;
}
\OC\Files\Filesystem::tearDown();
\OC\Files\Filesystem::mount($this->storage, [], '/');
\OC_User::setUserId('');
$user = \OC::$server->getUserManager()->get($this->user);
if ($user !== null) {
$user->delete();
}
\OC::$server->getConfig()->deleteAllUserValues($this->user);
parent::tearDown();

View file

@ -49,6 +49,8 @@ class SubAdminTest extends \Test\TestCase {
private $groups;
protected function setUp(): void {
parent::setUp();
$this->users = [];
$this->groups = [];

View file

@ -25,14 +25,21 @@ namespace Test;
use DOMDocument;
use DOMNode;
use OC\Command\QueueBus;
use OC\Files\Config\MountProviderCollection;
use OC\Files\Filesystem;
use OC\Files\Mount\CacheMountProvider;
use OC\Files\Mount\LocalHomeMountProvider;
use OC\Files\Mount\RootMountProvider;
use OC\Files\SetupManager;
use OC\Template\Base;
use OCP\Command\IBus;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Defaults;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\Security\ISecureRandom;
use Psr\Log\LoggerInterface;
abstract class TestCase extends \PHPUnit\Framework\TestCase {
/** @var \OC\Command\QueueBus */
@ -276,6 +283,22 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase {
self::tearDownAfterClassCleanStrayHooks();
self::tearDownAfterClassCleanStrayLocks();
/** @var SetupManager $setupManager */
$setupManager = \OC::$server->get(SetupManager::class);
$setupManager->tearDown();
/** @var MountProviderCollection $mountProviderCollection */
$mountProviderCollection = \OC::$server->get(MountProviderCollection::class);
$mountProviderCollection->clearProviders();
/** @var IConfig $config */
$config = \OC::$server->get(IConfig::class);
$mountProviderCollection->registerProvider(new CacheMountProvider($config));
$mountProviderCollection->registerHomeProvider(new LocalHomeMountProvider());
$mountProviderCollection->registerRootProvider(new RootMountProvider($config, \OC::$server->get(LoggerInterface::class)));
$setupManager->setupRoot();
parent::tearDownAfterClass();
}

View file

@ -9,12 +9,13 @@
namespace Test\Traits;
use OC\Encryption\EncryptionWrapper;
use OC\Files\Filesystem;
use OC\Files\SetupManager;
use OC\Memcache\ArrayCache;
use OCA\Encryption\AppInfo\Application;
use OCA\Encryption\KeyManager;
use OCA\Encryption\Users\Setup;
use OCP\Encryption\IManager;
use OCP\IUserManager;
/**
* Enables encryption
@ -31,6 +32,11 @@ trait EncryptionTrait {
private $originalEncryptionModule;
/** @var IUserManager */
private $userManager;
/** @var SetupManager */
private $setupManager;
/**
* @var \OCP\IConfig
*/
@ -47,18 +53,20 @@ trait EncryptionTrait {
// needed for fully logout
\OC::$server->getUserSession()->setUser(null);
Filesystem::tearDown();
$this->setupManager->tearDown();
\OC_User::setUserId($user);
$this->postLogin();
\OC_Util::setupFS($user);
if (\OC::$server->getUserManager()->userExists($user)) {
if ($this->userManager->userExists($user)) {
\OC::$server->getUserFolder($user);
}
}
protected function setupForUser($name, $password) {
\OC_Util::tearDownFS();
\OC_Util::setupFS($name);
$this->setupManager->tearDown();
$this->setupManager->setupForUser($this->userManager->get($name));
$container = $this->encryptionApp->getContainer();
/** @var KeyManager $keyManager */
$keyManager = $container->query(KeyManager::class);
@ -86,6 +94,9 @@ trait EncryptionTrait {
$this->markTestSkipped('Encryption not ready');
}
$this->userManager = \OC::$server->get(IUserManager::class);
$this->setupManager = \OC::$server->get(SetupManager::class);
\OC_App::loadApp('encryption');
$this->encryptionApp = new Application([], $isReady);

View file

@ -8,6 +8,21 @@
namespace Test\Traits;
use OC\User\User;
use OCP\IUser;
class DummyUser extends User {
private string $uid;
public function __construct(string $uid) {
$this->uid = $uid;
}
public function getUID(): string {
return $this->uid;
}
}
/**
* Allow creating users in a temporary backend
*/
@ -17,8 +32,9 @@ trait UserTrait {
*/
protected $userBackend;
protected function createUser($name, $password) {
protected function createUser($name, $password): IUser {
$this->userBackend->createUser($name, $password);
return new DummyUser($name);
}
protected function setUpUserTrait() {