<commit_before><?php
/**
 * @copyright Copyright (c) 2016, ownCloud, Inc.
 *
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author J0WI <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author scambra <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 *
 * @license AGPL-3.0
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program. If not, see <http://www.gnu.org/licenses/>
 *
 */
namespace OCA\Files_Sharing;

use OC\Files\Cache\FailedCache;
use OC\Files\Cache\NullWatcher;
use OC\Files\Cache\Watcher;
use OC\Files\Storage\Common;
use OCP\Files\Folder;
use OCP\Files\Node;
use OC\Files\Storage\FailedStorage;
use OC\Files\Storage\Wrapper\PermissionsMask;
use OC\User\NoUserException;
use OCA\Files_External\Config\ExternalMountPoint;
use OCP\Constants;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IDisableEncryptionStorage;
use OCP\Files\Storage\IStorage;
use OCP\IUserManager;
use OCP\Lock\ILockingProvider;
use OCP\Share\IShare;

/**
 * Convert target path to source path and pass the function call to the correct storage provider
 */
class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage, IDisableEncryptionStorage {

	/** @var \OCP\Share\IShare */
	private $superShare;

	/** @var \OCP\Share\IShare[] */
	private $groupedShares;

	/**
	 * @var \OC\Files\View
	 */
	private $ownerView;

	private $initialized = false;

	/**
	 * @var ICacheEntry
	 */
	private $sourceRootInfo;

	/** @var string */
	private $user;

	/**
	 * @var \OCP\ILogger
	 */
	private $logger;

	/** @var  IStorage */
	private $nonMaskedStorage;

	private $options;

	/** @var boolean */
	private $sharingDisabledForUser;

	/** @var ?Folder $ownerUserFolder */
	private $ownerUserFolder = null;

	private string $sourcePath = '';

	public function __construct($arguments) {
		$this->ownerView = $arguments['ownerView'];
		$this->logger = \OC::$server->getLogger();

		$this->superShare = $arguments['superShare'];
		$this->groupedShares = $arguments['groupedShares'];

		$this->user = $arguments['user'];
		if (isset($arguments['sharingDisabledForUser'])) {
			$this->sharingDisabledForUser = $arguments['sharingDisabledForUser'];
		} else {
			$this->sharingDisabledForUser = false;
		}

		parent::__construct([
			'storage' => null,
			'root' => null,
		]);
	}

	/**
	 * @return ICacheEntry
	 */
	private function getSourceRootInfo() {
		if (is_null($this->sourceRootInfo)) {
			if (is_null($this->superShare->getNodeCacheEntry())) {
				$this->init();
				$this->sourceRootInfo = $this->nonMaskedStorage->getCache()->get($this->rootPath);
			} else {
				$this->sourceRootInfo = $this->superShare->getNodeCacheEntry();
			}
		}
		return $this->sourceRootInfo;
	}

	private function init() {
		if ($this->initialized) {
			return;
		}
		$this->initialized = true;
		try {
			/** @var IRootFolder $rootFolder */
			$rootFolder = \OC::$server->get(IRootFolder::class);
			$this->ownerUserFolder = $rootFolder->getUserFolder($this->superShare->getShareOwner());
			$sourceId = $this->superShare->getNodeId();
			$ownerNodes = $this->ownerUserFolder->getById($sourceId);
			/** @var Node|false $ownerNode */
			$ownerNode = current($ownerNodes);
			if (!$ownerNode) {
				$this->storage = new FailedStorage(['exception' => new NotFoundException("File by id $sourceId not found")]);
				$this->cache = new FailedCache();
				$this->rootPath = '';
			} else {
				$this->nonMaskedStorage = $ownerNode->getStorage();
				$this->sourcePath = $ownerNode->getPath();
				$this->rootPath = $ownerNode->getInternalPath();
				$this->storage = new PermissionsMask([
					'storage' => $this->nonMaskedStorage,
					'mask' => $this->superShare->getPermissions(),
				]);
			}
		} catch (NotFoundException $e) {
			// original file not accessible or deleted, set FailedStorage
			$this->storage = new FailedStorage(['exception' => $e]);
			$this->cache = new FailedCache();
			$this->rootPath = '';
		} catch (NoUserException $e) {
			// sharer user deleted, set FailedStorage
			$this->storage = new FailedStorage(['exception' => $e]);
			$this->cache = new FailedCache();
			$this->rootPath = '';
		} catch (\Exception $e) {
			$this->storage = new FailedStorage(['exception' => $e]);
			$this->cache = new FailedCache();
			$this->rootPath = '';
			$this->logger->logException($e);
		}

		if (!$this->nonMaskedStorage) {
			$this->nonMaskedStorage = $this->storage;
		}
	}

	/**
	 * @inheritdoc
	 */
	public function instanceOfStorage($class): bool {
		if ($class === '\OC\Files\Storage\Common' || $class == Common::class) {
			return true;
		}
		if (in_array($class, ['\OC\Files\Storage\Home', '\OC\Files\ObjectStore\HomeObjectStoreStorage', '\OCP\Files\IHomeStorage'])) {
			return false;
		}
		return parent::instanceOfStorage($class);
	}

	/**
	 * @return string
	 */
	public function getShareId() {
		return $this->superShare->getId();
	}

