123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- <?php
- /**
- * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
- * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
- namespace Test\Files;
- use OC\Files\Mount\MountPoint;
- use OC\Files\Storage\Temporary;
- use OC\User\NoUserException;
- use OCP\Files\Config\IMountProvider;
- use OCP\Files\Storage\IStorageFactory;
- use OCP\IUser;
- class DummyMountProvider implements IMountProvider {
- private $mounts = [];
- /**
- * @param array $mounts
- */
- public function __construct(array $mounts) {
- $this->mounts = $mounts;
- }
- /**
- * Get the pre-registered mount points
- *
- * @param IUser $user
- * @param IStorageFactory $loader
- * @return \OCP\Files\Mount\IMountPoint[]
- */
- public function getMountsForUser(IUser $user, IStorageFactory $loader) {
- return isset($this->mounts[$user->getUID()]) ? $this->mounts[$user->getUID()] : [];
- }
- }
- /**
- * Class FilesystemTest
- *
- * @group DB
- *
- * @package Test\Files
- */
- class FilesystemTest extends \Test\TestCase {
- public const TEST_FILESYSTEM_USER1 = 'test-filesystem-user1';
- public const TEST_FILESYSTEM_USER2 = 'test-filesystem-user1';
- /**
- * @var array tmpDirs
- */
- private $tmpDirs = [];
- /**
- * @return array
- */
- private function getStorageData() {
- $dir = \OC::$server->getTempManager()->getTemporaryFolder();
- $this->tmpDirs[] = $dir;
- return ['datadir' => $dir];
- }
- protected function setUp(): void {
- parent::setUp();
- $userBackend = new \Test\Util\User\Dummy();
- $userBackend->createUser(self::TEST_FILESYSTEM_USER1, self::TEST_FILESYSTEM_USER1);
- $userBackend->createUser(self::TEST_FILESYSTEM_USER2, self::TEST_FILESYSTEM_USER2);
- \OC::$server->getUserManager()->registerBackend($userBackend);
- $this->loginAsUser();
- }
- protected function tearDown(): void {
- foreach ($this->tmpDirs as $dir) {
- \OC_Helper::rmdirr($dir);
- }
- $this->logout();
- $this->invokePrivate('\OC\Files\Filesystem', 'normalizedPathCache', [null]);
- parent::tearDown();
- }
- public function testMount() {
- \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', self::getStorageData(), '/');
- $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/'));
- $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/some/folder'));
- [, $internalPath] = \OC\Files\Filesystem::resolvePath('/');
- $this->assertEquals('', $internalPath);
- [, $internalPath] = \OC\Files\Filesystem::resolvePath('/some/folder');
- $this->assertEquals('some/folder', $internalPath);
- \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', self::getStorageData(), '/some');
- $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/'));
- $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/folder'));
- $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/'));
- $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some'));
- [, $internalPath] = \OC\Files\Filesystem::resolvePath('/some/folder');
- $this->assertEquals('folder', $internalPath);
- }
- public function normalizePathData() {
- return [
- ['/', ''],
- ['/', '/'],
- ['/', '//'],
- ['/', '/', false],
- ['/', '//', false],
- ['/path', '/path/'],
- ['/path/', '/path/', false],
- ['/path', 'path'],
- ['/foo/bar', '/foo//bar/'],
- ['/foo/bar/', '/foo//bar/', false],
- ['/foo/bar', '/foo////bar'],
- ['/foo/bar', '/foo/////bar'],
- ['/foo/bar', '/foo/bar/.'],
- ['/foo/bar', '/foo/bar/./'],
- ['/foo/bar/', '/foo/bar/./', false],
- ['/foo/bar', '/foo/bar/./.'],
- ['/foo/bar', '/foo/bar/././'],
- ['/foo/bar/', '/foo/bar/././', false],
- ['/foo/bar', '/foo/./bar/'],
- ['/foo/bar/', '/foo/./bar/', false],
- ['/foo/.bar', '/foo/.bar/'],
- ['/foo/.bar/', '/foo/.bar/', false],
- ['/foo/.bar/tee', '/foo/.bar/tee'],
- ['/foo/bar.', '/foo/bar./'],
- ['/foo/bar./', '/foo/bar./', false],
- ['/foo/bar./tee', '/foo/bar./tee'],
- ['/foo/.bar.', '/foo/.bar./'],
- ['/foo/.bar./', '/foo/.bar./', false],
- ['/foo/.bar./tee', '/foo/.bar./tee'],
- ['/foo/bar', '/.////././//./foo/.///././//./bar/././/./.'],
- ['/foo/bar/', '/.////././//./foo/.///././//./bar/./././.', false],
- ['/foo/bar', '/.////././//./foo/.///././//./bar/././/././'],
- ['/foo/bar/', '/.////././//./foo/.///././//./bar/././/././', false],
- ['/foo/.bar', '/.////././//./foo/./././/./.bar/././/././'],
- ['/foo/.bar/', '/.////././//./foo/./././/./.bar/././/././', false],
- ['/foo/.bar/tee./', '/.////././//./foo/./././/./.bar/tee././/././', false],
- ['/foo/bar.', '/.////././//./foo/./././/./bar./././/././'],
- ['/foo/bar./', '/.////././//./foo/./././/./bar./././/././', false],
- ['/foo/bar./tee./', '/.////././//./foo/./././/./bar./tee././/././', false],
- ['/foo/.bar.', '/.////././//./foo/./././/./.bar./././/././'],
- ['/foo/.bar./', '/.////././//./foo/./././/./.bar./././././', false],
- ['/foo/.bar./tee./', '/.////././//./foo/./././/./.bar./tee././././', false],
- // Windows paths
- ['/', ''],
- ['/', '\\'],
- ['/', '\\', false],
- ['/', '\\\\'],
- ['/', '\\\\', false],
- ['/path', '\\path'],
- ['/path', '\\path', false],
- ['/path', '\\path\\'],
- ['/path/', '\\path\\', false],
- ['/foo/bar', '\\foo\\\\bar\\'],
- ['/foo/bar/', '\\foo\\\\bar\\', false],
- ['/foo/bar', '\\foo\\\\\\\\bar'],
- ['/foo/bar', '\\foo\\\\\\\\\\bar'],
- ['/foo/bar', '\\foo\\bar\\.'],
- ['/foo/bar', '\\foo\\bar\\.\\'],
- ['/foo/bar/', '\\foo\\bar\\.\\', false],
- ['/foo/bar', '\\foo\\bar\\.\\.'],
- ['/foo/bar', '\\foo\\bar\\.\\.\\'],
- ['/foo/bar/', '\\foo\\bar\\.\\.\\', false],
- ['/foo/bar', '\\foo\\.\\bar\\'],
- ['/foo/bar/', '\\foo\\.\\bar\\', false],
- ['/foo/.bar', '\\foo\\.bar\\'],
- ['/foo/.bar/', '\\foo\\.bar\\', false],
- ['/foo/.bar/tee', '\\foo\\.bar\\tee'],
- // Absolute windows paths NOT marked as absolute
- ['/C:', 'C:\\'],
- ['/C:/', 'C:\\', false],
- ['/C:/tests', 'C:\\tests'],
- ['/C:/tests', 'C:\\tests', false],
- ['/C:/tests', 'C:\\tests\\'],
- ['/C:/tests/', 'C:\\tests\\', false],
- ['/C:/tests/bar', 'C:\\tests\\.\\.\\bar'],
- ['/C:/tests/bar/', 'C:\\tests\\.\\.\\bar\\.\\', false],
- // normalize does not resolve '..' (by design)
- ['/foo/..', '/foo/../'],
- ['/foo/../bar', '/foo/../bar/.'],
- ['/foo/..', '\\foo\\..\\'],
- ['/foo/../bar', '\\foo\\..\\bar'],
- ];
- }
- /**
- * @dataProvider normalizePathData
- */
- public function testNormalizePath($expected, $path, $stripTrailingSlash = true) {
- $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash));
- }
- public function normalizePathKeepUnicodeData() {
- $nfdName = 'ümlaut';
- $nfcName = 'ümlaut';
- return [
- ['/' . $nfcName, $nfcName, true],
- ['/' . $nfcName, $nfcName, false],
- ['/' . $nfdName, $nfdName, true],
- ['/' . $nfcName, $nfdName, false],
- ];
- }
- /**
- * @dataProvider normalizePathKeepUnicodeData
- */
- public function testNormalizePathKeepUnicode($expected, $path, $keepUnicode = false) {
- $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, true, false, $keepUnicode));
- }
- public function testNormalizePathKeepUnicodeCache() {
- $nfdName = 'ümlaut';
- $nfcName = 'ümlaut';
- // call in succession due to cache
- $this->assertEquals('/' . $nfcName, \OC\Files\Filesystem::normalizePath($nfdName, true, false, false));
- $this->assertEquals('/' . $nfdName, \OC\Files\Filesystem::normalizePath($nfdName, true, false, true));
- }
- public function isValidPathData() {
- return [
- ['/', true],
- ['/path', true],
- ['/foo/bar', true],
- ['/foo//bar/', true],
- ['/foo////bar', true],
- ['/foo//\///bar', true],
- ['/foo/bar/.', true],
- ['/foo/bar/./', true],
- ['/foo/bar/./.', true],
- ['/foo/bar/././', true],
- ['/foo/bar/././..bar', true],
- ['/foo/bar/././..bar/a', true],
- ['/foo/bar/././..', false],
- ['/foo/bar/././../', false],
- ['/foo/bar/.././', false],
- ['/foo/bar/../../', false],
- ['/foo/bar/../..\\', false],
- ['..', false],
- ['../', false],
- ['../foo/bar', false],
- ['..\foo/bar', false],
- ];
- }
- /**
- * @dataProvider isValidPathData
- */
- public function testIsValidPath($path, $expected) {
- $this->assertSame($expected, \OC\Files\Filesystem::isValidPath($path));
- }
- public function isFileBlacklistedData() {
- return [
- ['/etc/foo/bar/foo.txt', false],
- ['\etc\foo/bar\foo.txt', false],
- ['.htaccess', true],
- ['.htaccess/', true],
- ['.htaccess\\', true],
- ['/etc/foo\bar/.htaccess\\', true],
- ['/etc/foo\bar/.htaccess/', true],
- ['/etc/foo\bar/.htaccess/foo', false],
- ['//foo//bar/\.htaccess/', true],
- ['\foo\bar\.HTAccess', true],
- ];
- }
- /**
- * @dataProvider isFileBlacklistedData
- */
- public function testIsFileBlacklisted($path, $expected) {
- $this->assertSame($expected, \OC\Files\Filesystem::isFileBlacklisted($path));
- }
- public function testNormalizePathUTF8() {
- if (!class_exists('Patchwork\PHP\Shim\Normalizer')) {
- $this->markTestSkipped('UTF8 normalizer Patchwork was not found');
- }
- $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("/foo/baru\xCC\x88"));
- $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("\\foo\\baru\xCC\x88"));
- }
- public function testHooks() {
- if (\OC\Files\Filesystem::getView()) {
- $user = \OC_User::getUser();
- } else {
- $user = self::TEST_FILESYSTEM_USER1;
- $backend = new \Test\Util\User\Dummy();
- \OC_User::useBackend($backend);
- $backend->createUser($user, $user);
- $userObj = \OC::$server->getUserManager()->get($user);
- \OC::$server->getUserSession()->setUser($userObj);
- \OC\Files\Filesystem::init($user, '/' . $user . '/files');
- }
- \OC_Hook::clear('OC_Filesystem');
- \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
- \OC\Files\Filesystem::mount('OC\Files\Storage\Temporary', [], '/');
- $rootView = new \OC\Files\View('');
- $rootView->mkdir('/' . $user);
- $rootView->mkdir('/' . $user . '/files');
- // \OC\Files\Filesystem::file_put_contents('/foo', 'foo');
- \OC\Files\Filesystem::mkdir('/bar');
- // \OC\Files\Filesystem::file_put_contents('/bar//foo', 'foo');
- $tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
- file_put_contents($tmpFile, 'foo');
- $fh = fopen($tmpFile, 'r');
- // \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh);
- }
- /**
- * Tests that an exception is thrown when passed user does not exist.
- *
- */
- public function testLocalMountWhenUserDoesNotExist() {
- $this->expectException(\OC\User\NoUserException::class);
- $userId = $this->getUniqueID('user_');
- \OC\Files\Filesystem::initMountPoints($userId);
- }
- public function testNullUserThrows() {
- $this->expectException(\OC\User\NoUserException::class);
- \OC\Files\Filesystem::initMountPoints(null);
- }
- public function testNullUserThrowsTwice() {
- $thrown = 0;
- try {
- \OC\Files\Filesystem::initMountPoints(null);
- } catch (NoUserException $e) {
- $thrown++;
- }
- try {
- \OC\Files\Filesystem::initMountPoints(null);
- } catch (NoUserException $e) {
- $thrown++;
- }
- $this->assertEquals(2, $thrown);
- }
- /**
- * Tests that an exception is thrown when passed user does not exist.
- */
- public function testLocalMountWhenUserDoesNotExistTwice() {
- $thrown = 0;
- $userId = $this->getUniqueID('user_');
- try {
- \OC\Files\Filesystem::initMountPoints($userId);
- } catch (NoUserException $e) {
- $thrown++;
- }
- try {
- \OC\Files\Filesystem::initMountPoints($userId);
- } catch (NoUserException $e) {
- $thrown++;
- }
- $this->assertEquals(2, $thrown);
- }
- /**
- * Tests that the home storage is used for the user's mount point
- */
- public function testHomeMount() {
- $userId = $this->getUniqueID('user_');
- \OC::$server->getUserManager()->createUser($userId, $userId);
- \OC\Files\Filesystem::initMountPoints($userId);
- $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
- $this->assertTrue($homeMount->instanceOfStorage('\OCP\Files\IHomeStorage'));
- if ($homeMount->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')) {
- $this->assertEquals('object::user:' . $userId, $homeMount->getId());
- } elseif ($homeMount->instanceOfStorage('\OC\Files\Storage\Home')) {
- $this->assertEquals('home::' . $userId, $homeMount->getId());
- }
- $user = \OC::$server->getUserManager()->get($userId);
- if ($user !== null) {
- $user->delete();
- }
- }
- public function dummyHook($arguments) {
- $path = $arguments['path'];
- $this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized
- }
- /**
- * Test that the default cache dir is part of the user's home
- */
- public function testMountDefaultCacheDir() {
- $userId = $this->getUniqueID('user_');
- $config = \OC::$server->getConfig();
- $oldCachePath = $config->getSystemValueString('cache_path', '');
- // no cache path configured
- $config->setSystemValue('cache_path', '');
- \OC::$server->getUserManager()->createUser($userId, $userId);
- \OC\Files\Filesystem::initMountPoints($userId);
- $this->assertEquals(
- '/' . $userId . '/',
- \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache')
- );
- [$storage, $internalPath] = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache');
- $this->assertTrue($storage->instanceOfStorage('\OCP\Files\IHomeStorage'));
- $this->assertEquals('cache', $internalPath);
- $user = \OC::$server->getUserManager()->get($userId);
- if ($user !== null) {
- $user->delete();
- }
- $config->setSystemValue('cache_path', $oldCachePath);
- }
- /**
- * Test that an external cache is mounted into
- * the user's home
- */
- public function testMountExternalCacheDir() {
- $userId = $this->getUniqueID('user_');
- $config = \OC::$server->getConfig();
- $oldCachePath = $config->getSystemValueString('cache_path', '');
- // set cache path to temp dir
- $cachePath = \OC::$server->getTempManager()->getTemporaryFolder() . '/extcache';
- $config->setSystemValue('cache_path', $cachePath);
- \OC::$server->getUserManager()->createUser($userId, $userId);
- \OC\Files\Filesystem::initMountPoints($userId);
- $this->assertEquals(
- '/' . $userId . '/cache/',
- \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache')
- );
- [$storage, $internalPath] = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache');
- $this->assertTrue($storage->instanceOfStorage('\OC\Files\Storage\Local'));
- $this->assertEquals('', $internalPath);
- $user = \OC::$server->getUserManager()->get($userId);
- if ($user !== null) {
- $user->delete();
- }
- $config->setSystemValue('cache_path', $oldCachePath);
- }
- public function testRegisterMountProviderAfterSetup() {
- \OC\Files\Filesystem::initMountPoints(self::TEST_FILESYSTEM_USER2);
- $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/foo/bar'));
- $mount = new MountPoint(new Temporary([]), '/foo/bar');
- $mountProvider = new DummyMountProvider([self::TEST_FILESYSTEM_USER2 => [$mount]]);
- \OC::$server->getMountProviderCollection()->registerProvider($mountProvider);
- $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::getMountPoint('/foo/bar'));
- }
- }
|