2012-10-21 02:12:58 +02:00
|
|
|
|
<?php
|
|
|
|
|
/**
|
2024-05-10 15:09:14 +02:00
|
|
|
|
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
|
|
|
|
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
|
|
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
|
*/
|
2012-10-21 02:12:58 +02:00
|
|
|
|
|
2012-10-26 12:30:25 +02:00
|
|
|
|
namespace Test\Files;
|
|
|
|
|
|
2014-02-18 16:31:40 +01:00
|
|
|
|
use OC\Files\Cache\Watcher;
|
2017-03-17 10:59:53 +01:00
|
|
|
|
use OC\Files\Filesystem;
|
2015-03-05 17:22:48 +01:00
|
|
|
|
use OC\Files\Mount\MountPoint;
|
2022-02-23 18:29:08 +01:00
|
|
|
|
use OC\Files\SetupManager;
|
2019-11-22 20:52:10 +01:00
|
|
|
|
use OC\Files\Storage\Common;
|
2021-12-06 15:33:47 +01:00
|
|
|
|
use OC\Files\Storage\Storage;
|
2014-10-14 17:15:46 +02:00
|
|
|
|
use OC\Files\Storage\Temporary;
|
2016-12-01 18:52:32 +01:00
|
|
|
|
use OC\Files\View;
|
2023-08-15 18:21:04 +02:00
|
|
|
|
use OC\Share20\ShareDisableChecker;
|
2024-09-24 10:37:38 +02:00
|
|
|
|
use OCA\Files_Trashbin\Trash\ITrashManager;
|
2022-06-29 15:34:06 +02:00
|
|
|
|
use OCP\Cache\CappedMemoryCache;
|
2020-02-18 17:58:16 +01:00
|
|
|
|
use OCP\Constants;
|
2016-09-12 21:32:11 +02:00
|
|
|
|
use OCP\Files\Config\IMountProvider;
|
2015-11-10 11:06:48 +01:00
|
|
|
|
use OCP\Files\FileInfo;
|
2024-11-28 19:08:27 +01:00
|
|
|
|
use OCP\Files\ForbiddenException;
|
2021-01-05 09:12:11 +01:00
|
|
|
|
use OCP\Files\GenericFileException;
|
2022-02-23 18:29:08 +01:00
|
|
|
|
use OCP\Files\Mount\IMountManager;
|
2017-07-19 19:44:10 +02:00
|
|
|
|
use OCP\Files\Storage\IStorage;
|
2023-08-15 18:33:57 +02:00
|
|
|
|
use OCP\IDBConnection;
|
2025-04-10 11:29:21 +02:00
|
|
|
|
use OCP\IUserManager;
|
2015-05-05 13:48:49 +02:00
|
|
|
|
use OCP\Lock\ILockingProvider;
|
2017-03-17 10:59:53 +01:00
|
|
|
|
use OCP\Lock\LockedException;
|
2024-09-24 10:37:38 +02:00
|
|
|
|
use OCP\Server;
|
2023-08-29 17:07:38 -05:00
|
|
|
|
use OCP\Share\IManager as IShareManager;
|
2020-06-24 16:49:16 +02:00
|
|
|
|
use OCP\Share\IShare;
|
2017-03-17 10:59:53 +01:00
|
|
|
|
use OCP\Util;
|
2024-09-24 10:37:38 +02:00
|
|
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
2017-03-17 10:59:53 +01:00
|
|
|
|
use Test\HookHelper;
|
2019-11-22 20:52:10 +01:00
|
|
|
|
use Test\TestMoveableMountPoint;
|
2019-10-29 13:49:41 +01:00
|
|
|
|
use Test\Traits\UserTrait;
|
2014-02-18 16:31:40 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
class TemporaryNoTouch extends Temporary {
|
2024-10-01 16:12:30 +02:00
|
|
|
|
public function touch(string $path, ?int $mtime = null): bool {
|
2013-02-10 12:44:27 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
class TemporaryNoCross extends Temporary {
|
2024-10-01 16:12:30 +02:00
|
|
|
|
public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath, bool $preserveMtime = false): bool {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
return Common::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime);
|
2015-01-16 13:33:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-01 16:12:30 +02:00
|
|
|
|
public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
|
2015-01-16 13:33:17 +01:00
|
|
|
|
return Common::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
class TemporaryNoLocal extends Temporary {
|
2024-10-01 16:12:30 +02:00
|
|
|
|
public function instanceOfStorage(string $class): bool {
|
|
|
|
|
if ($class === '\OC\Files\Storage\Local') {
|
2015-01-16 13:33:17 +01:00
|
|
|
|
return false;
|
|
|
|
|
} else {
|
2024-10-01 16:12:30 +02:00
|
|
|
|
return parent::instanceOfStorage($class);
|
2015-01-16 13:33:17 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 01:52:41 +01:00
|
|
|
|
/**
|
2016-05-20 15:38:20 +02:00
|
|
|
|
* Class ViewTest
|
2015-11-03 01:52:41 +01:00
|
|
|
|
*
|
|
|
|
|
* @group DB
|
|
|
|
|
*
|
|
|
|
|
* @package Test\Files
|
|
|
|
|
*/
|
2016-05-20 15:38:20 +02:00
|
|
|
|
class ViewTest extends \Test\TestCase {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
use UserTrait;
|
|
|
|
|
|
2012-10-21 02:12:58 +02:00
|
|
|
|
/**
|
2013-12-12 15:14:44 +01:00
|
|
|
|
* @var \OC\Files\Storage\Storage[] $storages
|
2012-10-21 02:12:58 +02:00
|
|
|
|
*/
|
2019-10-29 13:49:41 +01:00
|
|
|
|
private $storages = [];
|
2015-08-07 15:43:27 +02:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
2014-05-08 15:19:54 +02:00
|
|
|
|
private $user;
|
2012-10-21 02:12:58 +02:00
|
|
|
|
|
2015-08-07 15:43:27 +02:00
|
|
|
|
/**
|
|
|
|
|
* @var \OCP\IUser
|
|
|
|
|
*/
|
|
|
|
|
private $userObject;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @var \OCP\IGroup
|
|
|
|
|
*/
|
|
|
|
|
private $groupObject;
|
|
|
|
|
|
2014-11-12 15:54:41 +01:00
|
|
|
|
/** @var \OC\Files\Storage\Storage */
|
2014-06-06 10:41:49 +02:00
|
|
|
|
private $tempStorage;
|
|
|
|
|
|
2019-11-21 16:40:38 +01:00
|
|
|
|
protected function setUp(): void {
|
2014-11-12 15:54:41 +01:00
|
|
|
|
parent::setUp();
|
2015-06-19 13:54:00 +02:00
|
|
|
|
\OC_Hook::clear();
|
2014-11-12 15:54:41 +01:00
|
|
|
|
|
2025-04-10 11:29:21 +02:00
|
|
|
|
Server::get(IUserManager::class)->clearBackends();
|
|
|
|
|
Server::get(IUserManager::class)->registerBackend(new \Test\Util\User\Dummy());
|
2013-06-26 20:48:54 +02:00
|
|
|
|
|
|
|
|
|
//login
|
2015-08-07 15:43:27 +02:00
|
|
|
|
$userManager = \OC::$server->getUserManager();
|
|
|
|
|
$groupManager = \OC::$server->getGroupManager();
|
|
|
|
|
$this->user = 'test';
|
|
|
|
|
$this->userObject = $userManager->createUser('test', 'test');
|
|
|
|
|
|
|
|
|
|
$this->groupObject = $groupManager->createGroup('group1');
|
|
|
|
|
$this->groupObject->addUser($this->userObject);
|
2013-06-26 20:48:54 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::loginAsUser($this->user);
|
2022-02-23 18:29:08 +01:00
|
|
|
|
|
|
|
|
|
/** @var IMountManager $manager */
|
|
|
|
|
$manager = \OC::$server->get(IMountManager::class);
|
|
|
|
|
$manager->removeMount('/test');
|
2014-06-06 10:41:49 +02:00
|
|
|
|
|
|
|
|
|
$this->tempStorage = null;
|
2012-10-21 02:12:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 16:40:38 +01:00
|
|
|
|
protected function tearDown(): void {
|
2013-06-26 20:48:54 +02:00
|
|
|
|
\OC_User::setUserId($this->user);
|
2012-10-21 02:12:58 +02:00
|
|
|
|
foreach ($this->storages as $storage) {
|
|
|
|
|
$cache = $storage->getCache();
|
2012-10-28 11:26:31 +01:00
|
|
|
|
$ids = $cache->getAll();
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$cache->clear();
|
|
|
|
|
}
|
2014-06-06 10:41:49 +02:00
|
|
|
|
|
2016-07-08 15:55:17 +02:00
|
|
|
|
if ($this->tempStorage) {
|
2014-06-06 10:41:49 +02:00
|
|
|
|
system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir()));
|
|
|
|
|
}
|
2014-11-12 15:54:41 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::logout();
|
2015-08-07 15:43:27 +02:00
|
|
|
|
|
2022-02-23 18:29:08 +01:00
|
|
|
|
/** @var SetupManager $setupManager */
|
|
|
|
|
$setupManager = \OC::$server->get(SetupManager::class);
|
|
|
|
|
$setupManager->setupRoot();
|
|
|
|
|
|
2015-08-07 15:43:27 +02:00
|
|
|
|
$this->userObject->delete();
|
|
|
|
|
$this->groupObject->delete();
|
|
|
|
|
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$mountProviderCollection = \OC::$server->getMountProviderCollection();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::invokePrivate($mountProviderCollection, 'providers', [[]]);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2014-11-12 15:54:41 +01:00
|
|
|
|
parent::tearDown();
|
2012-10-21 02:12:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2012-10-21 02:12:58 +02:00
|
|
|
|
public function testCacheAPI(): void {
|
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
|
|
|
|
$storage3 = $this->getTestStorage();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$root = self::getUniqueID('/');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], $root . '/');
|
|
|
|
|
Filesystem::mount($storage2, [], $root . '/substorage');
|
|
|
|
|
Filesystem::mount($storage3, [], $root . '/folder/anotherstorage');
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$textSize = strlen("dummy file data\n");
|
2018-08-28 15:58:27 +02:00
|
|
|
|
$imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo/logo.png');
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$storageSize = $textSize * 2 + $imageSize;
|
|
|
|
|
|
2014-06-03 11:34:48 +02:00
|
|
|
|
$storageInfo = $storage3->getCache()->get('');
|
|
|
|
|
$this->assertEquals($storageSize, $storageInfo['size']);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View($root);
|
2012-10-26 12:30:25 +02:00
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('/foo.txt');
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$this->assertEquals($textSize, $cachedData['size']);
|
|
|
|
|
$this->assertEquals('text/plain', $cachedData['mimetype']);
|
2013-01-07 01:03:11 +01:00
|
|
|
|
$this->assertNotEquals(-1, $cachedData['permissions']);
|
2012-10-21 02:12:58 +02:00
|
|
|
|
|
2012-10-26 12:30:25 +02:00
|
|
|
|
$cachedData = $rootView->getFileInfo('/');
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$this->assertEquals($storageSize * 3, $cachedData['size']);
|
|
|
|
|
$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
|
|
|
|
|
|
2013-11-18 17:29:30 +01:00
|
|
|
|
// get cached data excluding mount points
|
|
|
|
|
$cachedData = $rootView->getFileInfo('/', false);
|
|
|
|
|
$this->assertEquals($storageSize, $cachedData['size']);
|
|
|
|
|
$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
|
|
|
|
|
|
2012-10-26 12:30:25 +02:00
|
|
|
|
$cachedData = $rootView->getFileInfo('/folder');
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$this->assertEquals($storageSize + $textSize, $cachedData['size']);
|
|
|
|
|
$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
|
|
|
|
|
|
2012-10-26 12:30:25 +02:00
|
|
|
|
$folderData = $rootView->getDirectoryContent('/');
|
2012-10-21 02:12:58 +02:00
|
|
|
|
/**
|
|
|
|
|
* expected entries:
|
2012-11-25 16:08:35 +01:00
|
|
|
|
* folder
|
2012-10-21 02:12:58 +02:00
|
|
|
|
* foo.png
|
|
|
|
|
* foo.txt
|
|
|
|
|
* substorage
|
|
|
|
|
*/
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(4, $folderData);
|
2012-11-25 16:08:35 +01:00
|
|
|
|
$this->assertEquals('folder', $folderData[0]['name']);
|
|
|
|
|
$this->assertEquals('foo.png', $folderData[1]['name']);
|
|
|
|
|
$this->assertEquals('foo.txt', $folderData[2]['name']);
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$this->assertEquals('substorage', $folderData[3]['name']);
|
|
|
|
|
|
2012-11-25 16:08:35 +01:00
|
|
|
|
$this->assertEquals($storageSize + $textSize, $folderData[0]['size']);
|
|
|
|
|
$this->assertEquals($imageSize, $folderData[1]['size']);
|
|
|
|
|
$this->assertEquals($textSize, $folderData[2]['size']);
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$this->assertEquals($storageSize, $folderData[3]['size']);
|
2012-10-26 12:37:49 +02:00
|
|
|
|
|
2012-11-24 23:41:39 +01:00
|
|
|
|
$folderData = $rootView->getDirectoryContent('/substorage');
|
|
|
|
|
/**
|
|
|
|
|
* expected entries:
|
2012-11-25 16:08:35 +01:00
|
|
|
|
* folder
|
2012-11-24 23:41:39 +01:00
|
|
|
|
* foo.png
|
|
|
|
|
* foo.txt
|
|
|
|
|
*/
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(3, $folderData);
|
2012-11-25 16:08:35 +01:00
|
|
|
|
$this->assertEquals('folder', $folderData[0]['name']);
|
|
|
|
|
$this->assertEquals('foo.png', $folderData[1]['name']);
|
|
|
|
|
$this->assertEquals('foo.txt', $folderData[2]['name']);
|
2012-11-24 23:41:39 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$folderView = new View($root . '/folder');
|
2012-10-26 12:37:49 +02:00
|
|
|
|
$this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/'));
|
2012-10-26 12:43:23 +02:00
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('/foo.txt');
|
|
|
|
|
$this->assertFalse($cachedData['encrypted']);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$id = $rootView->putFileInfo('/foo.txt', ['encrypted' => true]);
|
2012-10-26 12:43:23 +02:00
|
|
|
|
$cachedData = $rootView->getFileInfo('/foo.txt');
|
|
|
|
|
$this->assertTrue($cachedData['encrypted']);
|
|
|
|
|
$this->assertEquals($cachedData['fileid'], $id);
|
2012-12-11 01:06:21 +01:00
|
|
|
|
|
|
|
|
|
$this->assertFalse($rootView->getFileInfo('/non/existing'));
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$this->assertEquals([], $rootView->getDirectoryContent('/non/existing'));
|
2012-10-21 02:12:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testGetPath(): void {
|
2013-01-27 00:13:16 +01:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
|
|
|
|
$storage3 = $this->getTestStorage();
|
2022-02-23 18:29:08 +01:00
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
|
|
|
|
Filesystem::mount($storage3, [], '/folder/anotherstorage');
|
2013-01-27 00:13:16 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2013-01-27 00:13:16 +01:00
|
|
|
|
|
2022-02-23 18:29:08 +01:00
|
|
|
|
|
2013-01-27 00:13:16 +01:00
|
|
|
|
$cachedData = $rootView->getFileInfo('/foo.txt');
|
2015-06-15 14:10:10 +02:00
|
|
|
|
/** @var int $id1 */
|
2013-01-27 00:13:16 +01:00
|
|
|
|
$id1 = $cachedData['fileid'];
|
|
|
|
|
$this->assertEquals('/foo.txt', $rootView->getPath($id1));
|
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('/substorage/foo.txt');
|
2015-06-15 14:10:10 +02:00
|
|
|
|
/** @var int $id2 */
|
2013-01-27 00:13:16 +01:00
|
|
|
|
$id2 = $cachedData['fileid'];
|
|
|
|
|
$this->assertEquals('/substorage/foo.txt', $rootView->getPath($id2));
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$folderView = new View('/substorage');
|
2013-01-27 00:13:16 +01:00
|
|
|
|
$this->assertEquals('/foo.txt', $folderView->getPath($id2));
|
2015-06-15 14:10:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-24 16:49:16 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
public function testGetPathNotExisting(): void {
|
2019-11-27 15:27:18 +01:00
|
|
|
|
$this->expectException(\OCP\Files\NotFoundException::class);
|
|
|
|
|
|
2015-06-15 14:10:10 +02:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
2015-06-15 14:10:10 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2015-06-15 14:10:10 +02:00
|
|
|
|
$cachedData = $rootView->getFileInfo('/foo.txt');
|
|
|
|
|
/** @var int $id1 */
|
|
|
|
|
$id1 = $cachedData['fileid'];
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$folderView = new View('/substorage');
|
2013-01-27 00:13:16 +01:00
|
|
|
|
$this->assertNull($folderView->getPath($id1));
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testMountPointOverwrite(): void {
|
2013-01-22 20:57:15 +01:00
|
|
|
|
$storage1 = $this->getTestStorage(false);
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
|
|
|
|
$storage1->mkdir('substorage');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
2013-01-22 20:57:15 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2013-01-22 20:57:15 +01:00
|
|
|
|
$folderContent = $rootView->getDirectoryContent('/');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(4, $folderContent);
|
2013-01-22 20:57:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-07 15:43:27 +02:00
|
|
|
|
public function sharingDisabledPermissionProvider() {
|
|
|
|
|
return [
|
|
|
|
|
['no', '', true],
|
|
|
|
|
['yes', 'group1', false],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider sharingDisabledPermissionProvider
|
|
|
|
|
*/
|
|
|
|
|
public function testRemoveSharePermissionWhenSharingDisabledForUser($excludeGroups, $excludeGroupsList, $expectedShareable): void {
|
2016-06-14 11:03:32 +02:00
|
|
|
|
// Reset sharing disabled for users cache
|
2023-08-15 18:21:04 +02:00
|
|
|
|
self::invokePrivate(\OC::$server->get(ShareDisableChecker::class), 'sharingDisabledForUsersCache', [new CappedMemoryCache()]);
|
2016-06-14 11:03:32 +02:00
|
|
|
|
|
2018-01-17 21:10:40 +01:00
|
|
|
|
$config = \OC::$server->getConfig();
|
|
|
|
|
$oldExcludeGroupsFlag = $config->getAppValue('core', 'shareapi_exclude_groups', 'no');
|
|
|
|
|
$oldExcludeGroupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
|
|
|
|
|
$config->setAppValue('core', 'shareapi_exclude_groups', $excludeGroups);
|
|
|
|
|
$config->setAppValue('core', 'shareapi_exclude_groups_list', $excludeGroupsList);
|
2015-08-07 15:43:27 +02:00
|
|
|
|
|
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/mount');
|
2015-08-07 15:43:27 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/');
|
2015-08-07 15:43:27 +02:00
|
|
|
|
|
|
|
|
|
$folderContent = $view->getDirectoryContent('');
|
|
|
|
|
$this->assertEquals($expectedShareable, $folderContent[0]->isShareable());
|
|
|
|
|
|
|
|
|
|
$folderContent = $view->getDirectoryContent('mount');
|
|
|
|
|
$this->assertEquals($expectedShareable, $folderContent[0]->isShareable());
|
|
|
|
|
|
2018-01-17 21:10:40 +01:00
|
|
|
|
$config->setAppValue('core', 'shareapi_exclude_groups', $oldExcludeGroupsFlag);
|
|
|
|
|
$config->setAppValue('core', 'shareapi_exclude_groups_list', $oldExcludeGroupsList);
|
2016-06-14 11:03:32 +02:00
|
|
|
|
|
|
|
|
|
// Reset sharing disabled for users cache
|
2023-08-15 18:21:04 +02:00
|
|
|
|
self::invokePrivate(\OC::$server->get(ShareDisableChecker::class), 'sharingDisabledForUsersCache', [new CappedMemoryCache()]);
|
2015-08-07 15:43:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testCacheIncompleteFolder(): void {
|
2012-12-15 03:20:50 +01:00
|
|
|
|
$storage1 = $this->getTestStorage(false);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/incomplete');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('/incomplete');
|
2012-12-15 03:20:50 +01:00
|
|
|
|
|
|
|
|
|
$entries = $rootView->getDirectoryContent('/');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(3, $entries);
|
2012-12-15 03:20:50 +01:00
|
|
|
|
|
|
|
|
|
// /folder will already be in the cache but not scanned
|
|
|
|
|
$entries = $rootView->getDirectoryContent('/folder');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(1, $entries);
|
2012-12-15 03:20:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-21 22:05:29 +02:00
|
|
|
|
public function testAutoScan(): void {
|
|
|
|
|
$storage1 = $this->getTestStorage(false);
|
|
|
|
|
$storage2 = $this->getTestStorage(false);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
2012-10-21 22:05:29 +02:00
|
|
|
|
$textSize = strlen("dummy file data\n");
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2012-10-26 12:30:25 +02:00
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('/');
|
2012-10-21 22:05:29 +02:00
|
|
|
|
$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
|
|
|
|
|
$this->assertEquals(-1, $cachedData['size']);
|
|
|
|
|
|
2012-10-26 12:30:25 +02:00
|
|
|
|
$folderData = $rootView->getDirectoryContent('/substorage/folder');
|
2012-10-21 22:05:29 +02:00
|
|
|
|
$this->assertEquals('text/plain', $folderData[0]['mimetype']);
|
|
|
|
|
$this->assertEquals($textSize, $folderData[0]['size']);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testSearch(): void {
|
2012-10-26 13:23:15 +02:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
|
|
|
|
$storage3 = $this->getTestStorage();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
|
|
|
|
Filesystem::mount($storage3, [], '/folder/anotherstorage');
|
2012-10-26 13:23:15 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2012-10-26 13:23:15 +02:00
|
|
|
|
|
|
|
|
|
$results = $rootView->search('foo');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(6, $results);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$paths = [];
|
2012-10-26 13:23:15 +02:00
|
|
|
|
foreach ($results as $result) {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertEquals($result['path'], Filesystem::normalizePath($result['path']));
|
2012-10-26 13:23:15 +02:00
|
|
|
|
$paths[] = $result['path'];
|
|
|
|
|
}
|
|
|
|
|
$this->assertContains('/foo.txt', $paths);
|
|
|
|
|
$this->assertContains('/foo.png', $paths);
|
|
|
|
|
$this->assertContains('/substorage/foo.txt', $paths);
|
|
|
|
|
$this->assertContains('/substorage/foo.png', $paths);
|
|
|
|
|
$this->assertContains('/folder/anotherstorage/foo.txt', $paths);
|
|
|
|
|
$this->assertContains('/folder/anotherstorage/foo.png', $paths);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$folderView = new View('/folder');
|
2012-10-26 13:23:15 +02:00
|
|
|
|
$results = $folderView->search('bar');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(2, $results);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$paths = [];
|
2012-10-26 13:23:15 +02:00
|
|
|
|
foreach ($results as $result) {
|
|
|
|
|
$paths[] = $result['path'];
|
|
|
|
|
}
|
|
|
|
|
$this->assertContains('/anotherstorage/folder/bar.txt', $paths);
|
|
|
|
|
$this->assertContains('/bar.txt', $paths);
|
|
|
|
|
|
|
|
|
|
$results = $folderView->search('foo');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(2, $results);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$paths = [];
|
2012-10-26 13:23:15 +02:00
|
|
|
|
foreach ($results as $result) {
|
|
|
|
|
$paths[] = $result['path'];
|
|
|
|
|
}
|
|
|
|
|
$this->assertContains('/anotherstorage/foo.txt', $paths);
|
|
|
|
|
$this->assertContains('/anotherstorage/foo.png', $paths);
|
2012-10-27 10:34:25 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$this->assertCount(6, $rootView->searchByMime('text'));
|
|
|
|
|
$this->assertCount(3, $folderView->searchByMime('text'));
|
2012-10-26 13:23:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testWatcher(): void {
|
2012-10-28 11:43:45 +01:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
2014-02-18 16:31:40 +01:00
|
|
|
|
$storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS);
|
2012-10-28 11:43:45 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2012-10-28 11:43:45 +01:00
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('foo.txt');
|
|
|
|
|
$this->assertEquals(16, $cachedData['size']);
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$rootView->putFileInfo('foo.txt', ['storage_mtime' => 10]);
|
2012-10-28 11:43:45 +01:00
|
|
|
|
$storage1->file_put_contents('foo.txt', 'foo');
|
|
|
|
|
clearstatcache();
|
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('foo.txt');
|
|
|
|
|
$this->assertEquals(3, $cachedData['size']);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testCopyBetweenStorageNoCross(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage1 = $this->getTestStorage(true, TemporaryNoCross::class);
|
|
|
|
|
$storage2 = $this->getTestStorage(true, TemporaryNoCross::class);
|
2015-01-16 13:33:17 +01:00
|
|
|
|
$this->copyBetweenStorages($storage1, $storage2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testCopyBetweenStorageCross(): void {
|
2013-05-19 14:20:46 -04:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2015-01-16 13:33:17 +01:00
|
|
|
|
$this->copyBetweenStorages($storage1, $storage2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testCopyBetweenStorageCrossNonLocal(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage1 = $this->getTestStorage(true, TemporaryNoLocal::class);
|
|
|
|
|
$storage2 = $this->getTestStorage(true, TemporaryNoLocal::class);
|
2015-01-16 13:33:17 +01:00
|
|
|
|
$this->copyBetweenStorages($storage1, $storage2);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
public function copyBetweenStorages($storage1, $storage2) {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
2013-05-19 14:20:46 -04:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2013-05-19 15:04:41 -04:00
|
|
|
|
$rootView->mkdir('substorage/emptyfolder');
|
2013-05-19 14:20:46 -04:00
|
|
|
|
$rootView->copy('substorage', 'anotherfolder');
|
|
|
|
|
$this->assertTrue($rootView->is_dir('/anotherfolder'));
|
|
|
|
|
$this->assertTrue($rootView->is_dir('/substorage'));
|
2013-05-19 15:04:41 -04:00
|
|
|
|
$this->assertTrue($rootView->is_dir('/anotherfolder/emptyfolder'));
|
|
|
|
|
$this->assertTrue($rootView->is_dir('/substorage/emptyfolder'));
|
2013-05-19 14:20:46 -04:00
|
|
|
|
$this->assertTrue($rootView->file_exists('/anotherfolder/foo.txt'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('/anotherfolder/foo.png'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('/anotherfolder/folder/bar.txt'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('/substorage/foo.txt'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('/substorage/foo.png'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('/substorage/folder/bar.txt'));
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testMoveBetweenStorageNoCross(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage1 = $this->getTestStorage(true, TemporaryNoCross::class);
|
|
|
|
|
$storage2 = $this->getTestStorage(true, TemporaryNoCross::class);
|
2015-01-16 13:33:17 +01:00
|
|
|
|
$this->moveBetweenStorages($storage1, $storage2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testMoveBetweenStorageCross(): void {
|
2013-05-19 14:20:46 -04:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2015-01-16 13:33:17 +01:00
|
|
|
|
$this->moveBetweenStorages($storage1, $storage2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testMoveBetweenStorageCrossNonLocal(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage1 = $this->getTestStorage(true, TemporaryNoLocal::class);
|
|
|
|
|
$storage2 = $this->getTestStorage(true, TemporaryNoLocal::class);
|
2015-01-16 13:33:17 +01:00
|
|
|
|
$this->moveBetweenStorages($storage1, $storage2);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
public function moveBetweenStorages($storage1, $storage2) {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
2013-05-19 14:20:46 -04:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2013-05-19 14:20:46 -04:00
|
|
|
|
$rootView->rename('foo.txt', 'substorage/folder/foo.txt');
|
|
|
|
|
$this->assertFalse($rootView->file_exists('foo.txt'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('substorage/folder/foo.txt'));
|
|
|
|
|
$rootView->rename('substorage/folder', 'anotherfolder');
|
|
|
|
|
$this->assertFalse($rootView->is_dir('substorage/folder'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('anotherfolder/foo.txt'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('anotherfolder/bar.txt'));
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 13:17:36 +01:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testUnlink(): void {
|
2014-01-08 13:17:36 +01:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
2014-01-08 13:17:36 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2014-01-08 13:17:36 +01:00
|
|
|
|
$rootView->file_put_contents('/foo.txt', 'asd');
|
|
|
|
|
$rootView->file_put_contents('/substorage/bar.txt', 'asd');
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($rootView->file_exists('foo.txt'));
|
|
|
|
|
$this->assertTrue($rootView->file_exists('substorage/bar.txt'));
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($rootView->unlink('foo.txt'));
|
|
|
|
|
$this->assertTrue($rootView->unlink('substorage/bar.txt'));
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($rootView->file_exists('foo.txt'));
|
|
|
|
|
$this->assertFalse($rootView->file_exists('substorage/bar.txt'));
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-08 15:56:34 +01:00
|
|
|
|
public function rmdirOrUnlinkDataProvider() {
|
|
|
|
|
return [['rmdir'], ['unlink']];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider rmdirOrUnlinkDataProvider
|
|
|
|
|
*/
|
|
|
|
|
public function testRmdir($method): void {
|
|
|
|
|
$storage1 = $this->getTestStorage();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
2017-02-08 15:56:34 +01:00
|
|
|
|
|
|
|
|
|
$rootView = new View('');
|
|
|
|
|
$rootView->mkdir('sub');
|
|
|
|
|
$rootView->mkdir('sub/deep');
|
|
|
|
|
$rootView->file_put_contents('/sub/deep/foo.txt', 'asd');
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($rootView->file_exists('sub/deep/foo.txt'));
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($rootView->$method('sub'));
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($rootView->file_exists('sub'));
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 13:17:36 +01:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testUnlinkRootMustFail(): void {
|
2014-01-08 13:17:36 +01:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/substorage');
|
2014-01-08 13:17:36 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2014-01-08 13:17:36 +01:00
|
|
|
|
$rootView->file_put_contents('/foo.txt', 'asd');
|
|
|
|
|
$rootView->file_put_contents('/substorage/bar.txt', 'asd');
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($rootView->unlink(''));
|
|
|
|
|
$this->assertFalse($rootView->unlink('/'));
|
|
|
|
|
$this->assertFalse($rootView->unlink('substorage'));
|
|
|
|
|
$this->assertFalse($rootView->unlink('/substorage'));
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 09:31:22 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testTouch(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getTestStorage(true, TemporaryNoTouch::class);
|
2013-02-10 12:44:27 +01:00
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2013-02-10 12:44:27 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2013-02-10 12:44:27 +01:00
|
|
|
|
$oldCachedData = $rootView->getFileInfo('foo.txt');
|
|
|
|
|
|
|
|
|
|
$rootView->touch('foo.txt', 500);
|
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('foo.txt');
|
|
|
|
|
$this->assertEquals(500, $cachedData['mtime']);
|
|
|
|
|
$this->assertEquals($oldCachedData['storage_mtime'], $cachedData['storage_mtime']);
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$rootView->putFileInfo('foo.txt', ['storage_mtime' => 1000]); //make sure the watcher detects the change
|
2013-02-10 12:44:27 +01:00
|
|
|
|
$rootView->file_put_contents('foo.txt', 'asd');
|
|
|
|
|
$cachedData = $rootView->getFileInfo('foo.txt');
|
2014-08-04 16:17:11 +02:00
|
|
|
|
$this->assertGreaterThanOrEqual($oldCachedData['mtime'], $cachedData['mtime']);
|
2013-02-10 12:44:27 +01:00
|
|
|
|
$this->assertEquals($cachedData['storage_mtime'], $cachedData['mtime']);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 17:04:55 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
|
|
|
|
public function testTouchFloat(): void {
|
|
|
|
|
$storage = $this->getTestStorage(true, TemporaryNoTouch::class);
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2017-03-27 17:04:55 +02:00
|
|
|
|
|
|
|
|
|
$rootView = new View('');
|
|
|
|
|
$oldCachedData = $rootView->getFileInfo('foo.txt');
|
|
|
|
|
|
|
|
|
|
$rootView->touch('foo.txt', 500.5);
|
|
|
|
|
|
|
|
|
|
$cachedData = $rootView->getFileInfo('foo.txt');
|
|
|
|
|
$this->assertEquals(500, $cachedData['mtime']);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 15:25:38 +02:00
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testViewHooks(): void {
|
2013-08-29 15:25:38 +02:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$defaultRoot = Filesystem::getRoot();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], $defaultRoot . '/substorage');
|
2013-08-29 15:25:38 +02:00
|
|
|
|
\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
|
|
|
|
$subView = new View($defaultRoot . '/substorage');
|
2013-08-29 15:25:38 +02:00
|
|
|
|
$this->hookPath = null;
|
|
|
|
|
|
|
|
|
|
$rootView->file_put_contents('/foo.txt', 'asd');
|
|
|
|
|
$this->assertNull($this->hookPath);
|
|
|
|
|
|
|
|
|
|
$subView->file_put_contents('/foo.txt', 'asd');
|
|
|
|
|
$this->assertEquals('/substorage/foo.txt', $this->hookPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private $hookPath;
|
|
|
|
|
|
2014-04-28 10:49:35 +02:00
|
|
|
|
public function dummyHook($params) {
|
2013-08-29 15:25:38 +02:00
|
|
|
|
$this->hookPath = $params['path'];
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-22 01:23:18 +02:00
|
|
|
|
public function testSearchNotOutsideView(): void {
|
|
|
|
|
$storage1 = $this->getTestStorage();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
2013-09-22 01:23:18 +02:00
|
|
|
|
$storage1->rename('folder', 'foo');
|
|
|
|
|
$scanner = $storage1->getScanner();
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/foo');
|
2013-09-22 01:23:18 +02:00
|
|
|
|
|
|
|
|
|
$result = $view->search('.txt');
|
|
|
|
|
$this->assertCount(1, $result);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-21 02:12:58 +02:00
|
|
|
|
/**
|
2012-10-21 22:05:29 +02:00
|
|
|
|
* @param bool $scan
|
2013-09-22 01:23:18 +02:00
|
|
|
|
* @param string $class
|
2012-10-26 12:30:25 +02:00
|
|
|
|
* @return \OC\Files\Storage\Storage
|
2012-10-21 02:12:58 +02:00
|
|
|
|
*/
|
2017-03-17 10:59:53 +01:00
|
|
|
|
private function getTestStorage($scan = true, $class = Temporary::class) {
|
2013-02-10 12:44:27 +01:00
|
|
|
|
/**
|
|
|
|
|
* @var \OC\Files\Storage\Storage $storage
|
|
|
|
|
*/
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new $class([]);
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$textData = "dummy file data\n";
|
2018-08-28 15:58:27 +02:00
|
|
|
|
$imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo/logo.png');
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$storage->mkdir('folder');
|
|
|
|
|
$storage->file_put_contents('foo.txt', $textData);
|
|
|
|
|
$storage->file_put_contents('foo.png', $imgData);
|
|
|
|
|
$storage->file_put_contents('folder/bar.txt', $textData);
|
|
|
|
|
|
2012-10-21 22:05:29 +02:00
|
|
|
|
if ($scan) {
|
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
}
|
2012-10-21 02:12:58 +02:00
|
|
|
|
$this->storages[] = $storage;
|
|
|
|
|
return $storage;
|
|
|
|
|
}
|
2013-10-09 20:46:43 +02:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @medium
|
|
|
|
|
*/
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function testViewHooksIfRootStartsTheSame(): void {
|
2013-10-09 20:46:43 +02:00
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$defaultRoot = Filesystem::getRoot();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], $defaultRoot . '_substorage');
|
2013-10-09 20:46:43 +02:00
|
|
|
|
\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$subView = new View($defaultRoot . '_substorage');
|
2013-10-09 20:46:43 +02:00
|
|
|
|
$this->hookPath = null;
|
|
|
|
|
|
|
|
|
|
$subView->file_put_contents('/foo.txt', 'asd');
|
|
|
|
|
$this->assertNull($this->hookPath);
|
|
|
|
|
}
|
2013-10-10 11:34:30 +02:00
|
|
|
|
|
2014-04-28 10:49:35 +02:00
|
|
|
|
private $hookWritePath;
|
|
|
|
|
private $hookCreatePath;
|
|
|
|
|
private $hookUpdatePath;
|
|
|
|
|
|
|
|
|
|
public function dummyHookWrite($params) {
|
|
|
|
|
$this->hookWritePath = $params['path'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function dummyHookUpdate($params) {
|
|
|
|
|
$this->hookUpdatePath = $params['path'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function dummyHookCreate($params) {
|
|
|
|
|
$this->hookCreatePath = $params['path'];
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-09 20:34:18 +02:00
|
|
|
|
public function testEditNoCreateHook(): void {
|
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$defaultRoot = Filesystem::getRoot();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
Filesystem::mount($storage2, [], $defaultRoot);
|
2014-04-28 10:49:35 +02:00
|
|
|
|
\OC_Hook::connect('OC_Filesystem', 'post_create', $this, 'dummyHookCreate');
|
|
|
|
|
\OC_Hook::connect('OC_Filesystem', 'post_update', $this, 'dummyHookUpdate');
|
|
|
|
|
\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHookWrite');
|
2013-10-09 20:34:18 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($defaultRoot);
|
2014-04-28 10:49:35 +02:00
|
|
|
|
$this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
|
2013-10-09 20:34:18 +02:00
|
|
|
|
|
|
|
|
|
$view->file_put_contents('/asd.txt', 'foo');
|
2014-04-28 10:49:35 +02:00
|
|
|
|
$this->assertEquals('/asd.txt', $this->hookCreatePath);
|
|
|
|
|
$this->assertNull($this->hookUpdatePath);
|
|
|
|
|
$this->assertEquals('/asd.txt', $this->hookWritePath);
|
|
|
|
|
|
|
|
|
|
$this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
|
2013-10-09 20:34:18 +02:00
|
|
|
|
|
|
|
|
|
$view->file_put_contents('/asd.txt', 'foo');
|
2014-04-28 10:49:35 +02:00
|
|
|
|
$this->assertNull($this->hookCreatePath);
|
|
|
|
|
$this->assertEquals('/asd.txt', $this->hookUpdatePath);
|
|
|
|
|
$this->assertEquals('/asd.txt', $this->hookWritePath);
|
|
|
|
|
|
|
|
|
|
\OC_Hook::clear('OC_Filesystem', 'post_create');
|
|
|
|
|
\OC_Hook::clear('OC_Filesystem', 'post_update');
|
|
|
|
|
\OC_Hook::clear('OC_Filesystem', 'post_write');
|
2013-10-09 20:34:18 +02:00
|
|
|
|
}
|
2013-10-10 16:06:26 +02:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider resolvePathTestProvider
|
|
|
|
|
*/
|
|
|
|
|
public function testResolvePath($expected, $pathToTest): void {
|
|
|
|
|
$storage1 = $this->getTestStorage();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
2013-10-10 16:06:26 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('');
|
2013-10-10 16:06:26 +02:00
|
|
|
|
|
|
|
|
|
$result = $view->resolvePath($pathToTest);
|
|
|
|
|
$this->assertEquals($expected, $result[1]);
|
|
|
|
|
|
|
|
|
|
$exists = $view->file_exists($pathToTest);
|
|
|
|
|
$this->assertTrue($exists);
|
|
|
|
|
|
|
|
|
|
$exists = $view->file_exists($result[1]);
|
|
|
|
|
$this->assertTrue($exists);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
public function resolvePathTestProvider() {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
return [
|
|
|
|
|
['foo.txt', 'foo.txt'],
|
|
|
|
|
['foo.txt', '/foo.txt'],
|
|
|
|
|
['folder', 'folder'],
|
|
|
|
|
['folder', '/folder'],
|
|
|
|
|
['folder', 'folder/'],
|
|
|
|
|
['folder', '/folder/'],
|
|
|
|
|
['folder/bar.txt', 'folder/bar.txt'],
|
|
|
|
|
['folder/bar.txt', '/folder/bar.txt'],
|
|
|
|
|
['', ''],
|
|
|
|
|
['', '/'],
|
|
|
|
|
];
|
2013-10-10 16:06:26 +02:00
|
|
|
|
}
|
2013-12-12 13:43:55 +01:00
|
|
|
|
|
|
|
|
|
public function testUTF8Names(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$names = ['虚', '和知しゃ和で', 'regular ascii', 'sɨˈrɪlɪk', 'ѨѬ', 'أنا أحب القراءة كثيرا'];
|
2013-12-12 13:43:55 +01:00
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2013-12-12 13:43:55 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2013-12-12 13:43:55 +01:00
|
|
|
|
foreach ($names as $name) {
|
|
|
|
|
$rootView->file_put_contents('/' . $name, 'dummy content');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$list = $rootView->getDirectoryContent('/');
|
|
|
|
|
|
|
|
|
|
$this->assertCount(count($names), $list);
|
|
|
|
|
foreach ($list as $item) {
|
|
|
|
|
$this->assertContains($item['name'], $names);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
|
|
|
|
|
$list = $cache->getFolderContents('');
|
|
|
|
|
|
|
|
|
|
$this->assertCount(count($names), $list);
|
|
|
|
|
foreach ($list as $item) {
|
|
|
|
|
$this->assertContains($item['name'], $names);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-01-14 15:11:41 +01:00
|
|
|
|
|
2014-12-10 12:20:30 +01:00
|
|
|
|
public function xtestLongPath() {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2014-05-08 15:19:54 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2014-05-08 15:19:54 +02:00
|
|
|
|
|
|
|
|
|
$longPath = '';
|
2014-09-23 11:17:31 -04:00
|
|
|
|
$ds = DIRECTORY_SEPARATOR;
|
|
|
|
|
/*
|
|
|
|
|
* 4096 is the maximum path length in file_cache.path in *nix
|
|
|
|
|
* 1024 is the max path length in mac
|
|
|
|
|
*/
|
2014-05-08 15:19:54 +02:00
|
|
|
|
$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
|
2015-12-18 11:19:53 +01:00
|
|
|
|
$tmpdirLength = strlen(\OC::$server->getTempManager()->getTemporaryFolder());
|
2016-07-08 15:55:17 +02:00
|
|
|
|
if (\OC_Util::runningOnMac()) {
|
2014-09-23 11:17:31 -04:00
|
|
|
|
$depth = ((1024 - $tmpdirLength) / 57);
|
|
|
|
|
} else {
|
|
|
|
|
$depth = ((4000 - $tmpdirLength) / 57);
|
|
|
|
|
}
|
2014-06-03 11:34:48 +02:00
|
|
|
|
foreach (range(0, $depth - 1) as $i) {
|
2014-09-23 11:17:31 -04:00
|
|
|
|
$longPath .= $ds . $folderName;
|
2014-05-08 15:19:54 +02:00
|
|
|
|
$result = $rootView->mkdir($longPath);
|
|
|
|
|
$this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath));
|
|
|
|
|
|
2014-09-23 11:17:31 -04:00
|
|
|
|
$result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem');
|
2014-05-08 15:19:54 +02:00
|
|
|
|
$this->assertEquals(5, $result, "file_put_contents failed on $i");
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($rootView->file_exists($longPath));
|
2014-09-23 11:17:31 -04:00
|
|
|
|
$this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt"));
|
2014-05-08 15:19:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
|
|
|
|
|
$longPath = $folderName;
|
2014-06-03 11:34:48 +02:00
|
|
|
|
foreach (range(0, $depth - 1) as $i) {
|
2014-05-08 15:19:54 +02:00
|
|
|
|
$cachedFolder = $cache->get($longPath);
|
|
|
|
|
$this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i");
|
|
|
|
|
$this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i");
|
|
|
|
|
|
|
|
|
|
$cachedFile = $cache->get($longPath . '/test.txt');
|
|
|
|
|
$this->assertTrue(is_array($cachedFile), "No cache entry for file at $i");
|
|
|
|
|
$this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i");
|
|
|
|
|
|
2014-09-23 11:17:31 -04:00
|
|
|
|
$longPath .= $ds . $folderName;
|
2014-05-08 15:19:54 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-14 15:11:41 +01:00
|
|
|
|
public function testTouchNotSupported(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new TemporaryNoTouch([]);
|
2014-01-14 15:11:41 +01:00
|
|
|
|
$scanner = $storage->getScanner();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2014-01-14 15:11:41 +01:00
|
|
|
|
$past = time() - 100;
|
|
|
|
|
$storage->file_put_contents('test', 'foobar');
|
|
|
|
|
$scanner->scan('');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('');
|
2014-01-14 15:11:41 +01:00
|
|
|
|
$info = $view->getFileInfo('/test/test');
|
|
|
|
|
|
|
|
|
|
$view->touch('/test/test', $past);
|
|
|
|
|
$scanner->scanFile('test', \OC\Files\Cache\Scanner::REUSE_ETAG);
|
|
|
|
|
|
|
|
|
|
$info2 = $view->getFileInfo('/test/test');
|
2014-02-27 09:39:34 +01:00
|
|
|
|
$this->assertSame($info['etag'], $info2['etag']);
|
2014-01-14 15:11:41 +01:00
|
|
|
|
}
|
2014-05-13 14:17:51 +02:00
|
|
|
|
|
2014-10-14 17:15:46 +02:00
|
|
|
|
public function testWatcherEtagCrossStorage(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage1 = new Temporary([]);
|
|
|
|
|
$storage2 = new Temporary([]);
|
2014-10-14 17:15:46 +02:00
|
|
|
|
$scanner1 = $storage1->getScanner();
|
|
|
|
|
$scanner2 = $storage2->getScanner();
|
|
|
|
|
$storage1->mkdir('sub');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/test/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/test/sub/storage');
|
2014-10-14 17:15:46 +02:00
|
|
|
|
|
|
|
|
|
$past = time() - 100;
|
|
|
|
|
$storage2->file_put_contents('test.txt', 'foobar');
|
|
|
|
|
$scanner1->scan('');
|
|
|
|
|
$scanner2->scan('');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('');
|
2014-10-14 17:15:46 +02:00
|
|
|
|
|
|
|
|
|
$storage2->getWatcher('')->setPolicy(Watcher::CHECK_ALWAYS);
|
|
|
|
|
|
|
|
|
|
$oldFileInfo = $view->getFileInfo('/test/sub/storage/test.txt');
|
|
|
|
|
$oldFolderInfo = $view->getFileInfo('/test');
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage2->getCache()->update($oldFileInfo->getId(), [
|
|
|
|
|
'storage_mtime' => $past,
|
|
|
|
|
]);
|
2014-10-14 17:15:46 +02:00
|
|
|
|
|
2016-11-09 16:14:54 +01:00
|
|
|
|
$oldEtag = $oldFolderInfo->getEtag();
|
|
|
|
|
|
2014-10-14 17:15:46 +02:00
|
|
|
|
$view->getFileInfo('/test/sub/storage/test.txt');
|
|
|
|
|
$newFolderInfo = $view->getFileInfo('/test');
|
|
|
|
|
|
2016-11-09 16:14:54 +01:00
|
|
|
|
$this->assertNotEquals($newFolderInfo->getEtag(), $oldEtag);
|
2014-10-14 17:15:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 14:17:51 +02:00
|
|
|
|
/**
|
|
|
|
|
* @dataProvider absolutePathProvider
|
|
|
|
|
*/
|
|
|
|
|
public function testGetAbsolutePath($expectedPath, $relativePath): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/files');
|
2014-05-13 14:17:51 +02:00
|
|
|
|
$this->assertEquals($expectedPath, $view->getAbsolutePath($relativePath));
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-13 13:59:28 +01:00
|
|
|
|
public function testPartFileInfo(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2015-01-13 13:59:28 +01:00
|
|
|
|
$scanner = $storage->getScanner();
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2015-01-13 13:59:28 +01:00
|
|
|
|
$storage->file_put_contents('test.part', 'foobar');
|
|
|
|
|
$scanner->scan('');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/test');
|
2015-01-13 13:59:28 +01:00
|
|
|
|
$info = $view->getFileInfo('test.part');
|
|
|
|
|
|
|
|
|
|
$this->assertInstanceOf('\OCP\Files\FileInfo', $info);
|
|
|
|
|
$this->assertNull($info->getId());
|
|
|
|
|
$this->assertEquals(6, $info->getSize());
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
public function absolutePathProvider() {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
return [
|
|
|
|
|
['/files/', ''],
|
|
|
|
|
['/files/0', '0'],
|
|
|
|
|
['/files/false', 'false'],
|
|
|
|
|
['/files/true', 'true'],
|
|
|
|
|
['/files/', '/'],
|
|
|
|
|
['/files/test', 'test'],
|
|
|
|
|
['/files/test', '/test'],
|
|
|
|
|
];
|
2014-05-13 14:17:51 +02:00
|
|
|
|
}
|
2014-05-08 15:19:54 +02:00
|
|
|
|
|
2015-02-04 12:07:16 +01:00
|
|
|
|
/**
|
2015-05-21 11:10:14 +02:00
|
|
|
|
* @dataProvider chrootRelativePathProvider
|
2015-02-04 12:07:16 +01:00
|
|
|
|
*/
|
2017-03-17 10:59:53 +01:00
|
|
|
|
public function testChrootGetRelativePath($root, $absolutePath, $expectedPath): void {
|
|
|
|
|
$view = new View('/files');
|
2015-05-20 18:31:32 +02:00
|
|
|
|
$view->chroot($root);
|
2015-02-04 12:07:16 +01:00
|
|
|
|
$this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 11:10:14 +02:00
|
|
|
|
public function chrootRelativePathProvider() {
|
|
|
|
|
return $this->relativePathProvider('/');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider initRelativePathProvider
|
|
|
|
|
*/
|
|
|
|
|
public function testInitGetRelativePath($root, $absolutePath, $expectedPath): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($root);
|
2015-05-21 11:10:14 +02:00
|
|
|
|
$this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function initRelativePathProvider() {
|
|
|
|
|
return $this->relativePathProvider(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function relativePathProvider($missingRootExpectedPath) {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
return [
|
2015-05-21 11:10:14 +02:00
|
|
|
|
// No root - returns the path
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['', '/files', '/files'],
|
|
|
|
|
['', '/files/', '/files/'],
|
2015-05-20 18:31:32 +02:00
|
|
|
|
|
2015-05-21 11:10:14 +02:00
|
|
|
|
// Root equals path - /
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['/files/', '/files/', '/'],
|
|
|
|
|
['/files/', '/files', '/'],
|
|
|
|
|
['/files', '/files/', '/'],
|
|
|
|
|
['/files', '/files', '/'],
|
2015-05-21 11:10:14 +02:00
|
|
|
|
|
|
|
|
|
// False negatives: chroot fixes those by adding the leading slash.
|
|
|
|
|
// But setting them up with this root (instead of chroot($root))
|
2015-09-24 15:01:45 +05:45
|
|
|
|
// will fail them, although they should be the same.
|
2015-05-21 11:10:14 +02:00
|
|
|
|
// TODO init should be fixed, so it also adds the leading slash
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['files/', '/files/', $missingRootExpectedPath],
|
|
|
|
|
['files', '/files/', $missingRootExpectedPath],
|
|
|
|
|
['files/', '/files', $missingRootExpectedPath],
|
|
|
|
|
['files', '/files', $missingRootExpectedPath],
|
2015-05-21 11:10:14 +02:00
|
|
|
|
|
|
|
|
|
// False negatives: Paths provided to the method should have a leading slash
|
|
|
|
|
// TODO input should be checked to have a leading slash
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['/files/', 'files/', null],
|
|
|
|
|
['/files', 'files/', null],
|
|
|
|
|
['/files/', 'files', null],
|
|
|
|
|
['/files', 'files', null],
|
2015-05-21 11:10:14 +02:00
|
|
|
|
|
|
|
|
|
// with trailing slashes
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['/files/', '/files/0', '0'],
|
|
|
|
|
['/files/', '/files/false', 'false'],
|
|
|
|
|
['/files/', '/files/true', 'true'],
|
|
|
|
|
['/files/', '/files/test', 'test'],
|
|
|
|
|
['/files/', '/files/test/foo', 'test/foo'],
|
2015-05-21 11:10:14 +02:00
|
|
|
|
|
|
|
|
|
// without trailing slashes
|
|
|
|
|
// TODO false expectation: Should match "with trailing slashes"
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['/files', '/files/0', '/0'],
|
|
|
|
|
['/files', '/files/false', '/false'],
|
|
|
|
|
['/files', '/files/true', '/true'],
|
|
|
|
|
['/files', '/files/test', '/test'],
|
|
|
|
|
['/files', '/files/test/foo', '/test/foo'],
|
2015-05-21 11:10:14 +02:00
|
|
|
|
|
|
|
|
|
// leading slashes
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['/files/', '/files_trashbin/', null],
|
|
|
|
|
['/files', '/files_trashbin/', null],
|
|
|
|
|
['/files/', '/files_trashbin', null],
|
|
|
|
|
['/files', '/files_trashbin', null],
|
2015-05-21 11:10:14 +02:00
|
|
|
|
|
|
|
|
|
// no leading slashes
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['files/', 'files_trashbin/', null],
|
|
|
|
|
['files', 'files_trashbin/', null],
|
|
|
|
|
['files/', 'files_trashbin', null],
|
|
|
|
|
['files', 'files_trashbin', null],
|
2015-05-21 11:10:14 +02:00
|
|
|
|
|
|
|
|
|
// mixed leading slashes
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['files/', '/files_trashbin/', null],
|
|
|
|
|
['/files/', 'files_trashbin/', null],
|
|
|
|
|
['files', '/files_trashbin/', null],
|
|
|
|
|
['/files', 'files_trashbin/', null],
|
|
|
|
|
['files/', '/files_trashbin', null],
|
|
|
|
|
['/files/', 'files_trashbin', null],
|
|
|
|
|
['files', '/files_trashbin', null],
|
|
|
|
|
['/files', 'files_trashbin', null],
|
|
|
|
|
|
|
|
|
|
['files', 'files_trashbin/test', null],
|
|
|
|
|
['/files', '/files_trashbin/test', null],
|
|
|
|
|
['/files', 'files_trashbin/test', null],
|
|
|
|
|
];
|
2015-02-04 12:07:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 17:48:09 +01:00
|
|
|
|
public function testFileView(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2015-01-26 17:48:09 +01:00
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'bar');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2015-01-26 17:48:09 +01:00
|
|
|
|
$scanner->scan('');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/test/foo.txt');
|
2015-01-26 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
$this->assertEquals('bar', $view->file_get_contents(''));
|
|
|
|
|
$fh = tmpfile();
|
|
|
|
|
fwrite($fh, 'foo');
|
|
|
|
|
rewind($fh);
|
|
|
|
|
$view->file_put_contents('', $fh);
|
|
|
|
|
$this->assertEquals('foo', $view->file_get_contents(''));
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 15:19:54 +02:00
|
|
|
|
/**
|
|
|
|
|
* @dataProvider tooLongPathDataProvider
|
|
|
|
|
*/
|
2014-06-03 11:34:48 +02:00
|
|
|
|
public function testTooLongPath($operation, $param0 = null): void {
|
2019-11-27 15:27:18 +01:00
|
|
|
|
$this->expectException(\OCP\Files\InvalidPathException::class);
|
|
|
|
|
|
2014-05-08 15:19:54 +02:00
|
|
|
|
|
|
|
|
|
$longPath = '';
|
|
|
|
|
// 4000 is the maximum path length in file_cache.path
|
|
|
|
|
$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
|
2014-06-03 11:34:48 +02:00
|
|
|
|
$depth = (4000 / 57);
|
|
|
|
|
foreach (range(0, $depth + 1) as $i) {
|
|
|
|
|
$longPath .= '/' . $folderName;
|
2014-05-08 15:19:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2014-06-06 10:41:49 +02:00
|
|
|
|
$this->tempStorage = $storage; // for later hard cleanup
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2014-05-08 15:19:54 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$rootView = new View('');
|
2014-05-08 15:19:54 +02:00
|
|
|
|
|
|
|
|
|
if ($param0 === '@0') {
|
|
|
|
|
$param0 = $longPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($operation === 'hash') {
|
|
|
|
|
$param0 = $longPath;
|
|
|
|
|
$longPath = 'md5';
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
call_user_func([$rootView, $operation], $longPath, $param0);
|
2014-05-08 15:19:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function tooLongPathDataProvider() {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
return [
|
|
|
|
|
['getAbsolutePath'],
|
|
|
|
|
['getRelativePath'],
|
|
|
|
|
['getMountPoint'],
|
|
|
|
|
['resolvePath'],
|
|
|
|
|
['getLocalFile'],
|
|
|
|
|
['mkdir'],
|
|
|
|
|
['rmdir'],
|
|
|
|
|
['opendir'],
|
|
|
|
|
['is_dir'],
|
|
|
|
|
['is_file'],
|
|
|
|
|
['stat'],
|
|
|
|
|
['filetype'],
|
|
|
|
|
['filesize'],
|
|
|
|
|
['readfile'],
|
|
|
|
|
['isCreatable'],
|
|
|
|
|
['isReadable'],
|
|
|
|
|
['isUpdatable'],
|
|
|
|
|
['isDeletable'],
|
|
|
|
|
['isSharable'],
|
|
|
|
|
['file_exists'],
|
|
|
|
|
['filemtime'],
|
|
|
|
|
['touch'],
|
|
|
|
|
['file_get_contents'],
|
|
|
|
|
['unlink'],
|
|
|
|
|
['deleteAll'],
|
|
|
|
|
['toTmpFile'],
|
|
|
|
|
['getMimeType'],
|
|
|
|
|
['free_space'],
|
|
|
|
|
['getFileInfo'],
|
|
|
|
|
['getDirectoryContent'],
|
|
|
|
|
['getOwner'],
|
|
|
|
|
['getETag'],
|
|
|
|
|
['file_put_contents', 'ipsum'],
|
|
|
|
|
['rename', '@0'],
|
|
|
|
|
['copy', '@0'],
|
|
|
|
|
['fopen', 'r'],
|
|
|
|
|
['fromTmpFile', '@0'],
|
|
|
|
|
['hash'],
|
|
|
|
|
['hasUpdated', 0],
|
|
|
|
|
['putFileInfo', []],
|
|
|
|
|
];
|
2014-05-08 15:19:54 +02:00
|
|
|
|
}
|
2015-01-23 15:11:27 +01:00
|
|
|
|
|
|
|
|
|
public function testRenameCrossStoragePreserveMtime(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage1 = new Temporary([]);
|
|
|
|
|
$storage2 = new Temporary([]);
|
2015-01-23 15:11:27 +01:00
|
|
|
|
$storage1->mkdir('sub');
|
|
|
|
|
$storage1->mkdir('foo');
|
|
|
|
|
$storage1->file_put_contents('foo.txt', 'asd');
|
|
|
|
|
$storage1->file_put_contents('foo/bar.txt', 'asd');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/test/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/test/sub/storage');
|
2015-01-23 15:11:27 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('');
|
2015-01-23 15:11:27 +01:00
|
|
|
|
$time = time() - 200;
|
|
|
|
|
$view->touch('/test/foo.txt', $time);
|
|
|
|
|
$view->touch('/test/foo', $time);
|
|
|
|
|
$view->touch('/test/foo/bar.txt', $time);
|
|
|
|
|
|
|
|
|
|
$view->rename('/test/foo.txt', '/test/sub/storage/foo.txt');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals($time, $view->filemtime('/test/sub/storage/foo.txt'));
|
|
|
|
|
|
|
|
|
|
$view->rename('/test/foo', '/test/sub/storage/foo');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals($time, $view->filemtime('/test/sub/storage/foo/bar.txt'));
|
|
|
|
|
}
|
2015-01-20 12:59:57 +01:00
|
|
|
|
|
2015-02-25 12:44:44 +01:00
|
|
|
|
public function testRenameFailDeleteTargetKeepSource(): void {
|
|
|
|
|
$this->doTestCopyRenameFail('rename');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCopyFailDeleteTargetKeepSource(): void {
|
|
|
|
|
$this->doTestCopyRenameFail('copy');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function doTestCopyRenameFail($operation) {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage1 = new Temporary([]);
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var \PHPUnit\Framework\MockObject\MockObject|Temporary $storage2 */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage2 = $this->getMockBuilder(TemporaryNoCross::class)
|
2015-03-05 11:49:31 +01:00
|
|
|
|
->setConstructorArgs([[]])
|
2021-01-05 08:53:21 +01:00
|
|
|
|
->setMethods(['fopen', 'writeStream'])
|
2015-03-05 11:49:31 +01:00
|
|
|
|
->getMock();
|
|
|
|
|
|
2020-06-30 16:09:50 +02:00
|
|
|
|
$storage2->method('writeStream')
|
2021-01-05 09:12:11 +01:00
|
|
|
|
->willThrowException(new GenericFileException('Failed to copy stream'));
|
2015-03-05 11:49:31 +01:00
|
|
|
|
|
2015-02-25 12:44:44 +01:00
|
|
|
|
$storage1->mkdir('sub');
|
|
|
|
|
$storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH');
|
|
|
|
|
$storage1->mkdir('dirtomove');
|
|
|
|
|
$storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits
|
2015-09-24 15:01:45 +05:45
|
|
|
|
$storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit
|
2015-02-25 12:44:44 +01:00
|
|
|
|
$storage2->file_put_contents('existing.txt', '0123');
|
|
|
|
|
$storage1->getScanner()->scan('');
|
|
|
|
|
$storage2->getScanner()->scan('');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], '/test/');
|
|
|
|
|
Filesystem::mount($storage2, [], '/test/sub/storage');
|
2015-02-25 12:44:44 +01:00
|
|
|
|
|
|
|
|
|
// move file
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('');
|
2015-02-25 12:44:44 +01:00
|
|
|
|
$this->assertTrue($storage1->file_exists('foo.txt'));
|
|
|
|
|
$this->assertFalse($storage2->file_exists('foo.txt'));
|
|
|
|
|
$this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/foo.txt'));
|
|
|
|
|
$this->assertFalse($storage2->file_exists('foo.txt'));
|
|
|
|
|
$this->assertFalse($storage2->getCache()->get('foo.txt'));
|
|
|
|
|
$this->assertTrue($storage1->file_exists('foo.txt'));
|
|
|
|
|
|
|
|
|
|
// if target exists, it will be deleted too
|
|
|
|
|
$this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/existing.txt'));
|
|
|
|
|
$this->assertFalse($storage2->file_exists('existing.txt'));
|
|
|
|
|
$this->assertFalse($storage2->getCache()->get('existing.txt'));
|
|
|
|
|
$this->assertTrue($storage1->file_exists('foo.txt'));
|
|
|
|
|
|
|
|
|
|
// move folder
|
|
|
|
|
$this->assertFalse($view->$operation('/test/dirtomove/', '/test/sub/storage/dirtomove/'));
|
|
|
|
|
// since the move failed, the full source tree is kept
|
|
|
|
|
$this->assertTrue($storage1->file_exists('dirtomove/indir1.txt'));
|
|
|
|
|
$this->assertTrue($storage1->file_exists('dirtomove/indir2.txt'));
|
2015-03-05 11:49:31 +01:00
|
|
|
|
// second file not moved/copied
|
2015-02-25 12:44:44 +01:00
|
|
|
|
$this->assertFalse($storage2->file_exists('dirtomove/indir2.txt'));
|
|
|
|
|
$this->assertFalse($storage2->getCache()->get('dirtomove/indir2.txt'));
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:59:57 +01:00
|
|
|
|
public function testDeleteFailKeepCache(): void {
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2019-10-29 13:49:41 +01:00
|
|
|
|
->setConstructorArgs([[]])
|
|
|
|
|
->setMethods(['unlink'])
|
2015-01-20 12:59:57 +01:00
|
|
|
|
->getMock();
|
|
|
|
|
$storage->expects($this->once())
|
|
|
|
|
->method('unlink')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturn(false);
|
2015-01-20 12:59:57 +01:00
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'asd');
|
|
|
|
|
$scanner->scan('');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2015-01-20 12:59:57 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/test');
|
2015-01-20 12:59:57 +01:00
|
|
|
|
|
|
|
|
|
$this->assertFalse($view->unlink('foo.txt'));
|
|
|
|
|
$this->assertTrue($cache->inCache('foo.txt'));
|
|
|
|
|
}
|
2015-02-18 16:01:24 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
public function directoryTraversalProvider() {
|
2015-02-18 16:01:24 +01:00
|
|
|
|
return [
|
|
|
|
|
['../test/'],
|
|
|
|
|
['..\\test\\my/../folder'],
|
|
|
|
|
['/test/my/../foo\\'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider directoryTraversalProvider
|
|
|
|
|
* @param string $root
|
|
|
|
|
*/
|
|
|
|
|
public function testConstructDirectoryTraversalException($root): void {
|
2019-11-27 15:27:18 +01:00
|
|
|
|
$this->expectException(\Exception::class);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
new View($root);
|
2015-02-18 16:01:24 +01:00
|
|
|
|
}
|
2015-02-27 14:26:52 +01:00
|
|
|
|
|
|
|
|
|
public function testRenameOverWrite(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2015-02-27 14:26:52 +01:00
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$storage->mkdir('sub');
|
|
|
|
|
$storage->mkdir('foo');
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'asd');
|
|
|
|
|
$storage->file_put_contents('foo/bar.txt', 'asd');
|
|
|
|
|
$scanner->scan('');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('');
|
2015-02-27 14:26:52 +01:00
|
|
|
|
$this->assertTrue($view->rename('/test/foo.txt', '/test/foo/bar.txt'));
|
|
|
|
|
}
|
2015-03-05 17:22:48 +01:00
|
|
|
|
|
|
|
|
|
public function testSetMountOptionsInStorage(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$mount = new MountPoint(Temporary::class, '/asd/', [[]], Filesystem::getLoader(), ['foo' => 'bar']);
|
|
|
|
|
Filesystem::getMountManager()->addMount($mount);
|
2015-03-05 17:22:48 +01:00
|
|
|
|
/** @var \OC\Files\Storage\Common $storage */
|
|
|
|
|
$storage = $mount->getStorage();
|
|
|
|
|
$this->assertEquals($storage->getMountOption('foo'), 'bar');
|
|
|
|
|
}
|
2015-03-05 17:27:10 +01:00
|
|
|
|
|
|
|
|
|
public function testSetMountOptionsWatcherPolicy(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$mount = new MountPoint(Temporary::class, '/asd/', [[]], Filesystem::getLoader(), ['filesystem_check_changes' => Watcher::CHECK_NEVER]);
|
|
|
|
|
Filesystem::getMountManager()->addMount($mount);
|
2015-03-05 17:27:10 +01:00
|
|
|
|
/** @var \OC\Files\Storage\Common $storage */
|
|
|
|
|
$storage = $mount->getStorage();
|
|
|
|
|
$watcher = $storage->getWatcher();
|
|
|
|
|
$this->assertEquals(Watcher::CHECK_NEVER, $watcher->getPolicy());
|
|
|
|
|
}
|
2015-04-22 16:24:25 +02:00
|
|
|
|
|
|
|
|
|
public function testGetAbsolutePathOnNull(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View();
|
2015-04-22 16:24:25 +02:00
|
|
|
|
$this->assertNull($view->getAbsolutePath(null));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGetRelativePathOnNull(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View();
|
2015-04-22 16:24:25 +02:00
|
|
|
|
$this->assertNull($view->getRelativePath(null));
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-24 16:49:16 +02:00
|
|
|
|
|
2015-04-22 16:24:25 +02:00
|
|
|
|
public function testNullAsRoot(): void {
|
2023-03-13 18:33:12 +01:00
|
|
|
|
$this->expectException(\TypeError::class);
|
2019-11-27 15:27:18 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
new View(null);
|
2015-04-22 16:24:25 +02:00
|
|
|
|
}
|
2015-05-05 13:48:49 +02:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* e.g. reading from a folder that's being renamed
|
|
|
|
|
*
|
2015-06-12 11:41:05 +02:00
|
|
|
|
*
|
|
|
|
|
* @dataProvider dataLockPaths
|
|
|
|
|
*
|
|
|
|
|
* @param string $rootPath
|
|
|
|
|
* @param string $pathPrefix
|
2015-05-05 13:48:49 +02:00
|
|
|
|
*/
|
2015-06-12 11:41:05 +02:00
|
|
|
|
public function testReadFromWriteLockedPath($rootPath, $pathPrefix): void {
|
2019-11-27 15:27:18 +01:00
|
|
|
|
$this->expectException(\OCP\Lock\LockedException::class);
|
|
|
|
|
|
2015-06-12 11:41:05 +02:00
|
|
|
|
$rootPath = str_replace('{folder}', 'files', $rootPath);
|
|
|
|
|
$pathPrefix = str_replace('{folder}', 'files', $pathPrefix);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($rootPath);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-12 11:41:05 +02:00
|
|
|
|
$this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
|
|
|
|
|
$view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reading from a files_encryption folder that's being renamed
|
|
|
|
|
*
|
|
|
|
|
* @dataProvider dataLockPaths
|
|
|
|
|
*
|
|
|
|
|
* @param string $rootPath
|
|
|
|
|
* @param string $pathPrefix
|
|
|
|
|
*/
|
|
|
|
|
public function testReadFromWriteUnlockablePath($rootPath, $pathPrefix): void {
|
|
|
|
|
$rootPath = str_replace('{folder}', 'files_encryption', $rootPath);
|
|
|
|
|
$pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($rootPath);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-12 11:41:05 +02:00
|
|
|
|
$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
|
|
|
|
|
$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED));
|
2015-05-05 13:48:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* e.g. writing a file that's being downloaded
|
|
|
|
|
*
|
2015-06-12 11:41:05 +02:00
|
|
|
|
*
|
|
|
|
|
* @dataProvider dataLockPaths
|
|
|
|
|
*
|
|
|
|
|
* @param string $rootPath
|
|
|
|
|
* @param string $pathPrefix
|
2015-05-05 13:48:49 +02:00
|
|
|
|
*/
|
2015-06-12 11:41:05 +02:00
|
|
|
|
public function testWriteToReadLockedFile($rootPath, $pathPrefix): void {
|
2019-11-27 15:27:18 +01:00
|
|
|
|
$this->expectException(\OCP\Lock\LockedException::class);
|
|
|
|
|
|
2015-06-12 11:41:05 +02:00
|
|
|
|
$rootPath = str_replace('{folder}', 'files', $rootPath);
|
|
|
|
|
$pathPrefix = str_replace('{folder}', 'files', $pathPrefix);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($rootPath);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-12 11:41:05 +02:00
|
|
|
|
$this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
|
|
|
|
|
$view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Writing a file that's being downloaded
|
|
|
|
|
*
|
|
|
|
|
* @dataProvider dataLockPaths
|
|
|
|
|
*
|
|
|
|
|
* @param string $rootPath
|
|
|
|
|
* @param string $pathPrefix
|
|
|
|
|
*/
|
|
|
|
|
public function testWriteToReadUnlockableFile($rootPath, $pathPrefix): void {
|
|
|
|
|
$rootPath = str_replace('{folder}', 'files_encryption', $rootPath);
|
|
|
|
|
$pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($rootPath);
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-12 11:41:05 +02:00
|
|
|
|
$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
|
|
|
|
|
$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 12:38:48 +02:00
|
|
|
|
/**
|
|
|
|
|
* Test that locks are on mount point paths instead of mount root
|
|
|
|
|
*/
|
|
|
|
|
public function testLockLocalMountPointPathInsteadOfStorageRoot(): void {
|
2023-08-29 18:16:45 -05:00
|
|
|
|
$lockingProvider = \OC::$server->get(ILockingProvider::class);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/testuser/files/');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$mountedStorage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
|
|
|
|
|
$this->assertTrue(
|
|
|
|
|
$view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, true),
|
|
|
|
|
'Can lock mount point'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// no exception here because storage root was not locked
|
|
|
|
|
$mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
|
|
|
|
|
|
|
|
|
|
$thrown = false;
|
|
|
|
|
try {
|
|
|
|
|
$storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
} catch (LockedException $e) {
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$thrown = true;
|
|
|
|
|
}
|
|
|
|
|
$this->assertTrue($thrown, 'Mount point path was locked on root storage');
|
|
|
|
|
|
|
|
|
|
$lockingProvider->releaseAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test that locks are on mount point paths and also mount root when requested
|
|
|
|
|
*/
|
|
|
|
|
public function testLockStorageRootButNotLocalMountPoint(): void {
|
2023-08-29 18:16:45 -05:00
|
|
|
|
$lockingProvider = \OC::$server->get(ILockingProvider::class);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/testuser/files/');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$mountedStorage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
|
|
|
|
|
$this->assertTrue(
|
|
|
|
|
$view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, false),
|
|
|
|
|
'Can lock mount point'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$thrown = false;
|
|
|
|
|
try {
|
|
|
|
|
$mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
} catch (LockedException $e) {
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$thrown = true;
|
|
|
|
|
}
|
|
|
|
|
$this->assertTrue($thrown, 'Mount point storage root was locked on original storage');
|
|
|
|
|
|
|
|
|
|
// local mount point was not locked
|
|
|
|
|
$storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
|
|
|
|
|
|
|
|
|
|
$lockingProvider->releaseAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test that locks are on mount point paths and also mount root when requested
|
|
|
|
|
*/
|
|
|
|
|
public function testLockMountPointPathFailReleasesBoth(): void {
|
2023-08-29 18:16:45 -05:00
|
|
|
|
$lockingProvider = \OC::$server->get(ILockingProvider::class);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/testuser/files/');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$mountedStorage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint.txt');
|
2015-06-22 12:38:48 +02:00
|
|
|
|
|
|
|
|
|
// this would happen if someone is writing on the mount point
|
|
|
|
|
$mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
|
|
|
|
|
|
|
|
|
|
$thrown = false;
|
|
|
|
|
try {
|
2015-09-24 15:01:45 +05:45
|
|
|
|
// this actually acquires two locks, one on the mount point and one on the storage root,
|
2015-06-22 12:38:48 +02:00
|
|
|
|
// but the one on the storage root will fail
|
|
|
|
|
$view->lockFile('/mountpoint.txt', ILockingProvider::LOCK_SHARED);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
} catch (LockedException $e) {
|
2015-06-22 12:38:48 +02:00
|
|
|
|
$thrown = true;
|
|
|
|
|
}
|
|
|
|
|
$this->assertTrue($thrown, 'Cannot acquire shared lock because storage root is already locked');
|
|
|
|
|
|
|
|
|
|
// from here we expect that the lock on the local mount point was released properly
|
|
|
|
|
// so acquiring an exclusive lock will succeed
|
|
|
|
|
$storage->acquireLock('/testuser/files/mountpoint.txt', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
|
|
|
|
|
|
|
|
|
|
$lockingProvider->releaseAll();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-12 11:41:05 +02:00
|
|
|
|
public function dataLockPaths() {
|
|
|
|
|
return [
|
|
|
|
|
['/testuser/{folder}', ''],
|
|
|
|
|
['/testuser', '/{folder}'],
|
|
|
|
|
['', '/testuser/{folder}'],
|
|
|
|
|
];
|
2015-05-05 13:48:49 +02:00
|
|
|
|
}
|
2015-06-11 18:32:15 +02:00
|
|
|
|
|
|
|
|
|
public function pathRelativeToFilesProvider() {
|
|
|
|
|
return [
|
|
|
|
|
['admin/files', ''],
|
|
|
|
|
['admin/files/x', 'x'],
|
|
|
|
|
['/admin/files', ''],
|
|
|
|
|
['/admin/files/sub', 'sub'],
|
|
|
|
|
['/admin/files/sub/', 'sub'],
|
|
|
|
|
['/admin/files/sub/sub2', 'sub/sub2'],
|
|
|
|
|
['//admin//files/sub//sub2', 'sub/sub2'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider pathRelativeToFilesProvider
|
|
|
|
|
*/
|
|
|
|
|
public function testGetPathRelativeToFiles($path, $expectedPath): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View();
|
2015-06-11 18:32:15 +02:00
|
|
|
|
$this->assertEquals($expectedPath, $view->getPathRelativeToFiles($path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function pathRelativeToFilesProviderExceptionCases() {
|
|
|
|
|
return [
|
|
|
|
|
[''],
|
|
|
|
|
['x'],
|
|
|
|
|
['files'],
|
|
|
|
|
['/files'],
|
|
|
|
|
['/admin/files_versions/abc'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider pathRelativeToFilesProviderExceptionCases
|
2017-03-20 11:06:08 +01:00
|
|
|
|
* @param string $path
|
2015-06-11 18:32:15 +02:00
|
|
|
|
*/
|
|
|
|
|
public function testGetPathRelativeToFilesWithInvalidArgument($path): void {
|
2019-11-27 15:27:18 +01:00
|
|
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
|
|
|
$this->expectExceptionMessage('$absolutePath must be relative to "files"');
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View();
|
2015-06-11 18:32:15 +02:00
|
|
|
|
$view->getPathRelativeToFiles($path);
|
|
|
|
|
}
|
2015-06-16 11:40:27 +02:00
|
|
|
|
|
|
|
|
|
public function testChangeLock(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/testuser/files/');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/');
|
2015-06-16 11:40:27 +02:00
|
|
|
|
|
|
|
|
|
$view->lockFile('/test/sub', ILockingProvider::LOCK_SHARED);
|
|
|
|
|
$this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
|
|
|
|
|
$this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
|
|
|
|
|
|
|
|
|
|
$view->changeLock('//test/sub', ILockingProvider::LOCK_EXCLUSIVE);
|
|
|
|
|
$this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
|
|
|
|
|
|
|
|
|
|
$view->changeLock('test/sub', ILockingProvider::LOCK_SHARED);
|
|
|
|
|
$this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
|
|
|
|
|
|
|
|
|
|
$view->unlockFile('/test/sub/', ILockingProvider::LOCK_SHARED);
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
|
|
|
|
|
$this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
|
|
|
|
|
}
|
2015-06-01 14:08:14 +02:00
|
|
|
|
|
|
|
|
|
public function hookPathProvider() {
|
|
|
|
|
return [
|
|
|
|
|
['/foo/files', '/foo', true],
|
|
|
|
|
['/foo/files/bar', '/foo', true],
|
|
|
|
|
['/foo', '/foo', false],
|
|
|
|
|
['/foo', '/files/foo', true],
|
2015-07-28 15:24:46 +02:00
|
|
|
|
['/foo', 'filesfoo', false],
|
|
|
|
|
['', '/foo/files', true],
|
2019-10-29 13:49:41 +01:00
|
|
|
|
['', '/foo/files/bar.txt', true],
|
2015-06-01 14:08:14 +02:00
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider hookPathProvider
|
|
|
|
|
* @param $root
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param $shouldEmit
|
|
|
|
|
*/
|
|
|
|
|
public function testHookPaths($root, $path, $shouldEmit): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$filesystemReflection = new \ReflectionClass(Filesystem::class);
|
2015-06-01 14:08:14 +02:00
|
|
|
|
$defaultRootValue = $filesystemReflection->getProperty('defaultInstance');
|
|
|
|
|
$defaultRootValue->setAccessible(true);
|
|
|
|
|
$oldRoot = $defaultRootValue->getValue();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$defaultView = new View('/foo/files');
|
2023-08-10 16:44:43 +02:00
|
|
|
|
$defaultRootValue->setValue(null, $defaultView);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($root);
|
|
|
|
|
$result = self::invokePrivate($view, 'shouldEmitHooks', [$path]);
|
2023-08-10 16:44:43 +02:00
|
|
|
|
$defaultRootValue->setValue(null, $oldRoot);
|
2015-06-01 14:08:14 +02:00
|
|
|
|
$this->assertEquals($shouldEmit, $result);
|
|
|
|
|
}
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2015-10-02 12:14:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* Create test movable mount points
|
|
|
|
|
*
|
|
|
|
|
* @param array $mountPoints array of mount point locations
|
|
|
|
|
* @return array array of MountPoint objects
|
|
|
|
|
*/
|
|
|
|
|
private function createTestMovableMountPoints($mountPoints) {
|
|
|
|
|
$mounts = [];
|
|
|
|
|
foreach ($mountPoints as $mountPoint) {
|
2021-12-06 15:33:47 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Storage::class)
|
2015-10-02 12:14:24 +02:00
|
|
|
|
->setMethods([])
|
|
|
|
|
->getMock();
|
2021-12-06 15:33:47 +01:00
|
|
|
|
$storage->method('getId')->willReturn('non-null-id');
|
2023-02-06 18:56:54 +01:00
|
|
|
|
$storage->method('getStorageCache')->willReturnCallback(function () use ($storage) {
|
2023-08-15 18:33:57 +02:00
|
|
|
|
return new \OC\Files\Cache\Storage($storage, true, \OC::$server->get(IDBConnection::class));
|
2023-02-06 18:56:54 +01:00
|
|
|
|
});
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2016-09-12 21:32:11 +02:00
|
|
|
|
$mounts[] = $this->getMockBuilder(TestMoveableMountPoint::class)
|
|
|
|
|
->setMethods(['moveMount'])
|
|
|
|
|
->setConstructorArgs([$storage, $mountPoint])
|
|
|
|
|
->getMock();
|
2015-10-02 12:14:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var IMountProvider|\PHPUnit\Framework\MockObject\MockObject $mountProvider */
|
2016-09-12 21:32:11 +02:00
|
|
|
|
$mountProvider = $this->createMock(IMountProvider::class);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$mountProvider->expects($this->any())
|
|
|
|
|
->method('getMountsForUser')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturn($mounts);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
|
|
|
|
$mountProviderCollection = \OC::$server->getMountProviderCollection();
|
|
|
|
|
$mountProviderCollection->registerProvider($mountProvider);
|
|
|
|
|
|
|
|
|
|
return $mounts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test mount point move
|
|
|
|
|
*/
|
|
|
|
|
public function testMountPointMove(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::loginAsUser($this->user);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2020-02-18 17:58:16 +01:00
|
|
|
|
[$mount1, $mount2] = $this->createTestMovableMountPoints([
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$this->user . '/files/mount1',
|
|
|
|
|
$this->user . '/files/mount2',
|
|
|
|
|
]);
|
|
|
|
|
$mount1->expects($this->once())
|
|
|
|
|
->method('moveMount')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturn(true);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
|
|
|
|
$mount2->expects($this->once())
|
|
|
|
|
->method('moveMount')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturn(true);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$view->mkdir('sub');
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($view->rename('mount1', 'renamed_mount'), 'Can rename mount point');
|
|
|
|
|
$this->assertTrue($view->rename('mount2', 'sub/moved_mount'), 'Can move a mount point into a subdirectory');
|
|
|
|
|
}
|
2015-11-10 11:06:48 +01:00
|
|
|
|
|
2024-11-28 19:08:27 +01:00
|
|
|
|
public function testMoveMountPointOverwrite(): void {
|
|
|
|
|
self::loginAsUser($this->user);
|
|
|
|
|
|
|
|
|
|
[$mount1, $mount2] = $this->createTestMovableMountPoints([
|
|
|
|
|
$this->user . '/files/mount1',
|
|
|
|
|
$this->user . '/files/mount2',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$mount1->expects($this->never())
|
|
|
|
|
->method('moveMount');
|
|
|
|
|
|
|
|
|
|
$mount2->expects($this->never())
|
|
|
|
|
->method('moveMount');
|
|
|
|
|
|
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
|
|
|
|
|
|
|
|
|
$this->expectException(ForbiddenException::class);
|
|
|
|
|
$view->rename('mount1', 'mount2');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMoveMountPointIntoMount(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::loginAsUser($this->user);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2020-02-18 17:58:16 +01:00
|
|
|
|
[$mount1, $mount2] = $this->createTestMovableMountPoints([
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$this->user . '/files/mount1',
|
|
|
|
|
$this->user . '/files/mount2',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$mount1->expects($this->never())
|
|
|
|
|
->method('moveMount');
|
|
|
|
|
|
|
|
|
|
$mount2->expects($this->never())
|
|
|
|
|
->method('moveMount');
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2024-11-28 19:08:27 +01:00
|
|
|
|
$this->expectException(ForbiddenException::class);
|
|
|
|
|
$view->rename('mount1', 'mount2/sub');
|
2015-10-02 12:14:24 +02:00
|
|
|
|
}
|
2015-11-10 11:06:48 +01:00
|
|
|
|
|
2015-10-02 12:14:24 +02:00
|
|
|
|
/**
|
|
|
|
|
* Test that moving a mount point into a shared folder is forbidden
|
|
|
|
|
*/
|
|
|
|
|
public function testMoveMountPointIntoSharedFolder(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::loginAsUser($this->user);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2024-09-04 22:24:19 +02:00
|
|
|
|
[$mount1, $mount2] = $this->createTestMovableMountPoints([
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$this->user . '/files/mount1',
|
2024-09-04 22:24:19 +02:00
|
|
|
|
$this->user . '/files/mount2',
|
2015-10-02 12:14:24 +02:00
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$mount1->expects($this->never())
|
|
|
|
|
->method('moveMount');
|
|
|
|
|
|
2024-09-04 22:24:19 +02:00
|
|
|
|
$mount2->expects($this->once())
|
|
|
|
|
->method('moveMount')
|
|
|
|
|
->willReturn(true);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$view->mkdir('shareddir');
|
|
|
|
|
$view->mkdir('shareddir/sub');
|
|
|
|
|
$view->mkdir('shareddir/sub2');
|
2024-09-04 22:24:19 +02:00
|
|
|
|
// Create a similar named but non-shared folder
|
|
|
|
|
$view->mkdir('shareddir notshared');
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
|
|
|
|
$fileId = $view->getFileInfo('shareddir')->getId();
|
|
|
|
|
$userObject = \OC::$server->getUserManager()->createUser('test2', 'IHateNonMockableStaticClasses');
|
2018-03-16 14:59:21 +01:00
|
|
|
|
|
|
|
|
|
$userFolder = \OC::$server->getUserFolder($this->user);
|
|
|
|
|
$shareDir = $userFolder->get('shareddir');
|
2023-08-29 17:07:38 -05:00
|
|
|
|
$shareManager = \OC::$server->get(IShareManager::class);
|
2018-03-16 14:59:21 +01:00
|
|
|
|
$share = $shareManager->newShare();
|
|
|
|
|
$share->setSharedWith('test2')
|
|
|
|
|
->setSharedBy($this->user)
|
2020-06-24 16:49:16 +02:00
|
|
|
|
->setShareType(IShare::TYPE_USER)
|
2018-03-16 14:59:21 +01:00
|
|
|
|
->setPermissions(\OCP\Constants::PERMISSION_READ)
|
|
|
|
|
->setNode($shareDir);
|
|
|
|
|
$shareManager->createShare($share);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2024-11-28 19:08:27 +01:00
|
|
|
|
try {
|
|
|
|
|
$view->rename('mount1', 'shareddir');
|
|
|
|
|
$this->fail('Cannot overwrite shared folder');
|
|
|
|
|
} catch (ForbiddenException $e) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
$view->rename('mount1', 'shareddir/sub');
|
|
|
|
|
$this->fail('Cannot move mount point into shared folder');
|
|
|
|
|
} catch (ForbiddenException $e) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
$view->rename('mount1', 'shareddir/sub/sub2');
|
|
|
|
|
$this->fail('Cannot move mount point into shared subfolder');
|
|
|
|
|
} catch (ForbiddenException $e) {
|
|
|
|
|
|
|
|
|
|
}
|
2024-09-04 22:24:19 +02:00
|
|
|
|
$this->assertTrue($view->rename('mount2', 'shareddir notshared/sub'), 'Can move mount point into a similarly named but non-shared folder');
|
2015-10-02 12:14:24 +02:00
|
|
|
|
|
2020-11-29 22:50:30 +01:00
|
|
|
|
$shareManager->deleteShare($share);
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$userObject->delete();
|
|
|
|
|
}
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
public function basicOperationProviderForLocks() {
|
|
|
|
|
return [
|
|
|
|
|
// --- write hook ----
|
|
|
|
|
[
|
|
|
|
|
'touch',
|
|
|
|
|
['touch-create.txt'],
|
|
|
|
|
'touch-create.txt',
|
|
|
|
|
'create',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_EXCLUSIVE,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'fopen',
|
|
|
|
|
['test-write.txt', 'w'],
|
|
|
|
|
'test-write.txt',
|
|
|
|
|
'write',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_EXCLUSIVE,
|
|
|
|
|
null,
|
|
|
|
|
// exclusive lock stays until fclose
|
|
|
|
|
ILockingProvider::LOCK_EXCLUSIVE,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'mkdir',
|
|
|
|
|
['newdir'],
|
|
|
|
|
'newdir',
|
|
|
|
|
'write',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_EXCLUSIVE,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'file_put_contents',
|
|
|
|
|
['file_put_contents.txt', 'blah'],
|
|
|
|
|
'file_put_contents.txt',
|
|
|
|
|
'write',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_EXCLUSIVE,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
2024-09-19 18:19:16 +02:00
|
|
|
|
null,
|
|
|
|
|
0,
|
2015-06-19 13:54:00 +02:00
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// ---- delete hook ----
|
|
|
|
|
[
|
|
|
|
|
'rmdir',
|
|
|
|
|
['dir'],
|
|
|
|
|
'dir',
|
|
|
|
|
'delete',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_EXCLUSIVE,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'unlink',
|
|
|
|
|
['test.txt'],
|
|
|
|
|
'test.txt',
|
|
|
|
|
'delete',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_EXCLUSIVE,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// ---- read hook (no post hooks) ----
|
|
|
|
|
[
|
|
|
|
|
'file_get_contents',
|
|
|
|
|
['test.txt'],
|
|
|
|
|
'test.txt',
|
|
|
|
|
'read',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
null,
|
2024-09-19 18:19:16 +02:00
|
|
|
|
null,
|
|
|
|
|
false,
|
2015-06-19 13:54:00 +02:00
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'fopen',
|
|
|
|
|
['test.txt', 'r'],
|
|
|
|
|
'test.txt',
|
|
|
|
|
'read',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
null,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'opendir',
|
|
|
|
|
['dir'],
|
|
|
|
|
'dir',
|
|
|
|
|
'read',
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
null,
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// ---- no lock, touch hook ---
|
|
|
|
|
['touch', ['test.txt'], 'test.txt', 'touch', null, null, null],
|
|
|
|
|
|
|
|
|
|
// ---- no hooks, no locks ---
|
|
|
|
|
['is_dir', ['dir'], 'dir', null],
|
|
|
|
|
['is_file', ['dir'], 'dir', null],
|
2024-09-19 18:19:16 +02:00
|
|
|
|
[
|
|
|
|
|
'stat',
|
|
|
|
|
['dir'],
|
|
|
|
|
'dir',
|
|
|
|
|
null,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
null,
|
|
|
|
|
false,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'filetype',
|
|
|
|
|
['dir'],
|
|
|
|
|
'dir',
|
|
|
|
|
null,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
null,
|
|
|
|
|
false,
|
|
|
|
|
],
|
2023-01-23 10:25:06 +01:00
|
|
|
|
[
|
|
|
|
|
'filesize',
|
|
|
|
|
['dir'],
|
|
|
|
|
'dir',
|
|
|
|
|
null,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
null,
|
|
|
|
|
/* Return an int */
|
|
|
|
|
100
|
|
|
|
|
],
|
2015-06-19 13:54:00 +02:00
|
|
|
|
['isCreatable', ['dir'], 'dir', null],
|
|
|
|
|
['isReadable', ['dir'], 'dir', null],
|
|
|
|
|
['isUpdatable', ['dir'], 'dir', null],
|
|
|
|
|
['isDeletable', ['dir'], 'dir', null],
|
|
|
|
|
['isSharable', ['dir'], 'dir', null],
|
|
|
|
|
['file_exists', ['dir'], 'dir', null],
|
2024-09-19 18:19:16 +02:00
|
|
|
|
[
|
|
|
|
|
'filemtime',
|
|
|
|
|
['dir'],
|
|
|
|
|
'dir',
|
|
|
|
|
null,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
ILockingProvider::LOCK_SHARED,
|
|
|
|
|
null,
|
|
|
|
|
false,
|
|
|
|
|
],
|
2015-06-19 13:54:00 +02:00
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test whether locks are set before and after the operation
|
|
|
|
|
*
|
|
|
|
|
* @dataProvider basicOperationProviderForLocks
|
|
|
|
|
*
|
|
|
|
|
* @param string $operation operation name on the view
|
|
|
|
|
* @param array $operationArgs arguments for the operation
|
|
|
|
|
* @param string $lockedPath path of the locked item to check
|
|
|
|
|
* @param string $hookType hook type
|
|
|
|
|
* @param int $expectedLockBefore expected lock during pre hooks
|
2017-03-17 10:59:53 +01:00
|
|
|
|
* @param int $expectedLockDuring expected lock during operation
|
2015-06-19 13:54:00 +02:00
|
|
|
|
* @param int $expectedLockAfter expected lock during post hooks
|
|
|
|
|
* @param int $expectedStrayLock expected lock after returning, should
|
|
|
|
|
* be null (unlock) for most operations
|
|
|
|
|
*/
|
|
|
|
|
public function testLockBasicOperation(
|
|
|
|
|
$operation,
|
|
|
|
|
$operationArgs,
|
|
|
|
|
$lockedPath,
|
|
|
|
|
$hookType,
|
|
|
|
|
$expectedLockBefore = ILockingProvider::LOCK_SHARED,
|
|
|
|
|
$expectedLockDuring = ILockingProvider::LOCK_SHARED,
|
|
|
|
|
$expectedLockAfter = ILockingProvider::LOCK_SHARED,
|
2023-01-23 10:25:06 +01:00
|
|
|
|
$expectedStrayLock = null,
|
|
|
|
|
$returnValue = true,
|
2015-06-19 13:54:00 +02:00
|
|
|
|
): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2024-09-24 10:37:38 +02:00
|
|
|
|
/** @var Temporary&MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->setMethods([$operation])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
2024-09-24 10:37:38 +02:00
|
|
|
|
/* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
|
|
|
|
|
Server::get(ITrashManager::class)->pauseTrash();
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
// work directly on disk because mkdir might be mocked
|
|
|
|
|
$realPath = $storage->getSourcePath('');
|
|
|
|
|
mkdir($realPath . '/files');
|
|
|
|
|
mkdir($realPath . '/files/dir');
|
|
|
|
|
file_put_contents($realPath . '/files/test.txt', 'blah');
|
|
|
|
|
$storage->getScanner()->scan('files');
|
|
|
|
|
|
|
|
|
|
$storage->expects($this->once())
|
|
|
|
|
->method($operation)
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2023-01-23 10:25:06 +01:00
|
|
|
|
function () use ($view, $lockedPath, &$lockTypeDuring, $returnValue) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypeDuring = $this->getFileLockType($view, $lockedPath);
|
|
|
|
|
|
2023-01-23 10:25:06 +01:00
|
|
|
|
return $returnValue;
|
2015-06-19 13:54:00 +02:00
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $lockedPath), 'File not locked before operation');
|
|
|
|
|
|
|
|
|
|
$this->connectMockHooks($hookType, $view, $lockedPath, $lockTypePre, $lockTypePost);
|
|
|
|
|
|
|
|
|
|
// do operation
|
2019-10-29 13:49:41 +01:00
|
|
|
|
call_user_func_array([$view, $operation], $operationArgs);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
if ($hookType !== null) {
|
|
|
|
|
$this->assertEquals($expectedLockBefore, $lockTypePre, 'File locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals($expectedLockAfter, $lockTypePost, 'File locked properly during post-hook');
|
|
|
|
|
$this->assertEquals($expectedLockDuring, $lockTypeDuring, 'File locked properly during operation');
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertNull($lockTypeDuring, 'File not locked during operation');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->assertEquals($expectedStrayLock, $this->getFileLockType($view, $lockedPath));
|
2024-09-24 10:37:38 +02:00
|
|
|
|
|
|
|
|
|
/* Resume trash to avoid side effects */
|
|
|
|
|
Server::get(ITrashManager::class)->resumeTrash();
|
2015-06-19 13:54:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test locks for file_put_content with stream.
|
|
|
|
|
* This code path uses $storage->fopen instead
|
|
|
|
|
*/
|
|
|
|
|
public function testLockFilePutContentWithStream(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$path = 'test_file_put_contents.txt';
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->setMethods(['fopen'])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$storage->mkdir('files');
|
|
|
|
|
|
|
|
|
|
$storage->expects($this->once())
|
|
|
|
|
->method('fopen')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () use ($view, $path, &$lockTypeDuring) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypeDuring = $this->getFileLockType($view, $path);
|
|
|
|
|
|
|
|
|
|
return fopen('php://temp', 'r+');
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
|
|
|
|
|
|
|
|
|
|
// do operation
|
|
|
|
|
$view->file_put_contents($path, fopen('php://temp', 'r+'));
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePost, 'File locked properly during post-hook');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test locks for fopen with fclose at the end
|
|
|
|
|
*/
|
|
|
|
|
public function testLockFopen(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$path = 'test_file_put_contents.txt';
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->setMethods(['fopen'])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$storage->mkdir('files');
|
|
|
|
|
|
|
|
|
|
$storage->expects($this->once())
|
|
|
|
|
->method('fopen')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () use ($view, $path, &$lockTypeDuring) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypeDuring = $this->getFileLockType($view, $path);
|
|
|
|
|
|
|
|
|
|
return fopen('php://temp', 'r+');
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
|
|
|
|
|
|
|
|
|
|
// do operation
|
|
|
|
|
$res = $view->fopen($path, 'w');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
|
2016-05-19 09:44:53 +02:00
|
|
|
|
$this->assertNull($lockTypePost, 'No post hook, no lock check possible');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File still locked after fopen');
|
|
|
|
|
|
|
|
|
|
fclose($res);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $path), 'File unlocked after fclose');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test locks for fopen with fclose at the end
|
|
|
|
|
*
|
|
|
|
|
* @dataProvider basicOperationProviderForLocks
|
|
|
|
|
*
|
|
|
|
|
* @param string $operation operation name on the view
|
|
|
|
|
* @param array $operationArgs arguments for the operation
|
|
|
|
|
* @param string $path path of the locked item to check
|
|
|
|
|
*/
|
|
|
|
|
public function testLockBasicOperationUnlocksAfterException(
|
|
|
|
|
$operation,
|
|
|
|
|
$operationArgs,
|
|
|
|
|
$path,
|
|
|
|
|
): void {
|
2019-06-21 16:23:47 +02:00
|
|
|
|
if ($operation === 'touch') {
|
|
|
|
|
$this->markTestSkipped('touch handles storage exceptions internally');
|
|
|
|
|
}
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->setMethods([$operation])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
2024-09-24 10:37:38 +02:00
|
|
|
|
/* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
|
|
|
|
|
Server::get(ITrashManager::class)->pauseTrash();
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
// work directly on disk because mkdir might be mocked
|
|
|
|
|
$realPath = $storage->getSourcePath('');
|
|
|
|
|
mkdir($realPath . '/files');
|
|
|
|
|
mkdir($realPath . '/files/dir');
|
|
|
|
|
file_put_contents($realPath . '/files/test.txt', 'blah');
|
|
|
|
|
$storage->getScanner()->scan('files');
|
|
|
|
|
|
|
|
|
|
$storage->expects($this->once())
|
|
|
|
|
->method($operation)
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
throw new \Exception('Simulated exception');
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$thrown = false;
|
|
|
|
|
try {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
call_user_func_array([$view, $operation], $operationArgs);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
$thrown = true;
|
|
|
|
|
$this->assertEquals('Simulated exception', $e->getMessage());
|
|
|
|
|
}
|
|
|
|
|
$this->assertTrue($thrown, 'Exception was rethrown');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
|
2024-09-24 10:37:38 +02:00
|
|
|
|
|
|
|
|
|
/* Resume trash to avoid side effects */
|
|
|
|
|
Server::get(ITrashManager::class)->resumeTrash();
|
2015-06-19 13:54:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-22 15:32:48 +01:00
|
|
|
|
public function testLockBasicOperationUnlocksAfterLockException(): void {
|
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
|
|
|
|
|
|
|
|
|
$storage = new Temporary([]);
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2019-01-22 15:32:48 +01:00
|
|
|
|
|
|
|
|
|
$storage->mkdir('files');
|
|
|
|
|
$storage->mkdir('files/dir');
|
|
|
|
|
$storage->file_put_contents('files/test.txt', 'blah');
|
|
|
|
|
$storage->getScanner()->scan('files');
|
|
|
|
|
|
|
|
|
|
// get a shared lock
|
|
|
|
|
$handle = $view->fopen('test.txt', 'r');
|
|
|
|
|
|
|
|
|
|
$thrown = false;
|
|
|
|
|
try {
|
|
|
|
|
// try (and fail) to get a write lock
|
|
|
|
|
$view->unlink('test.txt');
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
$thrown = true;
|
|
|
|
|
$this->assertInstanceOf(LockedException::class, $e);
|
|
|
|
|
}
|
|
|
|
|
$this->assertTrue($thrown, 'Exception was rethrown');
|
|
|
|
|
|
|
|
|
|
// clean shared lock
|
|
|
|
|
fclose($handle);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, 'test.txt'), 'File got unlocked');
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-19 13:54:00 +02:00
|
|
|
|
/**
|
|
|
|
|
* Test locks for fopen with fclose at the end
|
|
|
|
|
*
|
|
|
|
|
* @dataProvider basicOperationProviderForLocks
|
|
|
|
|
*
|
|
|
|
|
* @param string $operation operation name on the view
|
|
|
|
|
* @param array $operationArgs arguments for the operation
|
|
|
|
|
* @param string $path path of the locked item to check
|
|
|
|
|
* @param string $hookType hook type
|
|
|
|
|
*/
|
|
|
|
|
public function testLockBasicOperationUnlocksAfterCancelledHook(
|
|
|
|
|
$operation,
|
|
|
|
|
$operationArgs,
|
|
|
|
|
$path,
|
|
|
|
|
$hookType,
|
|
|
|
|
): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->setMethods([$operation])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$storage->mkdir('files');
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Util::connectHook(
|
|
|
|
|
Filesystem::CLASSNAME,
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$hookType,
|
2017-03-17 10:59:53 +01:00
|
|
|
|
HookHelper::class,
|
2015-06-19 13:54:00 +02:00
|
|
|
|
'cancellingCallback'
|
|
|
|
|
);
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
call_user_func_array([$view, $operation], $operationArgs);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function lockFileRenameOrCopyDataProvider() {
|
|
|
|
|
return [
|
|
|
|
|
['rename', ILockingProvider::LOCK_EXCLUSIVE],
|
|
|
|
|
['copy', ILockingProvider::LOCK_SHARED],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test locks for rename or copy operation
|
|
|
|
|
*
|
|
|
|
|
* @dataProvider lockFileRenameOrCopyDataProvider
|
|
|
|
|
*
|
|
|
|
|
* @param string $operation operation to be done on the view
|
|
|
|
|
* @param int $expectedLockTypeSourceDuring expected lock type on source file during
|
|
|
|
|
* the operation
|
|
|
|
|
*/
|
|
|
|
|
public function testLockFileRename($operation, $expectedLockTypeSourceDuring): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2020-02-18 17:58:16 +01:00
|
|
|
|
->setMethods([$operation, 'getMetaData', 'filemtime'])
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->getMock();
|
|
|
|
|
|
2020-02-18 17:58:16 +01:00
|
|
|
|
$storage->expects($this->any())
|
|
|
|
|
->method('getMetaData')
|
|
|
|
|
->will($this->returnValue([
|
|
|
|
|
'mtime' => 1885434487,
|
|
|
|
|
'etag' => '',
|
|
|
|
|
'mimetype' => 'text/plain',
|
|
|
|
|
'permissions' => Constants::PERMISSION_ALL,
|
|
|
|
|
'size' => 3
|
|
|
|
|
]));
|
2015-10-19 15:48:49 +02:00
|
|
|
|
$storage->expects($this->any())
|
|
|
|
|
->method('filemtime')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturn(123456789);
|
2015-10-19 15:48:49 +02:00
|
|
|
|
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$sourcePath = 'original.txt';
|
|
|
|
|
$targetPath = 'target.txt';
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$storage->mkdir('files');
|
|
|
|
|
$view->file_put_contents($sourcePath, 'meh');
|
|
|
|
|
|
|
|
|
|
$storage->expects($this->once())
|
|
|
|
|
->method($operation)
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
|
|
|
|
|
$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->connectMockHooks($operation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
|
|
|
|
|
$this->connectMockHooks($operation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
|
|
|
|
|
|
|
|
|
|
$view->$operation($sourcePath, $targetPath);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
|
|
|
|
|
}
|
2015-06-29 16:45:08 +02:00
|
|
|
|
|
2015-09-22 11:18:42 +02:00
|
|
|
|
/**
|
|
|
|
|
* simulate a failed copy operation.
|
|
|
|
|
* We expect that we catch the exception, free the lock and re-throw it.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
public function testLockFileCopyException(): void {
|
2019-11-27 15:27:18 +01:00
|
|
|
|
$this->expectException(\Exception::class);
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-09-22 11:18:42 +02:00
|
|
|
|
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2015-09-22 11:18:42 +02:00
|
|
|
|
->setMethods(['copy'])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
|
|
$sourcePath = 'original.txt';
|
|
|
|
|
$targetPath = 'target.txt';
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
2015-09-22 11:18:42 +02:00
|
|
|
|
$storage->mkdir('files');
|
|
|
|
|
$view->file_put_contents($sourcePath, 'meh');
|
|
|
|
|
|
|
|
|
|
$storage->expects($this->once())
|
|
|
|
|
->method('copy')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () {
|
2015-09-22 11:18:42 +02:00
|
|
|
|
throw new \Exception();
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-09-22 11:18:42 +02:00
|
|
|
|
|
|
|
|
|
$this->connectMockHooks('copy', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
|
|
|
|
|
$this->connectMockHooks('copy', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$view->copy($sourcePath, $targetPath);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
|
|
|
|
|
throw $e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-29 16:45:08 +02:00
|
|
|
|
/**
|
|
|
|
|
* Test rename operation: unlock first path when second path was locked
|
|
|
|
|
*/
|
|
|
|
|
public function testLockFileRenameUnlockOnException(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::loginAsUser('test');
|
2015-06-29 16:45:08 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-29 16:45:08 +02:00
|
|
|
|
|
|
|
|
|
$sourcePath = 'original.txt';
|
|
|
|
|
$targetPath = 'target.txt';
|
|
|
|
|
$view->file_put_contents($sourcePath, 'meh');
|
|
|
|
|
|
|
|
|
|
// simulate that the target path is already locked
|
|
|
|
|
$view->lockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file is locked before operation');
|
|
|
|
|
|
|
|
|
|
$thrown = false;
|
|
|
|
|
try {
|
|
|
|
|
$view->rename($sourcePath, $targetPath);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
} catch (LockedException $e) {
|
2015-06-29 16:45:08 +02:00
|
|
|
|
$thrown = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($thrown, 'LockedException thrown');
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file still locked after operation');
|
|
|
|
|
|
|
|
|
|
$view->unlockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
|
|
|
|
|
}
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2015-11-10 11:06:48 +01:00
|
|
|
|
/**
|
|
|
|
|
* Test rename operation: unlock first path when second path was locked
|
|
|
|
|
*/
|
|
|
|
|
public function testGetOwner(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::loginAsUser('test');
|
2015-11-10 11:06:48 +01:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/test/files/');
|
2015-11-10 11:06:48 +01:00
|
|
|
|
|
|
|
|
|
$path = 'foo.txt';
|
|
|
|
|
$view->file_put_contents($path, 'meh');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals('test', $view->getFileInfo($path)->getOwner()->getUID());
|
|
|
|
|
|
|
|
|
|
$folderInfo = $view->getDirectoryContent('');
|
|
|
|
|
$folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
|
|
|
|
|
return $info->getName() === 'foo.txt';
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
$this->assertEquals('test', $folderInfo[0]->getOwner()->getUID());
|
|
|
|
|
|
|
|
|
|
$subStorage = new Temporary();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::mount($subStorage, [], '/test/files/asd');
|
2015-11-10 11:06:48 +01:00
|
|
|
|
|
|
|
|
|
$folderInfo = $view->getDirectoryContent('');
|
|
|
|
|
$folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
|
|
|
|
|
return $info->getName() === 'asd';
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
$this->assertEquals('test', $folderInfo[0]->getOwner()->getUID());
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-19 13:54:00 +02:00
|
|
|
|
public function lockFileRenameOrCopyCrossStorageDataProvider() {
|
|
|
|
|
return [
|
|
|
|
|
['rename', 'moveFromStorage', ILockingProvider::LOCK_EXCLUSIVE],
|
|
|
|
|
['copy', 'copyFromStorage', ILockingProvider::LOCK_SHARED],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test locks for rename or copy operation cross-storage
|
|
|
|
|
*
|
|
|
|
|
* @dataProvider lockFileRenameOrCopyCrossStorageDataProvider
|
|
|
|
|
*
|
|
|
|
|
* @param string $viewOperation operation to be done on the view
|
|
|
|
|
* @param string $storageOperation operation to be mocked on the storage
|
|
|
|
|
* @param int $expectedLockTypeSourceDuring expected lock type on source file during
|
|
|
|
|
* the operation
|
|
|
|
|
*/
|
|
|
|
|
public function testLockFileRenameCrossStorage($viewOperation, $storageOperation, $expectedLockTypeSourceDuring): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage = $this->getMockBuilder(Temporary::class)
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->setMethods([$storageOperation])
|
|
|
|
|
->getMock();
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage2 */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$storage2 = $this->getMockBuilder(Temporary::class)
|
2020-02-18 17:58:16 +01:00
|
|
|
|
->setMethods([$storageOperation, 'getMetaData', 'filemtime'])
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->getMock();
|
|
|
|
|
|
2020-02-18 17:58:16 +01:00
|
|
|
|
$storage2->expects($this->any())
|
|
|
|
|
->method('getMetaData')
|
|
|
|
|
->will($this->returnValue([
|
|
|
|
|
'mtime' => 1885434487,
|
|
|
|
|
'etag' => '',
|
|
|
|
|
'mimetype' => 'text/plain',
|
|
|
|
|
'permissions' => Constants::PERMISSION_ALL,
|
|
|
|
|
'size' => 3
|
|
|
|
|
]));
|
2015-10-19 15:48:49 +02:00
|
|
|
|
$storage2->expects($this->any())
|
|
|
|
|
->method('filemtime')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturn(123456789);
|
2015-10-19 15:48:49 +02:00
|
|
|
|
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$sourcePath = 'original.txt';
|
|
|
|
|
$targetPath = 'substorage/target.txt';
|
|
|
|
|
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], $this->user . '/');
|
|
|
|
|
Filesystem::mount($storage2, [], $this->user . '/files/substorage');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$storage->mkdir('files');
|
|
|
|
|
$view->file_put_contents($sourcePath, 'meh');
|
2024-12-03 16:24:28 +01:00
|
|
|
|
$storage2->getUpdater()->update('');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$storage->expects($this->never())
|
|
|
|
|
->method($storageOperation);
|
|
|
|
|
$storage2->expects($this->once())
|
|
|
|
|
->method($storageOperation)
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
|
|
|
|
|
$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->connectMockHooks($viewOperation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
|
|
|
|
|
$this->connectMockHooks($viewOperation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
|
|
|
|
|
|
|
|
|
|
$view->$viewOperation($sourcePath, $targetPath);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test locks when moving a mount point
|
|
|
|
|
*/
|
|
|
|
|
public function testLockMoveMountPoint(): void {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
self::loginAsUser('test');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2020-02-18 17:58:16 +01:00
|
|
|
|
[$mount] = $this->createTestMovableMountPoints([
|
2015-10-02 12:14:24 +02:00
|
|
|
|
$this->user . '/files/substorage',
|
|
|
|
|
]);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files/');
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$view->mkdir('subdir');
|
|
|
|
|
|
|
|
|
|
$sourcePath = 'substorage';
|
|
|
|
|
$targetPath = 'subdir/substorage_moved';
|
|
|
|
|
|
|
|
|
|
$mount->expects($this->once())
|
|
|
|
|
->method('moveMount')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function ($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath, true);
|
|
|
|
|
$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath, true);
|
|
|
|
|
|
|
|
|
|
$lockTypeSharedRootDuring = $this->getFileLockType($view, $sourcePath, false);
|
|
|
|
|
|
|
|
|
|
$mount->setMountPoint($target);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
$this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost, true);
|
|
|
|
|
$this->connectMockHooks('rename', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost, true);
|
|
|
|
|
// in pre-hook, mount point is still on $sourcePath
|
|
|
|
|
$this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSharedRootPre, $dummy, false);
|
|
|
|
|
// in post-hook, mount point is now on $targetPath
|
|
|
|
|
$this->connectMockHooks('rename', $view, $targetPath, $dummy, $lockTypeSharedRootPost, false);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked before operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked before operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked before operation');
|
|
|
|
|
|
|
|
|
|
$view->rename($sourcePath, $targetPath);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source path locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeSourceDuring, 'Source path locked properly during operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source path locked properly during post-hook');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target path locked properly during pre-hook');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target path locked properly during operation');
|
|
|
|
|
$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target path locked properly during post-hook');
|
|
|
|
|
|
|
|
|
|
$this->assertNull($lockTypeSharedRootPre, 'Shared storage root not locked during pre-hook');
|
|
|
|
|
$this->assertNull($lockTypeSharedRootDuring, 'Shared storage root not locked during move');
|
|
|
|
|
$this->assertNull($lockTypeSharedRootPost, 'Shared storage root not locked during post-hook');
|
|
|
|
|
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked after operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked after operation');
|
|
|
|
|
$this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked after operation');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Connect hook callbacks for hook type
|
|
|
|
|
*
|
|
|
|
|
* @param string $hookType hook type or null for none
|
2017-03-17 10:59:53 +01:00
|
|
|
|
* @param View $view view to check the lock on
|
2015-06-19 13:54:00 +02:00
|
|
|
|
* @param string $path path for which to check the lock
|
|
|
|
|
* @param int $lockTypePre variable to receive lock type that was active in the pre-hook
|
|
|
|
|
* @param int $lockTypePost variable to receive lock type that was active in the post-hook
|
|
|
|
|
* @param bool $onMountPoint true to check the mount point instead of the
|
|
|
|
|
* mounted storage
|
|
|
|
|
*/
|
|
|
|
|
private function connectMockHooks($hookType, $view, $path, &$lockTypePre, &$lockTypePost, $onMountPoint = false) {
|
|
|
|
|
if ($hookType === null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-25 00:03:28 +02:00
|
|
|
|
$eventHandler = $this->getMockBuilder(\stdclass::class)
|
2015-06-19 13:54:00 +02:00
|
|
|
|
->setMethods(['preCallback', 'postCallback'])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
|
|
$eventHandler->expects($this->any())
|
|
|
|
|
->method('preCallback')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () use ($view, $path, $onMountPoint, &$lockTypePre) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypePre = $this->getFileLockType($view, $path, $onMountPoint);
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$eventHandler->expects($this->any())
|
|
|
|
|
->method('postCallback')
|
2020-03-25 22:21:27 +01:00
|
|
|
|
->willReturnCallback(
|
2015-11-10 11:06:48 +01:00
|
|
|
|
function () use ($view, $path, $onMountPoint, &$lockTypePost) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$lockTypePost = $this->getFileLockType($view, $path, $onMountPoint);
|
|
|
|
|
}
|
2020-03-25 22:21:27 +01:00
|
|
|
|
);
|
2015-06-19 13:54:00 +02:00
|
|
|
|
|
|
|
|
|
if ($hookType !== null) {
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Util::connectHook(
|
|
|
|
|
Filesystem::CLASSNAME,
|
2015-06-19 13:54:00 +02:00
|
|
|
|
$hookType,
|
|
|
|
|
$eventHandler,
|
|
|
|
|
'preCallback'
|
|
|
|
|
);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Util::connectHook(
|
|
|
|
|
Filesystem::CLASSNAME,
|
2015-06-19 13:54:00 +02:00
|
|
|
|
'post_' . $hookType,
|
|
|
|
|
$eventHandler,
|
|
|
|
|
'postCallback'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the file lock type
|
|
|
|
|
*
|
2017-03-17 10:59:53 +01:00
|
|
|
|
* @param View $view view
|
2015-06-19 13:54:00 +02:00
|
|
|
|
* @param string $path path
|
|
|
|
|
* @param bool $onMountPoint true to check the mount point instead of the
|
|
|
|
|
* mounted storage
|
|
|
|
|
*
|
|
|
|
|
* @return int lock type or null if file was not locked
|
|
|
|
|
*/
|
2017-03-17 10:59:53 +01:00
|
|
|
|
private function getFileLockType(View $view, $path, $onMountPoint = false) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
if ($this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE, $onMountPoint)) {
|
|
|
|
|
return ILockingProvider::LOCK_EXCLUSIVE;
|
2020-04-10 10:35:09 +02:00
|
|
|
|
} elseif ($this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED, $onMountPoint)) {
|
2015-06-19 13:54:00 +02:00
|
|
|
|
return ILockingProvider::LOCK_SHARED;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2015-10-16 16:51:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function testRemoveMoveableMountPoint(): void {
|
|
|
|
|
$mountPoint = '/' . $this->user . '/files/mount/';
|
|
|
|
|
|
|
|
|
|
// Mock the mount point
|
2020-08-11 21:32:18 +02:00
|
|
|
|
/** @var TestMoveableMountPoint|\PHPUnit\Framework\MockObject\MockObject $mount */
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$mount = $this->createMock(TestMoveableMountPoint::class);
|
2015-10-16 16:51:44 +02:00
|
|
|
|
$mount->expects($this->once())
|
|
|
|
|
->method('getMountPoint')
|
|
|
|
|
->willReturn($mountPoint);
|
|
|
|
|
$mount->expects($this->once())
|
|
|
|
|
->method('removeMount')
|
|
|
|
|
->willReturn('foo');
|
|
|
|
|
$mount->expects($this->any())
|
|
|
|
|
->method('getInternalPath')
|
|
|
|
|
->willReturn('');
|
|
|
|
|
|
|
|
|
|
// Register mount
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Filesystem::getMountManager()->addMount($mount);
|
2015-10-16 16:51:44 +02:00
|
|
|
|
|
|
|
|
|
// Listen for events
|
2017-10-25 00:03:28 +02:00
|
|
|
|
$eventHandler = $this->getMockBuilder(\stdclass::class)
|
2015-10-16 16:51:44 +02:00
|
|
|
|
->setMethods(['umount', 'post_umount'])
|
|
|
|
|
->getMock();
|
|
|
|
|
$eventHandler->expects($this->once())
|
|
|
|
|
->method('umount')
|
2017-03-17 10:59:53 +01:00
|
|
|
|
->with([Filesystem::signal_param_path => '/mount']);
|
2015-10-16 16:51:44 +02:00
|
|
|
|
$eventHandler->expects($this->once())
|
|
|
|
|
->method('post_umount')
|
2017-03-17 10:59:53 +01:00
|
|
|
|
->with([Filesystem::signal_param_path => '/mount']);
|
|
|
|
|
Util::connectHook(
|
|
|
|
|
Filesystem::CLASSNAME,
|
2015-10-16 16:51:44 +02:00
|
|
|
|
'umount',
|
|
|
|
|
$eventHandler,
|
|
|
|
|
'umount'
|
|
|
|
|
);
|
2017-03-17 10:59:53 +01:00
|
|
|
|
Util::connectHook(
|
|
|
|
|
Filesystem::CLASSNAME,
|
2015-10-16 16:51:44 +02:00
|
|
|
|
'post_umount',
|
|
|
|
|
$eventHandler,
|
|
|
|
|
'post_umount'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
//Delete the mountpoint
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/' . $this->user . '/files');
|
2015-10-16 16:51:44 +02:00
|
|
|
|
$this->assertEquals('foo', $view->rmdir('mount'));
|
|
|
|
|
}
|
2015-12-02 16:48:15 +01:00
|
|
|
|
|
|
|
|
|
public function mimeFilterProvider() {
|
|
|
|
|
return [
|
|
|
|
|
[null, ['test1.txt', 'test2.txt', 'test3.md', 'test4.png']],
|
|
|
|
|
['text/plain', ['test1.txt', 'test2.txt']],
|
|
|
|
|
['text/markdown', ['test3.md']],
|
|
|
|
|
['text', ['test1.txt', 'test2.txt', 'test3.md']],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $filter
|
|
|
|
|
* @param string[] $expected
|
|
|
|
|
* @dataProvider mimeFilterProvider
|
|
|
|
|
*/
|
|
|
|
|
public function testGetDirectoryContentMimeFilter($filter, $expected): void {
|
|
|
|
|
$storage1 = new Temporary();
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$root = self::getUniqueID('/');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage1, [], $root . '/');
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View($root);
|
2015-12-02 16:48:15 +01:00
|
|
|
|
|
|
|
|
|
$view->file_put_contents('test1.txt', 'asd');
|
|
|
|
|
$view->file_put_contents('test2.txt', 'asd');
|
|
|
|
|
$view->file_put_contents('test3.md', 'asd');
|
|
|
|
|
$view->file_put_contents('test4.png', '');
|
|
|
|
|
|
|
|
|
|
$content = $view->getDirectoryContent('', $filter);
|
|
|
|
|
|
2016-05-24 15:07:23 +02:00
|
|
|
|
$files = array_map(function (FileInfo $info) {
|
2015-12-02 16:48:15 +01:00
|
|
|
|
return $info->getName();
|
|
|
|
|
}, $content);
|
|
|
|
|
sort($files);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals($expected, $files);
|
|
|
|
|
}
|
2016-04-19 17:01:34 +02:00
|
|
|
|
|
|
|
|
|
public function testFilePutContentsClearsChecksum(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2016-04-19 17:01:34 +02:00
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'bar');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2016-04-19 17:01:34 +02:00
|
|
|
|
$scanner->scan('');
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/test/foo.txt');
|
2016-04-19 17:01:34 +02:00
|
|
|
|
$view->putFileInfo('.', ['checksum' => '42']);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals('bar', $view->file_get_contents(''));
|
|
|
|
|
$fh = tmpfile();
|
|
|
|
|
fwrite($fh, 'fooo');
|
|
|
|
|
rewind($fh);
|
2020-02-18 17:58:16 +01:00
|
|
|
|
clearstatcache();
|
2016-04-19 17:01:34 +02:00
|
|
|
|
$view->file_put_contents('', $fh);
|
|
|
|
|
$this->assertEquals('fooo', $view->file_get_contents(''));
|
|
|
|
|
$data = $view->getFileInfo('.');
|
|
|
|
|
$this->assertEquals('', $data->getChecksum());
|
|
|
|
|
}
|
2016-05-24 15:07:23 +02:00
|
|
|
|
|
|
|
|
|
public function testDeleteGhostFile(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2016-05-24 15:07:23 +02:00
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'bar');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2016-05-24 15:07:23 +02:00
|
|
|
|
$scanner->scan('');
|
|
|
|
|
|
|
|
|
|
$storage->unlink('foo.txt');
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($cache->inCache('foo.txt'));
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/test');
|
2016-05-24 15:07:23 +02:00
|
|
|
|
$rootInfo = $view->getFileInfo('');
|
|
|
|
|
$this->assertEquals(3, $rootInfo->getSize());
|
|
|
|
|
$view->unlink('foo.txt');
|
|
|
|
|
$newInfo = $view->getFileInfo('');
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($cache->inCache('foo.txt'));
|
|
|
|
|
$this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
|
|
|
|
|
$this->assertEquals(0, $newInfo->getSize());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testDeleteGhostFolder(): void {
|
2019-10-29 13:49:41 +01:00
|
|
|
|
$storage = new Temporary([]);
|
2016-05-24 15:07:23 +02:00
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
$storage->mkdir('foo');
|
|
|
|
|
$storage->file_put_contents('foo/foo.txt', 'bar');
|
2019-10-29 13:49:41 +01:00
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
2016-05-24 15:07:23 +02:00
|
|
|
|
$scanner->scan('');
|
|
|
|
|
|
|
|
|
|
$storage->rmdir('foo');
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($cache->inCache('foo'));
|
|
|
|
|
$this->assertTrue($cache->inCache('foo/foo.txt'));
|
|
|
|
|
|
2017-03-17 10:59:53 +01:00
|
|
|
|
$view = new View('/test');
|
2016-05-24 15:07:23 +02:00
|
|
|
|
$rootInfo = $view->getFileInfo('');
|
|
|
|
|
$this->assertEquals(3, $rootInfo->getSize());
|
|
|
|
|
$view->rmdir('foo');
|
|
|
|
|
$newInfo = $view->getFileInfo('');
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($cache->inCache('foo'));
|
|
|
|
|
$this->assertFalse($cache->inCache('foo/foo.txt'));
|
|
|
|
|
$this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
|
|
|
|
|
$this->assertEquals(0, $newInfo->getSize());
|
|
|
|
|
}
|
2016-12-01 18:52:32 +01:00
|
|
|
|
|
|
|
|
|
public function testCreateParentDirectories(): void {
|
|
|
|
|
$view = $this->getMockBuilder(View::class)
|
|
|
|
|
->disableOriginalConstructor()
|
|
|
|
|
->setMethods([
|
|
|
|
|
'is_file',
|
|
|
|
|
'file_exists',
|
|
|
|
|
'mkdir',
|
|
|
|
|
])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
2022-06-20 10:53:06 +02:00
|
|
|
|
$view->expects($this->exactly(3))
|
2016-12-01 18:52:32 +01:00
|
|
|
|
->method('is_file')
|
2022-06-20 10:53:06 +02:00
|
|
|
|
->withConsecutive(
|
|
|
|
|
['/new'],
|
|
|
|
|
['/new/folder'],
|
|
|
|
|
['/new/folder/structure'],
|
|
|
|
|
)
|
2016-12-01 18:52:32 +01:00
|
|
|
|
->willReturn(false);
|
2022-06-20 10:53:06 +02:00
|
|
|
|
$view->expects($this->exactly(3))
|
2016-12-01 18:52:32 +01:00
|
|
|
|
->method('file_exists')
|
2022-06-20 10:53:06 +02:00
|
|
|
|
->withConsecutive(
|
|
|
|
|
['/new'],
|
|
|
|
|
['/new/folder'],
|
|
|
|
|
['/new/folder/structure'],
|
|
|
|
|
)->willReturnOnConsecutiveCalls(
|
|
|
|
|
true,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
);
|
|
|
|
|
$view->expects($this->exactly(2))
|
2016-12-01 18:52:32 +01:00
|
|
|
|
->method('mkdir')
|
2022-06-20 10:53:06 +02:00
|
|
|
|
->withConsecutive(
|
|
|
|
|
['/new/folder'],
|
|
|
|
|
['/new/folder/structure'],
|
|
|
|
|
);
|
2016-12-01 18:52:32 +01:00
|
|
|
|
|
|
|
|
|
$this->assertTrue(self::invokePrivate($view, 'createParentDirectories', ['/new/folder/structure']));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testCreateParentDirectoriesWithExistingFile(): void {
|
|
|
|
|
$view = $this->getMockBuilder(View::class)
|
|
|
|
|
->disableOriginalConstructor()
|
|
|
|
|
->setMethods([
|
|
|
|
|
'is_file',
|
|
|
|
|
'file_exists',
|
|
|
|
|
'mkdir',
|
|
|
|
|
])
|
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
|
|
$view
|
|
|
|
|
->expects($this->once())
|
|
|
|
|
->method('is_file')
|
|
|
|
|
->with('/file.txt')
|
|
|
|
|
->willReturn(true);
|
|
|
|
|
$this->assertFalse(self::invokePrivate($view, 'createParentDirectories', ['/file.txt/folder/structure']));
|
|
|
|
|
}
|
2019-10-29 13:49:41 +01:00
|
|
|
|
|
|
|
|
|
public function testCacheExtension(): void {
|
|
|
|
|
$storage = new Temporary([]);
|
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'bar');
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
|
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
|
|
|
|
$view = new View('/test');
|
|
|
|
|
|
|
|
|
|
$info = $view->getFileInfo('/foo.txt');
|
|
|
|
|
$this->assertEquals(0, $info->getUploadTime());
|
|
|
|
|
$this->assertEquals(0, $info->getCreationTime());
|
|
|
|
|
|
|
|
|
|
$view->putFileInfo('/foo.txt', ['upload_time' => 25]);
|
|
|
|
|
|
|
|
|
|
$info = $view->getFileInfo('/foo.txt');
|
|
|
|
|
$this->assertEquals(25, $info->getUploadTime());
|
|
|
|
|
$this->assertEquals(0, $info->getCreationTime());
|
|
|
|
|
}
|
2022-08-16 17:24:06 +02:00
|
|
|
|
|
|
|
|
|
public function testFopenGone(): void {
|
|
|
|
|
$storage = new Temporary([]);
|
|
|
|
|
$scanner = $storage->getScanner();
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'bar');
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
|
|
|
|
|
Filesystem::mount($storage, [], '/test/');
|
|
|
|
|
$view = new View('/test');
|
|
|
|
|
|
|
|
|
|
$storage->unlink('foo.txt');
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($cache->inCache('foo.txt'));
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($view->fopen('foo.txt', 'r'));
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($cache->inCache('foo.txt'));
|
|
|
|
|
}
|
2024-08-22 12:04:31 +02:00
|
|
|
|
|
|
|
|
|
public function testMountpointParentsCreated(): void {
|
|
|
|
|
$storage1 = $this->getTestStorage();
|
|
|
|
|
Filesystem::mount($storage1, [], '/');
|
|
|
|
|
|
|
|
|
|
$storage2 = $this->getTestStorage();
|
|
|
|
|
Filesystem::mount($storage2, [], '/A/B/C');
|
|
|
|
|
|
|
|
|
|
$rootView = new View('');
|
|
|
|
|
|
|
|
|
|
$folderData = $rootView->getDirectoryContent('/');
|
|
|
|
|
$this->assertCount(4, $folderData);
|
|
|
|
|
$this->assertEquals('folder', $folderData[0]['name']);
|
|
|
|
|
$this->assertEquals('foo.png', $folderData[1]['name']);
|
|
|
|
|
$this->assertEquals('foo.txt', $folderData[2]['name']);
|
|
|
|
|
$this->assertEquals('A', $folderData[3]['name']);
|
|
|
|
|
|
|
|
|
|
$folderData = $rootView->getDirectoryContent('/A');
|
|
|
|
|
$this->assertCount(1, $folderData);
|
|
|
|
|
$this->assertEquals('B', $folderData[0]['name']);
|
|
|
|
|
|
|
|
|
|
$folderData = $rootView->getDirectoryContent('/A/B');
|
|
|
|
|
$this->assertCount(1, $folderData);
|
|
|
|
|
$this->assertEquals('C', $folderData[0]['name']);
|
|
|
|
|
|
|
|
|
|
$folderData = $rootView->getDirectoryContent('/A/B/C');
|
|
|
|
|
$this->assertCount(3, $folderData);
|
|
|
|
|
$this->assertEquals('folder', $folderData[0]['name']);
|
|
|
|
|
$this->assertEquals('foo.png', $folderData[1]['name']);
|
|
|
|
|
$this->assertEquals('foo.txt', $folderData[2]['name']);
|
|
|
|
|
}
|
2024-12-03 18:29:32 +01:00
|
|
|
|
|
|
|
|
|
public function testCopyPreservesContent() {
|
|
|
|
|
$viewUser1 = new View('/' . 'userId' . '/files');
|
|
|
|
|
$viewUser1->mkdir('');
|
|
|
|
|
$viewUser1->file_put_contents('foo.txt', 'foo');
|
|
|
|
|
$viewUser1->copy('foo.txt', 'bar.txt');
|
|
|
|
|
$this->assertEquals('foo', $viewUser1->file_get_contents('bar.txt'));
|
|
|
|
|
}
|
2012-10-21 02:12:58 +02:00
|
|
|
|
}
|