	private function isValid(): bool {
		return $this->getSourceRootInfo() && ($this->getSourceRootInfo()->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
	}

	/**
	 * get id of the mount point
	 *<commit_msg>also apply the fix for the other storage types<commit_after><?php
/**
 * @copyright Copyright (c) 2016, ownCloud, Inc.
 *
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author J0WI <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author scambra <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 *
 * @license AGPL-3.0
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program. If not, see <http://www.gnu.org/licenses/>
 *
 */
namespace OCA\Files_Sharing;

use OC\Files\Cache\FailedCache;
use OC\Files\Cache\NullWatcher;
use OC\Files\Cache\Watcher;
use OC\Files\ObjectStore\HomeObjectStoreStorage;
use OC\Files\Storage\Common;
use OC\Files\Storage\Home;
use OCP\Files\Folder;
use OCP\Files\IHomeStorage;
use OCP\Files\Node;
use OC\Files\Storage\FailedStorage;
use OC\Files\Storage\Wrapper\PermissionsMask;
use OC\User\NoUserException;
use OCA\Files_External\Config\ExternalMountPoint;
use OCP\Constants;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IDisableEncryptionStorage;
use OCP\Files\Storage\IStorage;
use OCP\IUserManager;
use OCP\Lock\ILockingProvider;
use OCP\Share\IShare;

/**
 * Convert target path to source path and pass the function call to the correct storage provider
 */
class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage, IDisableEncryptionStorage {

	/** @var \OCP\Share\IShare */
	private $superShare;

	/** @var \OCP\Share\IShare[] */
	private $groupedShares;

	/**
	 * @var \OC\Files\View
	 */
	private $ownerView;

	private $initialized = false;

	/**
	 * @var ICacheEntry
	 */
	private $sourceRootInfo;

	/** @var string */
	private $user;

	/**
	 * @var \OCP\ILogger
	 */
	private $logger;

	/** @var  IStorage */
	private $nonMaskedStorage;

	private $options;

	/** @var boolean */
	private $sharingDisabledForUser;

	/** @var ?Folder $ownerUserFolder */
	private $ownerUserFolder = null;

	private string $sourcePath = '';

	public function __construct($arguments) {
		$this->ownerView = $arguments['ownerView'];
		$this->logger = \OC::$server->getLogger();

		$this->superShare = $arguments['superShare'];
		$this->groupedShares = $arguments['groupedShares'];

		$this->user = $arguments['user'];
		if (isset($arguments['sharingDisabledForUser'])) {
			$this->sharingDisabledForUser = $arguments['sharingDisabledForUser'];
		} else {
			$this->sharingDisabledForUser = false;
		}

		parent::__construct([
			'storage' => null,
			'root' => null,
		]);
	}

	/**
	 * @return ICacheEntry
	 */
	private function getSourceRootInfo() {
		if (is_null($this->sourceRootInfo)) {
			if (is_null($this->superShare->getNodeCacheEntry())) {
				$this->init();
				$this->sourceRootInfo = $this->nonMaskedStorage->getCache()->get($this->rootPath);
			} else {
				$this->sourceRootInfo = $this->superShare->getNodeCacheEntry();
			}
		}
		return $this->sourceRootInfo;
	}

	private function init() {
		if ($this->initialized) {
			return;
		}
		$this->initialized = true;
		try {
			/** @var IRootFolder $rootFolder */
			$rootFolder = \OC::$server->get(IRootFolder::class);
			$this->ownerUserFolder = $rootFolder->getUserFolder($this->superShare->getShareOwner());
			$sourceId = $this->superShare->getNodeId();
			$ownerNodes = $this->ownerUserFolder->getById($sourceId);
			/** @var Node|false $ownerNode */
			$ownerNode = current($ownerNodes);
			if (!$ownerNode) {
				$this->storage = new FailedStorage(['exception' => new NotFoundException("File by id $sourceId not found")]);
				$this->cache = new FailedCache();
				$this->rootPath = '';
			} else {
				$this->nonMaskedStorage = $ownerNode->getStorage();
				$this->sourcePath = $ownerNode->getPath();
				$this->rootPath = $ownerNode->getInternalPath();
				$this->storage = new PermissionsMask([
					'storage' => $this->nonMaskedStorage,
					'mask' => $this->superShare->getPermissions(),
				]);
			}
		} catch (NotFoundException $e) {
			// original file not accessible or deleted, set FailedStorage
			$this->storage = new FailedStorage(['exception' => $e]);
			$this->cache = new FailedCache();
			$this->rootPath = '';
		} catch (NoUserException $e) {
			// sharer user deleted, set FailedStorage
			$this->storage = new FailedStorage(['exception' => $e]);
			$this->cache = new FailedCache();
			$this->rootPath = '';
		} catch (\Exception $e) {
			$this->storage = new FailedStorage(['exception' => $e]);
			$this->cache = new FailedCache();
			$this->rootPath = '';
			$this->logger->logException($e);
		}

		if (!$this->nonMaskedStorage) {
			$this->nonMaskedStorage = $this->storage;
		}
	}

	/**
	 * @inheritdoc
	 */
	public function instanceOfStorage($class): bool {
		if ($class === '\OC\Files\Storage\Common' || $class == Common::class) {
			return true;
		}
		if (in_array($class, [
			'\OC\Files\Storage\Home',
			'\OC\Files\ObjectStore\HomeObjectStoreStorage',
			'\OCP\Files\IHomeStorage',
			Home::class,
			HomeObjectStoreStorage::class,
			IHomeStorage::class
		])) {
			return false;
		}
		return parent::instanceOfStorage($class);
	}

	/**
	 * @return string
	 */
	public function getShareId() {
		return $this->superShare->getId();
	}

	private function isValid(): bool {
		return $this->getSourceRootInfo() && ($this->getSourceRootInfo()->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
	}

	/**
	 * get id of the mount point
	 *
{'fraction_non_alphanumeric': 0.16324123989218328, 'fraction_numerical': 0.0015161725067385444, 'mean_word_length': 4.091337907375643, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 217, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7045589', 'n_tokens_mistral': 4172, 'n_tokens_neox': 3788, 'n_words': 893}