aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Files/Storage/Wrapper
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Files/Storage/Wrapper')
-rw-r--r--lib/private/Files/Storage/Wrapper/Availability.php381
-rw-r--r--lib/private/Files/Storage/Wrapper/Encoding.php343
-rw-r--r--lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php30
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php450
-rw-r--r--lib/private/Files/Storage/Wrapper/Jail.php382
-rw-r--r--lib/private/Files/Storage/Wrapper/KnownMtime.php38
-rw-r--r--lib/private/Files/Storage/Wrapper/PermissionsMask.php80
-rw-r--r--lib/private/Files/Storage/Wrapper/Quota.php115
-rw-r--r--lib/private/Files/Storage/Wrapper/Wrapper.php470
9 files changed, 490 insertions, 1799 deletions
diff --git a/lib/private/Files/Storage/Wrapper/Availability.php b/lib/private/Files/Storage/Wrapper/Availability.php
index 693d943f0dc..32c51a1b25e 100644
--- a/lib/private/Files/Storage/Wrapper/Availability.php
+++ b/lib/private/Files/Storage/Wrapper/Availability.php
@@ -1,28 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @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 OC\Files\Storage\Wrapper;
@@ -42,12 +23,12 @@ class Availability extends Wrapper {
/** @var IConfig */
protected $config;
- public function __construct($parameters) {
- $this->config = $parameters['config'] ?? \OC::$server->getConfig();
+ public function __construct(array $parameters) {
+ $this->config = $parameters['config'] ?? \OCP\Server::get(IConfig::class);
parent::__construct($parameters);
}
- public static function shouldRecheck($availability) {
+ public static function shouldRecheck($availability): bool {
if (!$availability['available']) {
// trigger a recheck if TTL reached
if ((time() - $availability['last_checked']) > self::RECHECK_TTL_SEC) {
@@ -59,10 +40,8 @@ class Availability extends Wrapper {
/**
* Only called if availability === false
- *
- * @return bool
*/
- private function updateAvailability() {
+ private function updateAvailability(): bool {
// reset availability to false so that multiple requests don't recheck concurrently
$this->setAvailability(false);
try {
@@ -74,10 +53,7 @@ class Availability extends Wrapper {
return $result;
}
- /**
- * @return bool
- */
- private function isAvailable() {
+ private function isAvailable(): bool {
$availability = $this->getAvailability();
if (self::shouldRecheck($availability)) {
return $this->updateAvailability();
@@ -88,297 +64,137 @@ class Availability extends Wrapper {
/**
* @throws StorageNotAvailableException
*/
- private function checkAvailability() {
+ private function checkAvailability(): void {
if (!$this->isAvailable()) {
throw new StorageNotAvailableException();
}
}
- /** {@inheritdoc} */
- public function mkdir($path) {
+ /**
+ * Handles availability checks and delegates method calls dynamically
+ */
+ private function handleAvailability(string $method, mixed ...$args): mixed {
$this->checkAvailability();
try {
- return parent::mkdir($path);
+ return call_user_func_array([parent::class, $method], $args);
} catch (StorageNotAvailableException $e) {
$this->setUnavailable($e);
+ return false;
}
}
- /** {@inheritdoc} */
- public function rmdir($path) {
- $this->checkAvailability();
- try {
- return parent::rmdir($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function mkdir(string $path): bool {
+ return $this->handleAvailability('mkdir', $path);
}
- /** {@inheritdoc} */
- public function opendir($path) {
- $this->checkAvailability();
- try {
- return parent::opendir($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function rmdir(string $path): bool {
+ return $this->handleAvailability('rmdir', $path);
}
- /** {@inheritdoc} */
- public function is_dir($path) {
- $this->checkAvailability();
- try {
- return parent::is_dir($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function opendir(string $path) {
+ return $this->handleAvailability('opendir', $path);
}
- /** {@inheritdoc} */
- public function is_file($path) {
- $this->checkAvailability();
- try {
- return parent::is_file($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function is_dir(string $path): bool {
+ return $this->handleAvailability('is_dir', $path);
}
- /** {@inheritdoc} */
- public function stat($path) {
- $this->checkAvailability();
- try {
- return parent::stat($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function is_file(string $path): bool {
+ return $this->handleAvailability('is_file', $path);
}
- /** {@inheritdoc} */
- public function filetype($path) {
- $this->checkAvailability();
- try {
- return parent::filetype($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function stat(string $path): array|false {
+ return $this->handleAvailability('stat', $path);
}
- /** {@inheritdoc} */
- public function filesize($path): false|int|float {
- $this->checkAvailability();
- try {
- return parent::filesize($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function filetype(string $path): string|false {
+ return $this->handleAvailability('filetype', $path);
}
- /** {@inheritdoc} */
- public function isCreatable($path) {
- $this->checkAvailability();
- try {
- return parent::isCreatable($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function filesize(string $path): int|float|false {
+ return $this->handleAvailability('filesize', $path);
}
- /** {@inheritdoc} */
- public function isReadable($path) {
- $this->checkAvailability();
- try {
- return parent::isReadable($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function isCreatable(string $path): bool {
+ return $this->handleAvailability('isCreatable', $path);
}
- /** {@inheritdoc} */
- public function isUpdatable($path) {
- $this->checkAvailability();
- try {
- return parent::isUpdatable($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function isReadable(string $path): bool {
+ return $this->handleAvailability('isReadable', $path);
}
- /** {@inheritdoc} */
- public function isDeletable($path) {
- $this->checkAvailability();
- try {
- return parent::isDeletable($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function isUpdatable(string $path): bool {
+ return $this->handleAvailability('isUpdatable', $path);
}
- /** {@inheritdoc} */
- public function isSharable($path) {
- $this->checkAvailability();
- try {
- return parent::isSharable($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function isDeletable(string $path): bool {
+ return $this->handleAvailability('isDeletable', $path);
}
- /** {@inheritdoc} */
- public function getPermissions($path) {
- $this->checkAvailability();
- try {
- return parent::getPermissions($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function isSharable(string $path): bool {
+ return $this->handleAvailability('isSharable', $path);
}
- /** {@inheritdoc} */
- public function file_exists($path) {
- if ($path === '') {
- return true;
- }
- $this->checkAvailability();
- try {
- return parent::file_exists($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function getPermissions(string $path): int {
+ return $this->handleAvailability('getPermissions', $path);
}
- /** {@inheritdoc} */
- public function filemtime($path) {
- $this->checkAvailability();
- try {
- return parent::filemtime($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
+ public function file_exists(string $path): bool {
+ if ($path === '') {
+ return true;
}
+ return $this->handleAvailability('file_exists', $path);
}
- /** {@inheritdoc} */
- public function file_get_contents($path) {
- $this->checkAvailability();
- try {
- return parent::file_get_contents($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function filemtime(string $path): int|false {
+ return $this->handleAvailability('filemtime', $path);
}
- /** {@inheritdoc} */
- public function file_put_contents($path, $data) {
- $this->checkAvailability();
- try {
- return parent::file_put_contents($path, $data);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function file_get_contents(string $path): string|false {
+ return $this->handleAvailability('file_get_contents', $path);
}
- /** {@inheritdoc} */
- public function unlink($path) {
- $this->checkAvailability();
- try {
- return parent::unlink($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function file_put_contents(string $path, mixed $data): int|float|false {
+ return $this->handleAvailability('file_put_contents', $path, $data);
}
- /** {@inheritdoc} */
- public function rename($source, $target) {
- $this->checkAvailability();
- try {
- return parent::rename($source, $target);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function unlink(string $path): bool {
+ return $this->handleAvailability('unlink', $path);
}
- /** {@inheritdoc} */
- public function copy($source, $target) {
- $this->checkAvailability();
- try {
- return parent::copy($source, $target);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function rename(string $source, string $target): bool {
+ return $this->handleAvailability('rename', $source, $target);
}
- /** {@inheritdoc} */
- public function fopen($path, $mode) {
- $this->checkAvailability();
- try {
- return parent::fopen($path, $mode);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function copy(string $source, string $target): bool {
+ return $this->handleAvailability('copy', $source, $target);
}
- /** {@inheritdoc} */
- public function getMimeType($path) {
- $this->checkAvailability();
- try {
- return parent::getMimeType($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function fopen(string $path, string $mode) {
+ return $this->handleAvailability('fopen', $path, $mode);
}
- /** {@inheritdoc} */
- public function hash($type, $path, $raw = false) {
- $this->checkAvailability();
- try {
- return parent::hash($type, $path, $raw);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function getMimeType(string $path): string|false {
+ return $this->handleAvailability('getMimeType', $path);
}
- /** {@inheritdoc} */
- public function free_space($path) {
- $this->checkAvailability();
- try {
- return parent::free_space($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function hash(string $type, string $path, bool $raw = false): string|false {
+ return $this->handleAvailability('hash', $type, $path, $raw);
}
- /** {@inheritdoc} */
- public function search($query) {
- $this->checkAvailability();
- try {
- return parent::search($query);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function free_space(string $path): int|float|false {
+ return $this->handleAvailability('free_space', $path);
}
- /** {@inheritdoc} */
- public function touch($path, $mtime = null) {
- $this->checkAvailability();
- try {
- return parent::touch($path, $mtime);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function touch(string $path, ?int $mtime = null): bool {
+ return $this->handleAvailability('touch', $path, $mtime);
}
- /** {@inheritdoc} */
- public function getLocalFile($path) {
- $this->checkAvailability();
- try {
- return parent::getLocalFile($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function getLocalFile(string $path): string|false {
+ return $this->handleAvailability('getLocalFile', $path);
}
- /** {@inheritdoc} */
- public function hasUpdated($path, $time) {
+ public function hasUpdated(string $path, int $time): bool {
if (!$this->isAvailable()) {
return false;
}
@@ -391,62 +207,38 @@ class Availability extends Wrapper {
}
}
- /** {@inheritdoc} */
- public function getOwner($path) {
+ public function getOwner(string $path): string|false {
try {
return parent::getOwner($path);
} catch (StorageNotAvailableException $e) {
$this->setUnavailable($e);
+ return false;
}
}
- /** {@inheritdoc} */
- public function getETag($path) {
- $this->checkAvailability();
- try {
- return parent::getETag($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function getETag(string $path): string|false {
+ return $this->handleAvailability('getETag', $path);
}
- /** {@inheritdoc} */
- public function getDirectDownload($path) {
- $this->checkAvailability();
- try {
- return parent::getDirectDownload($path);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function getDirectDownload(string $path): array|false {
+ return $this->handleAvailability('getDirectDownload', $path);
}
- /** {@inheritdoc} */
- public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
- $this->checkAvailability();
- try {
- return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
+ return $this->handleAvailability('copyFromStorage', $sourceStorage, $sourceInternalPath, $targetInternalPath);
}
- /** {@inheritdoc} */
- public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
- $this->checkAvailability();
- try {
- return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
- } catch (StorageNotAvailableException $e) {
- $this->setUnavailable($e);
- }
+ public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
+ return $this->handleAvailability('moveFromStorage', $sourceStorage, $sourceInternalPath, $targetInternalPath);
}
- /** {@inheritdoc} */
- public function getMetaData($path) {
+ public function getMetaData(string $path): ?array {
$this->checkAvailability();
try {
return parent::getMetaData($path);
} catch (StorageNotAvailableException $e) {
$this->setUnavailable($e);
+ return null;
}
}
@@ -473,12 +265,13 @@ class Availability extends Wrapper {
- public function getDirectoryContent($directory): \Traversable {
+ public function getDirectoryContent(string $directory): \Traversable {
$this->checkAvailability();
try {
return parent::getDirectoryContent($directory);
} catch (StorageNotAvailableException $e) {
$this->setUnavailable($e);
+ return new \EmptyIterator();
}
}
}
diff --git a/lib/private/Files/Storage/Wrapper/Encoding.php b/lib/private/Files/Storage/Wrapper/Encoding.php
index 1bdb0e39f14..92e20cfb3df 100644
--- a/lib/private/Files/Storage/Wrapper/Encoding.php
+++ b/lib/private/Files/Storage/Wrapper/Encoding.php
@@ -1,35 +1,15 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
- * @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 OC\Files\Storage\Wrapper;
use OC\Files\Filesystem;
use OCP\Cache\CappedMemoryCache;
+use OCP\Files\Cache\IScanner;
use OCP\Files\Storage\IStorage;
use OCP\ICache;
@@ -48,19 +28,15 @@ class Encoding extends Wrapper {
/**
* @param array $parameters
*/
- public function __construct($parameters) {
+ public function __construct(array $parameters) {
$this->storage = $parameters['storage'];
$this->namesCache = new CappedMemoryCache();
}
/**
* Returns whether the given string is only made of ASCII characters
- *
- * @param string $str string
- *
- * @return bool true if the string is all ASCII, false otherwise
*/
- private function isAscii($str) {
+ private function isAscii(string $str): bool {
return !preg_match('/[\\x80-\\xff]+/', $str);
}
@@ -69,11 +45,9 @@ class Encoding extends Wrapper {
* each form for each path section and returns the correct form.
* If no existing path found, returns the path as it was given.
*
- * @param string $fullPath path to check
- *
* @return string original or converted path
*/
- private function findPathToUse($fullPath) {
+ private function findPathToUse(string $fullPath): string {
$cachedPath = $this->namesCache[$fullPath];
if ($cachedPath !== null) {
return $cachedPath;
@@ -97,12 +71,11 @@ class Encoding extends Wrapper {
* Checks whether the last path section of the given path exists in NFC or NFD form
* and returns the correct form. If no existing path found, returns null.
*
- * @param string $basePath base path to check
* @param string $lastSection last section of the path to check for NFD/NFC variations
*
* @return string|null original or converted path, or null if none of the forms was found
*/
- private function findPathToUseLastSection($basePath, $lastSection) {
+ private function findPathToUseLastSection(string $basePath, string $lastSection): ?string {
$fullPath = $basePath . $lastSection;
if ($lastSection === '' || $this->isAscii($lastSection) || $this->storage->file_exists($fullPath)) {
$this->namesCache[$fullPath] = $fullPath;
@@ -126,13 +99,7 @@ class Encoding extends Wrapper {
return null;
}
- /**
- * see https://www.php.net/manual/en/function.mkdir.php
- *
- * @param string $path
- * @return bool
- */
- public function mkdir($path) {
+ public function mkdir(string $path): bool {
// note: no conversion here, method should not be called with non-NFC names!
$result = $this->storage->mkdir($path);
if ($result) {
@@ -141,13 +108,7 @@ class Encoding extends Wrapper {
return $result;
}
- /**
- * see https://www.php.net/manual/en/function.rmdir.php
- *
- * @param string $path
- * @return bool
- */
- public function rmdir($path) {
+ public function rmdir(string $path): bool {
$result = $this->storage->rmdir($this->findPathToUse($path));
if ($result) {
unset($this->namesCache[$path]);
@@ -155,175 +116,72 @@ class Encoding extends Wrapper {
return $result;
}
- /**
- * see https://www.php.net/manual/en/function.opendir.php
- *
- * @param string $path
- * @return resource|false
- */
- public function opendir($path) {
+ public function opendir(string $path) {
$handle = $this->storage->opendir($this->findPathToUse($path));
return EncodingDirectoryWrapper::wrap($handle);
}
- /**
- * see https://www.php.net/manual/en/function.is_dir.php
- *
- * @param string $path
- * @return bool
- */
- public function is_dir($path) {
+ public function is_dir(string $path): bool {
return $this->storage->is_dir($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.is_file.php
- *
- * @param string $path
- * @return bool
- */
- public function is_file($path) {
+ public function is_file(string $path): bool {
return $this->storage->is_file($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.stat.php
- * only the following keys are required in the result: size and mtime
- *
- * @param string $path
- * @return array|bool
- */
- public function stat($path) {
+ public function stat(string $path): array|false {
return $this->storage->stat($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.filetype.php
- *
- * @param string $path
- * @return string|bool
- */
- public function filetype($path) {
+ public function filetype(string $path): string|false {
return $this->storage->filetype($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.filesize.php
- * The result for filesize when called on a folder is required to be 0
- */
- public function filesize($path): false|int|float {
+ public function filesize(string $path): int|float|false {
return $this->storage->filesize($this->findPathToUse($path));
}
- /**
- * check if a file can be created in $path
- *
- * @param string $path
- * @return bool
- */
- public function isCreatable($path) {
+ public function isCreatable(string $path): bool {
return $this->storage->isCreatable($this->findPathToUse($path));
}
- /**
- * check if a file can be read
- *
- * @param string $path
- * @return bool
- */
- public function isReadable($path) {
+ public function isReadable(string $path): bool {
return $this->storage->isReadable($this->findPathToUse($path));
}
- /**
- * check if a file can be written to
- *
- * @param string $path
- * @return bool
- */
- public function isUpdatable($path) {
+ public function isUpdatable(string $path): bool {
return $this->storage->isUpdatable($this->findPathToUse($path));
}
- /**
- * check if a file can be deleted
- *
- * @param string $path
- * @return bool
- */
- public function isDeletable($path) {
+ public function isDeletable(string $path): bool {
return $this->storage->isDeletable($this->findPathToUse($path));
}
- /**
- * check if a file can be shared
- *
- * @param string $path
- * @return bool
- */
- public function isSharable($path) {
+ public function isSharable(string $path): bool {
return $this->storage->isSharable($this->findPathToUse($path));
}
- /**
- * get the full permissions of a path.
- * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
- *
- * @param string $path
- * @return int
- */
- public function getPermissions($path) {
+ public function getPermissions(string $path): int {
return $this->storage->getPermissions($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.file_exists.php
- *
- * @param string $path
- * @return bool
- */
- public function file_exists($path) {
+ public function file_exists(string $path): bool {
return $this->storage->file_exists($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.filemtime.php
- *
- * @param string $path
- * @return int|bool
- */
- public function filemtime($path) {
+ public function filemtime(string $path): int|false {
return $this->storage->filemtime($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.file_get_contents.php
- *
- * @param string $path
- * @return string|false
- */
- public function file_get_contents($path) {
+ public function file_get_contents(string $path): string|false {
return $this->storage->file_get_contents($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.file_put_contents.php
- *
- * @param string $path
- * @param mixed $data
- * @return int|float|false
- */
- public function file_put_contents($path, $data) {
+ public function file_put_contents(string $path, mixed $data): int|float|false {
return $this->storage->file_put_contents($this->findPathToUse($path), $data);
}
- /**
- * see https://www.php.net/manual/en/function.unlink.php
- *
- * @param string $path
- * @return bool
- */
- public function unlink($path) {
+ public function unlink(string $path): bool {
$result = $this->storage->unlink($this->findPathToUse($path));
if ($result) {
unset($this->namesCache[$path]);
@@ -331,37 +189,16 @@ class Encoding extends Wrapper {
return $result;
}
- /**
- * see https://www.php.net/manual/en/function.rename.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function rename($source, $target) {
+ public function rename(string $source, string $target): bool {
// second name always NFC
return $this->storage->rename($this->findPathToUse($source), $this->findPathToUse($target));
}
- /**
- * see https://www.php.net/manual/en/function.copy.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function copy($source, $target) {
+ public function copy(string $source, string $target): bool {
return $this->storage->copy($this->findPathToUse($source), $this->findPathToUse($target));
}
- /**
- * see https://www.php.net/manual/en/function.fopen.php
- *
- * @param string $path
- * @param string $mode
- * @return resource|bool
- */
- public function fopen($path, $mode) {
+ public function fopen(string $path, string $mode) {
$result = $this->storage->fopen($this->findPathToUse($path), $mode);
if ($result && $mode !== 'r' && $mode !== 'rb') {
unset($this->namesCache[$path]);
@@ -369,131 +206,49 @@ class Encoding extends Wrapper {
return $result;
}
- /**
- * get the mimetype for a file or folder
- * The mimetype for a folder is required to be "httpd/unix-directory"
- *
- * @param string $path
- * @return string|bool
- */
- public function getMimeType($path) {
+ public function getMimeType(string $path): string|false {
return $this->storage->getMimeType($this->findPathToUse($path));
}
- /**
- * see https://www.php.net/manual/en/function.hash.php
- *
- * @param string $type
- * @param string $path
- * @param bool $raw
- * @return string|bool
- */
- public function hash($type, $path, $raw = false) {
+ public function hash(string $type, string $path, bool $raw = false): string|false {
return $this->storage->hash($type, $this->findPathToUse($path), $raw);
}
- /**
- * see https://www.php.net/manual/en/function.free_space.php
- *
- * @param string $path
- * @return int|float|bool
- */
- public function free_space($path) {
+ public function free_space(string $path): int|float|false {
return $this->storage->free_space($this->findPathToUse($path));
}
- /**
- * search for occurrences of $query in file names
- *
- * @param string $query
- * @return array|bool
- */
- public function search($query) {
- return $this->storage->search($query);
- }
-
- /**
- * see https://www.php.net/manual/en/function.touch.php
- * If the backend does not support the operation, false should be returned
- *
- * @param string $path
- * @param int $mtime
- * @return bool
- */
- public function touch($path, $mtime = null) {
+ public function touch(string $path, ?int $mtime = null): bool {
return $this->storage->touch($this->findPathToUse($path), $mtime);
}
- /**
- * get the path to a local version of the file.
- * The local version of the file can be temporary and doesn't have to be persistent across requests
- *
- * @param string $path
- * @return string|false
- */
- public function getLocalFile($path) {
+ public function getLocalFile(string $path): string|false {
return $this->storage->getLocalFile($this->findPathToUse($path));
}
- /**
- * check if a file or folder has been updated since $time
- *
- * @param string $path
- * @param int $time
- * @return bool
- *
- * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
- * returning true for other changes in the folder is optional
- */
- public function hasUpdated($path, $time) {
+ public function hasUpdated(string $path, int $time): bool {
return $this->storage->hasUpdated($this->findPathToUse($path), $time);
}
- /**
- * get a cache instance for the storage
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
- * @return \OC\Files\Cache\Cache
- */
- public function getCache($path = '', $storage = null) {
+ public function getCache(string $path = '', ?IStorage $storage = null): \OCP\Files\Cache\ICache {
if (!$storage) {
$storage = $this;
}
return $this->storage->getCache($this->findPathToUse($path), $storage);
}
- /**
- * get a scanner instance for the storage
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
- * @return \OC\Files\Cache\Scanner
- */
- public function getScanner($path = '', $storage = null) {
+ public function getScanner(string $path = '', ?IStorage $storage = null): IScanner {
if (!$storage) {
$storage = $this;
}
return $this->storage->getScanner($this->findPathToUse($path), $storage);
}
- /**
- * get the ETag for a file or folder
- *
- * @param string $path
- * @return string|false
- */
- public function getETag($path) {
+ public function getETag(string $path): string|false {
return $this->storage->getETag($this->findPathToUse($path));
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if ($sourceStorage === $this) {
return $this->copy($sourceInternalPath, $this->findPathToUse($targetInternalPath));
}
@@ -505,13 +260,7 @@ class Encoding extends Wrapper {
return $result;
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if ($sourceStorage === $this) {
$result = $this->rename($sourceInternalPath, $this->findPathToUse($targetInternalPath));
if ($result) {
@@ -529,13 +278,15 @@ class Encoding extends Wrapper {
return $result;
}
- public function getMetaData($path) {
+ public function getMetaData(string $path): ?array {
$entry = $this->storage->getMetaData($this->findPathToUse($path));
- $entry['name'] = trim(Filesystem::normalizePath($entry['name']), '/');
+ if ($entry !== null) {
+ $entry['name'] = trim(Filesystem::normalizePath($entry['name']), '/');
+ }
return $entry;
}
- public function getDirectoryContent($directory): \Traversable {
+ public function getDirectoryContent(string $directory): \Traversable {
$entries = $this->storage->getDirectoryContent($this->findPathToUse($directory));
foreach ($entries as $entry) {
$entry['name'] = trim(Filesystem::normalizePath($entry['name']), '/');
diff --git a/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php b/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php
index 3cda399f22d..0a90b49f0f1 100644
--- a/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php
+++ b/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php
@@ -1,26 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2021, Nextcloud GmbH.
- *
- * @author Robin Appelman <robin@icewind.nl>
- * @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: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OC\Files\Storage\Wrapper;
use Icewind\Streams\DirectoryWrapper;
@@ -30,11 +13,7 @@ use OC\Files\Filesystem;
* Normalize file names while reading directory entries
*/
class EncodingDirectoryWrapper extends DirectoryWrapper {
- /**
- * @psalm-suppress ImplementedReturnTypeMismatch Until return type is fixed upstream
- * @return string|false
- */
- public function dir_readdir() {
+ public function dir_readdir(): string|false {
$file = readdir($this->source);
if ($file !== false && $file !== '.' && $file !== '..') {
$file = trim(Filesystem::normalizePath($file), '/');
@@ -45,7 +24,6 @@ class EncodingDirectoryWrapper extends DirectoryWrapper {
/**
* @param resource $source
- * @param callable $filter
* @return resource|false
*/
public static function wrap($source) {
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index e68e1f65048..58bd4dfddcf 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -1,57 +1,29 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author jknockaert <jasper@knockaert.nl>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Piotr M <mrow4a@yahoo.com>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
- * @author Vincent Petry <vincent@nextcloud.com>
- * @author Richard Steinmetz <richard@steinmetz.cloud>
- *
- * @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 OC\Files\Storage\Wrapper;
use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
-use OC\Encryption\Update;
use OC\Encryption\Util;
use OC\Files\Cache\CacheEntry;
use OC\Files\Filesystem;
use OC\Files\Mount\Manager;
use OC\Files\ObjectStore\ObjectStoreStorage;
+use OC\Files\Storage\Common;
use OC\Files\Storage\LocalTempFileTrait;
use OC\Memcache\ArrayCache;
use OCP\Cache\CappedMemoryCache;
-use OCP\Encryption\Exceptions\GenericEncryptionException;
+use OCP\Encryption\Exceptions\InvalidHeaderException;
use OCP\Encryption\IFile;
use OCP\Encryption\IManager;
use OCP\Encryption\Keys\IStorage;
+use OCP\Files;
use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\GenericFileException;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage;
use Psr\Log\LoggerInterface;
@@ -59,90 +31,42 @@ use Psr\Log\LoggerInterface;
class Encryption extends Wrapper {
use LocalTempFileTrait;
- /** @var string */
- private $mountPoint;
-
- /** @var \OC\Encryption\Util */
- private $util;
-
- /** @var \OCP\Encryption\IManager */
- private $encryptionManager;
-
- private LoggerInterface $logger;
-
- /** @var string */
- private $uid;
-
- /** @var array */
- protected $unencryptedSize;
-
- /** @var \OCP\Encryption\IFile */
- private $fileHelper;
-
- /** @var IMountPoint */
- private $mount;
-
- /** @var IStorage */
- private $keyStorage;
-
- /** @var Update */
- private $update;
-
- /** @var Manager */
- private $mountManager;
-
- /** @var array remember for which path we execute the repair step to avoid recursions */
- private $fixUnencryptedSizeOf = [];
-
- /** @var ArrayCache */
- private $arrayCache;
-
+ private string $mountPoint;
+ protected array $unencryptedSize = [];
+ private IMountPoint $mount;
+ /** for which path we execute the repair step to avoid recursions */
+ private array $fixUnencryptedSizeOf = [];
/** @var CappedMemoryCache<bool> */
private CappedMemoryCache $encryptedPaths;
-
- private $enabled = true;
+ private bool $enabled = true;
/**
* @param array $parameters
*/
public function __construct(
- $parameters,
- ?IManager $encryptionManager = null,
- ?Util $util = null,
- ?LoggerInterface $logger = null,
- ?IFile $fileHelper = null,
- $uid = null,
- ?IStorage $keyStorage = null,
- ?Update $update = null,
- ?Manager $mountManager = null,
- ?ArrayCache $arrayCache = null
+ array $parameters,
+ private IManager $encryptionManager,
+ private Util $util,
+ private LoggerInterface $logger,
+ private IFile $fileHelper,
+ private ?string $uid,
+ private IStorage $keyStorage,
+ private Manager $mountManager,
+ private ArrayCache $arrayCache,
) {
$this->mountPoint = $parameters['mountPoint'];
$this->mount = $parameters['mount'];
- $this->encryptionManager = $encryptionManager;
- $this->util = $util;
- $this->logger = $logger;
- $this->uid = $uid;
- $this->fileHelper = $fileHelper;
- $this->keyStorage = $keyStorage;
- $this->unencryptedSize = [];
- $this->update = $update;
- $this->mountManager = $mountManager;
- $this->arrayCache = $arrayCache;
$this->encryptedPaths = new CappedMemoryCache();
parent::__construct($parameters);
}
- /**
- * see https://www.php.net/manual/en/function.filesize.php
- * The result for filesize when called on a folder is required to be 0
- */
- public function filesize($path): false|int|float {
+ public function filesize(string $path): int|float|false {
$fullPath = $this->getFullPath($path);
$info = $this->getCache()->get($path);
if ($info === false) {
- return false;
+ /* Pass call to wrapped storage, it may be a special file like a part file */
+ return $this->storage->filesize($path);
}
if (isset($this->unencryptedSize[$fullPath])) {
$size = $this->unencryptedSize[$fullPath];
@@ -180,11 +104,6 @@ class Encryption extends Wrapper {
return $this->storage->filesize($path);
}
- /**
- * @param string $path
- * @param array $data
- * @return array
- */
private function modifyMetaData(string $path, array $data): array {
$fullPath = $this->getFullPath($path);
$info = $this->getCache()->get($path);
@@ -208,7 +127,7 @@ class Encryption extends Wrapper {
return $data;
}
- public function getMetaData($path) {
+ public function getMetaData(string $path): ?array {
$data = $this->storage->getMetaData($path);
if (is_null($data)) {
return null;
@@ -216,24 +135,18 @@ class Encryption extends Wrapper {
return $this->modifyMetaData($path, $data);
}
- public function getDirectoryContent($directory): \Traversable {
+ public function getDirectoryContent(string $directory): \Traversable {
$parent = rtrim($directory, '/');
foreach ($this->getWrapperStorage()->getDirectoryContent($directory) as $data) {
yield $this->modifyMetaData($parent . '/' . $data['name'], $data);
}
}
- /**
- * see https://www.php.net/manual/en/function.file_get_contents.php
- *
- * @param string $path
- * @return string|false
- */
- public function file_get_contents($path) {
+ public function file_get_contents(string $path): string|false {
$encryptionModule = $this->getEncryptionModule($path);
if ($encryptionModule) {
- $handle = $this->fopen($path, "r");
+ $handle = $this->fopen($path, 'r');
if (!$handle) {
return false;
}
@@ -244,14 +157,7 @@ class Encryption extends Wrapper {
return $this->storage->file_get_contents($path);
}
- /**
- * see https://www.php.net/manual/en/function.file_put_contents.php
- *
- * @param string $path
- * @param mixed $data
- * @return int|false
- */
- public function file_put_contents($path, $data) {
+ public function file_put_contents(string $path, mixed $data): int|float|false {
// file put content will always be translated to a stream write
$handle = $this->fopen($path, 'w');
if (is_resource($handle)) {
@@ -263,13 +169,7 @@ class Encryption extends Wrapper {
return false;
}
- /**
- * see https://www.php.net/manual/en/function.unlink.php
- *
- * @param string $path
- * @return bool
- */
- public function unlink($path) {
+ public function unlink(string $path): bool {
$fullPath = $this->getFullPath($path);
if ($this->util->isExcluded($fullPath)) {
return $this->storage->unlink($path);
@@ -283,21 +183,14 @@ class Encryption extends Wrapper {
return $this->storage->unlink($path);
}
- /**
- * see https://www.php.net/manual/en/function.rename.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function rename($source, $target) {
+ public function rename(string $source, string $target): bool {
$result = $this->storage->rename($source, $target);
- if ($result &&
+ if ($result
// versions always use the keys from the original file, so we can skip
// this step for versions
- $this->isVersion($target) === false &&
- $this->encryptionManager->isEnabled()) {
+ && $this->isVersion($target) === false
+ && $this->encryptionManager->isEnabled()) {
$sourcePath = $this->getFullPath($source);
if (!$this->util->isExcluded($sourcePath)) {
$targetPath = $this->getFullPath($target);
@@ -315,18 +208,12 @@ class Encryption extends Wrapper {
return $result;
}
- /**
- * see https://www.php.net/manual/en/function.rmdir.php
- *
- * @param string $path
- * @return bool
- */
- public function rmdir($path) {
+ public function rmdir(string $path): bool {
$result = $this->storage->rmdir($path);
$fullPath = $this->getFullPath($path);
- if ($result &&
- $this->util->isExcluded($fullPath) === false &&
- $this->encryptionManager->isEnabled()
+ if ($result
+ && $this->util->isExcluded($fullPath) === false
+ && $this->encryptionManager->isEnabled()
) {
$this->keyStorage->deleteAllFileKeys($fullPath);
}
@@ -334,20 +221,14 @@ class Encryption extends Wrapper {
return $result;
}
- /**
- * check if a file can be read
- *
- * @param string $path
- * @return bool
- */
- public function isReadable($path) {
+ public function isReadable(string $path): bool {
$isReadable = true;
$metaData = $this->getMetaData($path);
if (
- !$this->is_dir($path) &&
- isset($metaData['encrypted']) &&
- $metaData['encrypted'] === true
+ !$this->is_dir($path)
+ && isset($metaData['encrypted'])
+ && $metaData['encrypted'] === true
) {
$fullPath = $this->getFullPath($path);
$module = $this->getEncryptionModule($path);
@@ -357,13 +238,7 @@ class Encryption extends Wrapper {
return $this->storage->isReadable($path) && $isReadable;
}
- /**
- * see https://www.php.net/manual/en/function.copy.php
- *
- * @param string $source
- * @param string $target
- */
- public function copy($source, $target): bool {
+ public function copy(string $source, string $target): bool {
$sourcePath = $this->getFullPath($source);
if ($this->util->isExcluded($sourcePath)) {
@@ -376,16 +251,7 @@ class Encryption extends Wrapper {
return $this->copyFromStorage($this, $source, $target);
}
- /**
- * see https://www.php.net/manual/en/function.fopen.php
- *
- * @param string $path
- * @param string $mode
- * @return resource|bool
- * @throws GenericEncryptionException
- * @throws ModuleDoesNotExistsException
- */
- public function fopen($path, $mode) {
+ public function fopen(string $path, string $mode) {
// check if the file is stored in the array cache, this means that we
// copy a file over to the versions folder, in this case we don't want to
// decrypt it
@@ -438,10 +304,8 @@ class Encryption extends Wrapper {
// if we update a encrypted file with a un-encrypted one we change the db flag
if ($targetIsEncrypted && $encryptionEnabled === false) {
$cache = $this->storage->getCache();
- if ($cache) {
- $entry = $cache->get($path);
- $cache->update($entry->getId(), ['encrypted' => 0]);
- }
+ $entry = $cache->get($path);
+ $cache->update($entry->getId(), ['encrypted' => 0]);
}
if ($encryptionEnabled) {
// if $encryptionModuleId is empty, the default module will be used
@@ -456,7 +320,7 @@ class Encryption extends Wrapper {
if (!empty($encryptionModuleId)) {
$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
$shouldEncrypt = true;
- } elseif (empty($encryptionModuleId) && $info['encrypted'] === true) {
+ } elseif ($info !== false && $info['encrypted'] === true) {
// we come from a old installation. No header and/or no module defined
// but the file is encrypted. In this case we need to use the
// OC_DEFAULT_MODULE to read the file
@@ -482,6 +346,16 @@ class Encryption extends Wrapper {
if ($shouldEncrypt === true && $encryptionModule !== null) {
$this->encryptedPaths->set($this->util->stripPartialFileExtension($path), true);
$headerSize = $this->getHeaderSize($path);
+ if ($mode === 'r' && $headerSize === 0) {
+ $firstBlock = $this->readFirstBlock($path);
+ if (!$firstBlock) {
+ throw new InvalidHeaderException("Unable to get header block for $path");
+ } elseif (!str_starts_with($firstBlock, Util::HEADER_START)) {
+ throw new InvalidHeaderException("Unable to get header size for $path, file doesn't start with encryption header");
+ } else {
+ throw new InvalidHeaderException("Unable to get header size for $path, even though file does start with encryption header");
+ }
+ }
$source = $this->storage->fopen($path, $mode);
if (!is_resource($source)) {
return false;
@@ -499,7 +373,7 @@ class Encryption extends Wrapper {
/**
- * perform some plausibility checks if the the unencrypted size is correct.
+ * perform some plausibility checks if the unencrypted size is correct.
* If not, we calculate the correct unencrypted size and return it
*
* @param string $path internal path relative to the storage root
@@ -511,9 +385,9 @@ class Encryption extends Wrapper {
$size = $this->storage->filesize($path);
$result = $unencryptedSize;
- if ($unencryptedSize < 0 ||
- ($size > 0 && $unencryptedSize === $size) ||
- $unencryptedSize > $size
+ if ($unencryptedSize < 0
+ || ($size > 0 && $unencryptedSize === $size)
+ || $unencryptedSize > $size
) {
// check if we already calculate the unencrypted size for the
// given path to avoid recursions
@@ -537,10 +411,8 @@ class Encryption extends Wrapper {
* @param string $path internal path relative to the storage root
* @param int $size size of the physical file
* @param int $unencryptedSize size of the unencrypted file
- *
- * @return int calculated unencrypted size
*/
- protected function fixUnencryptedSize(string $path, int $size, int $unencryptedSize): int {
+ protected function fixUnencryptedSize(string $path, int $size, int $unencryptedSize): int|float {
$headerSize = $this->getHeaderSize($path);
$header = $this->getHeader($path);
$encryptionModule = $this->getEncryptionModule($path);
@@ -609,12 +481,10 @@ class Encryption extends Wrapper {
// write to cache if applicable
$cache = $this->storage->getCache();
- if ($cache) {
- $entry = $cache->get($path);
- $cache->update($entry['fileid'], [
- 'unencrypted_size' => $newUnencryptedSize
- ]);
- }
+ $entry = $cache->get($path);
+ $cache->update($entry['fileid'], [
+ 'unencrypted_size' => $newUnencryptedSize
+ ]);
return $newUnencryptedSize;
}
@@ -628,7 +498,7 @@ class Encryption extends Wrapper {
* This is required as stream_read only returns smaller chunks of data when the stream fetches from a
* remote storage over the internet and it does not care about the given $blockSize.
*
- * @param handle the stream to read from
+ * @param resource $handle the stream to read from
* @param int $blockSize Length of requested data block in bytes
* @return string Data fetched from stream.
*/
@@ -646,19 +516,12 @@ class Encryption extends Wrapper {
return $data;
}
- /**
- * @param Storage\IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @param bool $preserveMtime
- * @return bool
- */
public function moveFromStorage(
Storage\IStorage $sourceStorage,
- $sourceInternalPath,
- $targetInternalPath,
- $preserveMtime = true
- ) {
+ string $sourceInternalPath,
+ string $targetInternalPath,
+ $preserveMtime = true,
+ ): bool {
if ($sourceStorage === $this) {
return $this->rename($sourceInternalPath, $targetInternalPath);
}
@@ -675,31 +538,34 @@ class Encryption extends Wrapper {
$result = $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, true);
if ($result) {
- if ($sourceStorage->is_dir($sourceInternalPath)) {
- $result &= $sourceStorage->rmdir($sourceInternalPath);
- } else {
- $result &= $sourceStorage->unlink($sourceInternalPath);
+ $setPreserveCacheOnDelete = $sourceStorage->instanceOfStorage(ObjectStoreStorage::class) && !$this->instanceOfStorage(ObjectStoreStorage::class);
+ if ($setPreserveCacheOnDelete) {
+ /** @var ObjectStoreStorage $sourceStorage */
+ $sourceStorage->setPreserveCacheOnDelete(true);
+ }
+ try {
+ if ($sourceStorage->is_dir($sourceInternalPath)) {
+ $result = $sourceStorage->rmdir($sourceInternalPath);
+ } else {
+ $result = $sourceStorage->unlink($sourceInternalPath);
+ }
+ } finally {
+ if ($setPreserveCacheOnDelete) {
+ /** @var ObjectStoreStorage $sourceStorage */
+ $sourceStorage->setPreserveCacheOnDelete(false);
+ }
}
}
return $result;
}
-
- /**
- * @param Storage\IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @param bool $preserveMtime
- * @param bool $isRename
- * @return bool
- */
public function copyFromStorage(
Storage\IStorage $sourceStorage,
- $sourceInternalPath,
- $targetInternalPath,
+ string $sourceInternalPath,
+ string $targetInternalPath,
$preserveMtime = false,
- $isRename = false
- ) {
+ $isRename = false,
+ ): bool {
// TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed:
// - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage
// - copy the file cache update from $this->copyBetweenStorage to this method
@@ -711,20 +577,14 @@ class Encryption extends Wrapper {
/**
* Update the encrypted cache version in the database
- *
- * @param Storage\IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @param bool $isRename
- * @param bool $keepEncryptionVersion
*/
private function updateEncryptedVersion(
Storage\IStorage $sourceStorage,
- $sourceInternalPath,
- $targetInternalPath,
- $isRename,
- $keepEncryptionVersion
- ) {
+ string $sourceInternalPath,
+ string $targetInternalPath,
+ bool $isRename,
+ bool $keepEncryptionVersion,
+ ): void {
$isEncrypted = $this->encryptionManager->isEnabled() && $this->shouldEncrypt($targetInternalPath);
$cacheInformation = [
'encrypted' => $isEncrypted,
@@ -764,26 +624,19 @@ class Encryption extends Wrapper {
/**
* copy file between two storages
- *
- * @param Storage\IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @param bool $preserveMtime
- * @param bool $isRename
- * @return bool
* @throws \Exception
*/
private function copyBetweenStorage(
Storage\IStorage $sourceStorage,
- $sourceInternalPath,
- $targetInternalPath,
- $preserveMtime,
- $isRename
- ) {
+ string $sourceInternalPath,
+ string $targetInternalPath,
+ bool $preserveMtime,
+ bool $isRename,
+ ): bool {
// for versions we have nothing to do, because versions should always use the
// key from the original file. Just create a 1:1 copy and done
- if ($this->isVersion($targetInternalPath) ||
- $this->isVersion($sourceInternalPath)) {
+ if ($this->isVersion($targetInternalPath)
+ || $this->isVersion($sourceInternalPath)) {
// remember that we try to create a version so that we can detect it during
// fopen($sourceInternalPath) and by-pass the encryption in order to
// create a 1:1 copy of the file
@@ -806,9 +659,8 @@ class Encryption extends Wrapper {
// first copy the keys that we reuse the existing file key on the target location
// and don't create a new one which would break versions for example.
- $mount = $this->mountManager->findByStorageId($sourceStorage->getId());
- if (count($mount) === 1) {
- $mountPoint = $mount[0]->getMountPoint();
+ if ($sourceStorage->instanceOfStorage(Common::class) && $sourceStorage->getMountOption('mount_point')) {
+ $mountPoint = $sourceStorage->getMountOption('mount_point');
$source = $mountPoint . '/' . $sourceInternalPath;
$target = $this->getFullPath($targetInternalPath);
$this->copyKeys($source, $target);
@@ -824,9 +676,9 @@ class Encryption extends Wrapper {
$result = true;
}
if (is_resource($dh)) {
- while ($result and ($file = readdir($dh)) !== false) {
+ while ($result && ($file = readdir($dh)) !== false) {
if (!Filesystem::isIgnoredDir($file)) {
- $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename);
+ $result = $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, $preserveMtime, $isRename);
}
}
}
@@ -834,12 +686,16 @@ class Encryption extends Wrapper {
try {
$source = $sourceStorage->fopen($sourceInternalPath, 'r');
$target = $this->fopen($targetInternalPath, 'w');
- [, $result] = \OC_Helper::streamCopy($source, $target);
+ if ($source === false || $target === false) {
+ $result = false;
+ } else {
+ [, $result] = Files::streamCopy($source, $target, true);
+ }
} finally {
- if (is_resource($source)) {
+ if (isset($source) && $source !== false) {
fclose($source);
}
- if (is_resource($target)) {
+ if (isset($target) && $target !== false) {
fclose($target);
}
}
@@ -858,7 +714,7 @@ class Encryption extends Wrapper {
return (bool)$result;
}
- public function getLocalFile($path) {
+ public function getLocalFile(string $path): string|false {
if ($this->encryptionManager->isEnabled()) {
$cachedFile = $this->getCachedFile($path);
if (is_string($cachedFile)) {
@@ -868,14 +724,14 @@ class Encryption extends Wrapper {
return $this->storage->getLocalFile($path);
}
- public function isLocal() {
+ public function isLocal(): bool {
if ($this->encryptionManager->isEnabled()) {
return false;
}
return $this->storage->isLocal();
}
- public function stat($path) {
+ public function stat(string $path): array|false {
$stat = $this->storage->stat($path);
if (!$stat) {
return false;
@@ -887,8 +743,11 @@ class Encryption extends Wrapper {
return $stat;
}
- public function hash($type, $path, $raw = false) {
+ public function hash(string $type, string $path, bool $raw = false): string|false {
$fh = $this->fopen($path, 'rb');
+ if ($fh === false) {
+ return false;
+ }
$ctx = hash_init($type);
hash_update_stream($ctx, $fh);
fclose($fh);
@@ -901,21 +760,21 @@ class Encryption extends Wrapper {
* @param string $path relative to mount point
* @return string full path including mount point
*/
- protected function getFullPath($path) {
+ protected function getFullPath(string $path): string {
return Filesystem::normalizePath($this->mountPoint . '/' . $path);
}
/**
* read first block of encrypted file, typically this will contain the
* encryption header
- *
- * @param string $path
- * @return string
*/
- protected function readFirstBlock($path) {
+ protected function readFirstBlock(string $path): string {
$firstBlock = '';
if ($this->storage->is_file($path)) {
$handle = $this->storage->fopen($path, 'r');
+ if ($handle === false) {
+ return '';
+ }
$firstBlock = fread($handle, $this->util->getHeaderSize());
fclose($handle);
}
@@ -924,11 +783,8 @@ class Encryption extends Wrapper {
/**
* return header size of given file
- *
- * @param string $path
- * @return int
*/
- protected function getHeaderSize($path) {
+ protected function getHeaderSize(string $path): int {
$headerSize = 0;
$realFile = $this->util->stripPartialFileExtension($path);
if ($this->storage->is_file($realFile)) {
@@ -945,11 +801,8 @@ class Encryption extends Wrapper {
/**
* read header from file
- *
- * @param string $path
- * @return array
*/
- protected function getHeader($path) {
+ protected function getHeader(string $path): array {
$realFile = $this->util->stripPartialFileExtension($path);
$exists = $this->storage->is_file($realFile);
if ($exists) {
@@ -981,12 +834,10 @@ class Encryption extends Wrapper {
/**
* read encryption module needed to read/write the file located at $path
*
- * @param string $path
- * @return null|\OCP\Encryption\IEncryptionModule
* @throws ModuleDoesNotExistsException
* @throws \Exception
*/
- protected function getEncryptionModule($path) {
+ protected function getEncryptionModule(string $path): ?\OCP\Encryption\IEncryptionModule {
$encryptionModule = null;
$header = $this->getHeader($path);
$encryptionModuleId = $this->util->getEncryptionModuleId($header);
@@ -1002,11 +853,7 @@ class Encryption extends Wrapper {
return $encryptionModule;
}
- /**
- * @param string $path
- * @param int $unencryptedSize
- */
- public function updateUnencryptedSize($path, $unencryptedSize) {
+ public function updateUnencryptedSize(string $path, int|float $unencryptedSize): void {
$this->unencryptedSize[$path] = $unencryptedSize;
}
@@ -1015,9 +862,8 @@ class Encryption extends Wrapper {
*
* @param string $source path relative to data/
* @param string $target path relative to data/
- * @return bool
*/
- protected function copyKeys($source, $target) {
+ protected function copyKeys(string $source, string $target): bool {
if (!$this->util->isExcluded($source)) {
return $this->keyStorage->copyKeys($source, $target);
}
@@ -1027,22 +873,16 @@ class Encryption extends Wrapper {
/**
* check if path points to a files version
- *
- * @param $path
- * @return bool
*/
- protected function isVersion($path) {
+ protected function isVersion(string $path): bool {
$normalized = Filesystem::normalizePath($path);
return substr($normalized, 0, strlen('/files_versions/')) === '/files_versions/';
}
/**
* check if the given storage should be encrypted or not
- *
- * @param $path
- * @return bool
*/
- protected function shouldEncrypt($path) {
+ protected function shouldEncrypt(string $path): bool {
$fullPath = $this->getFullPath($path);
$mountPointConfig = $this->mount->getOption('encrypt', true);
if ($mountPointConfig === false) {
@@ -1065,7 +905,10 @@ class Encryption extends Wrapper {
public function writeStream(string $path, $stream, ?int $size = null): int {
// always fall back to fopen
$target = $this->fopen($path, 'w');
- [$count, $result] = \OC_Helper::streamCopy($stream, $target);
+ if ($target === false) {
+ throw new GenericFileException("Failed to open $path for writing");
+ }
+ [$count, $result] = Files::streamCopy($stream, $target, true);
fclose($stream);
fclose($target);
@@ -1084,11 +927,20 @@ class Encryption extends Wrapper {
/**
* Allow temporarily disabling the wrapper
- *
- * @param bool $enabled
- * @return void
*/
public function setEnabled(bool $enabled): void {
$this->enabled = $enabled;
}
+
+ /**
+ * Check if the on-disk data for a file has a valid encrypted header
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function hasValidHeader(string $path): bool {
+ $firstBlock = $this->readFirstBlock($path);
+ $header = $this->util->parseRawHeader($firstBlock);
+ return (count($header) > 0);
+ }
}
diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php
index d072421233a..38b113cef88 100644
--- a/lib/private/Files/Storage/Wrapper/Jail.php
+++ b/lib/private/Files/Storage/Wrapper/Jail.php
@@ -1,30 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
- *
- * @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 OC\Files\Storage\Wrapper;
@@ -32,6 +11,10 @@ use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Cache\Wrapper\JailPropagator;
use OC\Files\Cache\Wrapper\JailWatcher;
use OC\Files\Filesystem;
+use OCP\Files;
+use OCP\Files\Cache\ICache;
+use OCP\Files\Cache\IPropagator;
+use OCP\Files\Cache\IWatcher;
use OCP\Files\Storage\IStorage;
use OCP\Files\Storage\IWriteStreamStorage;
use OCP\Lock\ILockingProvider;
@@ -48,29 +31,29 @@ class Jail extends Wrapper {
protected $rootPath;
/**
- * @param array $arguments ['storage' => $storage, 'root' => $root]
+ * @param array $parameters ['storage' => $storage, 'root' => $root]
*
* $storage: The storage that will be wrapper
* $root: The folder in the wrapped storage that will become the root folder of the wrapped storage
*/
- public function __construct($arguments) {
- parent::__construct($arguments);
- $this->rootPath = $arguments['root'];
+ public function __construct(array $parameters) {
+ parent::__construct($parameters);
+ $this->rootPath = $parameters['root'];
}
- public function getUnjailedPath($path) {
+ public function getUnjailedPath(string $path): string {
return trim(Filesystem::normalizePath($this->rootPath . '/' . $path), '/');
}
/**
* This is separate from Wrapper::getWrapperStorage so we can get the jailed storage consistently even if the jail is inside another wrapper
*/
- public function getUnjailedStorage() {
+ public function getUnjailedStorage(): IStorage {
return $this->storage;
}
- public function getJailedPath($path) {
+ public function getJailedPath(string $path): ?string {
$root = rtrim($this->rootPath, '/') . '/';
if ($path !== $this->rootPath && !str_starts_with($path, $root)) {
@@ -81,427 +64,178 @@ class Jail extends Wrapper {
}
}
- public function getId() {
+ public function getId(): string {
return parent::getId();
}
- /**
- * see https://www.php.net/manual/en/function.mkdir.php
- *
- * @param string $path
- * @return bool
- */
- public function mkdir($path) {
+ public function mkdir(string $path): bool {
return $this->getWrapperStorage()->mkdir($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.rmdir.php
- *
- * @param string $path
- * @return bool
- */
- public function rmdir($path) {
+ public function rmdir(string $path): bool {
return $this->getWrapperStorage()->rmdir($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.opendir.php
- *
- * @param string $path
- * @return resource|false
- */
- public function opendir($path) {
+ public function opendir(string $path) {
return $this->getWrapperStorage()->opendir($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.is_dir.php
- *
- * @param string $path
- * @return bool
- */
- public function is_dir($path) {
+ public function is_dir(string $path): bool {
return $this->getWrapperStorage()->is_dir($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.is_file.php
- *
- * @param string $path
- * @return bool
- */
- public function is_file($path) {
+ public function is_file(string $path): bool {
return $this->getWrapperStorage()->is_file($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.stat.php
- * only the following keys are required in the result: size and mtime
- *
- * @param string $path
- * @return array|bool
- */
- public function stat($path) {
+ public function stat(string $path): array|false {
return $this->getWrapperStorage()->stat($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.filetype.php
- *
- * @param string $path
- * @return bool
- */
- public function filetype($path) {
+ public function filetype(string $path): string|false {
return $this->getWrapperStorage()->filetype($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.filesize.php
- * The result for filesize when called on a folder is required to be 0
- */
- public function filesize($path): false|int|float {
+ public function filesize(string $path): int|float|false {
return $this->getWrapperStorage()->filesize($this->getUnjailedPath($path));
}
- /**
- * check if a file can be created in $path
- *
- * @param string $path
- * @return bool
- */
- public function isCreatable($path) {
+ public function isCreatable(string $path): bool {
return $this->getWrapperStorage()->isCreatable($this->getUnjailedPath($path));
}
- /**
- * check if a file can be read
- *
- * @param string $path
- * @return bool
- */
- public function isReadable($path) {
+ public function isReadable(string $path): bool {
return $this->getWrapperStorage()->isReadable($this->getUnjailedPath($path));
}
- /**
- * check if a file can be written to
- *
- * @param string $path
- * @return bool
- */
- public function isUpdatable($path) {
+ public function isUpdatable(string $path): bool {
return $this->getWrapperStorage()->isUpdatable($this->getUnjailedPath($path));
}
- /**
- * check if a file can be deleted
- *
- * @param string $path
- * @return bool
- */
- public function isDeletable($path) {
+ public function isDeletable(string $path): bool {
return $this->getWrapperStorage()->isDeletable($this->getUnjailedPath($path));
}
- /**
- * check if a file can be shared
- *
- * @param string $path
- * @return bool
- */
- public function isSharable($path) {
+ public function isSharable(string $path): bool {
return $this->getWrapperStorage()->isSharable($this->getUnjailedPath($path));
}
- /**
- * get the full permissions of a path.
- * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
- *
- * @param string $path
- * @return int
- */
- public function getPermissions($path) {
+ public function getPermissions(string $path): int {
return $this->getWrapperStorage()->getPermissions($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.file_exists.php
- *
- * @param string $path
- * @return bool
- */
- public function file_exists($path) {
+ public function file_exists(string $path): bool {
return $this->getWrapperStorage()->file_exists($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.filemtime.php
- *
- * @param string $path
- * @return int|bool
- */
- public function filemtime($path) {
+ public function filemtime(string $path): int|false {
return $this->getWrapperStorage()->filemtime($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.file_get_contents.php
- *
- * @param string $path
- * @return string|false
- */
- public function file_get_contents($path) {
+ public function file_get_contents(string $path): string|false {
return $this->getWrapperStorage()->file_get_contents($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.file_put_contents.php
- *
- * @param string $path
- * @param mixed $data
- * @return int|float|false
- */
- public function file_put_contents($path, $data) {
+ public function file_put_contents(string $path, mixed $data): int|float|false {
return $this->getWrapperStorage()->file_put_contents($this->getUnjailedPath($path), $data);
}
- /**
- * see https://www.php.net/manual/en/function.unlink.php
- *
- * @param string $path
- * @return bool
- */
- public function unlink($path) {
+ public function unlink(string $path): bool {
return $this->getWrapperStorage()->unlink($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.rename.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function rename($source, $target) {
+ public function rename(string $source, string $target): bool {
return $this->getWrapperStorage()->rename($this->getUnjailedPath($source), $this->getUnjailedPath($target));
}
- /**
- * see https://www.php.net/manual/en/function.copy.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function copy($source, $target) {
+ public function copy(string $source, string $target): bool {
return $this->getWrapperStorage()->copy($this->getUnjailedPath($source), $this->getUnjailedPath($target));
}
- /**
- * see https://www.php.net/manual/en/function.fopen.php
- *
- * @param string $path
- * @param string $mode
- * @return resource|bool
- */
- public function fopen($path, $mode) {
+ public function fopen(string $path, string $mode) {
return $this->getWrapperStorage()->fopen($this->getUnjailedPath($path), $mode);
}
- /**
- * get the mimetype for a file or folder
- * The mimetype for a folder is required to be "httpd/unix-directory"
- *
- * @param string $path
- * @return string|bool
- */
- public function getMimeType($path) {
+ public function getMimeType(string $path): string|false {
return $this->getWrapperStorage()->getMimeType($this->getUnjailedPath($path));
}
- /**
- * see https://www.php.net/manual/en/function.hash.php
- *
- * @param string $type
- * @param string $path
- * @param bool $raw
- * @return string|bool
- */
- public function hash($type, $path, $raw = false) {
+ public function hash(string $type, string $path, bool $raw = false): string|false {
return $this->getWrapperStorage()->hash($type, $this->getUnjailedPath($path), $raw);
}
- /**
- * see https://www.php.net/manual/en/function.free_space.php
- *
- * @param string $path
- * @return int|float|bool
- */
- public function free_space($path) {
+ public function free_space(string $path): int|float|false {
return $this->getWrapperStorage()->free_space($this->getUnjailedPath($path));
}
- /**
- * search for occurrences of $query in file names
- *
- * @param string $query
- * @return array|bool
- */
- public function search($query) {
- return $this->getWrapperStorage()->search($query);
- }
-
- /**
- * see https://www.php.net/manual/en/function.touch.php
- * If the backend does not support the operation, false should be returned
- *
- * @param string $path
- * @param int $mtime
- * @return bool
- */
- public function touch($path, $mtime = null) {
+ public function touch(string $path, ?int $mtime = null): bool {
return $this->getWrapperStorage()->touch($this->getUnjailedPath($path), $mtime);
}
- /**
- * get the path to a local version of the file.
- * The local version of the file can be temporary and doesn't have to be persistent across requests
- *
- * @param string $path
- * @return string|false
- */
- public function getLocalFile($path) {
+ public function getLocalFile(string $path): string|false {
return $this->getWrapperStorage()->getLocalFile($this->getUnjailedPath($path));
}
- /**
- * check if a file or folder has been updated since $time
- *
- * @param string $path
- * @param int $time
- * @return bool
- *
- * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
- * returning true for other changes in the folder is optional
- */
- public function hasUpdated($path, $time) {
+ public function hasUpdated(string $path, int $time): bool {
return $this->getWrapperStorage()->hasUpdated($this->getUnjailedPath($path), $time);
}
- /**
- * get a cache instance for the storage
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage|null (optional) the storage to pass to the cache
- * @return \OC\Files\Cache\Cache
- */
- public function getCache($path = '', $storage = null) {
+ public function getCache(string $path = '', ?IStorage $storage = null): ICache {
$sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path));
return new CacheJail($sourceCache, $this->rootPath);
}
- /**
- * get the user id of the owner of a file or folder
- *
- * @param string $path
- * @return string
- */
- public function getOwner($path) {
+ public function getOwner(string $path): string|false {
return $this->getWrapperStorage()->getOwner($this->getUnjailedPath($path));
}
- /**
- * get a watcher instance for the cache
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
- * @return \OC\Files\Cache\Watcher
- */
- public function getWatcher($path = '', $storage = null) {
+ public function getWatcher(string $path = '', ?IStorage $storage = null): IWatcher {
$sourceWatcher = $this->getWrapperStorage()->getWatcher($this->getUnjailedPath($path), $this->getWrapperStorage());
return new JailWatcher($sourceWatcher, $this->rootPath);
}
- /**
- * get the ETag for a file or folder
- *
- * @param string $path
- * @return string|false
- */
- public function getETag($path) {
+ public function getETag(string $path): string|false {
return $this->getWrapperStorage()->getETag($this->getUnjailedPath($path));
}
- public function getMetaData($path) {
+ public function getMetaData(string $path): ?array {
return $this->getWrapperStorage()->getMetaData($this->getUnjailedPath($path));
}
- /**
- * @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) {
+ public function acquireLock(string $path, int $type, ILockingProvider $provider): void {
$this->getWrapperStorage()->acquireLock($this->getUnjailedPath($path), $type, $provider);
}
- /**
- * @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) {
+ public function releaseLock(string $path, int $type, ILockingProvider $provider): void {
$this->getWrapperStorage()->releaseLock($this->getUnjailedPath($path), $type, $provider);
}
- /**
- * @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) {
+ public function changeLock(string $path, int $type, ILockingProvider $provider): void {
$this->getWrapperStorage()->changeLock($this->getUnjailedPath($path), $type, $provider);
}
/**
* Resolve the path for the source of the share
- *
- * @param string $path
- * @return array
*/
- public function resolvePath($path) {
+ public function resolvePath(string $path): array {
return [$this->getWrapperStorage(), $this->getUnjailedPath($path)];
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if ($sourceStorage === $this) {
return $this->copy($sourceInternalPath, $targetInternalPath);
}
return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $this->getUnjailedPath($targetInternalPath));
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if ($sourceStorage === $this) {
return $this->rename($sourceInternalPath, $targetInternalPath);
}
return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $this->getUnjailedPath($targetInternalPath));
}
- public function getPropagator($storage = null) {
+ public function getPropagator(?IStorage $storage = null): IPropagator {
if (isset($this->propagator)) {
return $this->propagator;
}
@@ -520,14 +254,14 @@ class Jail extends Wrapper {
return $storage->writeStream($this->getUnjailedPath($path), $stream, $size);
} else {
$target = $this->fopen($path, 'w');
- [$count, $result] = \OC_Helper::streamCopy($stream, $target);
+ $count = Files::streamCopy($stream, $target);
fclose($stream);
fclose($target);
return $count;
}
}
- public function getDirectoryContent($directory): \Traversable {
+ public function getDirectoryContent(string $directory): \Traversable {
return $this->getWrapperStorage()->getDirectoryContent($this->getUnjailedPath($directory));
}
}
diff --git a/lib/private/Files/Storage/Wrapper/KnownMtime.php b/lib/private/Files/Storage/Wrapper/KnownMtime.php
index 9a71dc90367..657c6c9250c 100644
--- a/lib/private/Files/Storage/Wrapper/KnownMtime.php
+++ b/lib/private/Files/Storage/Wrapper/KnownMtime.php
@@ -1,5 +1,9 @@
<?php
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
namespace OC\Files\Storage\Wrapper;
use OCP\Cache\CappedMemoryCache;
@@ -16,13 +20,13 @@ class KnownMtime extends Wrapper {
private CappedMemoryCache $knowMtimes;
private ClockInterface $clock;
- public function __construct($arguments) {
- parent::__construct($arguments);
+ public function __construct(array $parameters) {
+ parent::__construct($parameters);
$this->knowMtimes = new CappedMemoryCache();
- $this->clock = $arguments['clock'];
+ $this->clock = $parameters['clock'];
}
- public function file_put_contents($path, $data) {
+ public function file_put_contents(string $path, mixed $data): int|float|false {
$result = parent::file_put_contents($path, $data);
if ($result) {
$now = $this->clock->now()->getTimestamp();
@@ -31,7 +35,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function stat($path) {
+ public function stat(string $path): array|false {
$stat = parent::stat($path);
if ($stat) {
$this->applyKnownMtime($path, $stat);
@@ -39,7 +43,7 @@ class KnownMtime extends Wrapper {
return $stat;
}
- public function getMetaData($path) {
+ public function getMetaData(string $path): ?array {
$stat = parent::getMetaData($path);
if ($stat) {
$this->applyKnownMtime($path, $stat);
@@ -47,19 +51,19 @@ class KnownMtime extends Wrapper {
return $stat;
}
- private function applyKnownMtime(string $path, array &$stat) {
+ private function applyKnownMtime(string $path, array &$stat): void {
if (isset($stat['mtime'])) {
$knownMtime = $this->knowMtimes->get($path) ?? 0;
$stat['mtime'] = max($stat['mtime'], $knownMtime);
}
}
- public function filemtime($path) {
+ public function filemtime(string $path): int|false {
$knownMtime = $this->knowMtimes->get($path) ?? 0;
return max(parent::filemtime($path), $knownMtime);
}
- public function mkdir($path) {
+ public function mkdir(string $path): bool {
$result = parent::mkdir($path);
if ($result) {
$this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
@@ -67,7 +71,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function rmdir($path) {
+ public function rmdir(string $path): bool {
$result = parent::rmdir($path);
if ($result) {
$this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
@@ -75,7 +79,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function unlink($path) {
+ public function unlink(string $path): bool {
$result = parent::unlink($path);
if ($result) {
$this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
@@ -83,7 +87,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function rename($source, $target) {
+ public function rename(string $source, string $target): bool {
$result = parent::rename($source, $target);
if ($result) {
$this->knowMtimes->set($target, $this->clock->now()->getTimestamp());
@@ -92,7 +96,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function copy($source, $target) {
+ public function copy(string $source, string $target): bool {
$result = parent::copy($source, $target);
if ($result) {
$this->knowMtimes->set($target, $this->clock->now()->getTimestamp());
@@ -100,7 +104,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function fopen($path, $mode) {
+ public function fopen(string $path, string $mode) {
$result = parent::fopen($path, $mode);
if ($result && $mode === 'w') {
$this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
@@ -108,7 +112,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function touch($path, $mtime = null) {
+ public function touch(string $path, ?int $mtime = null): bool {
$result = parent::touch($path, $mtime);
if ($result) {
$this->knowMtimes->set($path, $mtime ?? $this->clock->now()->getTimestamp());
@@ -116,7 +120,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
$result = parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
if ($result) {
$this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp());
@@ -124,7 +128,7 @@ class KnownMtime extends Wrapper {
return $result;
}
- public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
$result = parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
if ($result) {
$this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp());
diff --git a/lib/private/Files/Storage/Wrapper/PermissionsMask.php b/lib/private/Files/Storage/Wrapper/PermissionsMask.php
index a79eaad0569..684040146ba 100644
--- a/lib/private/Files/Storage/Wrapper/PermissionsMask.php
+++ b/lib/private/Files/Storage/Wrapper/PermissionsMask.php
@@ -1,34 +1,15 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @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 Stefan Weil <sw@weilnetz.de>
- *
- * @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 OC\Files\Storage\Wrapper;
use OC\Files\Cache\Wrapper\CachePermissionsMask;
use OCP\Constants;
+use OCP\Files\Storage\IStorage;
/**
* Mask the permissions of a storage
@@ -44,41 +25,41 @@ class PermissionsMask extends Wrapper {
private $mask;
/**
- * @param array $arguments ['storage' => $storage, 'mask' => $mask]
+ * @param array $parameters ['storage' => $storage, 'mask' => $mask]
*
* $storage: The storage the permissions mask should be applied on
* $mask: The permission bits that should be kept, a combination of the \OCP\Constant::PERMISSION_ constants
*/
- public function __construct($arguments) {
- parent::__construct($arguments);
- $this->mask = $arguments['mask'];
+ public function __construct(array $parameters) {
+ parent::__construct($parameters);
+ $this->mask = $parameters['mask'];
}
- private function checkMask($permissions) {
+ private function checkMask(int $permissions): bool {
return ($this->mask & $permissions) === $permissions;
}
- public function isUpdatable($path) {
+ public function isUpdatable(string $path): bool {
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::isUpdatable($path);
}
- public function isCreatable($path) {
+ public function isCreatable(string $path): bool {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::isCreatable($path);
}
- public function isDeletable($path) {
+ public function isDeletable(string $path): bool {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::isDeletable($path);
}
- public function isSharable($path) {
+ public function isSharable(string $path): bool {
return $this->checkMask(Constants::PERMISSION_SHARE) and parent::isSharable($path);
}
- public function getPermissions($path) {
+ public function getPermissions(string $path): int {
return $this->storage->getPermissions($path) & $this->mask;
}
- public function rename($source, $target) {
+ public function rename(string $source, string $target): bool {
//This is a rename of the transfer file to the original file
if (dirname($source) === dirname($target) && strpos($source, '.ocTransferId') > 0) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::rename($source, $target);
@@ -86,33 +67,33 @@ class PermissionsMask extends Wrapper {
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($source, $target);
}
- public function copy($source, $target) {
+ public function copy(string $source, string $target): bool {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($source, $target);
}
- public function touch($path, $mtime = null) {
+ public function touch(string $path, ?int $mtime = null): bool {
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE;
return $this->checkMask($permissions) and parent::touch($path, $mtime);
}
- public function mkdir($path) {
+ public function mkdir(string $path): bool {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::mkdir($path);
}
- public function rmdir($path) {
+ public function rmdir(string $path): bool {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::rmdir($path);
}
- public function unlink($path) {
+ public function unlink(string $path): bool {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::unlink($path);
}
- public function file_put_contents($path, $data) {
+ public function file_put_contents(string $path, mixed $data): int|float|false {
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE;
return $this->checkMask($permissions) ? parent::file_put_contents($path, $data) : false;
}
- public function fopen($path, $mode) {
+ public function fopen(string $path, string $mode) {
if ($mode === 'r' or $mode === 'rb') {
return parent::fopen($path, $mode);
} else {
@@ -121,14 +102,7 @@ class PermissionsMask extends Wrapper {
}
}
- /**
- * get a cache instance for the storage
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
- * @return \OC\Files\Cache\Cache
- */
- public function getCache($path = '', $storage = null) {
+ public function getCache(string $path = '', ?IStorage $storage = null): \OCP\Files\Cache\ICache {
if (!$storage) {
$storage = $this;
}
@@ -136,7 +110,7 @@ class PermissionsMask extends Wrapper {
return new CachePermissionsMask($sourceCache, $this->mask);
}
- public function getMetaData($path) {
+ public function getMetaData(string $path): ?array {
$data = parent::getMetaData($path);
if ($data && isset($data['permissions'])) {
@@ -146,14 +120,14 @@ class PermissionsMask extends Wrapper {
return $data;
}
- public function getScanner($path = '', $storage = null) {
+ public function getScanner(string $path = '', ?IStorage $storage = null): \OCP\Files\Cache\IScanner {
if (!$storage) {
$storage = $this->storage;
}
return parent::getScanner($path, $storage);
}
- public function getDirectoryContent($directory): \Traversable {
+ public function getDirectoryContent(string $directory): \Traversable {
foreach ($this->getWrapperStorage()->getDirectoryContent($directory) as $data) {
$data['scan_permissions'] = $data['scan_permissions'] ?? $data['permissions'];
$data['permissions'] &= $this->mask;
diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php
index 35dbc9fcd26..35a265f8c8e 100644
--- a/lib/private/Files/Storage/Wrapper/Quota.php
+++ b/lib/private/Files/Storage/Wrapper/Quota.php
@@ -1,34 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @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 Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
- * @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 OC\Files\Storage\Wrapper;
@@ -46,11 +21,12 @@ class Quota extends Wrapper {
protected string $sizeRoot;
private SystemConfig $config;
private bool $quotaIncludeExternalStorage;
+ private bool $enabled = true;
/**
* @param array $parameters
*/
- public function __construct($parameters) {
+ public function __construct(array $parameters) {
parent::__construct($parameters);
$this->quota = $parameters['quota'] ?? null;
$this->quotaCallback = $parameters['quotaCallback'] ?? null;
@@ -58,14 +34,11 @@ class Quota extends Wrapper {
$this->quotaIncludeExternalStorage = $parameters['include_external_storage'] ?? false;
}
- /**
- * @return int|float quota value
- */
public function getQuota(): int|float {
if ($this->quota === null) {
$quotaCallback = $this->quotaCallback;
if ($quotaCallback === null) {
- throw new \Exception("No quota or quota callback provider");
+ throw new \Exception('No quota or quota callback provider');
}
$this->quota = $quotaCallback();
}
@@ -74,15 +47,13 @@ class Quota extends Wrapper {
}
private function hasQuota(): bool {
+ if (!$this->enabled) {
+ return false;
+ }
return $this->getQuota() !== FileInfo::SPACE_UNLIMITED;
}
- /**
- * @param string $path
- * @param IStorage $storage
- * @return int|float
- */
- protected function getSize($path, $storage = null) {
+ protected function getSize(string $path, ?IStorage $storage = null): int|float {
if ($this->quotaIncludeExternalStorage) {
$rootInfo = Filesystem::getFileInfo('', 'ext');
if ($rootInfo) {
@@ -100,13 +71,7 @@ class Quota extends Wrapper {
}
}
- /**
- * Get free space as limited by the quota
- *
- * @param string $path
- * @return int|float|bool
- */
- public function free_space($path) {
+ public function free_space(string $path): int|float|false {
if (!$this->hasQuota()) {
return $this->storage->free_space($path);
}
@@ -126,14 +91,7 @@ class Quota extends Wrapper {
}
}
- /**
- * see https://www.php.net/manual/en/function.file_put_contents.php
- *
- * @param string $path
- * @param mixed $data
- * @return int|float|false
- */
- public function file_put_contents($path, $data) {
+ public function file_put_contents(string $path, mixed $data): int|float|false {
if (!$this->hasQuota()) {
return $this->storage->file_put_contents($path, $data);
}
@@ -145,14 +103,7 @@ class Quota extends Wrapper {
}
}
- /**
- * see https://www.php.net/manual/en/function.copy.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function copy($source, $target) {
+ public function copy(string $source, string $target): bool {
if (!$this->hasQuota()) {
return $this->storage->copy($source, $target);
}
@@ -164,14 +115,7 @@ class Quota extends Wrapper {
}
}
- /**
- * see https://www.php.net/manual/en/function.fopen.php
- *
- * @param string $path
- * @param string $mode
- * @return resource|bool
- */
- public function fopen($path, $mode) {
+ public function fopen(string $path, string $mode) {
if (!$this->hasQuota()) {
return $this->storage->fopen($path, $mode);
}
@@ -195,10 +139,9 @@ class Quota extends Wrapper {
* Checks whether the given path is a part file
*
* @param string $path Path that may identify a .part file
- * @return bool
* @note this is needed for reusing keys
*/
- private function isPartFile($path) {
+ private function isPartFile(string $path): bool {
$extension = pathinfo($path, PATHINFO_EXTENSION);
return ($extension === 'part');
@@ -207,17 +150,11 @@ class Quota extends Wrapper {
/**
* Only apply quota for files, not metadata, trash or others
*/
- private function shouldApplyQuota(string $path): bool {
+ protected function shouldApplyQuota(string $path): bool {
return str_starts_with(ltrim($path, '/'), 'files/');
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if (!$this->hasQuota()) {
return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
}
@@ -229,13 +166,7 @@ class Quota extends Wrapper {
}
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if (!$this->hasQuota()) {
return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
}
@@ -247,7 +178,7 @@ class Quota extends Wrapper {
}
}
- public function mkdir($path) {
+ public function mkdir(string $path): bool {
if (!$this->hasQuota()) {
return $this->storage->mkdir($path);
}
@@ -259,7 +190,7 @@ class Quota extends Wrapper {
return parent::mkdir($path);
}
- public function touch($path, $mtime = null) {
+ public function touch(string $path, ?int $mtime = null): bool {
if (!$this->hasQuota()) {
return $this->storage->touch($path, $mtime);
}
@@ -270,4 +201,8 @@ class Quota extends Wrapper {
return parent::touch($path, $mtime);
}
+
+ public function enableQuota(bool $enabled): void {
+ $this->enabled = $enabled;
+ }
}
diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php
index 9b7ca0214d1..7af11dd5ef7 100644
--- a/lib/private/Files/Storage/Wrapper/Wrapper.php
+++ b/lib/private/Files/Storage/Wrapper/Wrapper.php
@@ -1,38 +1,20 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
- * @author Vincent Petry <vincent@nextcloud.com>
- * @author Vinicius Cubas Brand <vinicius@eita.org.br>
- *
- * @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 OC\Files\Storage\Wrapper;
use OC\Files\Storage\FailedStorage;
-use OCP\Files\InvalidPathException;
+use OC\Files\Storage\Storage;
+use OCP\Files;
+use OCP\Files\Cache\ICache;
+use OCP\Files\Cache\IPropagator;
+use OCP\Files\Cache\IScanner;
+use OCP\Files\Cache\IUpdater;
+use OCP\Files\Cache\IWatcher;
use OCP\Files\Storage\ILockingStorage;
use OCP\Files\Storage\IStorage;
use OCP\Files\Storage\IWriteStreamStorage;
@@ -55,16 +37,13 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
/**
* @param array $parameters
*/
- public function __construct($parameters) {
+ public function __construct(array $parameters) {
$this->storage = $parameters['storage'];
}
- /**
- * @return \OC\Files\Storage\Storage
- */
- public function getWrapperStorage() {
+ public function getWrapperStorage(): Storage {
if (!$this->storage) {
- $message = "storage wrapper " . get_class($this) . " doesn't have a wrapped storage set";
+ $message = 'storage wrapper ' . get_class($this) . " doesn't have a wrapped storage set";
$logger = Server::get(LoggerInterface::class);
$logger->error($message);
$this->storage = new FailedStorage(['exception' => new \Exception($message)]);
@@ -72,430 +51,178 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $this->storage;
}
- /**
- * Get the identifier for the storage,
- * the returned id should be the same for every storage object that is created with the same parameters
- * and two storage objects with the same id should refer to two storages that display the same files.
- *
- * @return string
- */
- public function getId() {
+ public function getId(): string {
return $this->getWrapperStorage()->getId();
}
- /**
- * see https://www.php.net/manual/en/function.mkdir.php
- *
- * @param string $path
- * @return bool
- */
- public function mkdir($path) {
+ public function mkdir(string $path): bool {
return $this->getWrapperStorage()->mkdir($path);
}
- /**
- * see https://www.php.net/manual/en/function.rmdir.php
- *
- * @param string $path
- * @return bool
- */
- public function rmdir($path) {
+ public function rmdir(string $path): bool {
return $this->getWrapperStorage()->rmdir($path);
}
- /**
- * see https://www.php.net/manual/en/function.opendir.php
- *
- * @param string $path
- * @return resource|false
- */
- public function opendir($path) {
+ public function opendir(string $path) {
return $this->getWrapperStorage()->opendir($path);
}
- /**
- * see https://www.php.net/manual/en/function.is_dir.php
- *
- * @param string $path
- * @return bool
- */
- public function is_dir($path) {
+ public function is_dir(string $path): bool {
return $this->getWrapperStorage()->is_dir($path);
}
- /**
- * see https://www.php.net/manual/en/function.is_file.php
- *
- * @param string $path
- * @return bool
- */
- public function is_file($path) {
+ public function is_file(string $path): bool {
return $this->getWrapperStorage()->is_file($path);
}
- /**
- * see https://www.php.net/manual/en/function.stat.php
- * only the following keys are required in the result: size and mtime
- *
- * @param string $path
- * @return array|bool
- */
- public function stat($path) {
+ public function stat(string $path): array|false {
return $this->getWrapperStorage()->stat($path);
}
- /**
- * see https://www.php.net/manual/en/function.filetype.php
- *
- * @param string $path
- * @return string|bool
- */
- public function filetype($path) {
+ public function filetype(string $path): string|false {
return $this->getWrapperStorage()->filetype($path);
}
- /**
- * see https://www.php.net/manual/en/function.filesize.php
- * The result for filesize when called on a folder is required to be 0
- */
- public function filesize($path): false|int|float {
+ public function filesize(string $path): int|float|false {
return $this->getWrapperStorage()->filesize($path);
}
- /**
- * check if a file can be created in $path
- *
- * @param string $path
- * @return bool
- */
- public function isCreatable($path) {
+ public function isCreatable(string $path): bool {
return $this->getWrapperStorage()->isCreatable($path);
}
- /**
- * check if a file can be read
- *
- * @param string $path
- * @return bool
- */
- public function isReadable($path) {
+ public function isReadable(string $path): bool {
return $this->getWrapperStorage()->isReadable($path);
}
- /**
- * check if a file can be written to
- *
- * @param string $path
- * @return bool
- */
- public function isUpdatable($path) {
+ public function isUpdatable(string $path): bool {
return $this->getWrapperStorage()->isUpdatable($path);
}
- /**
- * check if a file can be deleted
- *
- * @param string $path
- * @return bool
- */
- public function isDeletable($path) {
+ public function isDeletable(string $path): bool {
return $this->getWrapperStorage()->isDeletable($path);
}
- /**
- * check if a file can be shared
- *
- * @param string $path
- * @return bool
- */
- public function isSharable($path) {
+ public function isSharable(string $path): bool {
return $this->getWrapperStorage()->isSharable($path);
}
- /**
- * get the full permissions of a path.
- * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
- *
- * @param string $path
- * @return int
- */
- public function getPermissions($path) {
+ public function getPermissions(string $path): int {
return $this->getWrapperStorage()->getPermissions($path);
}
- /**
- * see https://www.php.net/manual/en/function.file_exists.php
- *
- * @param string $path
- * @return bool
- */
- public function file_exists($path) {
+ public function file_exists(string $path): bool {
return $this->getWrapperStorage()->file_exists($path);
}
- /**
- * see https://www.php.net/manual/en/function.filemtime.php
- *
- * @param string $path
- * @return int|bool
- */
- public function filemtime($path) {
+ public function filemtime(string $path): int|false {
return $this->getWrapperStorage()->filemtime($path);
}
- /**
- * see https://www.php.net/manual/en/function.file_get_contents.php
- *
- * @param string $path
- * @return string|false
- */
- public function file_get_contents($path) {
+ public function file_get_contents(string $path): string|false {
return $this->getWrapperStorage()->file_get_contents($path);
}
- /**
- * see https://www.php.net/manual/en/function.file_put_contents.php
- *
- * @param string $path
- * @param mixed $data
- * @return int|float|false
- */
- public function file_put_contents($path, $data) {
+ public function file_put_contents(string $path, mixed $data): int|float|false {
return $this->getWrapperStorage()->file_put_contents($path, $data);
}
- /**
- * see https://www.php.net/manual/en/function.unlink.php
- *
- * @param string $path
- * @return bool
- */
- public function unlink($path) {
+ public function unlink(string $path): bool {
return $this->getWrapperStorage()->unlink($path);
}
- /**
- * see https://www.php.net/manual/en/function.rename.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function rename($source, $target) {
+ public function rename(string $source, string $target): bool {
return $this->getWrapperStorage()->rename($source, $target);
}
- /**
- * see https://www.php.net/manual/en/function.copy.php
- *
- * @param string $source
- * @param string $target
- * @return bool
- */
- public function copy($source, $target) {
+ public function copy(string $source, string $target): bool {
return $this->getWrapperStorage()->copy($source, $target);
}
- /**
- * see https://www.php.net/manual/en/function.fopen.php
- *
- * @param string $path
- * @param string $mode
- * @return resource|bool
- */
- public function fopen($path, $mode) {
+ public function fopen(string $path, string $mode) {
return $this->getWrapperStorage()->fopen($path, $mode);
}
- /**
- * get the mimetype for a file or folder
- * The mimetype for a folder is required to be "httpd/unix-directory"
- *
- * @param string $path
- * @return string|bool
- */
- public function getMimeType($path) {
+ public function getMimeType(string $path): string|false {
return $this->getWrapperStorage()->getMimeType($path);
}
- /**
- * see https://www.php.net/manual/en/function.hash.php
- *
- * @param string $type
- * @param string $path
- * @param bool $raw
- * @return string|bool
- */
- public function hash($type, $path, $raw = false) {
+ public function hash(string $type, string $path, bool $raw = false): string|false {
return $this->getWrapperStorage()->hash($type, $path, $raw);
}
- /**
- * see https://www.php.net/manual/en/function.free_space.php
- *
- * @param string $path
- * @return int|float|bool
- */
- public function free_space($path) {
+ public function free_space(string $path): int|float|false {
return $this->getWrapperStorage()->free_space($path);
}
- /**
- * search for occurrences of $query in file names
- *
- * @param string $query
- * @return array|bool
- */
- public function search($query) {
- return $this->getWrapperStorage()->search($query);
- }
-
- /**
- * see https://www.php.net/manual/en/function.touch.php
- * If the backend does not support the operation, false should be returned
- *
- * @param string $path
- * @param int $mtime
- * @return bool
- */
- public function touch($path, $mtime = null) {
+ public function touch(string $path, ?int $mtime = null): bool {
return $this->getWrapperStorage()->touch($path, $mtime);
}
- /**
- * get the path to a local version of the file.
- * The local version of the file can be temporary and doesn't have to be persistent across requests
- *
- * @param string $path
- * @return string|false
- */
- public function getLocalFile($path) {
+ public function getLocalFile(string $path): string|false {
return $this->getWrapperStorage()->getLocalFile($path);
}
- /**
- * check if a file or folder has been updated since $time
- *
- * @param string $path
- * @param int $time
- * @return bool
- *
- * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
- * returning true for other changes in the folder is optional
- */
- public function hasUpdated($path, $time) {
+ public function hasUpdated(string $path, int $time): bool {
return $this->getWrapperStorage()->hasUpdated($path, $time);
}
- /**
- * get a cache instance for the storage
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage|null (optional) the storage to pass to the cache
- * @return \OC\Files\Cache\Cache
- */
- public function getCache($path = '', $storage = null) {
+ public function getCache(string $path = '', ?IStorage $storage = null): ICache {
if (!$storage) {
$storage = $this;
}
return $this->getWrapperStorage()->getCache($path, $storage);
}
- /**
- * get a scanner instance for the storage
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
- * @return \OC\Files\Cache\Scanner
- */
- public function getScanner($path = '', $storage = null) {
+ public function getScanner(string $path = '', ?IStorage $storage = null): IScanner {
if (!$storage) {
$storage = $this;
}
return $this->getWrapperStorage()->getScanner($path, $storage);
}
-
- /**
- * get the user id of the owner of a file or folder
- *
- * @param string $path
- * @return string
- */
- public function getOwner($path) {
+ public function getOwner(string $path): string|false {
return $this->getWrapperStorage()->getOwner($path);
}
- /**
- * get a watcher instance for the cache
- *
- * @param string $path
- * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
- * @return \OC\Files\Cache\Watcher
- */
- public function getWatcher($path = '', $storage = null) {
+ public function getWatcher(string $path = '', ?IStorage $storage = null): IWatcher {
if (!$storage) {
$storage = $this;
}
return $this->getWrapperStorage()->getWatcher($path, $storage);
}
- public function getPropagator($storage = null) {
+ public function getPropagator(?IStorage $storage = null): IPropagator {
if (!$storage) {
$storage = $this;
}
return $this->getWrapperStorage()->getPropagator($storage);
}
- public function getUpdater($storage = null) {
+ public function getUpdater(?IStorage $storage = null): IUpdater {
if (!$storage) {
$storage = $this;
}
return $this->getWrapperStorage()->getUpdater($storage);
}
- /**
- * @return \OC\Files\Cache\Storage
- */
- public function getStorageCache() {
+ public function getStorageCache(): \OC\Files\Cache\Storage {
return $this->getWrapperStorage()->getStorageCache();
}
- /**
- * get the ETag for a file or folder
- *
- * @param string $path
- * @return string|false
- */
- public function getETag($path) {
+ public function getETag(string $path): string|false {
return $this->getWrapperStorage()->getETag($path);
}
- /**
- * Returns true
- *
- * @return true
- */
- public function test() {
+ public function test(): bool {
return $this->getWrapperStorage()->test();
}
- /**
- * Returns the wrapped storage's value for isLocal()
- *
- * @return bool wrapped storage's isLocal() value
- */
- public function isLocal() {
+ public function isLocal(): bool {
return $this->getWrapperStorage()->isLocal();
}
- /**
- * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
- *
- * @param class-string<IStorage> $class
- * @return bool
- */
- public function instanceOfStorage($class) {
+ public function instanceOfStorage(string $class): bool {
if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
// FIXME Temporary fix to keep existing checks working
$class = '\OCA\Files_Sharing\SharedStorage';
@@ -508,7 +235,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
* @psalm-param class-string<T> $class
* @psalm-return T|null
*/
- public function getInstanceOfStorage(string $class) {
+ public function getInstanceOfStorage(string $class): ?IStorage {
$storage = $this;
while ($storage instanceof Wrapper) {
if ($storage instanceof $class) {
@@ -525,61 +252,29 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
/**
* Pass any methods custom to specific storage implementations to the wrapped storage
*
- * @param string $method
- * @param array $args
* @return mixed
*/
- public function __call($method, $args) {
+ public function __call(string $method, array $args) {
return call_user_func_array([$this->getWrapperStorage(), $method], $args);
}
- /**
- * A custom storage implementation can return an url for direct download of a give file.
- *
- * For now the returned array can hold the parameter url - in future more attributes might follow.
- *
- * @param string $path
- * @return array|bool
- */
- public function getDirectDownload($path) {
+ public function getDirectDownload(string $path): array|false {
return $this->getWrapperStorage()->getDirectDownload($path);
}
- /**
- * Get availability of the storage
- *
- * @return array [ available, last_checked ]
- */
- public function getAvailability() {
+ public function getAvailability(): array {
return $this->getWrapperStorage()->getAvailability();
}
- /**
- * Set availability of the storage
- *
- * @param bool $isAvailable
- */
- public function setAvailability($isAvailable) {
+ public function setAvailability(bool $isAvailable): void {
$this->getWrapperStorage()->setAvailability($isAvailable);
}
- /**
- * @param string $path the path of the target folder
- * @param string $fileName the name of the file itself
- * @return void
- * @throws InvalidPathException
- */
- public function verifyPath($path, $fileName) {
+ public function verifyPath(string $path, string $fileName): void {
$this->getWrapperStorage()->verifyPath($path, $fileName);
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if ($sourceStorage === $this) {
return $this->copy($sourceInternalPath, $targetInternalPath);
}
@@ -587,13 +282,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
}
- /**
- * @param IStorage $sourceStorage
- * @param string $sourceInternalPath
- * @param string $targetInternalPath
- * @return bool
- */
- public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
if ($sourceStorage === $this) {
return $this->rename($sourceInternalPath, $targetInternalPath);
}
@@ -601,48 +290,29 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
}
- public function getMetaData($path) {
+ public function getMetaData(string $path): ?array {
return $this->getWrapperStorage()->getMetaData($path);
}
- /**
- * @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) {
+ public function acquireLock(string $path, int $type, ILockingProvider $provider): void {
if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->getWrapperStorage()->acquireLock($path, $type, $provider);
}
}
- /**
- * @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) {
+ public function releaseLock(string $path, int $type, ILockingProvider $provider): void {
if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->getWrapperStorage()->releaseLock($path, $type, $provider);
}
}
- /**
- * @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) {
+ public function changeLock(string $path, int $type, ILockingProvider $provider): void {
if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->getWrapperStorage()->changeLock($path, $type, $provider);
}
}
- /**
- * @return bool
- */
- public function needsPartFile() {
+ public function needsPartFile(): bool {
return $this->getWrapperStorage()->needsPartFile();
}
@@ -653,18 +323,18 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $storage->writeStream($path, $stream, $size);
} else {
$target = $this->fopen($path, 'w');
- [$count, $result] = \OC_Helper::streamCopy($stream, $target);
+ $count = Files::streamCopy($stream, $target);
fclose($stream);
fclose($target);
return $count;
}
}
- public function getDirectoryContent($directory): \Traversable {
+ public function getDirectoryContent(string $directory): \Traversable {
return $this->getWrapperStorage()->getDirectoryContent($directory);
}
- public function isWrapperOf(IStorage $storage) {
+ public function isWrapperOf(IStorage $storage): bool {
$wrapped = $this->getWrapperStorage();
if ($wrapped === $storage) {
return true;