diff options
Diffstat (limited to 'apps/dav/lib/Connector/Sabre/Node.php')
-rw-r--r-- | apps/dav/lib/Connector/Sabre/Node.php | 229 |
1 files changed, 97 insertions, 132 deletions
diff --git a/apps/dav/lib/Connector/Sabre/Node.php b/apps/dav/lib/Connector/Sabre/Node.php index e4517068f42..505e6b5eda4 100644 --- a/apps/dav/lib/Connector/Sabre/Node.php +++ b/apps/dav/lib/Connector/Sabre/Node.php @@ -1,37 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bart Visscher <bartv@thisnet.nl> - * @author Björn Schießle <bjoern@schiessle.org> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Daniel Calviño Sánchez <danxuliu@gmail.com> - * @author Jakob Sack <mail@jakobsack.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Klaas Freitag <freitag@owncloud.com> - * @author Markus Goetz <markus@woboq.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Tobias Kaminsky <tobias@kaminsky.me> - * @author Vincent Petry <vincent@nextcloud.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/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCA\DAV\Connector\Sabre; @@ -40,20 +12,19 @@ use OC\Files\Node\File; use OC\Files\Node\Folder; use OC\Files\View; use OCA\DAV\Connector\Sabre\Exception\InvalidPath; +use OCP\Constants; +use OCP\Files\DavUtil; use OCP\Files\FileInfo; +use OCP\Files\InvalidPathException; use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\Files\Storage\ISharedStorage; use OCP\Files\StorageNotAvailableException; -use OCP\Share\IShare; +use OCP\Server; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager; abstract class Node implements \Sabre\DAV\INode { - - /** - * @var \OC\Files\View - */ - protected $fileView; - /** * The path to the current node * @@ -68,10 +39,7 @@ abstract class Node implements \Sabre\DAV\INode { */ protected $property_cache = null; - /** - * @var \OCP\Files\FileInfo - */ - protected $info; + protected FileInfo $info; /** * @var IManager @@ -82,39 +50,45 @@ abstract class Node implements \Sabre\DAV\INode { /** * Sets up the node, expects a full path name - * - * @param \OC\Files\View $view - * @param \OCP\Files\FileInfo $info - * @param IManager $shareManager */ - public function __construct(View $view, FileInfo $info, IManager $shareManager = null) { - $this->fileView = $view; + public function __construct( + protected View $fileView, + FileInfo $info, + ?IManager $shareManager = null, + ) { $this->path = $this->fileView->getRelativePath($info->getPath()); $this->info = $info; if ($shareManager) { $this->shareManager = $shareManager; } else { - $this->shareManager = \OC::$server->getShareManager(); + $this->shareManager = Server::get(\OCP\Share\IManager::class); } if ($info instanceof Folder || $info instanceof File) { $this->node = $info; } else { - $root = \OC::$server->get(IRootFolder::class); + // The Node API assumes that the view passed doesn't have a fake root + $rootView = Server::get(View::class); + $root = Server::get(IRootFolder::class); if ($info->getType() === FileInfo::TYPE_FOLDER) { - $this->node = new Folder($root, $view, $this->path, $info); + $this->node = new Folder($root, $rootView, $this->fileView->getAbsolutePath($this->path), $info); } else { - $this->node = new File($root, $view, $this->path, $info); + $this->node = new File($root, $rootView, $this->fileView->getAbsolutePath($this->path), $info); } } } - protected function refreshInfo() { - $this->info = $this->fileView->getFileInfo($this->path); - $root = \OC::$server->get(IRootFolder::class); + protected function refreshInfo(): void { + $info = $this->fileView->getFileInfo($this->path); + if ($info === false) { + throw new \Sabre\DAV\Exception('Failed to get fileinfo for ' . $this->path); + } + $this->info = $info; + $root = Server::get(IRootFolder::class); + $rootView = Server::get(View::class); if ($this->info->getType() === FileInfo::TYPE_FOLDER) { - $this->node = new Folder($root, $this->fileView, $this->path, $this->info); + $this->node = new Folder($root, $rootView, $this->path, $this->info); } else { - $this->node = new File($root, $this->fileView, $this->path, $this->info); + $this->node = new File($root, $rootView, $this->path, $this->info); } } @@ -144,22 +118,21 @@ abstract class Node implements \Sabre\DAV\INode { * @throws \Sabre\DAV\Exception\Forbidden */ public function setName($name) { - - // rename is only allowed if the update privilege is granted - if (!($this->info->isUpdateable() || ($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === ''))) { + // rename is only allowed if the delete privilege is granted + // (basically rename is a copy with delete of the original node) + if (!($this->info->isDeletable() || ($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === ''))) { throw new \Sabre\DAV\Exception\Forbidden(); } [$parentPath,] = \Sabre\Uri\split($this->path); [, $newName] = \Sabre\Uri\split($name); + $newPath = $parentPath . '/' . $newName; // verify path of the target - $this->verifyPath(); - - $newPath = $parentPath . '/' . $newName; + $this->verifyPath($newPath); if (!$this->fileView->rename($this->path, $newPath)) { - throw new \Sabre\DAV\Exception('Failed to rename '. $this->path . ' to ' . $newPath); + throw new \Sabre\DAV\Exception('Failed to rename ' . $this->path . ' to ' . $newPath); } $this->path = $newPath; @@ -232,9 +205,10 @@ abstract class Node implements \Sabre\DAV\INode { /** * Returns the size of the node, in bytes * - * @return integer + * @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit + * @return int|float */ - public function getSize() { + public function getSize(): int|float { return $this->info->getSize(); } @@ -251,10 +225,8 @@ abstract class Node implements \Sabre\DAV\INode { * @return string|null */ public function getFileId() { - if ($this->info->getId()) { - $instanceId = \OC_Util::getInstanceId(); - $id = sprintf('%08d', $this->info->getId()); - return $id . $instanceId; + if ($id = $this->info->getId()) { + return DavUtil::getDavFileId($id); } return null; @@ -267,12 +239,15 @@ abstract class Node implements \Sabre\DAV\INode { return $this->info->getId(); } + public function getInternalPath(): string { + return $this->info->getInternalPath(); + } + /** * @param string $user * @return int */ public function getSharePermissions($user) { - // check of we access a federated share if ($user !== null) { try { @@ -289,8 +264,8 @@ abstract class Node implements \Sabre\DAV\INode { $storage = null; } - if ($storage && $storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { - /** @var \OCA\Files_Sharing\SharedStorage $storage */ + if ($storage && $storage->instanceOfStorage(ISharedStorage::class)) { + /** @var ISharedStorage $storage */ $permissions = (int)$storage->getShare()->getPermissions(); } else { $permissions = $this->info->getPermissions(); @@ -303,98 +278,88 @@ abstract class Node implements \Sabre\DAV\INode { $mountpoint = $this->info->getMountPoint(); if (!($mountpoint instanceof MoveableMount)) { $mountpointpath = $mountpoint->getMountPoint(); - if (substr($mountpointpath, -1) === '/') { + if (str_ends_with($mountpointpath, '/')) { $mountpointpath = substr($mountpointpath, 0, -1); } if (!$mountpoint->getOption('readonly', false) && $mountpointpath === $this->info->getPath()) { - $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE; + $permissions |= Constants::PERMISSION_DELETE | Constants::PERMISSION_UPDATE; } } /* * Files can't have create or delete permissions */ - if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - $permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE); + if ($this->info->getType() === FileInfo::TYPE_FILE) { + $permissions &= ~(Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE); } return $permissions; } /** - * @param string $user - * @return string + * @return array */ - public function getNoteFromShare($user) { - if ($user === null) { - return ''; + public function getShareAttributes(): array { + try { + $storage = $this->node->getStorage(); + } catch (NotFoundException $e) { + return []; } - $types = [ - IShare::TYPE_USER, - IShare::TYPE_GROUP, - IShare::TYPE_CIRCLE, - IShare::TYPE_ROOM - ]; - - foreach ($types as $shareType) { - $shares = $this->shareManager->getSharedWith($user, $shareType, $this, -1); - foreach ($shares as $share) { - $note = $share->getNote(); - if ($share->getShareOwner() !== $user && !empty($note)) { - return $note; - } + $attributes = []; + if ($storage->instanceOfStorage(ISharedStorage::class)) { + /** @var ISharedStorage $storage */ + $attributes = $storage->getShare()->getAttributes(); + if ($attributes === null) { + return []; + } else { + return $attributes->toArray(); + } + } + + return $attributes; + } + + public function getNoteFromShare(?string $user): ?string { + try { + $storage = $this->node->getStorage(); + } catch (NotFoundException) { + return null; + } + + if ($storage->instanceOfStorage(ISharedStorage::class)) { + /** @var ISharedStorage $storage */ + $share = $storage->getShare(); + if ($user === $share->getShareOwner()) { + // Note is only for recipient not the owner + return null; } + return $share->getNote(); } - return ''; + return null; } /** * @return string */ public function getDavPermissions() { - $p = ''; - if ($this->info->isShared()) { - $p .= 'S'; - } - if ($this->info->isShareable()) { - $p .= 'R'; - } - if ($this->info->isMounted()) { - $p .= 'M'; - } - if ($this->info->isReadable()) { - $p .= 'G'; - } - if ($this->info->isDeletable()) { - $p .= 'D'; - } - if ($this->info->isUpdateable()) { - $p .= 'NV'; // Renameable, Moveable - } - if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - if ($this->info->isUpdateable()) { - $p .= 'W'; - } - } else { - if ($this->info->isCreatable()) { - $p .= 'CK'; - } - } - return $p; + return DavUtil::getDavPermissions($this->info); } public function getOwner() { return $this->info->getOwner(); } - protected function verifyPath() { + protected function verifyPath(?string $path = null): void { try { - $fileName = basename($this->info->getPath()); - $this->fileView->verifyPath($this->path, $fileName); - } catch (\OCP\Files\InvalidPathException $ex) { + $path = $path ?? $this->info->getPath(); + $this->fileView->verifyPath( + dirname($path), + basename($path), + ); + } catch (InvalidPathException $ex) { throw new InvalidPath($ex->getMessage()); } } @@ -428,7 +393,7 @@ abstract class Node implements \Sabre\DAV\INode { return $this->node; } - protected function sanitizeMtime($mtimeFromRequest) { + protected function sanitizeMtime(string $mtimeFromRequest): int { return MtimeSanitizer::sanitizeMtime($mtimeFromRequest); } } |