summaryrefslogtreecommitdiffstats
path: root/apps/files_sharing/lib/SharedStorage.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_sharing/lib/SharedStorage.php')
-rw-r--r--apps/files_sharing/lib/SharedStorage.php445
1 files changed, 445 insertions, 0 deletions
diff --git a/apps/files_sharing/lib/SharedStorage.php b/apps/files_sharing/lib/SharedStorage.php
new file mode 100644
index 00000000000..78a63ac5bbc
--- /dev/null
+++ b/apps/files_sharing/lib/SharedStorage.php
@@ -0,0 +1,445 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ *
+ * @author Bart Visscher <bartv@thisnet.nl>
+ * @author Björn Schießle <bjoern@schiessle.org>
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author Michael Gapczynski <GapczynskiM@gmail.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <robin@icewind.nl>
+ * @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author scambra <sergio@entrecables.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @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\Filesystem;
+use OC\Files\Cache\FailedCache;
+use OCP\Constants;
+use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\NotFoundException;
+use OCP\Files\Storage\IStorage;
+use OCP\Lock\ILockingProvider;
+
+/**
+ * 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 {
+
+ /** @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;
+
+ 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'];
+
+ parent::__construct([
+ 'storage' => null,
+ 'root' => null,
+ ]);
+ }
+
+ private function init() {
+ if ($this->initialized) {
+ return;
+ }
+ $this->initialized = true;
+ try {
+ Filesystem::initMountPoints($this->superShare->getShareOwner());
+ $sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
+ list($this->storage, $this->rootPath) = $this->ownerView->resolvePath($sourcePath);
+ $this->sourceRootInfo = $this->storage->getCache()->get($this->rootPath);
+ } catch (NotFoundException $e) {
+ $this->storage = new FailedStorage(['exception' => $e]);
+ $this->rootPath = '';
+ } catch (\Exception $e) {
+ $this->storage = new FailedStorage(['exception' => $e]);
+ $this->rootPath = '';
+ $this->logger->logException($e);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function instanceOfStorage($class) {
+ if (in_array($class, ['\OC\Files\Storage\Home', '\OC\Files\ObjectStore\HomeObjectStoreStorage'])) {
+ return false;
+ }
+ return parent::instanceOfStorage($class);
+ }
+
+ /**
+ * @return string
+ */
+ public function getShareId() {
+ return $this->superShare->getId();
+ }
+
+ private function isValid() {
+ $this->init();
+ return $this->sourceRootInfo && ($this->sourceRootInfo->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
+ }
+
+ /**
+ * get id of the mount point
+ *
+ * @return string
+ */
+ public function getId() {
+ return 'shared::' . $this->getMountPoint();
+ }
+
+ /**
+ * Get the permissions granted for a shared file
+ *
+ * @param string $target Shared target file path
+ * @return int CRUDS permissions granted
+ */
+ public function getPermissions($target = '') {
+ if (!$this->isValid()) {
+ return 0;
+ }
+ $permissions = $this->superShare->getPermissions();
+ // part files and the mount point always have delete permissions
+ if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
+ $permissions |= \OCP\Constants::PERMISSION_DELETE;
+ }
+
+ if (\OCP\Util::isSharingDisabledForUser()) {
+ $permissions &= ~\OCP\Constants::PERMISSION_SHARE;
+ }
+
+ return $permissions;
+ }
+
+ public function isCreatable($path) {
+ return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_CREATE);
+ }
+
+ public function isReadable($path) {
+ if (!$this->isValid()) {
+ return false;
+ }
+ if (!$this->file_exists($path)) {
+ return false;
+ }
+ list($storage, $internalPath) = $this->resolvePath($path);
+ return $storage->isReadable($internalPath);
+ }
+
+ public function isUpdatable($path) {
+ return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_UPDATE);
+ }
+
+ public function isDeletable($path) {
+ return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_DELETE);
+ }
+
+ public function isSharable($path) {
+ if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
+ return false;
+ }
+ return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
+ }
+
+ public function fopen($path, $mode) {
+ if ($source = $this->getSourcePath($path)) {
+ switch ($mode) {
+ case 'r+':
+ case 'rb+':
+ case 'w+':
+ case 'wb+':
+ case 'x+':
+ case 'xb+':
+ case 'a+':
+ case 'ab+':
+ case 'w':
+ case 'wb':
+ case 'x':
+ case 'xb':
+ case 'a':
+ case 'ab':
+ $creatable = $this->isCreatable($path);
+ $updatable = $this->isUpdatable($path);
+ // if neither permissions given, no need to continue
+ if (!$creatable && !$updatable) {
+ return false;
+ }
+
+ $exists = $this->file_exists($path);
+ // if a file exists, updatable permissions are required
+ if ($exists && !$updatable) {
+ return false;
+ }
+
+ // part file is allowed if !$creatable but the final file is $updatable
+ if (pathinfo($path, PATHINFO_EXTENSION) !== 'part') {
+ if (!$exists && !$creatable) {
+ return false;
+ }
+ }
+ }
+ $info = array(
+ 'target' => $this->getMountPoint() . $path,
+ 'source' => $source,
+ 'mode' => $mode,
+ );
+ \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info);
+ return parent::fopen($path, $mode);
+ }
+ return false;
+ }
+
+ /**
+ * see http://php.net/manual/en/function.rename.php
+ *
+ * @param string $path1
+ * @param string $path2
+ * @return bool
+ */
+ public function rename($path1, $path2) {
+ $isPartFile = pathinfo($path1, PATHINFO_EXTENSION) === 'part';
+ $targetExists = $this->file_exists($path2);
+ $sameFodler = dirname($path1) === dirname($path2);
+
+ if ($targetExists || ($sameFodler && !$isPartFile)) {
+ if (!$this->isUpdatable('')) {
+ return false;
+ }
+ } else {
+ if (!$this->isCreatable('')) {
+ return false;
+ }
+ }
+
+ return parent::rename($path1, $path2);
+ }
+
+ /**
+ * return mount point of share, relative to data/user/files
+ *
+ * @return string
+ */
+ public function getMountPoint() {
+ return $this->superShare->getTarget();
+ }
+
+ /**
+ * @param string $path
+ */
+ public function setMountPoint($path) {
+ $this->superShare->setTarget($path);
+
+ foreach ($this->groupedShares as $share) {
+ $share->setTarget($path);
+ }
+ }
+
+ /**
+ * get the user who shared the file
+ *
+ * @return string
+ */
+ public function getSharedFrom() {
+ return $this->superShare->getShareOwner();
+ }
+
+ /**
+ * @return \OCP\Share\IShare
+ */
+ public function getShare() {
+ return $this->superShare;
+ }
+
+ /**
+ * return share type, can be "file" or "folder"
+ *
+ * @return string
+ */
+ public function getItemType() {
+ return $this->superShare->getNodeType();
+ }
+
+ public function getCache($path = '', $storage = null) {
+ $this->init();
+ if (is_null($this->storage) || $this->storage instanceof FailedStorage) {
+ return new FailedCache(false);
+ }
+ if (!$storage) {
+ $storage = $this;
+ }
+ return new \OCA\Files_Sharing\Cache($storage, $this->storage, $this->sourceRootInfo);
+ }
+
+ public function getScanner($path = '', $storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ return new \OCA\Files_Sharing\Scanner($storage);
+ }
+
+ public function getPropagator($storage = null) {
+ if (isset($this->propagator)) {
+ return $this->propagator;
+ }
+
+ if (!$storage) {
+ $storage = $this;
+ }
+ $this->propagator = new \OCA\Files_Sharing\SharedPropagator($storage, \OC::$server->getDatabaseConnection());
+ return $this->propagator;
+ }
+
+ public function getOwner($path) {
+ return $this->superShare->getShareOwner();
+ }
+
+ /**
+ * unshare complete storage, also the grouped shares
+ *
+ * @return bool
+ */
+ public function unshareStorage() {
+ foreach ($this->groupedShares as $share) {
+ \OC::$server->getShareManager()->deleteFromSelf($share, $this->user);
+ }
+ return true;
+ }
+
+ /**
+ * @param string $path
+ * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
+ * @param \OCP\Lock\ILockingProvider $provider
+ * @throws \OCP\Lock\LockedException
+ */
+ public function acquireLock($path, $type, ILockingProvider $provider) {
+ /** @var \OCP\Files\Storage $targetStorage */
+ list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
+ $targetStorage->acquireLock($targetInternalPath, $type, $provider);
+ // lock the parent folders of the owner when locking the share as recipient
+ if ($path === '') {
+ $sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
+ $this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
+ }
+ }
+
+ /**
+ * @param string $path
+ * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
+ * @param \OCP\Lock\ILockingProvider $provider
+ */
+ public function releaseLock($path, $type, ILockingProvider $provider) {
+ /** @var \OCP\Files\Storage $targetStorage */
+ list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
+ $targetStorage->releaseLock($targetInternalPath, $type, $provider);
+ // unlock the parent folders of the owner when unlocking the share as recipient
+ if ($path === '') {
+ $sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
+ $this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
+ }
+ }
+
+ /**
+ * @param string $path
+ * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
+ * @param \OCP\Lock\ILockingProvider $provider
+ */
+ public function changeLock($path, $type, ILockingProvider $provider) {
+ /** @var \OCP\Files\Storage $targetStorage */
+ list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
+ $targetStorage->changeLock($targetInternalPath, $type, $provider);
+ }
+
+ /**
+ * @return array [ available, last_checked ]
+ */
+ public function getAvailability() {
+ // shares do not participate in availability logic
+ return [
+ 'available' => true,
+ 'last_checked' => 0
+ ];
+ }
+
+ /**
+ * @param bool $available
+ */
+ public function setAvailability($available) {
+ // shares do not participate in availability logic
+ }
+
+ public function getSourceStorage() {
+ return $this->getWrapperStorage();
+ }
+
+ public function getWrapperStorage() {
+ $this->init();
+ return $this->storage;
+ }
+
+ public function file_get_contents($path) {
+ $info = [
+ 'target' => $this->getMountPoint() . '/' . $path,
+ 'source' => $this->getSourcePath($path),
+ ];
+ \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
+ return parent::file_get_contents($path);
+ }
+
+ public function file_put_contents($path, $data) {
+ $info = [
+ 'target' => $this->getMountPoint() . '/' . $path,
+ 'source' => $this->getSourcePath($path),
+ ];
+ \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
+ return parent::file_put_contents($path, $data);
+ }
+
+}