fix(Storage): Fix IStorage return types

Signed-off-by: provokateurin <kate@provokateurin.de>
pull/48219/head
provokateurin 2024-09-19 18:19:34 +07:00
parent 256a8d8903
commit 7cdccd058f
No known key found for this signature in database
26 changed files with 559 additions and 1565 deletions

@ -935,9 +935,6 @@
<InvalidNullableReturnType> <InvalidNullableReturnType>
<code><![CDATA[ICacheEntry]]></code> <code><![CDATA[ICacheEntry]]></code>
</InvalidNullableReturnType> </InvalidNullableReturnType>
<InvalidReturnStatement>
<code><![CDATA[new FailedCache()]]></code>
</InvalidReturnStatement>
<NullableReturnStatement> <NullableReturnStatement>
<code><![CDATA[$this->sourceRootInfo]]></code> <code><![CDATA[$this->sourceRootInfo]]></code>
</NullableReturnStatement> </NullableReturnStatement>
@ -2099,10 +2096,6 @@
<code><![CDATA[!$permissions]]></code> <code><![CDATA[!$permissions]]></code>
<code><![CDATA[$this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file)]]></code> <code><![CDATA[$this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file)]]></code>
</InvalidOperand> </InvalidOperand>
<NoInterfaceProperties>
<code><![CDATA[$storage->scanner]]></code>
<code><![CDATA[$storage->scanner]]></code>
</NoInterfaceProperties>
</file> </file>
<file src="lib/private/Files/Storage/DAV.php"> <file src="lib/private/Files/Storage/DAV.php">
<InvalidClass> <InvalidClass>
@ -2116,16 +2109,6 @@
<code><![CDATA[fopen]]></code> <code><![CDATA[fopen]]></code>
</InvalidReturnType> </InvalidReturnType>
</file> </file>
<file src="lib/private/Files/Storage/FailedStorage.php">
<InvalidReturnStatement>
<code><![CDATA[new FailedCache()]]></code>
<code><![CDATA[true]]></code>
</InvalidReturnStatement>
<InvalidReturnType>
<code><![CDATA[getCache]]></code>
<code><![CDATA[verifyPath]]></code>
</InvalidReturnType>
</file>
<file src="lib/private/Files/Storage/Local.php"> <file src="lib/private/Files/Storage/Local.php">
<TypeDoesNotContainNull> <TypeDoesNotContainNull>
<code><![CDATA[$space === false || is_null($space)]]></code> <code><![CDATA[$space === false || is_null($space)]]></code>
@ -2169,16 +2152,12 @@
</file> </file>
<file src="lib/private/Files/Storage/Wrapper/Encryption.php"> <file src="lib/private/Files/Storage/Wrapper/Encryption.php">
<InvalidOperand> <InvalidOperand>
<code><![CDATA[$result]]></code>
<code><![CDATA[$result]]></code>
<code><![CDATA[$this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename)]]></code> <code><![CDATA[$this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename)]]></code>
</InvalidOperand> </InvalidOperand>
<InvalidReturnStatement> <InvalidReturnStatement>
<code><![CDATA[$newUnencryptedSize]]></code>
<code><![CDATA[$result]]></code> <code><![CDATA[$result]]></code>
</InvalidReturnStatement> </InvalidReturnStatement>
<InvalidReturnType> <InvalidReturnType>
<code><![CDATA[bool]]></code>
<code><![CDATA[int]]></code> <code><![CDATA[int]]></code>
</InvalidReturnType> </InvalidReturnType>
<InvalidScalarArgument> <InvalidScalarArgument>
@ -2190,17 +2169,11 @@
<InvalidReturnStatement> <InvalidReturnStatement>
<code><![CDATA[$this->getWrapperStorage()->filetype($this->getUnjailedPath($path))]]></code> <code><![CDATA[$this->getWrapperStorage()->filetype($this->getUnjailedPath($path))]]></code>
</InvalidReturnStatement> </InvalidReturnStatement>
<InvalidReturnType> <InvalidReturnType/>
<code><![CDATA[bool]]></code>
</InvalidReturnType>
</file> </file>
<file src="lib/private/Files/Storage/Wrapper/Wrapper.php"> <file src="lib/private/Files/Storage/Wrapper/Wrapper.php">
<InvalidReturnStatement> <InvalidReturnStatement/>
<code><![CDATA[$this->getWrapperStorage()->test()]]></code> <InvalidReturnType/>
</InvalidReturnStatement>
<InvalidReturnType>
<code><![CDATA[true]]></code>
</InvalidReturnType>
</file> </file>
<file src="lib/private/Files/Stream/SeekableHttpStream.php"> <file src="lib/private/Files/Stream/SeekableHttpStream.php">
<InvalidReturnType> <InvalidReturnType>
@ -2370,20 +2343,6 @@
</NullableReturnStatement> </NullableReturnStatement>
</file> </file>
<file src="lib/private/Lockdown/Filesystem/NullStorage.php"> <file src="lib/private/Lockdown/Filesystem/NullStorage.php">
<InvalidNullableReturnType>
<code><![CDATA[getPermissions]]></code>
</InvalidNullableReturnType>
<InvalidReturnStatement>
<code><![CDATA[new IteratorDirectory([])]]></code>
<code><![CDATA[new NullCache()]]></code>
</InvalidReturnStatement>
<InvalidReturnType>
<code><![CDATA[getCache]]></code>
<code><![CDATA[opendir]]></code>
</InvalidReturnType>
<NullableReturnStatement>
<code><![CDATA[null]]></code>
</NullableReturnStatement>
<TooManyArguments> <TooManyArguments>
<code><![CDATA[new IteratorDirectory([])]]></code> <code><![CDATA[new IteratorDirectory([])]]></code>
</TooManyArguments> </TooManyArguments>

@ -17,6 +17,7 @@ use OC\Files\Cache\CacheEntry;
use OC\Files\Storage\PolyFill\CopyDirectory; use OC\Files\Storage\PolyFill\CopyDirectory;
use OCP\Files\Cache\ICache; use OCP\Files\Cache\ICache;
use OCP\Files\Cache\ICacheEntry; use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Cache\IScanner;
use OCP\Files\FileInfo; use OCP\Files\FileInfo;
use OCP\Files\GenericFileException; use OCP\Files\GenericFileException;
use OCP\Files\NotFoundException; use OCP\Files\NotFoundException;
@ -64,7 +65,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$this->logger = \OCP\Server::get(LoggerInterface::class); $this->logger = \OCP\Server::get(LoggerInterface::class);
} }
public function mkdir($path, bool $force = false) { public function mkdir($path, bool $force = false): bool {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
if (!$force && $this->file_exists($path)) { if (!$force && $this->file_exists($path)) {
$this->logger->warning("Tried to create an object store folder that already exists: $path"); $this->logger->warning("Tried to create an object store folder that already exists: $path");
@ -130,7 +131,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
* Object Stores use a NoopScanner because metadata is directly stored in * Object Stores use a NoopScanner because metadata is directly stored in
* the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere. * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
*/ */
public function getScanner($path = '', $storage = null) { public function getScanner($path = '', $storage = null): IScanner {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
@ -141,11 +142,11 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
return $this->scanner; return $this->scanner;
} }
public function getId() { public function getId(): string {
return $this->id; return $this->id;
} }
public function rmdir($path) { public function rmdir($path): bool {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
$entry = $this->getCache()->get($path); $entry = $this->getCache()->get($path);
@ -175,7 +176,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
return true; return true;
} }
public function unlink($path) { public function unlink($path): bool {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
$entry = $this->getCache()->get($path); $entry = $this->getCache()->get($path);
@ -209,7 +210,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
return true; return true;
} }
public function stat($path) { public function stat($path): array|false {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
$cacheEntry = $this->getCache()->get($path); $cacheEntry = $this->getCache()->get($path);
if ($cacheEntry instanceof CacheEntry) { if ($cacheEntry instanceof CacheEntry) {
@ -226,7 +227,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
} }
} }
public function getPermissions($path) { public function getPermissions($path): int {
$stat = $this->stat($path); $stat = $this->stat($path);
if (is_array($stat) && isset($stat['permissions'])) { if (is_array($stat) && isset($stat['permissions'])) {
@ -268,7 +269,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
} }
} }
public function filetype($path) { public function filetype($path): string|false {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
$stat = $this->stat($path); $stat = $this->stat($path);
if ($stat) { if ($stat) {
@ -373,12 +374,12 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
return false; return false;
} }
public function file_exists($path) { public function file_exists($path): bool {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
return (bool)$this->stat($path); return (bool)$this->stat($path);
} }
public function rename($source, $target) { public function rename($source, $target): bool {
$source = $this->normalizePath($source); $source = $this->normalizePath($source);
$target = $this->normalizePath($target); $target = $this->normalizePath($target);
$this->remove($target); $this->remove($target);
@ -387,12 +388,12 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
return true; return true;
} }
public function getMimeType($path) { public function getMimeType($path): string|false {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
return parent::getMimeType($path); return parent::getMimeType($path);
} }
public function touch($path, $mtime = null) { public function touch($path, $mtime = null): bool {
if (is_null($mtime)) { if (is_null($mtime)) {
$mtime = time(); $mtime = time();
} }
@ -443,22 +444,15 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$this->writeStream($path, fopen($tmpFile, 'r'), $size); $this->writeStream($path, fopen($tmpFile, 'r'), $size);
} }
/** public function hasUpdated($path, $time): bool {
* external changes are not supported, exclusive access to the object storage is assumed
*
* @param string $path
* @param int $time
* @return false
*/
public function hasUpdated($path, $time) {
return false; return false;
} }
public function needsPartFile() { public function needsPartFile(): bool {
return false; return false;
} }
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): int {
$fh = fopen('php://temp', 'w+'); $fh = fopen('php://temp', 'w+');
fwrite($fh, $data); fwrite($fh, $data);
rewind($fh); rewind($fh);
@ -571,7 +565,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$sourceInternalPath, $sourceInternalPath,
$targetInternalPath, $targetInternalPath,
$preserveMtime = false, $preserveMtime = false,
) { ): bool {
if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) { if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) {
/** @var ObjectStoreStorage $sourceStorage */ /** @var ObjectStoreStorage $sourceStorage */
if ($sourceStorage->getObjectStore()->getStorageId() === $this->getObjectStore()->getStorageId()) { if ($sourceStorage->getObjectStore()->getStorageId() === $this->getObjectStore()->getStorageId()) {
@ -627,7 +621,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
return true; return true;
} }
public function copy($source, $target) { public function copy($source, $target): bool {
$source = $this->normalizePath($source); $source = $this->normalizePath($source);
$target = $this->normalizePath($target); $target = $this->normalizePath($target);
@ -695,7 +689,6 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
} }
/** /**
*
* @throws GenericFileException * @throws GenericFileException
*/ */
public function putChunkedWritePart( public function putChunkedWritePart(

@ -17,6 +17,11 @@ use OC\Files\FilenameValidator;
use OC\Files\Filesystem; use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\Jail; use OC\Files\Storage\Wrapper\Jail;
use OC\Files\Storage\Wrapper\Wrapper; use OC\Files\Storage\Wrapper\Wrapper;
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\ForbiddenException; use OCP\Files\ForbiddenException;
use OCP\Files\GenericFileException; use OCP\Files\GenericFileException;
use OCP\Files\IFilenameValidator; use OCP\Files\IFilenameValidator;
@ -66,9 +71,8 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
* Remove a file or folder * Remove a file or folder
* *
* @param string $path * @param string $path
* @return bool
*/ */
protected function remove($path) { protected function remove($path): bool {
if ($this->is_dir($path)) { if ($this->is_dir($path)) {
return $this->rmdir($path); return $this->rmdir($path);
} elseif ($this->is_file($path)) { } elseif ($this->is_file($path)) {
@ -78,15 +82,15 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
public function is_dir($path) { public function is_dir($path): bool {
return $this->filetype($path) === 'dir'; return $this->filetype($path) === 'dir';
} }
public function is_file($path) { public function is_file($path): bool {
return $this->filetype($path) === 'file'; return $this->filetype($path) === 'file';
} }
public function filesize($path): false|int|float { public function filesize($path): int|float|false {
if ($this->is_dir($path)) { if ($this->is_dir($path)) {
return 0; //by definition return 0; //by definition
} else { } else {
@ -99,27 +103,27 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
public function isReadable($path) { public function isReadable($path): bool {
// at least check whether it exists // at least check whether it exists
// subclasses might want to implement this more thoroughly // subclasses might want to implement this more thoroughly
return $this->file_exists($path); return $this->file_exists($path);
} }
public function isUpdatable($path) { public function isUpdatable($path): bool {
// at least check whether it exists // at least check whether it exists
// subclasses might want to implement this more thoroughly // subclasses might want to implement this more thoroughly
// a non-existing file/folder isn't updatable // a non-existing file/folder isn't updatable
return $this->file_exists($path); return $this->file_exists($path);
} }
public function isCreatable($path) { public function isCreatable($path): bool {
if ($this->is_dir($path) && $this->isUpdatable($path)) { if ($this->is_dir($path) && $this->isUpdatable($path)) {
return true; return true;
} }
return false; return false;
} }
public function isDeletable($path) { public function isDeletable($path): bool {
if ($path === '' || $path === '/') { if ($path === '' || $path === '/') {
return $this->isUpdatable($path); return $this->isUpdatable($path);
} }
@ -127,11 +131,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->isUpdatable($parent) && $this->isUpdatable($path); return $this->isUpdatable($parent) && $this->isUpdatable($path);
} }
public function isSharable($path) { public function isSharable($path): bool {
return $this->isReadable($path); return $this->isReadable($path);
} }
public function getPermissions($path) { public function getPermissions($path): int {
$permissions = 0; $permissions = 0;
if ($this->isCreatable($path)) { if ($this->isCreatable($path)) {
$permissions |= \OCP\Constants::PERMISSION_CREATE; $permissions |= \OCP\Constants::PERMISSION_CREATE;
@ -151,7 +155,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $permissions; return $permissions;
} }
public function filemtime($path) { public function filemtime($path): int|false {
$stat = $this->stat($path); $stat = $this->stat($path);
if (isset($stat['mtime']) && $stat['mtime'] > 0) { if (isset($stat['mtime']) && $stat['mtime'] > 0) {
return $stat['mtime']; return $stat['mtime'];
@ -160,7 +164,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
public function file_get_contents($path) { public function file_get_contents($path): string|false {
$handle = $this->fopen($path, 'r'); $handle = $this->fopen($path, 'r');
if (!$handle) { if (!$handle) {
return false; return false;
@ -170,7 +174,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $data; return $data;
} }
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): int|float|false {
$handle = $this->fopen($path, 'w'); $handle = $this->fopen($path, 'w');
if (!$handle) { if (!$handle) {
return false; return false;
@ -181,14 +185,14 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $count; return $count;
} }
public function rename($source, $target) { public function rename($source, $target): bool {
$this->remove($target); $this->remove($target);
$this->removeCachedFile($source); $this->removeCachedFile($source);
return $this->copy($source, $target) and $this->remove($source); return $this->copy($source, $target) and $this->remove($source);
} }
public function copy($source, $target) { public function copy($source, $target): bool {
if ($this->is_dir($source)) { if ($this->is_dir($source)) {
$this->remove($target); $this->remove($target);
$dir = $this->opendir($source); $dir = $this->opendir($source);
@ -215,7 +219,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
public function getMimeType($path) { public function getMimeType($path): string|false {
if ($this->is_dir($path)) { if ($this->is_dir($path)) {
return 'httpd/unix-directory'; return 'httpd/unix-directory';
} elseif ($this->file_exists($path)) { } elseif ($this->file_exists($path)) {
@ -225,7 +229,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
public function hash($type, $path, $raw = false) { public function hash($type, $path, $raw = false): string|false {
$fh = $this->fopen($path, 'rb'); $fh = $this->fopen($path, 'rb');
$ctx = hash_init($type); $ctx = hash_init($type);
hash_update_stream($ctx, $fh); hash_update_stream($ctx, $fh);
@ -233,15 +237,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return hash_final($ctx, $raw); return hash_final($ctx, $raw);
} }
public function getLocalFile($path) { public function getLocalFile($path): string|false {
return $this->getCachedFile($path); return $this->getCachedFile($path);
} }
/** private function addLocalFolder($path, $target): void {
* @param string $path
* @param string $target
*/
private function addLocalFolder($path, $target) {
$dh = $this->opendir($path); $dh = $this->opendir($path);
if (is_resource($dh)) { if (is_resource($dh)) {
while (($file = readdir($dh)) !== false) { while (($file = readdir($dh)) !== false) {
@ -258,12 +258,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
/** protected function searchInDir($query, $dir = ''): array {
* @param string $query
* @param string $dir
* @return array
*/
protected function searchInDir($query, $dir = '') {
$files = []; $files = [];
$dh = $this->opendir($dir); $dh = $this->opendir($dir);
if (is_resource($dh)) { if (is_resource($dh)) {
@ -284,18 +279,15 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
/** /**
* @inheritDoc
* Check if a file or folder has been updated since $time * Check if a file or folder has been updated since $time
* *
* The method is only used to check if the cache needs to be updated. Storage backends that don't support checking * The method is only used to check if the cache needs to be updated. Storage backends that don't support checking
* the mtime should always return false here. As a result storage implementations that always return false expect * the mtime should always return false here. As a result storage implementations that always return false expect
* exclusive access to the backend and will not pick up files that have been added in a way that circumvents * exclusive access to the backend and will not pick up files that have been added in a way that circumvents
* Nextcloud filesystem. * Nextcloud filesystem.
*
* @param string $path
* @param int $time
* @return bool
*/ */
public function hasUpdated($path, $time) { public function hasUpdated($path, $time): bool {
return $this->filemtime($path) > $time; return $this->filemtime($path) > $time;
} }
@ -307,23 +299,18 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $dependencies; return $dependencies;
} }
/** public function getCache($path = '', $storage = null): ICache {
* @return Cache
*/
public function getCache($path = '', $storage = null) {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
/** @psalm-suppress NoInterfaceProperties The isset check is safe */ /** @var self $storage */
if (!isset($storage->cache)) { if (!isset($storage->cache)) {
$storage->cache = new Cache($storage, $this->getCacheDependencies()); $storage->cache = new Cache($storage, $this->getCacheDependencies());
} }
/** @psalm-suppress NullableReturnStatement False-positive, as the if above avoids this being null */
/** @psalm-suppress NoInterfaceProperties Legacy */
return $storage->cache; return $storage->cache;
} }
public function getScanner($path = '', $storage = null) { public function getScanner($path = '', $storage = null): IScanner {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
@ -336,7 +323,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $storage->scanner; return $storage->scanner;
} }
public function getWatcher($path = '', $storage = null) { public function getWatcher($path = '', $storage = null): IWatcher {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
@ -348,7 +335,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->watcher; return $this->watcher;
} }
public function getPropagator($storage = null) { public function getPropagator($storage = null): IPropagator {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
@ -363,27 +350,24 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $storage->propagator; return $storage->propagator;
} }
/** public function getUpdater($storage = null): IUpdater {
* get a propagator instance for the cache
*
* @param \OC\Files\Storage\Storage $storage (optional) the storage to pass to the watcher
* @return Updater
*/
public function getUpdater($storage = null) {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
if (!$storage->instanceOfStorage(self::class)) { if (!$storage->instanceOfStorage(self::class)) {
throw new \InvalidArgumentException('Storage is not of the correct class'); throw new \InvalidArgumentException('Storage is not of the correct class');
} }
/** @var self $storage */
if (!isset($storage->updater)) { if (!isset($storage->updater)) {
$storage->updater = new Updater($storage); $storage->updater = new Updater($storage);
} }
return $storage->updater; return $storage->updater;
} }
public function getStorageCache($storage = null) { public function getStorageCache($storage = null): \OC\Files\Cache\Storage {
return $this->getCache($storage)->getStorageCache(); /** @var Cache $cache */
$cache = $this->getCache($storage);
return $cache->getStorageCache();
} }
public function getOwner($path): string|false { public function getOwner($path): string|false {
@ -394,13 +378,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->owner; return $this->owner;
} }
/** public function getETag($path): string|false {
* get the ETag for a file or folder
*
* @param string $path
* @return string|false
*/
public function getETag($path) {
return uniqid(); return uniqid();
} }
@ -411,7 +389,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
* @param string $path The path to clean * @param string $path The path to clean
* @return string cleaned path * @return string cleaned path
*/ */
public function cleanPath($path) { public function cleanPath($path): string {
if (strlen($path) == 0 or $path[0] != '/') { if (strlen($path) == 0 or $path[0] != '/') {
$path = '/' . $path; $path = '/' . $path;
} }
@ -430,10 +408,8 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
/** /**
* Test a storage for availability * Test a storage for availability
*
* @return bool
*/ */
public function test() { public function test(): bool {
try { try {
if ($this->stat('')) { if ($this->stat('')) {
return true; return true;
@ -449,20 +425,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
/** public function free_space($path): int|float|false {
* get the free space in the storage
*
* @param string $path
* @return int|float|false
*/
public function free_space($path) {
return \OCP\Files\FileInfo::SPACE_UNKNOWN; return \OCP\Files\FileInfo::SPACE_UNKNOWN;
} }
/** public function isLocal(): bool {
* {@inheritdoc}
*/
public function isLocal() {
// the common implementation returns a temporary file by // the common implementation returns a temporary file by
// default, which is not local // default, which is not local
return false; return false;
@ -472,9 +439,8 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
* Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
* *
* @param string $class * @param string $class
* @return bool
*/ */
public function instanceOfStorage($class) { public function instanceOfStorage($class): bool {
if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') { if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
// FIXME Temporary fix to keep existing checks working // FIXME Temporary fix to keep existing checks working
$class = '\OCA\Files_Sharing\SharedStorage'; $class = '\OCA\Files_Sharing\SharedStorage';
@ -488,17 +454,12 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
* For now the returned array can hold the parameter url - in future more attributes might follow. * For now the returned array can hold the parameter url - in future more attributes might follow.
* *
* @param string $path * @param string $path
* @return array|false
*/ */
public function getDirectDownload($path) { public function getDirectDownload($path): array|false {
return []; return [];
} }
/** public function verifyPath($path, $fileName): void {
* @inheritdoc
* @throws InvalidPathException
*/
public function verifyPath($path, $fileName) {
$this->getFilenameValidator() $this->getFilenameValidator()
->validateFilename($fileName); ->validateFilename($fileName);
@ -527,30 +488,24 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->filenameValidator; return $this->filenameValidator;
} }
/** public function setMountOptions(array $options): void {
* @param array $options
*/
public function setMountOptions(array $options) {
$this->mountOptions = $options; $this->mountOptions = $options;
} }
/** /**
* @param string $name * @param string $name
* @param mixed $default * @param mixed $default
* @return mixed
*/ */
public function getMountOption($name, $default = null) { public function getMountOption($name, $default = null): mixed {
return $this->mountOptions[$name] ?? $default; return $this->mountOptions[$name] ?? $default;
} }
/** /**
* @param IStorage $sourceStorage
* @param string $sourceInternalPath * @param string $sourceInternalPath
* @param string $targetInternalPath * @param string $targetInternalPath
* @param bool $preserveMtime * @param bool $preserveMtime
* @return bool
*/ */
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false): bool {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
return $this->copy($sourceInternalPath, $targetInternalPath); return $this->copy($sourceInternalPath, $targetInternalPath);
} }
@ -595,9 +550,6 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
/** /**
* Check if a storage is the same as the current one, including wrapped storages * Check if a storage is the same as the current one, including wrapped storages
*
* @param IStorage $storage
* @return bool
*/ */
private function isSameStorage(IStorage $storage): bool { private function isSameStorage(IStorage $storage): bool {
while ($storage->instanceOfStorage(Wrapper::class)) { while ($storage->instanceOfStorage(Wrapper::class)) {
@ -611,12 +563,10 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
/** /**
* @param IStorage $sourceStorage
* @param string $sourceInternalPath * @param string $sourceInternalPath
* @param string $targetInternalPath * @param string $targetInternalPath
* @return bool
*/ */
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
if ($this->isSameStorage($sourceStorage)) { if ($this->isSameStorage($sourceStorage)) {
// resolve any jailed paths // resolve any jailed paths
while ($sourceStorage->instanceOfStorage(Jail::class)) { while ($sourceStorage->instanceOfStorage(Jail::class)) {
@ -645,7 +595,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $result; return $result;
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
if (Filesystem::isFileBlacklisted($path)) { if (Filesystem::isFileBlacklisted($path)) {
throw new ForbiddenException('Invalid path: ' . $path, false); throw new ForbiddenException('Invalid path: ' . $path, false);
} }
@ -675,7 +625,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $data; return $data;
} }
public function acquireLock($path, $type, ILockingProvider $provider) { public function acquireLock($path, $type, ILockingProvider $provider): void {
$logger = $this->getLockLogger(); $logger = $this->getLockLogger();
if ($logger) { if ($logger) {
$typeString = ($type === ILockingProvider::LOCK_SHARED) ? 'shared' : 'exclusive'; $typeString = ($type === ILockingProvider::LOCK_SHARED) ? 'shared' : 'exclusive';
@ -702,7 +652,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
public function releaseLock($path, $type, ILockingProvider $provider) { public function releaseLock($path, $type, ILockingProvider $provider): void {
$logger = $this->getLockLogger(); $logger = $this->getLockLogger();
if ($logger) { if ($logger) {
$typeString = ($type === ILockingProvider::LOCK_SHARED) ? 'shared' : 'exclusive'; $typeString = ($type === ILockingProvider::LOCK_SHARED) ? 'shared' : 'exclusive';
@ -729,7 +679,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} }
} }
public function changeLock($path, $type, ILockingProvider $provider) { public function changeLock($path, $type, ILockingProvider $provider): void {
$logger = $this->getLockLogger(); $logger = $this->getLockLogger();
if ($logger) { if ($logger) {
$typeString = ($type === ILockingProvider::LOCK_SHARED) ? 'shared' : 'exclusive'; $typeString = ($type === ILockingProvider::LOCK_SHARED) ? 'shared' : 'exclusive';
@ -767,45 +717,22 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
/** /**
* @return array [ available, last_checked ] * @return array [ available, last_checked ]
*/ */
public function getAvailability() { public function getAvailability(): array {
return $this->getStorageCache()->getAvailability(); return $this->getStorageCache()->getAvailability();
} }
/** public function setAvailability($isAvailable): void {
* @param bool $isAvailable
*/
public function setAvailability($isAvailable) {
$this->getStorageCache()->setAvailability($isAvailable); $this->getStorageCache()->setAvailability($isAvailable);
} }
/**
* Allow setting the storage owner
*
* This can be used for storages that do not have a dedicated owner, where we want to
* pass the user that we setup the mountpoint for along to the storage layer
*
* @param string|null $user
* @return void
*/
public function setOwner(?string $user): void { public function setOwner(?string $user): void {
$this->owner = $user; $this->owner = $user;
} }
/** public function needsPartFile(): bool {
* @return bool
*/
public function needsPartFile() {
return true; return true;
} }
/**
* fallback implementation
*
* @param string $path
* @param resource $stream
* @param int $size
* @return int
*/
public function writeStream(string $path, $stream, ?int $size = null): int { public function writeStream(string $path, $stream, ?int $size = null): int {
$target = $this->fopen($path, 'w'); $target = $this->fopen($path, 'w');
if (!$target) { if (!$target) {
@ -823,7 +750,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $count; return $count;
} }
public function getDirectoryContent($directory): \Traversable { public function getDirectoryContent($directory): \Traversable|false {
$dh = $this->opendir($directory); $dh = $this->opendir($directory);
if ($dh === false) { if ($dh === false) {

@ -18,43 +18,43 @@ class CommonTest extends \OC\Files\Storage\Common {
$this->storage = new \OC\Files\Storage\Local($params); $this->storage = new \OC\Files\Storage\Local($params);
} }
public function getId() { public function getId(): string {
return 'test::' . $this->storage->getId(); return 'test::' . $this->storage->getId();
} }
public function mkdir($path) { public function mkdir($path): bool {
return $this->storage->mkdir($path); return $this->storage->mkdir($path);
} }
public function rmdir($path) { public function rmdir($path): bool {
return $this->storage->rmdir($path); return $this->storage->rmdir($path);
} }
public function opendir($path) { public function opendir($path) {
return $this->storage->opendir($path); return $this->storage->opendir($path);
} }
public function stat($path) { public function stat($path): array|false {
return $this->storage->stat($path); return $this->storage->stat($path);
} }
public function filetype($path) { public function filetype($path): string|false {
return @$this->storage->filetype($path); return @$this->storage->filetype($path);
} }
public function isReadable($path) { public function isReadable($path): bool {
return $this->storage->isReadable($path); return $this->storage->isReadable($path);
} }
public function isUpdatable($path) { public function isUpdatable($path): bool {
return $this->storage->isUpdatable($path); return $this->storage->isUpdatable($path);
} }
public function file_exists($path) { public function file_exists($path): bool {
return $this->storage->file_exists($path); return $this->storage->file_exists($path);
} }
public function unlink($path) { public function unlink($path): bool {
return $this->storage->unlink($path); return $this->storage->unlink($path);
} }
public function fopen($path, $mode) { public function fopen($path, $mode) {
return $this->storage->fopen($path, $mode); return $this->storage->fopen($path, $mode);
} }
public function free_space($path) { public function free_space($path): int|float|false {
return $this->storage->free_space($path); return $this->storage->free_space($path);
} }
public function touch($path, $mtime = null) { public function touch($path, $mtime = null): bool {
return $this->storage->touch($path, $mtime); return $this->storage->touch($path, $mtime);
} }
} }

@ -128,7 +128,7 @@ class DAV extends Common {
$this->mimeTypeDetector = \OC::$server->getMimeTypeDetector(); $this->mimeTypeDetector = \OC::$server->getMimeTypeDetector();
} }
protected function init() { protected function init(): void {
if ($this->ready) { if ($this->ready) {
return; return;
} }
@ -177,17 +177,15 @@ class DAV extends Common {
/** /**
* Clear the stat cache * Clear the stat cache
*/ */
public function clearStatCache() { public function clearStatCache(): void {
$this->statCache->clear(); $this->statCache->clear();
} }
/** {@inheritdoc} */ public function getId(): string {
public function getId() {
return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root; return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
} }
/** {@inheritdoc} */ public function createBaseUri(): string {
public function createBaseUri() {
$baseUri = 'http'; $baseUri = 'http';
if ($this->secure) { if ($this->secure) {
$baseUri .= 's'; $baseUri .= 's';
@ -196,8 +194,7 @@ class DAV extends Common {
return $baseUri; return $baseUri;
} }
/** {@inheritdoc} */ public function mkdir($path): bool {
public function mkdir($path) {
$this->init(); $this->init();
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
$result = $this->simpleResponse('MKCOL', $path, null, 201); $result = $this->simpleResponse('MKCOL', $path, null, 201);
@ -207,8 +204,7 @@ class DAV extends Common {
return $result; return $result;
} }
/** {@inheritdoc} */ public function rmdir($path): bool {
public function rmdir($path) {
$this->init(); $this->init();
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
// FIXME: some WebDAV impl return 403 when trying to DELETE // FIXME: some WebDAV impl return 403 when trying to DELETE
@ -219,7 +215,6 @@ class DAV extends Common {
return $result; return $result;
} }
/** {@inheritdoc} */
public function opendir($path) { public function opendir($path) {
$this->init(); $this->init();
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
@ -244,11 +239,11 @@ class DAV extends Common {
* *
* @param string $path path to propfind * @param string $path path to propfind
* *
* @return array|boolean propfind response or false if the entry was not found * @return array|false propfind response or false if the entry was not found
* *
* @throws ClientHttpException * @throws ClientHttpException
*/ */
protected function propfind($path) { protected function propfind($path): array|false {
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
$cachedResponse = $this->statCache->get($path); $cachedResponse = $this->statCache->get($path);
// we either don't know it, or we know it exists but need more details // we either don't know it, or we know it exists but need more details
@ -276,8 +271,7 @@ class DAV extends Common {
return $response; return $response;
} }
/** {@inheritdoc} */ public function filetype($path): string|false {
public function filetype($path) {
try { try {
$response = $this->propfind($path); $response = $this->propfind($path);
if ($response === false) { if ($response === false) {
@ -295,8 +289,7 @@ class DAV extends Common {
return false; return false;
} }
/** {@inheritdoc} */ public function file_exists($path): bool {
public function file_exists($path) {
try { try {
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
$cachedState = $this->statCache->get($path); $cachedState = $this->statCache->get($path);
@ -314,8 +307,7 @@ class DAV extends Common {
return false; return false;
} }
/** {@inheritdoc} */ public function unlink($path): bool {
public function unlink($path) {
$this->init(); $this->init();
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
$result = $this->simpleResponse('DELETE', $path, null, 204); $result = $this->simpleResponse('DELETE', $path, null, 204);
@ -324,7 +316,6 @@ class DAV extends Common {
return $result; return $result;
} }
/** {@inheritdoc} */
public function fopen($path, $mode) { public function fopen($path, $mode) {
$this->init(); $this->init();
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
@ -402,13 +393,12 @@ class DAV extends Common {
/** /**
* @param string $tmpFile * @param string $tmpFile
*/ */
public function writeBack($tmpFile, $path) { public function writeBack($tmpFile, $path): void {
$this->uploadFile($tmpFile, $path); $this->uploadFile($tmpFile, $path);
unlink($tmpFile); unlink($tmpFile);
} }
/** {@inheritdoc} */ public function free_space($path): int|float|false {
public function free_space($path) {
$this->init(); $this->init();
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
try { try {
@ -426,8 +416,7 @@ class DAV extends Common {
} }
} }
/** {@inheritdoc} */ public function touch($path, $mtime = null): bool {
public function touch($path, $mtime = null) {
$this->init(); $this->init();
if (is_null($mtime)) { if (is_null($mtime)) {
$mtime = time(); $mtime = time();
@ -469,7 +458,7 @@ class DAV extends Common {
* @param mixed $data * @param mixed $data
* @return int|float|false * @return int|float|false
*/ */
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): int|float|false {
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
$result = parent::file_put_contents($path, $data); $result = parent::file_put_contents($path, $data);
$this->statCache->remove($path); $this->statCache->remove($path);
@ -480,7 +469,7 @@ class DAV extends Common {
* @param string $path * @param string $path
* @param string $target * @param string $target
*/ */
protected function uploadFile($path, $target) { protected function uploadFile($path, $target): void {
$this->init(); $this->init();
// invalidate // invalidate
@ -500,8 +489,7 @@ class DAV extends Common {
$this->removeCachedFile($target); $this->removeCachedFile($target);
} }
/** {@inheritdoc} */ public function rename($source, $target): bool {
public function rename($source, $target) {
$this->init(); $this->init();
$source = $this->cleanPath($source); $source = $this->cleanPath($source);
$target = $this->cleanPath($target); $target = $this->cleanPath($target);
@ -532,8 +520,7 @@ class DAV extends Common {
return false; return false;
} }
/** {@inheritdoc} */ public function copy($source, $target): bool {
public function copy($source, $target) {
$this->init(); $this->init();
$source = $this->cleanPath($source); $source = $this->cleanPath($source);
$target = $this->cleanPath($target); $target = $this->cleanPath($target);
@ -561,7 +548,7 @@ class DAV extends Common {
return false; return false;
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
if (Filesystem::isFileBlacklisted($path)) { if (Filesystem::isFileBlacklisted($path)) {
throw new ForbiddenException('Invalid path: ' . $path, false); throw new ForbiddenException('Invalid path: ' . $path, false);
} }
@ -623,24 +610,18 @@ class DAV extends Common {
]; ];
} }
/** {@inheritdoc} */ public function stat($path): array|false {
public function stat($path) {
$meta = $this->getMetaData($path); $meta = $this->getMetaData($path);
return $meta ?: false; return $meta ?: false;
} }
/** {@inheritdoc} */ public function getMimeType($path): string|false {
public function getMimeType($path) {
$meta = $this->getMetaData($path); $meta = $this->getMetaData($path);
return $meta ? $meta['mimetype'] : false; return $meta ? $meta['mimetype'] : false;
} }
/** public function cleanPath($path): string {
* @param string $path
* @return string
*/
public function cleanPath($path) {
if ($path === '') { if ($path === '') {
return $path; return $path;
} }
@ -655,7 +636,7 @@ class DAV extends Common {
* @param string $path to encode * @param string $path to encode
* @return string encoded path * @return string encoded path
*/ */
protected function encodePath($path) { protected function encodePath($path): string {
// slashes need to stay // slashes need to stay
return str_replace('%2F', '/', rawurlencode($path)); return str_replace('%2F', '/', rawurlencode($path));
} }
@ -669,7 +650,7 @@ class DAV extends Common {
* @throws StorageInvalidException * @throws StorageInvalidException
* @throws StorageNotAvailableException * @throws StorageNotAvailableException
*/ */
protected function simpleResponse($method, $path, $body, $expected) { protected function simpleResponse($method, $path, $body, $expected): bool {
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
try { try {
$response = $this->client->request($method, $this->encodePath($path), $body); $response = $this->client->request($method, $this->encodePath($path), $body);
@ -691,46 +672,37 @@ class DAV extends Common {
/** /**
* check if curl is installed * check if curl is installed
*/ */
public static function checkDependencies() { public static function checkDependencies(): bool {
return true; return true;
} }
/** {@inheritdoc} */ public function isUpdatable($path): bool {
public function isUpdatable($path) {
return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE); return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
} }
/** {@inheritdoc} */ public function isCreatable($path): bool {
public function isCreatable($path) {
return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE); return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
} }
/** {@inheritdoc} */ public function isSharable($path): bool {
public function isSharable($path) {
return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE); return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
} }
/** {@inheritdoc} */ public function isDeletable($path): bool {
public function isDeletable($path) {
return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE); return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
} }
/** {@inheritdoc} */ public function getPermissions($path): int {
public function getPermissions($path) {
$stat = $this->getMetaData($path); $stat = $this->getMetaData($path);
return $stat ? $stat['permissions'] : 0; return $stat ? $stat['permissions'] : 0;
} }
public function getETag($path) { public function getETag($path): string|false {
$meta = $this->getMetaData($path); $meta = $this->getMetaData($path);
return $meta ? $meta['etag'] : false; return $meta ? $meta['etag'] : false;
} }
/** protected function parsePermissions($permissionsString): int {
* @param string $permissionsString
* @return int
*/
protected function parsePermissions($permissionsString) {
$permissions = Constants::PERMISSION_READ; $permissions = Constants::PERMISSION_READ;
if (str_contains($permissionsString, 'R')) { if (str_contains($permissionsString, 'R')) {
$permissions |= Constants::PERMISSION_SHARE; $permissions |= Constants::PERMISSION_SHARE;
@ -748,15 +720,7 @@ class DAV extends Common {
return $permissions; return $permissions;
} }
/** public function hasUpdated($path, $time): bool {
* check if a file or folder has been updated since $time
*
* @param string $path
* @param int $time
* @throws \OCP\Files\StorageNotAvailableException
* @return bool
*/
public function hasUpdated($path, $time) {
$this->init(); $this->init();
$path = $this->cleanPath($path); $path = $this->cleanPath($path);
try { try {
@ -822,7 +786,7 @@ class DAV extends Common {
* which might be temporary * which might be temporary
* @throws ForbiddenException if the action is not allowed * @throws ForbiddenException if the action is not allowed
*/ */
protected function convertException(Exception $e, $path = '') { protected function convertException(Exception $e, $path = ''): void {
Server::get(LoggerInterface::class)->debug($e->getMessage(), ['app' => 'files_external', 'exception' => $e]); Server::get(LoggerInterface::class)->debug($e->getMessage(), ['app' => 'files_external', 'exception' => $e]);
if ($e instanceof ClientHttpException) { if ($e instanceof ClientHttpException) {
if ($e->getHttpStatus() === Http::STATUS_LOCKED) { if ($e->getHttpStatus() === Http::STATUS_LOCKED) {

@ -29,168 +29,163 @@ class FailedStorage extends Common {
} }
} }
public function getId() { public function getId(): string {
// we can't return anything sane here // we can't return anything sane here
return 'failedstorage'; return 'failedstorage';
} }
public function mkdir($path) { public function mkdir($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function rmdir($path) { public function rmdir($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function opendir($path) { public function opendir($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function is_dir($path) { public function is_dir($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function is_file($path) { public function is_file($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function stat($path) { public function stat($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function filetype($path) { public function filetype($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function filesize($path): false|int|float { public function filesize($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function isCreatable($path) { public function isCreatable($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function isReadable($path) { public function isReadable($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function isUpdatable($path) { public function isUpdatable($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function isDeletable($path) { public function isDeletable($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function isSharable($path) { public function isSharable($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function getPermissions($path) { public function getPermissions($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function file_exists($path) { public function file_exists($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function filemtime($path) { public function filemtime($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function file_get_contents($path) { public function file_get_contents($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function unlink($path) { public function unlink($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function rename($source, $target) { public function rename($source, $target): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function copy($source, $target) { public function copy($source, $target): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function fopen($path, $mode) { public function fopen($path, $mode): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function getMimeType($path) { public function getMimeType($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function hash($type, $path, $raw = false) { public function hash($type, $path, $raw = false): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function free_space($path) { public function free_space($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function search($query) { public function touch($path, $mtime = null): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function touch($path, $mtime = null) { public function getLocalFile($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function getLocalFile($path) { public function hasUpdated($path, $time): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function hasUpdated($path, $time) { public function getETag($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function getETag($path) { public function getDirectDownload($path): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function getDirectDownload($path) { public function verifyPath($path, $fileName): void {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function verifyPath($path, $fileName) {
return true;
} }
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function acquireLock($path, $type, ILockingProvider $provider) { public function acquireLock($path, $type, ILockingProvider $provider): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function releaseLock($path, $type, ILockingProvider $provider) { public function releaseLock($path, $type, ILockingProvider $provider): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function changeLock($path, $type, ILockingProvider $provider) { public function changeLock($path, $type, ILockingProvider $provider): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function getAvailability() { public function getAvailability(): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function setAvailability($isAvailable) { public function setAvailability($isAvailable): never {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
} }
public function getCache($path = '', $storage = null) { public function getCache($path = '', $storage = null): FailedCache {
return new FailedCache(); return new FailedCache();
} }
} }

@ -8,6 +8,8 @@
namespace OC\Files\Storage; namespace OC\Files\Storage;
use OC\Files\Cache\HomePropagator; use OC\Files\Cache\HomePropagator;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\IPropagator;
use OCP\IUser; use OCP\IUser;
/** /**
@ -38,41 +40,31 @@ class Home extends Local implements \OCP\Files\IHomeStorage {
parent::__construct(['datadir' => $datadir]); parent::__construct(['datadir' => $datadir]);
} }
public function getId() { public function getId(): string {
return $this->id; return $this->id;
} }
/** public function getCache($path = '', $storage = null): ICache {
* @return \OC\Files\Cache\HomeCache
*/
public function getCache($path = '', $storage = null) {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
if (!isset($this->cache)) { if (!isset($this->cache)) {
$this->cache = new \OC\Files\Cache\HomeCache($storage, $this->getCacheDependencies()); $this->cache = new \OC\Files\Cache\HomeCache($storage, $this->getCacheDependencies());
} }
/** @var \OC\Files\Cache\HomeCache */
return $this->cache; return $this->cache;
} }
public function getPropagator($storage = null) { public function getPropagator($storage = null): IPropagator {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
if (!isset($this->propagator)) { if (!isset($this->propagator)) {
$this->propagator = new HomePropagator($storage, \OC::$server->getDatabaseConnection()); $this->propagator = new HomePropagator($storage, \OC::$server->getDatabaseConnection());
} }
/** @var \OC\Files\Cache\Propagator */
return $this->propagator; return $this->propagator;
} }
/**
* Returns the owner of this home storage
*
* @return \OC\User\User owner of this home storage
*/
public function getUser(): IUser { public function getUser(): IUser {
return $this->user; return $this->user;
} }

@ -74,11 +74,11 @@ class Local extends \OC\Files\Storage\Common {
public function __destruct() { public function __destruct() {
} }
public function getId() { public function getId(): string {
return 'local::' . $this->datadir; return 'local::' . $this->datadir;
} }
public function mkdir($path) { public function mkdir($path): bool {
$sourcePath = $this->getSourcePath($path); $sourcePath = $this->getSourcePath($path);
$oldMask = umask($this->defUMask); $oldMask = umask($this->defUMask);
$result = @mkdir($sourcePath, 0777, true); $result = @mkdir($sourcePath, 0777, true);
@ -86,7 +86,7 @@ class Local extends \OC\Files\Storage\Common {
return $result; return $result;
} }
public function rmdir($path) { public function rmdir($path): bool {
if (!$this->isDeletable($path)) { if (!$this->isDeletable($path)) {
return false; return false;
} }
@ -129,7 +129,7 @@ class Local extends \OC\Files\Storage\Common {
return opendir($this->getSourcePath($path)); return opendir($this->getSourcePath($path));
} }
public function is_dir($path) { public function is_dir($path): bool {
if ($this->caseInsensitive && !$this->file_exists($path)) { if ($this->caseInsensitive && !$this->file_exists($path)) {
return false; return false;
} }
@ -139,14 +139,14 @@ class Local extends \OC\Files\Storage\Common {
return is_dir($this->getSourcePath($path)); return is_dir($this->getSourcePath($path));
} }
public function is_file($path) { public function is_file($path): bool {
if ($this->caseInsensitive && !$this->file_exists($path)) { if ($this->caseInsensitive && !$this->file_exists($path)) {
return false; return false;
} }
return is_file($this->getSourcePath($path)); return is_file($this->getSourcePath($path));
} }
public function stat($path) { public function stat($path): array|false {
$fullPath = $this->getSourcePath($path); $fullPath = $this->getSourcePath($path);
clearstatcache(true, $fullPath); clearstatcache(true, $fullPath);
if (!file_exists($fullPath)) { if (!file_exists($fullPath)) {
@ -164,7 +164,7 @@ class Local extends \OC\Files\Storage\Common {
return $statResult; return $statResult;
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
try { try {
$stat = $this->stat($path); $stat = $this->stat($path);
} catch (ForbiddenException $e) { } catch (ForbiddenException $e) {
@ -213,7 +213,7 @@ class Local extends \OC\Files\Storage\Common {
return $data; return $data;
} }
public function filetype($path) { public function filetype($path): string|false {
$filetype = filetype($this->getSourcePath($path)); $filetype = filetype($this->getSourcePath($path));
if ($filetype == 'link') { if ($filetype == 'link') {
$filetype = filetype(realpath($this->getSourcePath($path))); $filetype = filetype(realpath($this->getSourcePath($path)));
@ -221,7 +221,7 @@ class Local extends \OC\Files\Storage\Common {
return $filetype; return $filetype;
} }
public function filesize($path): false|int|float { public function filesize($path): int|float|false {
if (!$this->is_file($path)) { if (!$this->is_file($path)) {
return 0; return 0;
} }
@ -233,15 +233,15 @@ class Local extends \OC\Files\Storage\Common {
return filesize($fullPath); return filesize($fullPath);
} }
public function isReadable($path) { public function isReadable($path): bool {
return is_readable($this->getSourcePath($path)); return is_readable($this->getSourcePath($path));
} }
public function isUpdatable($path) { public function isUpdatable($path): bool {
return is_writable($this->getSourcePath($path)); return is_writable($this->getSourcePath($path));
} }
public function file_exists($path) { public function file_exists($path): bool {
if ($this->caseInsensitive) { if ($this->caseInsensitive) {
$fullPath = $this->getSourcePath($path); $fullPath = $this->getSourcePath($path);
$parentPath = dirname($fullPath); $parentPath = dirname($fullPath);
@ -255,7 +255,7 @@ class Local extends \OC\Files\Storage\Common {
} }
} }
public function filemtime($path) { public function filemtime($path): int|false {
$fullPath = $this->getSourcePath($path); $fullPath = $this->getSourcePath($path);
clearstatcache(true, $fullPath); clearstatcache(true, $fullPath);
if (!$this->file_exists($path)) { if (!$this->file_exists($path)) {
@ -268,7 +268,7 @@ class Local extends \OC\Files\Storage\Common {
return filemtime($fullPath); return filemtime($fullPath);
} }
public function touch($path, $mtime = null) { public function touch($path, $mtime = null): bool {
// sets the modification time of the file to the given value. // sets the modification time of the file to the given value.
// If mtime is nil the current time is set. // If mtime is nil the current time is set.
// note that the access time of the file always changes to the current time. // note that the access time of the file always changes to the current time.
@ -289,11 +289,11 @@ class Local extends \OC\Files\Storage\Common {
return $result; return $result;
} }
public function file_get_contents($path) { public function file_get_contents($path): string|false {
return file_get_contents($this->getSourcePath($path)); return file_get_contents($this->getSourcePath($path));
} }
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): int|float|false {
$oldMask = umask($this->defUMask); $oldMask = umask($this->defUMask);
if ($this->unlinkOnTruncate) { if ($this->unlinkOnTruncate) {
$this->unlink($path); $this->unlink($path);
@ -303,7 +303,7 @@ class Local extends \OC\Files\Storage\Common {
return $result; return $result;
} }
public function unlink($path) { public function unlink($path): bool {
if ($this->is_dir($path)) { if ($this->is_dir($path)) {
return $this->rmdir($path); return $this->rmdir($path);
} elseif ($this->is_file($path)) { } elseif ($this->is_file($path)) {
@ -313,7 +313,7 @@ class Local extends \OC\Files\Storage\Common {
} }
} }
private function checkTreeForForbiddenItems(string $path) { private function checkTreeForForbiddenItems(string $path): void {
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
foreach ($iterator as $file) { foreach ($iterator as $file) {
/** @var \SplFileInfo $file */ /** @var \SplFileInfo $file */
@ -364,7 +364,7 @@ class Local extends \OC\Files\Storage\Common {
return $this->copy($source, $target) && $this->unlink($source); return $this->copy($source, $target) && $this->unlink($source);
} }
public function copy($source, $target) { public function copy($source, $target): bool {
if ($this->is_dir($source)) { if ($this->is_dir($source)) {
return parent::copy($source, $target); return parent::copy($source, $target);
} else { } else {
@ -401,7 +401,7 @@ class Local extends \OC\Files\Storage\Common {
return hash_file($type, $this->getSourcePath($path), $raw); return hash_file($type, $this->getSourcePath($path), $raw);
} }
public function free_space($path) { public function free_space($path): int|float|false {
$sourcePath = $this->getSourcePath($path); $sourcePath = $this->getSourcePath($path);
// using !is_dir because $sourcePath might be a part file or // using !is_dir because $sourcePath might be a part file or
// non-existing file, so we'd still want to use the parent dir // non-existing file, so we'd still want to use the parent dir
@ -417,20 +417,19 @@ class Local extends \OC\Files\Storage\Common {
return Util::numericToNumber($space); return Util::numericToNumber($space);
} }
public function search($query) { public function search($query): array {
return $this->searchInDir($query); return $this->searchInDir($query);
} }
public function getLocalFile($path) { public function getLocalFile($path): string|false {
return $this->getSourcePath($path); return $this->getSourcePath($path);
} }
/** /**
* @param string $query * @param string $query
* @param string $dir * @param string $dir
* @return array
*/ */
protected function searchInDir($query, $dir = '') { protected function searchInDir($query, $dir = ''): array {
$files = []; $files = [];
$physicalDir = $this->getSourcePath($dir); $physicalDir = $this->getSourcePath($dir);
foreach (scandir($physicalDir) as $item) { foreach (scandir($physicalDir) as $item) {
@ -449,14 +448,7 @@ class Local extends \OC\Files\Storage\Common {
return $files; return $files;
} }
/** public function hasUpdated($path, $time): bool {
* check if a file or folder has been updated since $time
*
* @param string $path
* @param int $time
* @return bool
*/
public function hasUpdated($path, $time) {
if ($this->file_exists($path)) { if ($this->file_exists($path)) {
return $this->filemtime($path) > $time; return $this->filemtime($path) > $time;
} else { } else {
@ -468,10 +460,9 @@ class Local extends \OC\Files\Storage\Common {
* Get the source path (on disk) of a given path * Get the source path (on disk) of a given path
* *
* @param string $path * @param string $path
* @return string
* @throws ForbiddenException * @throws ForbiddenException
*/ */
public function getSourcePath($path) { public function getSourcePath($path): string {
if (Filesystem::isFileBlacklisted($path)) { if (Filesystem::isFileBlacklisted($path)) {
throw new ForbiddenException('Invalid path: ' . $path, false); throw new ForbiddenException('Invalid path: ' . $path, false);
} }
@ -503,14 +494,11 @@ class Local extends \OC\Files\Storage\Common {
throw new ForbiddenException('Following symlinks is not allowed', false); throw new ForbiddenException('Following symlinks is not allowed', false);
} }
/** public function isLocal(): bool {
* {@inheritdoc}
*/
public function isLocal() {
return true; return true;
} }
public function getETag($path) { public function getETag($path): string|false {
return $this->calculateEtag($path, $this->stat($path)); return $this->calculateEtag($path, $this->stat($path));
} }
@ -540,7 +528,7 @@ class Local extends \OC\Files\Storage\Common {
} }
} }
private function canDoCrossStorageMove(IStorage $sourceStorage) { private function canDoCrossStorageMove(IStorage $sourceStorage): bool {
/** @psalm-suppress UndefinedClass */ /** @psalm-suppress UndefinedClass */
return $sourceStorage->instanceOfStorage(Local::class) return $sourceStorage->instanceOfStorage(Local::class)
// Don't treat ACLStorageWrapper like local storage where copy can be done directly. // Don't treat ACLStorageWrapper like local storage where copy can be done directly.
@ -553,14 +541,7 @@ class Local extends \OC\Files\Storage\Common {
&& !$sourceStorage->instanceOfStorage(Encryption::class); && !$sourceStorage->instanceOfStorage(Encryption::class);
} }
/** public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @param bool $preserveMtime
* @return bool
*/
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) {
if ($this->canDoCrossStorageMove($sourceStorage)) { if ($this->canDoCrossStorageMove($sourceStorage)) {
if ($sourceStorage->instanceOfStorage(Jail::class)) { if ($sourceStorage->instanceOfStorage(Jail::class)) {
/** /**
@ -584,7 +565,7 @@ class Local extends \OC\Files\Storage\Common {
* @param string $targetInternalPath * @param string $targetInternalPath
* @return bool * @return bool
*/ */
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
if ($this->canDoCrossStorageMove($sourceStorage)) { if ($this->canDoCrossStorageMove($sourceStorage)) {
if ($sourceStorage->instanceOfStorage(Jail::class)) { if ($sourceStorage->instanceOfStorage(Jail::class)) {
/** /**

@ -9,15 +9,13 @@ declare(strict_types=1);
namespace OC\Files\Storage; namespace OC\Files\Storage;
use OC\Files\Cache\LocalRootScanner; use OC\Files\Cache\LocalRootScanner;
use OCP\Files\Cache\IScanner;
class LocalRootStorage extends Local { class LocalRootStorage extends Local {
public function getScanner($path = '', $storage = null) { public function getScanner($path = '', $storage = null): IScanner {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
if (!isset($storage->scanner)) { return $storage->scanner ?? ($storage->scanner = new LocalRootScanner($storage));
$storage->scanner = new LocalRootScanner($storage);
}
return $storage->scanner;
} }
} }

@ -32,7 +32,7 @@ trait LocalTempFileTrait {
/** /**
* @param string $path * @param string $path
*/ */
protected function removeCachedFile($path) { protected function removeCachedFile($path): void {
unset($this->cachedFiles[$path]); unset($this->cachedFiles[$path]);
} }

@ -12,31 +12,28 @@ trait CopyDirectory {
* Check if a path is a directory * Check if a path is a directory
* *
* @param string $path * @param string $path
* @return bool
*/ */
abstract public function is_dir($path); abstract public function is_dir($path): bool;
/** /**
* Check if a file or folder exists * Check if a file or folder exists
* *
* @param string $path * @param string $path
* @return bool
*/ */
abstract public function file_exists($path); abstract public function file_exists($path): bool;
/** /**
* Delete a file or folder * Delete a file or folder
* *
* @param string $path * @param string $path
* @return bool
*/ */
abstract public function unlink($path); abstract public function unlink($path): bool;
/** /**
* Open a directory handle for a folder * Open a directory handle for a folder
* *
* @param string $path * @param string $path
* @return resource | bool * @return resource|false
*/ */
abstract public function opendir($path); abstract public function opendir($path);
@ -44,11 +41,10 @@ trait CopyDirectory {
* Create a new folder * Create a new folder
* *
* @param string $path * @param string $path
* @return bool
*/ */
abstract public function mkdir($path); abstract public function mkdir($path): bool;
public function copy($source, $target) { public function copy($source, $target): bool {
if ($this->is_dir($source)) { if ($this->is_dir($source)) {
if ($this->file_exists($target)) { if ($this->file_exists($target)) {
$this->unlink($target); $this->unlink($target);
@ -62,12 +58,8 @@ trait CopyDirectory {
/** /**
* For adapters that don't support copying folders natively * For adapters that don't support copying folders natively
*
* @param $source
* @param $target
* @return bool
*/ */
protected function copyRecursive($source, $target) { protected function copyRecursive($source, $target): bool {
$dh = $this->opendir($source); $dh = $this->opendir($source);
$result = true; $result = true;
while (($file = readdir($dh)) !== false) { while (($file = readdir($dh)) !== false) {

@ -8,11 +8,11 @@
namespace OC\Files\Storage; namespace OC\Files\Storage;
use OC\Files\Cache\Cache; use OCP\Files\Cache\ICache;
use OC\Files\Cache\Propagator; use OCP\Files\Cache\IPropagator;
use OC\Files\Cache\Scanner; use OCP\Files\Cache\IScanner;
use OC\Files\Cache\Updater; use OCP\Files\Cache\IUpdater;
use OC\Files\Cache\Watcher; use OCP\Files\Cache\IWatcher;
use OCP\Files\Storage\ILockingStorage; use OCP\Files\Storage\ILockingStorage;
use OCP\Files\Storage\IStorage; use OCP\Files\Storage\IStorage;
@ -23,51 +23,44 @@ use OCP\Files\Storage\IStorage;
*/ */
interface Storage extends IStorage, ILockingStorage { interface Storage extends IStorage, ILockingStorage {
/** /**
* @inheritDoc * @param string $path
* @return Cache * @param ?IStorage $storage
*/ */
public function getCache($path = '', $storage = null); public function getCache($path = '', $storage = null): ICache;
/** /**
* @inheritDoc * @param string $path
* @return Scanner * @param ?IStorage $storage
*/ */
public function getScanner($path = '', $storage = null); public function getScanner($path = '', $storage = null): IScanner;
/** /**
* @inheritDoc * @param string $path
* @return Watcher * @param ?IStorage $storage
*/ */
public function getWatcher($path = '', $storage = null); public function getWatcher($path = '', $storage = null): IWatcher;
/** /**
* @inheritDoc * @param ?IStorage $storage
* @return Propagator
*/ */
public function getPropagator($storage = null); public function getPropagator($storage = null): IPropagator;
/** /**
* @inheritDoc * @param ?IStorage $storage
* @return Updater
*/ */
public function getUpdater($storage = null); public function getUpdater($storage = null): IUpdater;
/** public function getStorageCache(): \OC\Files\Cache\Storage;
* @return \OC\Files\Cache\Storage
*/
public function getStorageCache();
/** /**
* @param string $path * @param string $path
* @return array|null
*/ */
public function getMetaData($path); public function getMetaData($path): ?array;
/** /**
* Get the contents of a directory with metadata * Get the contents of a directory with metadata
* *
* @param string $directory * @param string $directory
* @return \Traversable an iterator, containing file metadata
* *
* The metadata array will contain the following fields * The metadata array will contain the following fields
* *
@ -79,5 +72,5 @@ interface Storage extends IStorage, ILockingStorage {
* - storage_mtime * - storage_mtime
* - permissions * - permissions
*/ */
public function getDirectoryContent($directory): \Traversable; public function getDirectoryContent($directory): \Traversable|false;
} }

@ -19,19 +19,7 @@ class StorageFactory implements IStorageFactory {
*/ */
private $storageWrappers = []; private $storageWrappers = [];
/** public function addStorageWrapper($wrapperName, $callback, $priority = 50, $existingMounts = []): bool {
* allow modifier storage behaviour by adding wrappers around storages
*
* $callback should be a function of type (string $mountPoint, Storage $storage) => Storage
*
* @param string $wrapperName name of the wrapper
* @param callable $callback callback
* @param int $priority wrappers with the lower priority are applied last (meaning they get called first)
* @param \OCP\Files\Mount\IMountPoint[] $existingMounts existing mount points to apply the wrapper to
* @return bool true if the wrapper was added, false if there was already a wrapper with this
* name registered
*/
public function addStorageWrapper($wrapperName, $callback, $priority = 50, $existingMounts = []) {
if (isset($this->storageWrappers[$wrapperName])) { if (isset($this->storageWrappers[$wrapperName])) {
return false; return false;
} }
@ -52,7 +40,7 @@ class StorageFactory implements IStorageFactory {
* @param string $wrapperName name of the wrapper * @param string $wrapperName name of the wrapper
* @internal * @internal
*/ */
public function removeStorageWrapper($wrapperName) { public function removeStorageWrapper($wrapperName): void {
unset($this->storageWrappers[$wrapperName]); unset($this->storageWrappers[$wrapperName]);
} }
@ -63,7 +51,7 @@ class StorageFactory implements IStorageFactory {
* @param array $arguments * @param array $arguments
* @return IStorage * @return IStorage
*/ */
public function getInstance(IMountPoint $mountPoint, $class, $arguments) { public function getInstance(IMountPoint $mountPoint, $class, $arguments): IStorage {
if (!($class instanceof IConstructableStorage)) { if (!($class instanceof IConstructableStorage)) {
\OCP\Server::get(LoggerInterface::class)->warning('Building a storage not implementing IConstructableStorage is deprecated since 31.0.0', ['class' => $class]); \OCP\Server::get(LoggerInterface::class)->warning('Building a storage not implementing IConstructableStorage is deprecated since 31.0.0', ['class' => $class]);
} }
@ -72,9 +60,8 @@ class StorageFactory implements IStorageFactory {
/** /**
* @param IStorage $storage * @param IStorage $storage
* @return IStorage
*/ */
public function wrap(IMountPoint $mountPoint, $storage) { public function wrap(IMountPoint $mountPoint, $storage): IStorage {
$wrappers = array_values($this->storageWrappers); $wrappers = array_values($this->storageWrappers);
usort($wrappers, function ($a, $b) { usort($wrappers, function ($a, $b) {
return $b['priority'] - $a['priority']; return $b['priority'] - $a['priority'];

@ -15,7 +15,7 @@ class Temporary extends Local {
parent::__construct(['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]); parent::__construct(['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]);
} }
public function cleanUp() { public function cleanUp(): void {
\OC_Helper::rmdirr($this->datadir); \OC_Helper::rmdirr($this->datadir);
} }
@ -24,7 +24,7 @@ class Temporary extends Local {
$this->cleanUp(); $this->cleanUp();
} }
public function getDataDir() { public function getDataDir(): array|string {
return $this->datadir; return $this->datadir;
} }
} }

@ -28,7 +28,7 @@ class Availability extends Wrapper {
parent::__construct($parameters); parent::__construct($parameters);
} }
public static function shouldRecheck($availability) { public static function shouldRecheck($availability): bool {
if (!$availability['available']) { if (!$availability['available']) {
// trigger a recheck if TTL reached // trigger a recheck if TTL reached
if ((time() - $availability['last_checked']) > self::RECHECK_TTL_SEC) { if ((time() - $availability['last_checked']) > self::RECHECK_TTL_SEC) {
@ -40,10 +40,8 @@ class Availability extends Wrapper {
/** /**
* Only called if availability === false * 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 // reset availability to false so that multiple requests don't recheck concurrently
$this->setAvailability(false); $this->setAvailability(false);
try { try {
@ -55,10 +53,7 @@ class Availability extends Wrapper {
return $result; return $result;
} }
/** private function isAvailable(): bool {
* @return bool
*/
private function isAvailable() {
$availability = $this->getAvailability(); $availability = $this->getAvailability();
if (self::shouldRecheck($availability)) { if (self::shouldRecheck($availability)) {
return $this->updateAvailability(); return $this->updateAvailability();
@ -69,154 +64,153 @@ class Availability extends Wrapper {
/** /**
* @throws StorageNotAvailableException * @throws StorageNotAvailableException
*/ */
private function checkAvailability() { private function checkAvailability(): void {
if (!$this->isAvailable()) { if (!$this->isAvailable()) {
throw new StorageNotAvailableException(); throw new StorageNotAvailableException();
} }
} }
/** {@inheritdoc} */ public function mkdir($path): bool {
public function mkdir($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::mkdir($path); return parent::mkdir($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function rmdir($path): bool {
public function rmdir($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::rmdir($path); return parent::rmdir($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */
public function opendir($path) { public function opendir($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::opendir($path); return parent::opendir($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function is_dir($path): bool {
public function is_dir($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::is_dir($path); return parent::is_dir($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function is_file($path): bool {
public function is_file($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::is_file($path); return parent::is_file($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function stat($path): array|false {
public function stat($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::stat($path); return parent::stat($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function filetype($path): string|false {
public function filetype($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::filetype($path); return parent::filetype($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function filesize($path): int|float|false {
public function filesize($path): false|int|float {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::filesize($path); return parent::filesize($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function isCreatable($path): bool {
public function isCreatable($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::isCreatable($path); return parent::isCreatable($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function isReadable($path): bool {
public function isReadable($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::isReadable($path); return parent::isReadable($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function isUpdatable($path): bool {
public function isUpdatable($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::isUpdatable($path); return parent::isUpdatable($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function isDeletable($path): bool {
public function isDeletable($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::isDeletable($path); return parent::isDeletable($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function isSharable($path): bool {
public function isSharable($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::isSharable($path); return parent::isSharable($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function getPermissions($path): int {
public function getPermissions($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::getPermissions($path); return parent::getPermissions($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return 0;
} }
} }
/** {@inheritdoc} */ public function file_exists($path): bool {
public function file_exists($path) {
if ($path === '') { if ($path === '') {
return true; return true;
} }
@ -225,91 +219,91 @@ class Availability extends Wrapper {
return parent::file_exists($path); return parent::file_exists($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function filemtime($path): int|false {
public function filemtime($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::filemtime($path); return parent::filemtime($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function file_get_contents($path): string|false {
public function file_get_contents($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::file_get_contents($path); return parent::file_get_contents($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function file_put_contents($path, $data): int|float|false {
public function file_put_contents($path, $data) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::file_put_contents($path, $data); return parent::file_put_contents($path, $data);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function unlink($path): bool {
public function unlink($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::unlink($path); return parent::unlink($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function rename($source, $target): bool {
public function rename($source, $target) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::rename($source, $target); return parent::rename($source, $target);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function copy($source, $target): bool {
public function copy($source, $target) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::copy($source, $target); return parent::copy($source, $target);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */
public function fopen($path, $mode) { public function fopen($path, $mode) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::fopen($path, $mode); return parent::fopen($path, $mode);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function getMimeType($path): string|false {
public function getMimeType($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::getMimeType($path); return parent::getMimeType($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function hash($type, $path, $raw = false): string|false {
public function hash($type, $path, $raw = false) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::hash($type, $path, $raw); return parent::hash($type, $path, $raw);
@ -319,48 +313,37 @@ class Availability extends Wrapper {
} }
} }
/** {@inheritdoc} */ public function free_space($path): int|float|false {
public function free_space($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::free_space($path); return parent::free_space($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function touch($path, $mtime = null): bool {
public function search($query) {
$this->checkAvailability();
try {
return parent::search($query);
} catch (StorageNotAvailableException $e) {
$this->setUnavailable($e);
}
}
/** {@inheritdoc} */
public function touch($path, $mtime = null) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::touch($path, $mtime); return parent::touch($path, $mtime);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function getLocalFile($path): string|false {
public function getLocalFile($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::getLocalFile($path); return parent::getLocalFile($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function hasUpdated($path, $time): bool {
public function hasUpdated($path, $time) {
if (!$this->isAvailable()) { if (!$this->isAvailable()) {
return false; return false;
} }
@ -382,52 +365,53 @@ class Availability extends Wrapper {
} }
} }
/** {@inheritdoc} */ public function getETag($path): string|false {
public function getETag($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::getETag($path); return parent::getETag($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function getDirectDownload($path): array|false {
public function getDirectDownload($path) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::getDirectDownload($path); return parent::getDirectDownload($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
/** {@inheritdoc} */ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::getMetaData($path); return parent::getMetaData($path);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return null;
} }
} }
@ -454,12 +438,13 @@ class Availability extends Wrapper {
public function getDirectoryContent($directory): \Traversable { public function getDirectoryContent($directory): \Traversable|false {
$this->checkAvailability(); $this->checkAvailability();
try { try {
return parent::getDirectoryContent($directory); return parent::getDirectoryContent($directory);
} catch (StorageNotAvailableException $e) { } catch (StorageNotAvailableException $e) {
$this->setUnavailable($e); $this->setUnavailable($e);
return false;
} }
} }
} }

@ -9,6 +9,7 @@ namespace OC\Files\Storage\Wrapper;
use OC\Files\Filesystem; use OC\Files\Filesystem;
use OCP\Cache\CappedMemoryCache; use OCP\Cache\CappedMemoryCache;
use OCP\Files\Cache\IScanner;
use OCP\Files\Storage\IStorage; use OCP\Files\Storage\IStorage;
use OCP\ICache; use OCP\ICache;
@ -36,10 +37,8 @@ class Encoding extends Wrapper {
* Returns whether the given string is only made of ASCII characters * Returns whether the given string is only made of ASCII characters
* *
* @param string $str string * @param string $str string
*
* @return bool true if the string is all ASCII, false otherwise
*/ */
private function isAscii($str) { private function isAscii($str): bool {
return !preg_match('/[\\x80-\\xff]+/', $str); return !preg_match('/[\\x80-\\xff]+/', $str);
} }
@ -52,7 +51,7 @@ class Encoding extends Wrapper {
* *
* @return string original or converted path * @return string original or converted path
*/ */
private function findPathToUse($fullPath) { private function findPathToUse($fullPath): string {
$cachedPath = $this->namesCache[$fullPath]; $cachedPath = $this->namesCache[$fullPath];
if ($cachedPath !== null) { if ($cachedPath !== null) {
return $cachedPath; return $cachedPath;
@ -81,7 +80,7 @@ class Encoding extends Wrapper {
* *
* @return string|null original or converted path, or null if none of the forms was found * @return string|null original or converted path, or null if none of the forms was found
*/ */
private function findPathToUseLastSection($basePath, $lastSection) { private function findPathToUseLastSection($basePath, $lastSection): ?string {
$fullPath = $basePath . $lastSection; $fullPath = $basePath . $lastSection;
if ($lastSection === '' || $this->isAscii($lastSection) || $this->storage->file_exists($fullPath)) { if ($lastSection === '' || $this->isAscii($lastSection) || $this->storage->file_exists($fullPath)) {
$this->namesCache[$fullPath] = $fullPath; $this->namesCache[$fullPath] = $fullPath;
@ -105,13 +104,7 @@ class Encoding extends Wrapper {
return null; return null;
} }
/** public function mkdir($path): bool {
* see https://www.php.net/manual/en/function.mkdir.php
*
* @param string $path
* @return bool
*/
public function mkdir($path) {
// note: no conversion here, method should not be called with non-NFC names! // note: no conversion here, method should not be called with non-NFC names!
$result = $this->storage->mkdir($path); $result = $this->storage->mkdir($path);
if ($result) { if ($result) {
@ -120,13 +113,7 @@ class Encoding extends Wrapper {
return $result; return $result;
} }
/** public function rmdir($path): bool {
* see https://www.php.net/manual/en/function.rmdir.php
*
* @param string $path
* @return bool
*/
public function rmdir($path) {
$result = $this->storage->rmdir($this->findPathToUse($path)); $result = $this->storage->rmdir($this->findPathToUse($path));
if ($result) { if ($result) {
unset($this->namesCache[$path]); unset($this->namesCache[$path]);
@ -134,175 +121,72 @@ class Encoding extends Wrapper {
return $result; 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($path) {
$handle = $this->storage->opendir($this->findPathToUse($path)); $handle = $this->storage->opendir($this->findPathToUse($path));
return EncodingDirectoryWrapper::wrap($handle); return EncodingDirectoryWrapper::wrap($handle);
} }
/** public function is_dir($path): bool {
* see https://www.php.net/manual/en/function.is_dir.php
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
return $this->storage->is_dir($this->findPathToUse($path)); return $this->storage->is_dir($this->findPathToUse($path));
} }
/** public function is_file($path): bool {
* see https://www.php.net/manual/en/function.is_file.php
*
* @param string $path
* @return bool
*/
public function is_file($path) {
return $this->storage->is_file($this->findPathToUse($path)); return $this->storage->is_file($this->findPathToUse($path));
} }
/** public function stat($path): array|false {
* 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) {
return $this->storage->stat($this->findPathToUse($path)); return $this->storage->stat($this->findPathToUse($path));
} }
/** public function filetype($path): string|false {
* see https://www.php.net/manual/en/function.filetype.php
*
* @param string $path
* @return string|bool
*/
public function filetype($path) {
return $this->storage->filetype($this->findPathToUse($path)); return $this->storage->filetype($this->findPathToUse($path));
} }
/** public function filesize($path): int|float|false {
* 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 {
return $this->storage->filesize($this->findPathToUse($path)); return $this->storage->filesize($this->findPathToUse($path));
} }
/** public function isCreatable($path): bool {
* check if a file can be created in $path
*
* @param string $path
* @return bool
*/
public function isCreatable($path) {
return $this->storage->isCreatable($this->findPathToUse($path)); return $this->storage->isCreatable($this->findPathToUse($path));
} }
/** public function isReadable($path): bool {
* check if a file can be read
*
* @param string $path
* @return bool
*/
public function isReadable($path) {
return $this->storage->isReadable($this->findPathToUse($path)); return $this->storage->isReadable($this->findPathToUse($path));
} }
/** public function isUpdatable($path): bool {
* check if a file can be written to
*
* @param string $path
* @return bool
*/
public function isUpdatable($path) {
return $this->storage->isUpdatable($this->findPathToUse($path)); return $this->storage->isUpdatable($this->findPathToUse($path));
} }
/** public function isDeletable($path): bool {
* check if a file can be deleted
*
* @param string $path
* @return bool
*/
public function isDeletable($path) {
return $this->storage->isDeletable($this->findPathToUse($path)); return $this->storage->isDeletable($this->findPathToUse($path));
} }
/** public function isSharable($path): bool {
* check if a file can be shared
*
* @param string $path
* @return bool
*/
public function isSharable($path) {
return $this->storage->isSharable($this->findPathToUse($path)); return $this->storage->isSharable($this->findPathToUse($path));
} }
/** public function getPermissions($path): int {
* 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) {
return $this->storage->getPermissions($this->findPathToUse($path)); return $this->storage->getPermissions($this->findPathToUse($path));
} }
/** public function file_exists($path): bool {
* see https://www.php.net/manual/en/function.file_exists.php
*
* @param string $path
* @return bool
*/
public function file_exists($path) {
return $this->storage->file_exists($this->findPathToUse($path)); return $this->storage->file_exists($this->findPathToUse($path));
} }
/** public function filemtime($path): int|false {
* see https://www.php.net/manual/en/function.filemtime.php
*
* @param string $path
* @return int|bool
*/
public function filemtime($path) {
return $this->storage->filemtime($this->findPathToUse($path)); return $this->storage->filemtime($this->findPathToUse($path));
} }
/** public function file_get_contents($path): string|false {
* see https://www.php.net/manual/en/function.file_get_contents.php
*
* @param string $path
* @return string|false
*/
public function file_get_contents($path) {
return $this->storage->file_get_contents($this->findPathToUse($path)); return $this->storage->file_get_contents($this->findPathToUse($path));
} }
/** public function file_put_contents($path, $data): int|float|false {
* 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) {
return $this->storage->file_put_contents($this->findPathToUse($path), $data); return $this->storage->file_put_contents($this->findPathToUse($path), $data);
} }
/** public function unlink($path): bool {
* see https://www.php.net/manual/en/function.unlink.php
*
* @param string $path
* @return bool
*/
public function unlink($path) {
$result = $this->storage->unlink($this->findPathToUse($path)); $result = $this->storage->unlink($this->findPathToUse($path));
if ($result) { if ($result) {
unset($this->namesCache[$path]); unset($this->namesCache[$path]);
@ -310,36 +194,15 @@ class Encoding extends Wrapper {
return $result; return $result;
} }
/** public function rename($source, $target): bool {
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function rename($source, $target) {
// second name always NFC // second name always NFC
return $this->storage->rename($this->findPathToUse($source), $this->findPathToUse($target)); return $this->storage->rename($this->findPathToUse($source), $this->findPathToUse($target));
} }
/** public function copy($source, $target): bool {
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function copy($source, $target) {
return $this->storage->copy($this->findPathToUse($source), $this->findPathToUse($target)); 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($path, $mode) {
$result = $this->storage->fopen($this->findPathToUse($path), $mode); $result = $this->storage->fopen($this->findPathToUse($path), $mode);
if ($result && $mode !== 'r' && $mode !== 'rb') { if ($result && $mode !== 'r' && $mode !== 'rb') {
@ -348,107 +211,49 @@ class Encoding extends Wrapper {
return $result; return $result;
} }
/** public function getMimeType($path): string|false {
* 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) {
return $this->storage->getMimeType($this->findPathToUse($path)); return $this->storage->getMimeType($this->findPathToUse($path));
} }
/** public function hash($type, $path, $raw = false): string|false {
* 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) {
return $this->storage->hash($type, $this->findPathToUse($path), $raw); return $this->storage->hash($type, $this->findPathToUse($path), $raw);
} }
/** public function free_space($path): int|float|false {
* see https://www.php.net/manual/en/function.free_space.php
*
* @param string $path
* @return int|float|bool
*/
public function free_space($path) {
return $this->storage->free_space($this->findPathToUse($path)); return $this->storage->free_space($this->findPathToUse($path));
} }
/** public function touch($path, $mtime = null): bool {
* 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) {
return $this->storage->touch($this->findPathToUse($path), $mtime); return $this->storage->touch($this->findPathToUse($path), $mtime);
} }
/** public function getLocalFile($path): string|false {
* 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) {
return $this->storage->getLocalFile($this->findPathToUse($path)); return $this->storage->getLocalFile($this->findPathToUse($path));
} }
/** public function hasUpdated($path, $time): bool {
* 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) {
return $this->storage->hasUpdated($this->findPathToUse($path), $time); return $this->storage->hasUpdated($this->findPathToUse($path), $time);
} }
public function getCache($path = '', $storage = null) { public function getCache($path = '', $storage = null): \OCP\Files\Cache\ICache {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
return $this->storage->getCache($this->findPathToUse($path), $storage); return $this->storage->getCache($this->findPathToUse($path), $storage);
} }
public function getScanner($path = '', $storage = null) { public function getScanner($path = '', $storage = null): IScanner {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
return $this->storage->getScanner($this->findPathToUse($path), $storage); return $this->storage->getScanner($this->findPathToUse($path), $storage);
} }
/** public function getETag($path): string|false {
* get the ETag for a file or folder
*
* @param string $path
* @return string|false
*/
public function getETag($path) {
return $this->storage->getETag($this->findPathToUse($path)); return $this->storage->getETag($this->findPathToUse($path));
} }
/** public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
return $this->copy($sourceInternalPath, $this->findPathToUse($targetInternalPath)); return $this->copy($sourceInternalPath, $this->findPathToUse($targetInternalPath));
} }
@ -460,13 +265,7 @@ class Encoding extends Wrapper {
return $result; return $result;
} }
/** public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
$result = $this->rename($sourceInternalPath, $this->findPathToUse($targetInternalPath)); $result = $this->rename($sourceInternalPath, $this->findPathToUse($targetInternalPath));
if ($result) { if ($result) {
@ -484,7 +283,7 @@ class Encoding extends Wrapper {
return $result; return $result;
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
$entry = $this->storage->getMetaData($this->findPathToUse($path)); $entry = $this->storage->getMetaData($this->findPathToUse($path));
$entry['name'] = trim(Filesystem::normalizePath($entry['name']), '/'); $entry['name'] = trim(Filesystem::normalizePath($entry['name']), '/');
return $entry; return $entry;

@ -13,11 +13,7 @@ use OC\Files\Filesystem;
* Normalize file names while reading directory entries * Normalize file names while reading directory entries
*/ */
class EncodingDirectoryWrapper extends DirectoryWrapper { class EncodingDirectoryWrapper extends DirectoryWrapper {
/** public function dir_readdir(): string|false {
* @psalm-suppress ImplementedReturnTypeMismatch Until return type is fixed upstream
* @return string|false
*/
public function dir_readdir() {
$file = readdir($this->source); $file = readdir($this->source);
if ($file !== false && $file !== '.' && $file !== '..') { if ($file !== false && $file !== '.' && $file !== '..') {
$file = trim(Filesystem::normalizePath($file), '/'); $file = trim(Filesystem::normalizePath($file), '/');
@ -28,7 +24,6 @@ class EncodingDirectoryWrapper extends DirectoryWrapper {
/** /**
* @param resource $source * @param resource $source
* @param callable $filter
* @return resource|false * @return resource|false
*/ */
public static function wrap($source) { public static function wrap($source) {

@ -18,7 +18,6 @@ use OC\Files\Storage\Common;
use OC\Files\Storage\LocalTempFileTrait; use OC\Files\Storage\LocalTempFileTrait;
use OC\Memcache\ArrayCache; use OC\Memcache\ArrayCache;
use OCP\Cache\CappedMemoryCache; use OCP\Cache\CappedMemoryCache;
use OCP\Encryption\Exceptions\GenericEncryptionException;
use OCP\Encryption\IFile; use OCP\Encryption\IFile;
use OCP\Encryption\IManager; use OCP\Encryption\IManager;
use OCP\Encryption\Keys\IStorage; use OCP\Encryption\Keys\IStorage;
@ -104,11 +103,7 @@ class Encryption extends Wrapper {
parent::__construct($parameters); parent::__construct($parameters);
} }
/** public function filesize($path): int|float|false {
* 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 {
$fullPath = $this->getFullPath($path); $fullPath = $this->getFullPath($path);
$info = $this->getCache()->get($path); $info = $this->getCache()->get($path);
@ -179,7 +174,7 @@ class Encryption extends Wrapper {
return $data; return $data;
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
$data = $this->storage->getMetaData($path); $data = $this->storage->getMetaData($path);
if (is_null($data)) { if (is_null($data)) {
return null; return null;
@ -194,13 +189,7 @@ class Encryption extends Wrapper {
} }
} }
/** public function file_get_contents($path): string|false {
* see https://www.php.net/manual/en/function.file_get_contents.php
*
* @param string $path
* @return string|false
*/
public function file_get_contents($path) {
$encryptionModule = $this->getEncryptionModule($path); $encryptionModule = $this->getEncryptionModule($path);
if ($encryptionModule) { if ($encryptionModule) {
@ -215,14 +204,7 @@ class Encryption extends Wrapper {
return $this->storage->file_get_contents($path); return $this->storage->file_get_contents($path);
} }
/** public function file_put_contents($path, $data): int|float|false {
* 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) {
// file put content will always be translated to a stream write // file put content will always be translated to a stream write
$handle = $this->fopen($path, 'w'); $handle = $this->fopen($path, 'w');
if (is_resource($handle)) { if (is_resource($handle)) {
@ -234,13 +216,7 @@ class Encryption extends Wrapper {
return false; return false;
} }
/** public function unlink($path): bool {
* see https://www.php.net/manual/en/function.unlink.php
*
* @param string $path
* @return bool
*/
public function unlink($path) {
$fullPath = $this->getFullPath($path); $fullPath = $this->getFullPath($path);
if ($this->util->isExcluded($fullPath)) { if ($this->util->isExcluded($fullPath)) {
return $this->storage->unlink($path); return $this->storage->unlink($path);
@ -254,14 +230,7 @@ class Encryption extends Wrapper {
return $this->storage->unlink($path); return $this->storage->unlink($path);
} }
/** public function rename($source, $target): bool {
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function rename($source, $target) {
$result = $this->storage->rename($source, $target); $result = $this->storage->rename($source, $target);
if ($result && if ($result &&
@ -286,13 +255,7 @@ class Encryption extends Wrapper {
return $result; return $result;
} }
/** public function rmdir($path): bool {
* see https://www.php.net/manual/en/function.rmdir.php
*
* @param string $path
* @return bool
*/
public function rmdir($path) {
$result = $this->storage->rmdir($path); $result = $this->storage->rmdir($path);
$fullPath = $this->getFullPath($path); $fullPath = $this->getFullPath($path);
if ($result && if ($result &&
@ -305,13 +268,7 @@ class Encryption extends Wrapper {
return $result; return $result;
} }
/** public function isReadable($path): bool {
* check if a file can be read
*
* @param string $path
* @return bool
*/
public function isReadable($path) {
$isReadable = true; $isReadable = true;
$metaData = $this->getMetaData($path); $metaData = $this->getMetaData($path);
@ -328,12 +285,6 @@ class Encryption extends Wrapper {
return $this->storage->isReadable($path) && $isReadable; 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($source, $target): bool {
$sourcePath = $this->getFullPath($source); $sourcePath = $this->getFullPath($source);
@ -347,15 +298,6 @@ class Encryption extends Wrapper {
return $this->copyFromStorage($this, $source, $target); 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($path, $mode) {
// check if the file is stored in the array cache, this means that we // 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 // copy a file over to the versions folder, in this case we don't want to
@ -409,10 +351,8 @@ class Encryption extends Wrapper {
// if we update a encrypted file with a un-encrypted one we change the db flag // if we update a encrypted file with a un-encrypted one we change the db flag
if ($targetIsEncrypted && $encryptionEnabled === false) { if ($targetIsEncrypted && $encryptionEnabled === false) {
$cache = $this->storage->getCache(); $cache = $this->storage->getCache();
if ($cache) { $entry = $cache->get($path);
$entry = $cache->get($path); $cache->update($entry->getId(), ['encrypted' => 0]);
$cache->update($entry->getId(), ['encrypted' => 0]);
}
} }
if ($encryptionEnabled) { if ($encryptionEnabled) {
// if $encryptionModuleId is empty, the default module will be used // if $encryptionModuleId is empty, the default module will be used
@ -508,10 +448,8 @@ class Encryption extends Wrapper {
* @param string $path internal path relative to the storage root * @param string $path internal path relative to the storage root
* @param int $size size of the physical file * @param int $size size of the physical file
* @param int $unencryptedSize size of the unencrypted 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); $headerSize = $this->getHeaderSize($path);
$header = $this->getHeader($path); $header = $this->getHeader($path);
$encryptionModule = $this->getEncryptionModule($path); $encryptionModule = $this->getEncryptionModule($path);
@ -580,12 +518,10 @@ class Encryption extends Wrapper {
// write to cache if applicable // write to cache if applicable
$cache = $this->storage->getCache(); $cache = $this->storage->getCache();
if ($cache) { $entry = $cache->get($path);
$entry = $cache->get($path); $cache->update($entry['fileid'], [
$cache->update($entry['fileid'], [ 'unencrypted_size' => $newUnencryptedSize
'unencrypted_size' => $newUnencryptedSize ]);
]);
}
return $newUnencryptedSize; return $newUnencryptedSize;
} }
@ -617,19 +553,12 @@ class Encryption extends Wrapper {
return $data; return $data;
} }
/**
* @param Storage\IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @param bool $preserveMtime
* @return bool
*/
public function moveFromStorage( public function moveFromStorage(
Storage\IStorage $sourceStorage, Storage\IStorage $sourceStorage,
$sourceInternalPath, $sourceInternalPath,
$targetInternalPath, $targetInternalPath,
$preserveMtime = true, $preserveMtime = true,
) { ): bool {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
return $this->rename($sourceInternalPath, $targetInternalPath); return $this->rename($sourceInternalPath, $targetInternalPath);
} }
@ -647,30 +576,21 @@ class Encryption extends Wrapper {
$result = $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, true); $result = $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, true);
if ($result) { if ($result) {
if ($sourceStorage->is_dir($sourceInternalPath)) { if ($sourceStorage->is_dir($sourceInternalPath)) {
$result &= $sourceStorage->rmdir($sourceInternalPath); $result = $sourceStorage->rmdir($sourceInternalPath);
} else { } else {
$result &= $sourceStorage->unlink($sourceInternalPath); $result = $sourceStorage->unlink($sourceInternalPath);
} }
} }
return $result; return $result;
} }
/**
* @param Storage\IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @param bool $preserveMtime
* @param bool $isRename
* @return bool
*/
public function copyFromStorage( public function copyFromStorage(
Storage\IStorage $sourceStorage, Storage\IStorage $sourceStorage,
$sourceInternalPath, $sourceInternalPath,
$targetInternalPath, $targetInternalPath,
$preserveMtime = false, $preserveMtime = false,
$isRename = false, $isRename = false,
) { ): bool {
// TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed: // TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed:
// - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage // - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage
// - copy the file cache update from $this->copyBetweenStorage to this method // - copy the file cache update from $this->copyBetweenStorage to this method
@ -695,7 +615,7 @@ class Encryption extends Wrapper {
$targetInternalPath, $targetInternalPath,
$isRename, $isRename,
$keepEncryptionVersion, $keepEncryptionVersion,
) { ): void {
$isEncrypted = $this->encryptionManager->isEnabled() && $this->shouldEncrypt($targetInternalPath); $isEncrypted = $this->encryptionManager->isEnabled() && $this->shouldEncrypt($targetInternalPath);
$cacheInformation = [ $cacheInformation = [
'encrypted' => $isEncrypted, 'encrypted' => $isEncrypted,
@ -750,7 +670,7 @@ class Encryption extends Wrapper {
$targetInternalPath, $targetInternalPath,
$preserveMtime, $preserveMtime,
$isRename, $isRename,
) { ): bool {
// for versions we have nothing to do, because versions should always use the // 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 // key from the original file. Just create a 1:1 copy and done
if ($this->isVersion($targetInternalPath) || if ($this->isVersion($targetInternalPath) ||
@ -828,7 +748,7 @@ class Encryption extends Wrapper {
return (bool)$result; return (bool)$result;
} }
public function getLocalFile($path) { public function getLocalFile($path): string|false {
if ($this->encryptionManager->isEnabled()) { if ($this->encryptionManager->isEnabled()) {
$cachedFile = $this->getCachedFile($path); $cachedFile = $this->getCachedFile($path);
if (is_string($cachedFile)) { if (is_string($cachedFile)) {
@ -838,14 +758,14 @@ class Encryption extends Wrapper {
return $this->storage->getLocalFile($path); return $this->storage->getLocalFile($path);
} }
public function isLocal() { public function isLocal(): bool {
if ($this->encryptionManager->isEnabled()) { if ($this->encryptionManager->isEnabled()) {
return false; return false;
} }
return $this->storage->isLocal(); return $this->storage->isLocal();
} }
public function stat($path) { public function stat($path): array|false {
$stat = $this->storage->stat($path); $stat = $this->storage->stat($path);
if (!$stat) { if (!$stat) {
return false; return false;
@ -857,7 +777,7 @@ class Encryption extends Wrapper {
return $stat; return $stat;
} }
public function hash($type, $path, $raw = false) { public function hash($type, $path, $raw = false): string|false {
$fh = $this->fopen($path, 'rb'); $fh = $this->fopen($path, 'rb');
$ctx = hash_init($type); $ctx = hash_init($type);
hash_update_stream($ctx, $fh); hash_update_stream($ctx, $fh);
@ -871,7 +791,7 @@ class Encryption extends Wrapper {
* @param string $path relative to mount point * @param string $path relative to mount point
* @return string full path including mount point * @return string full path including mount point
*/ */
protected function getFullPath($path) { protected function getFullPath($path): string {
return Filesystem::normalizePath($this->mountPoint . '/' . $path); return Filesystem::normalizePath($this->mountPoint . '/' . $path);
} }
@ -882,7 +802,7 @@ class Encryption extends Wrapper {
* @param string $path * @param string $path
* @return string * @return string
*/ */
protected function readFirstBlock($path) { protected function readFirstBlock($path): string {
$firstBlock = ''; $firstBlock = '';
if ($this->storage->is_file($path)) { if ($this->storage->is_file($path)) {
$handle = $this->storage->fopen($path, 'r'); $handle = $this->storage->fopen($path, 'r');
@ -898,7 +818,7 @@ class Encryption extends Wrapper {
* @param string $path * @param string $path
* @return int * @return int
*/ */
protected function getHeaderSize($path) { protected function getHeaderSize($path): int {
$headerSize = 0; $headerSize = 0;
$realFile = $this->util->stripPartialFileExtension($path); $realFile = $this->util->stripPartialFileExtension($path);
if ($this->storage->is_file($realFile)) { if ($this->storage->is_file($realFile)) {
@ -919,7 +839,7 @@ class Encryption extends Wrapper {
* @param string $path * @param string $path
* @return array * @return array
*/ */
protected function getHeader($path) { protected function getHeader($path): array {
$realFile = $this->util->stripPartialFileExtension($path); $realFile = $this->util->stripPartialFileExtension($path);
$exists = $this->storage->is_file($realFile); $exists = $this->storage->is_file($realFile);
if ($exists) { if ($exists) {
@ -956,7 +876,7 @@ class Encryption extends Wrapper {
* @throws ModuleDoesNotExistsException * @throws ModuleDoesNotExistsException
* @throws \Exception * @throws \Exception
*/ */
protected function getEncryptionModule($path) { protected function getEncryptionModule($path): ?\OCP\Encryption\IEncryptionModule {
$encryptionModule = null; $encryptionModule = null;
$header = $this->getHeader($path); $header = $this->getHeader($path);
$encryptionModuleId = $this->util->getEncryptionModuleId($header); $encryptionModuleId = $this->util->getEncryptionModuleId($header);
@ -976,7 +896,7 @@ class Encryption extends Wrapper {
* @param string $path * @param string $path
* @param int $unencryptedSize * @param int $unencryptedSize
*/ */
public function updateUnencryptedSize($path, $unencryptedSize) { public function updateUnencryptedSize($path, $unencryptedSize): void {
$this->unencryptedSize[$path] = $unencryptedSize; $this->unencryptedSize[$path] = $unencryptedSize;
} }
@ -987,7 +907,7 @@ class Encryption extends Wrapper {
* @param string $target path relative to data/ * @param string $target path relative to data/
* @return bool * @return bool
*/ */
protected function copyKeys($source, $target) { protected function copyKeys($source, $target): bool {
if (!$this->util->isExcluded($source)) { if (!$this->util->isExcluded($source)) {
return $this->keyStorage->copyKeys($source, $target); return $this->keyStorage->copyKeys($source, $target);
} }
@ -1001,7 +921,7 @@ class Encryption extends Wrapper {
* @param $path * @param $path
* @return bool * @return bool
*/ */
protected function isVersion($path) { protected function isVersion($path): bool {
$normalized = Filesystem::normalizePath($path); $normalized = Filesystem::normalizePath($path);
return substr($normalized, 0, strlen('/files_versions/')) === '/files_versions/'; return substr($normalized, 0, strlen('/files_versions/')) === '/files_versions/';
} }
@ -1012,7 +932,7 @@ class Encryption extends Wrapper {
* @param $path * @param $path
* @return bool * @return bool
*/ */
protected function shouldEncrypt($path) { protected function shouldEncrypt($path): bool {
$fullPath = $this->getFullPath($path); $fullPath = $this->getFullPath($path);
$mountPointConfig = $this->mount->getOption('encrypt', true); $mountPointConfig = $this->mount->getOption('encrypt', true);
if ($mountPointConfig === false) { if ($mountPointConfig === false) {

@ -11,6 +11,9 @@ use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Cache\Wrapper\JailPropagator; use OC\Files\Cache\Wrapper\JailPropagator;
use OC\Files\Cache\Wrapper\JailWatcher; use OC\Files\Cache\Wrapper\JailWatcher;
use OC\Files\Filesystem; use OC\Files\Filesystem;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\IPropagator;
use OCP\Files\Cache\IWatcher;
use OCP\Files\Storage\IStorage; use OCP\Files\Storage\IStorage;
use OCP\Files\Storage\IWriteStreamStorage; use OCP\Files\Storage\IWriteStreamStorage;
use OCP\Lock\ILockingProvider; use OCP\Lock\ILockingProvider;
@ -37,19 +40,19 @@ class Jail extends Wrapper {
$this->rootPath = $arguments['root']; $this->rootPath = $arguments['root'];
} }
public function getUnjailedPath($path) { public function getUnjailedPath($path): string {
return trim(Filesystem::normalizePath($this->rootPath . '/' . $path), '/'); 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 * 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; return $this->storage;
} }
public function getJailedPath($path) { public function getJailedPath($path): ?string {
$root = rtrim($this->rootPath, '/') . '/'; $root = rtrim($this->rootPath, '/') . '/';
if ($path !== $this->rootPath && !str_starts_with($path, $root)) { if ($path !== $this->rootPath && !str_starts_with($path, $root)) {
@ -60,305 +63,123 @@ class Jail extends Wrapper {
} }
} }
public function getId() { public function getId(): string {
return parent::getId(); return parent::getId();
} }
/** public function mkdir($path): bool {
* see https://www.php.net/manual/en/function.mkdir.php
*
* @param string $path
* @return bool
*/
public function mkdir($path) {
return $this->getWrapperStorage()->mkdir($this->getUnjailedPath($path)); return $this->getWrapperStorage()->mkdir($this->getUnjailedPath($path));
} }
/** public function rmdir($path): bool {
* see https://www.php.net/manual/en/function.rmdir.php
*
* @param string $path
* @return bool
*/
public function rmdir($path) {
return $this->getWrapperStorage()->rmdir($this->getUnjailedPath($path)); 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($path) {
return $this->getWrapperStorage()->opendir($this->getUnjailedPath($path)); return $this->getWrapperStorage()->opendir($this->getUnjailedPath($path));
} }
/** public function is_dir($path): bool {
* see https://www.php.net/manual/en/function.is_dir.php
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
return $this->getWrapperStorage()->is_dir($this->getUnjailedPath($path)); return $this->getWrapperStorage()->is_dir($this->getUnjailedPath($path));
} }
/** public function is_file($path): bool {
* see https://www.php.net/manual/en/function.is_file.php
*
* @param string $path
* @return bool
*/
public function is_file($path) {
return $this->getWrapperStorage()->is_file($this->getUnjailedPath($path)); return $this->getWrapperStorage()->is_file($this->getUnjailedPath($path));
} }
/** public function stat($path): array|false {
* 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) {
return $this->getWrapperStorage()->stat($this->getUnjailedPath($path)); return $this->getWrapperStorage()->stat($this->getUnjailedPath($path));
} }
/** public function filetype($path): string|false {
* see https://www.php.net/manual/en/function.filetype.php
*
* @param string $path
* @return bool
*/
public function filetype($path) {
return $this->getWrapperStorage()->filetype($this->getUnjailedPath($path)); return $this->getWrapperStorage()->filetype($this->getUnjailedPath($path));
} }
/** public function filesize($path): int|float|false {
* 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 {
return $this->getWrapperStorage()->filesize($this->getUnjailedPath($path)); return $this->getWrapperStorage()->filesize($this->getUnjailedPath($path));
} }
/** public function isCreatable($path): bool {
* check if a file can be created in $path
*
* @param string $path
* @return bool
*/
public function isCreatable($path) {
return $this->getWrapperStorage()->isCreatable($this->getUnjailedPath($path)); return $this->getWrapperStorage()->isCreatable($this->getUnjailedPath($path));
} }
/** public function isReadable($path): bool {
* check if a file can be read
*
* @param string $path
* @return bool
*/
public function isReadable($path) {
return $this->getWrapperStorage()->isReadable($this->getUnjailedPath($path)); return $this->getWrapperStorage()->isReadable($this->getUnjailedPath($path));
} }
/** public function isUpdatable($path): bool {
* check if a file can be written to
*
* @param string $path
* @return bool
*/
public function isUpdatable($path) {
return $this->getWrapperStorage()->isUpdatable($this->getUnjailedPath($path)); return $this->getWrapperStorage()->isUpdatable($this->getUnjailedPath($path));
} }
/** public function isDeletable($path): bool {
* check if a file can be deleted
*
* @param string $path
* @return bool
*/
public function isDeletable($path) {
return $this->getWrapperStorage()->isDeletable($this->getUnjailedPath($path)); return $this->getWrapperStorage()->isDeletable($this->getUnjailedPath($path));
} }
/** public function isSharable($path): bool {
* check if a file can be shared
*
* @param string $path
* @return bool
*/
public function isSharable($path) {
return $this->getWrapperStorage()->isSharable($this->getUnjailedPath($path)); return $this->getWrapperStorage()->isSharable($this->getUnjailedPath($path));
} }
/** public function getPermissions($path): int {
* 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) {
return $this->getWrapperStorage()->getPermissions($this->getUnjailedPath($path)); return $this->getWrapperStorage()->getPermissions($this->getUnjailedPath($path));
} }
/** public function file_exists($path): bool {
* see https://www.php.net/manual/en/function.file_exists.php
*
* @param string $path
* @return bool
*/
public function file_exists($path) {
return $this->getWrapperStorage()->file_exists($this->getUnjailedPath($path)); return $this->getWrapperStorage()->file_exists($this->getUnjailedPath($path));
} }
/** public function filemtime($path): int|false {
* see https://www.php.net/manual/en/function.filemtime.php
*
* @param string $path
* @return int|bool
*/
public function filemtime($path) {
return $this->getWrapperStorage()->filemtime($this->getUnjailedPath($path)); return $this->getWrapperStorage()->filemtime($this->getUnjailedPath($path));
} }
/** public function file_get_contents($path): string|false {
* see https://www.php.net/manual/en/function.file_get_contents.php
*
* @param string $path
* @return string|false
*/
public function file_get_contents($path) {
return $this->getWrapperStorage()->file_get_contents($this->getUnjailedPath($path)); return $this->getWrapperStorage()->file_get_contents($this->getUnjailedPath($path));
} }
/** public function file_put_contents($path, $data): int|float|false {
* 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) {
return $this->getWrapperStorage()->file_put_contents($this->getUnjailedPath($path), $data); return $this->getWrapperStorage()->file_put_contents($this->getUnjailedPath($path), $data);
} }
/** public function unlink($path): bool {
* see https://www.php.net/manual/en/function.unlink.php
*
* @param string $path
* @return bool
*/
public function unlink($path) {
return $this->getWrapperStorage()->unlink($this->getUnjailedPath($path)); return $this->getWrapperStorage()->unlink($this->getUnjailedPath($path));
} }
/** public function rename($source, $target): bool {
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function rename($source, $target) {
return $this->getWrapperStorage()->rename($this->getUnjailedPath($source), $this->getUnjailedPath($target)); return $this->getWrapperStorage()->rename($this->getUnjailedPath($source), $this->getUnjailedPath($target));
} }
/** public function copy($source, $target): bool {
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function copy($source, $target) {
return $this->getWrapperStorage()->copy($this->getUnjailedPath($source), $this->getUnjailedPath($target)); 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($path, $mode) {
return $this->getWrapperStorage()->fopen($this->getUnjailedPath($path), $mode); return $this->getWrapperStorage()->fopen($this->getUnjailedPath($path), $mode);
} }
/** public function getMimeType($path): string|false {
* 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) {
return $this->getWrapperStorage()->getMimeType($this->getUnjailedPath($path)); return $this->getWrapperStorage()->getMimeType($this->getUnjailedPath($path));
} }
/** public function hash($type, $path, $raw = false): string|false {
* 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) {
return $this->getWrapperStorage()->hash($type, $this->getUnjailedPath($path), $raw); return $this->getWrapperStorage()->hash($type, $this->getUnjailedPath($path), $raw);
} }
/** public function free_space($path): int|float|false {
* see https://www.php.net/manual/en/function.free_space.php
*
* @param string $path
* @return int|float|bool
*/
public function free_space($path) {
return $this->getWrapperStorage()->free_space($this->getUnjailedPath($path)); return $this->getWrapperStorage()->free_space($this->getUnjailedPath($path));
} }
/** public function touch($path, $mtime = null): bool {
* 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) {
return $this->getWrapperStorage()->touch($this->getUnjailedPath($path), $mtime); return $this->getWrapperStorage()->touch($this->getUnjailedPath($path), $mtime);
} }
/** public function getLocalFile($path): string|false {
* 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) {
return $this->getWrapperStorage()->getLocalFile($this->getUnjailedPath($path)); return $this->getWrapperStorage()->getLocalFile($this->getUnjailedPath($path));
} }
/** public function hasUpdated($path, $time): bool {
* 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) {
return $this->getWrapperStorage()->hasUpdated($this->getUnjailedPath($path), $time); return $this->getWrapperStorage()->hasUpdated($this->getUnjailedPath($path), $time);
} }
public function getCache($path = '', $storage = null) { public function getCache($path = '', $storage = null): ICache {
$sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path)); $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path));
return new CacheJail($sourceCache, $this->rootPath); return new CacheJail($sourceCache, $this->rootPath);
} }
@ -367,34 +188,28 @@ class Jail extends Wrapper {
return $this->getWrapperStorage()->getOwner($this->getUnjailedPath($path)); return $this->getWrapperStorage()->getOwner($this->getUnjailedPath($path));
} }
public function getWatcher($path = '', $storage = null) { public function getWatcher($path = '', $storage = null): IWatcher {
$sourceWatcher = $this->getWrapperStorage()->getWatcher($this->getUnjailedPath($path), $this->getWrapperStorage()); $sourceWatcher = $this->getWrapperStorage()->getWatcher($this->getUnjailedPath($path), $this->getWrapperStorage());
return new JailWatcher($sourceWatcher, $this->rootPath); return new JailWatcher($sourceWatcher, $this->rootPath);
} }
/** public function getETag($path): string|false {
* get the ETag for a file or folder
*
* @param string $path
* @return string|false
*/
public function getETag($path) {
return $this->getWrapperStorage()->getETag($this->getUnjailedPath($path)); return $this->getWrapperStorage()->getETag($this->getUnjailedPath($path));
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
return $this->getWrapperStorage()->getMetaData($this->getUnjailedPath($path)); return $this->getWrapperStorage()->getMetaData($this->getUnjailedPath($path));
} }
public function acquireLock($path, $type, ILockingProvider $provider) { public function acquireLock($path, $type, ILockingProvider $provider): void {
$this->getWrapperStorage()->acquireLock($this->getUnjailedPath($path), $type, $provider); $this->getWrapperStorage()->acquireLock($this->getUnjailedPath($path), $type, $provider);
} }
public function releaseLock($path, $type, ILockingProvider $provider) { public function releaseLock($path, $type, ILockingProvider $provider): void {
$this->getWrapperStorage()->releaseLock($this->getUnjailedPath($path), $type, $provider); $this->getWrapperStorage()->releaseLock($this->getUnjailedPath($path), $type, $provider);
} }
public function changeLock($path, $type, ILockingProvider $provider) { public function changeLock($path, $type, ILockingProvider $provider): void {
$this->getWrapperStorage()->changeLock($this->getUnjailedPath($path), $type, $provider); $this->getWrapperStorage()->changeLock($this->getUnjailedPath($path), $type, $provider);
} }
@ -402,39 +217,26 @@ class Jail extends Wrapper {
* Resolve the path for the source of the share * Resolve the path for the source of the share
* *
* @param string $path * @param string $path
* @return array
*/ */
public function resolvePath($path) { public function resolvePath($path): array {
return [$this->getWrapperStorage(), $this->getUnjailedPath($path)]; return [$this->getWrapperStorage(), $this->getUnjailedPath($path)];
} }
/** public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
return $this->copy($sourceInternalPath, $targetInternalPath); return $this->copy($sourceInternalPath, $targetInternalPath);
} }
return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $this->getUnjailedPath($targetInternalPath)); return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $this->getUnjailedPath($targetInternalPath));
} }
/** public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
return $this->rename($sourceInternalPath, $targetInternalPath); return $this->rename($sourceInternalPath, $targetInternalPath);
} }
return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $this->getUnjailedPath($targetInternalPath)); return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $this->getUnjailedPath($targetInternalPath));
} }
public function getPropagator($storage = null) { public function getPropagator($storage = null): IPropagator {
if (isset($this->propagator)) { if (isset($this->propagator)) {
return $this->propagator; return $this->propagator;
} }
@ -460,7 +262,7 @@ class Jail extends Wrapper {
} }
} }
public function getDirectoryContent($directory): \Traversable { public function getDirectoryContent($directory): \Traversable|false {
return $this->getWrapperStorage()->getDirectoryContent($this->getUnjailedPath($directory)); return $this->getWrapperStorage()->getDirectoryContent($this->getUnjailedPath($directory));
} }
} }

@ -26,7 +26,7 @@ class KnownMtime extends Wrapper {
$this->clock = $arguments['clock']; $this->clock = $arguments['clock'];
} }
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): int|float|false {
$result = parent::file_put_contents($path, $data); $result = parent::file_put_contents($path, $data);
if ($result) { if ($result) {
$now = $this->clock->now()->getTimestamp(); $now = $this->clock->now()->getTimestamp();
@ -35,7 +35,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function stat($path) { public function stat($path): array|false {
$stat = parent::stat($path); $stat = parent::stat($path);
if ($stat) { if ($stat) {
$this->applyKnownMtime($path, $stat); $this->applyKnownMtime($path, $stat);
@ -43,7 +43,7 @@ class KnownMtime extends Wrapper {
return $stat; return $stat;
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
$stat = parent::getMetaData($path); $stat = parent::getMetaData($path);
if ($stat) { if ($stat) {
$this->applyKnownMtime($path, $stat); $this->applyKnownMtime($path, $stat);
@ -51,19 +51,19 @@ class KnownMtime extends Wrapper {
return $stat; return $stat;
} }
private function applyKnownMtime(string $path, array &$stat) { private function applyKnownMtime(string $path, array &$stat): void {
if (isset($stat['mtime'])) { if (isset($stat['mtime'])) {
$knownMtime = $this->knowMtimes->get($path) ?? 0; $knownMtime = $this->knowMtimes->get($path) ?? 0;
$stat['mtime'] = max($stat['mtime'], $knownMtime); $stat['mtime'] = max($stat['mtime'], $knownMtime);
} }
} }
public function filemtime($path) { public function filemtime($path): int|false {
$knownMtime = $this->knowMtimes->get($path) ?? 0; $knownMtime = $this->knowMtimes->get($path) ?? 0;
return max(parent::filemtime($path), $knownMtime); return max(parent::filemtime($path), $knownMtime);
} }
public function mkdir($path) { public function mkdir($path): bool {
$result = parent::mkdir($path); $result = parent::mkdir($path);
if ($result) { if ($result) {
$this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
@ -71,7 +71,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function rmdir($path) { public function rmdir($path): bool {
$result = parent::rmdir($path); $result = parent::rmdir($path);
if ($result) { if ($result) {
$this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
@ -79,7 +79,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function unlink($path) { public function unlink($path): bool {
$result = parent::unlink($path); $result = parent::unlink($path);
if ($result) { if ($result) {
$this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
@ -87,7 +87,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function rename($source, $target) { public function rename($source, $target): bool {
$result = parent::rename($source, $target); $result = parent::rename($source, $target);
if ($result) { if ($result) {
$this->knowMtimes->set($target, $this->clock->now()->getTimestamp()); $this->knowMtimes->set($target, $this->clock->now()->getTimestamp());
@ -96,7 +96,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function copy($source, $target) { public function copy($source, $target): bool {
$result = parent::copy($source, $target); $result = parent::copy($source, $target);
if ($result) { if ($result) {
$this->knowMtimes->set($target, $this->clock->now()->getTimestamp()); $this->knowMtimes->set($target, $this->clock->now()->getTimestamp());
@ -112,7 +112,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function touch($path, $mtime = null) { public function touch($path, $mtime = null): bool {
$result = parent::touch($path, $mtime); $result = parent::touch($path, $mtime);
if ($result) { if ($result) {
$this->knowMtimes->set($path, $mtime ?? $this->clock->now()->getTimestamp()); $this->knowMtimes->set($path, $mtime ?? $this->clock->now()->getTimestamp());
@ -120,7 +120,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
$result = parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); $result = parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
if ($result) { if ($result) {
$this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp()); $this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp());
@ -128,7 +128,7 @@ class KnownMtime extends Wrapper {
return $result; return $result;
} }
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
$result = parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); $result = parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
if ($result) { if ($result) {
$this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp()); $this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp());

@ -34,31 +34,31 @@ class PermissionsMask extends Wrapper {
$this->mask = $arguments['mask']; $this->mask = $arguments['mask'];
} }
private function checkMask($permissions) { private function checkMask($permissions): bool {
return ($this->mask & $permissions) === $permissions; return ($this->mask & $permissions) === $permissions;
} }
public function isUpdatable($path) { public function isUpdatable($path): bool {
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::isUpdatable($path); return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::isUpdatable($path);
} }
public function isCreatable($path) { public function isCreatable($path): bool {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::isCreatable($path); return $this->checkMask(Constants::PERMISSION_CREATE) and parent::isCreatable($path);
} }
public function isDeletable($path) { public function isDeletable($path): bool {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::isDeletable($path); return $this->checkMask(Constants::PERMISSION_DELETE) and parent::isDeletable($path);
} }
public function isSharable($path) { public function isSharable($path): bool {
return $this->checkMask(Constants::PERMISSION_SHARE) and parent::isSharable($path); return $this->checkMask(Constants::PERMISSION_SHARE) and parent::isSharable($path);
} }
public function getPermissions($path) { public function getPermissions($path): int {
return $this->storage->getPermissions($path) & $this->mask; return $this->storage->getPermissions($path) & $this->mask;
} }
public function rename($source, $target) { public function rename($source, $target): bool {
//This is a rename of the transfer file to the original file //This is a rename of the transfer file to the original file
if (dirname($source) === dirname($target) && strpos($source, '.ocTransferId') > 0) { if (dirname($source) === dirname($target) && strpos($source, '.ocTransferId') > 0) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::rename($source, $target); return $this->checkMask(Constants::PERMISSION_CREATE) and parent::rename($source, $target);
@ -66,28 +66,28 @@ class PermissionsMask extends Wrapper {
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($source, $target); return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($source, $target);
} }
public function copy($source, $target) { public function copy($source, $target): bool {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($source, $target); return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($source, $target);
} }
public function touch($path, $mtime = null) { public function touch($path, $mtime = null): bool {
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; $permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE;
return $this->checkMask($permissions) and parent::touch($path, $mtime); return $this->checkMask($permissions) and parent::touch($path, $mtime);
} }
public function mkdir($path) { public function mkdir($path): bool {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::mkdir($path); return $this->checkMask(Constants::PERMISSION_CREATE) and parent::mkdir($path);
} }
public function rmdir($path) { public function rmdir($path): bool {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::rmdir($path); return $this->checkMask(Constants::PERMISSION_DELETE) and parent::rmdir($path);
} }
public function unlink($path) { public function unlink($path): bool {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::unlink($path); return $this->checkMask(Constants::PERMISSION_DELETE) and parent::unlink($path);
} }
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): int|float|false {
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; $permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE;
return $this->checkMask($permissions) ? parent::file_put_contents($path, $data) : false; return $this->checkMask($permissions) ? parent::file_put_contents($path, $data) : false;
} }
@ -101,7 +101,7 @@ class PermissionsMask extends Wrapper {
} }
} }
public function getCache($path = '', $storage = null) { public function getCache($path = '', $storage = null): \OCP\Files\Cache\ICache {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
@ -109,7 +109,7 @@ class PermissionsMask extends Wrapper {
return new CachePermissionsMask($sourceCache, $this->mask); return new CachePermissionsMask($sourceCache, $this->mask);
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
$data = parent::getMetaData($path); $data = parent::getMetaData($path);
if ($data && isset($data['permissions'])) { if ($data && isset($data['permissions'])) {
@ -119,7 +119,7 @@ class PermissionsMask extends Wrapper {
return $data; return $data;
} }
public function getScanner($path = '', $storage = null) { public function getScanner($path = '', $storage = null): \OCP\Files\Cache\IScanner {
if (!$storage) { if (!$storage) {
$storage = $this->storage; $storage = $this->storage;
} }

@ -33,9 +33,6 @@ class Quota extends Wrapper {
$this->quotaIncludeExternalStorage = $parameters['include_external_storage'] ?? false; $this->quotaIncludeExternalStorage = $parameters['include_external_storage'] ?? false;
} }
/**
* @return int|float quota value
*/
public function getQuota(): int|float { public function getQuota(): int|float {
if ($this->quota === null) { if ($this->quota === null) {
$quotaCallback = $this->quotaCallback; $quotaCallback = $this->quotaCallback;
@ -55,9 +52,8 @@ class Quota extends Wrapper {
/** /**
* @param string $path * @param string $path
* @param IStorage $storage * @param IStorage $storage
* @return int|float
*/ */
protected function getSize($path, $storage = null) { protected function getSize($path, $storage = null): int|float {
if ($this->quotaIncludeExternalStorage) { if ($this->quotaIncludeExternalStorage) {
$rootInfo = Filesystem::getFileInfo('', 'ext'); $rootInfo = Filesystem::getFileInfo('', 'ext');
if ($rootInfo) { if ($rootInfo) {
@ -75,13 +71,7 @@ class Quota extends Wrapper {
} }
} }
/** public function free_space($path): int|float|false {
* Get free space as limited by the quota
*
* @param string $path
* @return int|float|bool
*/
public function free_space($path) {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->free_space($path); return $this->storage->free_space($path);
} }
@ -101,14 +91,7 @@ class Quota extends Wrapper {
} }
} }
/** public function file_put_contents($path, $data): int|float|false {
* 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) {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->file_put_contents($path, $data); return $this->storage->file_put_contents($path, $data);
} }
@ -120,14 +103,7 @@ class Quota extends Wrapper {
} }
} }
/** public function copy($source, $target): bool {
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function copy($source, $target) {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->copy($source, $target); return $this->storage->copy($source, $target);
} }
@ -139,13 +115,6 @@ 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($path, $mode) {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->fopen($path, $mode); return $this->storage->fopen($path, $mode);
@ -170,10 +139,9 @@ class Quota extends Wrapper {
* Checks whether the given path is a part file * Checks whether the given path is a part file
* *
* @param string $path Path that may identify a .part file * @param string $path Path that may identify a .part file
* @return bool
* @note this is needed for reusing keys * @note this is needed for reusing keys
*/ */
private function isPartFile($path) { private function isPartFile($path): bool {
$extension = pathinfo($path, PATHINFO_EXTENSION); $extension = pathinfo($path, PATHINFO_EXTENSION);
return ($extension === 'part'); return ($extension === 'part');
@ -186,13 +154,7 @@ class Quota extends Wrapper {
return str_starts_with(ltrim($path, '/'), 'files/'); return str_starts_with(ltrim($path, '/'), 'files/');
} }
/** public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
} }
@ -204,13 +166,7 @@ class Quota extends Wrapper {
} }
} }
/** public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
} }
@ -222,7 +178,7 @@ class Quota extends Wrapper {
} }
} }
public function mkdir($path) { public function mkdir($path): bool {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->mkdir($path); return $this->storage->mkdir($path);
} }
@ -234,7 +190,7 @@ class Quota extends Wrapper {
return parent::mkdir($path); return parent::mkdir($path);
} }
public function touch($path, $mtime = null) { public function touch($path, $mtime = null): bool {
if (!$this->hasQuota()) { if (!$this->hasQuota()) {
return $this->storage->touch($path, $mtime); return $this->storage->touch($path, $mtime);
} }

@ -8,7 +8,12 @@
namespace OC\Files\Storage\Wrapper; namespace OC\Files\Storage\Wrapper;
use OC\Files\Storage\FailedStorage; use OC\Files\Storage\FailedStorage;
use OCP\Files\InvalidPathException; use OC\Files\Storage\Storage;
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\ILockingStorage;
use OCP\Files\Storage\IStorage; use OCP\Files\Storage\IStorage;
use OCP\Files\Storage\IWriteStreamStorage; use OCP\Files\Storage\IWriteStreamStorage;
@ -35,10 +40,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
$this->storage = $parameters['storage']; $this->storage = $parameters['storage'];
} }
/** public function getWrapperStorage(): Storage {
* @return \OC\Files\Storage\Storage
*/
public function getWrapperStorage() {
if (!$this->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 = Server::get(LoggerInterface::class);
@ -48,319 +50,130 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $this->storage; return $this->storage;
} }
/** public function getId(): string {
* 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() {
return $this->getWrapperStorage()->getId(); return $this->getWrapperStorage()->getId();
} }
/** public function mkdir($path): bool {
* see https://www.php.net/manual/en/function.mkdir.php
*
* @param string $path
* @return bool
*/
public function mkdir($path) {
return $this->getWrapperStorage()->mkdir($path); return $this->getWrapperStorage()->mkdir($path);
} }
/** public function rmdir($path): bool {
* see https://www.php.net/manual/en/function.rmdir.php
*
* @param string $path
* @return bool
*/
public function rmdir($path) {
return $this->getWrapperStorage()->rmdir($path); 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($path) {
return $this->getWrapperStorage()->opendir($path); return $this->getWrapperStorage()->opendir($path);
} }
/** public function is_dir($path): bool {
* see https://www.php.net/manual/en/function.is_dir.php
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
return $this->getWrapperStorage()->is_dir($path); return $this->getWrapperStorage()->is_dir($path);
} }
/** public function is_file($path): bool {
* see https://www.php.net/manual/en/function.is_file.php
*
* @param string $path
* @return bool
*/
public function is_file($path) {
return $this->getWrapperStorage()->is_file($path); return $this->getWrapperStorage()->is_file($path);
} }
/** public function stat($path): array|false {
* 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) {
return $this->getWrapperStorage()->stat($path); return $this->getWrapperStorage()->stat($path);
} }
/** public function filetype($path): string|false {
* see https://www.php.net/manual/en/function.filetype.php
*
* @param string $path
* @return string|bool
*/
public function filetype($path) {
return $this->getWrapperStorage()->filetype($path); return $this->getWrapperStorage()->filetype($path);
} }
/** public function filesize($path): int|float|false {
* 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 {
return $this->getWrapperStorage()->filesize($path); return $this->getWrapperStorage()->filesize($path);
} }
/** public function isCreatable($path): bool {
* check if a file can be created in $path
*
* @param string $path
* @return bool
*/
public function isCreatable($path) {
return $this->getWrapperStorage()->isCreatable($path); return $this->getWrapperStorage()->isCreatable($path);
} }
/** public function isReadable($path): bool {
* check if a file can be read
*
* @param string $path
* @return bool
*/
public function isReadable($path) {
return $this->getWrapperStorage()->isReadable($path); return $this->getWrapperStorage()->isReadable($path);
} }
/** public function isUpdatable($path): bool {
* check if a file can be written to
*
* @param string $path
* @return bool
*/
public function isUpdatable($path) {
return $this->getWrapperStorage()->isUpdatable($path); return $this->getWrapperStorage()->isUpdatable($path);
} }
/** public function isDeletable($path): bool {
* check if a file can be deleted
*
* @param string $path
* @return bool
*/
public function isDeletable($path) {
return $this->getWrapperStorage()->isDeletable($path); return $this->getWrapperStorage()->isDeletable($path);
} }
/** public function isSharable($path): bool {
* check if a file can be shared
*
* @param string $path
* @return bool
*/
public function isSharable($path) {
return $this->getWrapperStorage()->isSharable($path); return $this->getWrapperStorage()->isSharable($path);
} }
/** public function getPermissions($path): int {
* 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) {
return $this->getWrapperStorage()->getPermissions($path); return $this->getWrapperStorage()->getPermissions($path);
} }
/** public function file_exists($path): bool {
* see https://www.php.net/manual/en/function.file_exists.php
*
* @param string $path
* @return bool
*/
public function file_exists($path) {
return $this->getWrapperStorage()->file_exists($path); return $this->getWrapperStorage()->file_exists($path);
} }
/** public function filemtime($path): int|false {
* see https://www.php.net/manual/en/function.filemtime.php
*
* @param string $path
* @return int|bool
*/
public function filemtime($path) {
return $this->getWrapperStorage()->filemtime($path); return $this->getWrapperStorage()->filemtime($path);
} }
/** public function file_get_contents($path): string|false {
* see https://www.php.net/manual/en/function.file_get_contents.php
*
* @param string $path
* @return string|false
*/
public function file_get_contents($path) {
return $this->getWrapperStorage()->file_get_contents($path); return $this->getWrapperStorage()->file_get_contents($path);
} }
/** public function file_put_contents($path, $data): int|float|false {
* 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) {
return $this->getWrapperStorage()->file_put_contents($path, $data); return $this->getWrapperStorage()->file_put_contents($path, $data);
} }
/** public function unlink($path): bool {
* see https://www.php.net/manual/en/function.unlink.php
*
* @param string $path
* @return bool
*/
public function unlink($path) {
return $this->getWrapperStorage()->unlink($path); return $this->getWrapperStorage()->unlink($path);
} }
/** public function rename($source, $target): bool {
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function rename($source, $target) {
return $this->getWrapperStorage()->rename($source, $target); return $this->getWrapperStorage()->rename($source, $target);
} }
/** public function copy($source, $target): bool {
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $source
* @param string $target
* @return bool
*/
public function copy($source, $target) {
return $this->getWrapperStorage()->copy($source, $target); 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($path, $mode) {
return $this->getWrapperStorage()->fopen($path, $mode); return $this->getWrapperStorage()->fopen($path, $mode);
} }
/** public function getMimeType($path): string|false {
* 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) {
return $this->getWrapperStorage()->getMimeType($path); return $this->getWrapperStorage()->getMimeType($path);
} }
/** public function hash($type, $path, $raw = false): string|false {
* 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) {
return $this->getWrapperStorage()->hash($type, $path, $raw); return $this->getWrapperStorage()->hash($type, $path, $raw);
} }
/** public function free_space($path): int|float|false {
* see https://www.php.net/manual/en/function.free_space.php
*
* @param string $path
* @return int|float|bool
*/
public function free_space($path) {
return $this->getWrapperStorage()->free_space($path); return $this->getWrapperStorage()->free_space($path);
} }
/** public function touch($path, $mtime = null): bool {
* 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) {
return $this->getWrapperStorage()->touch($path, $mtime); return $this->getWrapperStorage()->touch($path, $mtime);
} }
/** public function getLocalFile($path): string|false {
* 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) {
return $this->getWrapperStorage()->getLocalFile($path); return $this->getWrapperStorage()->getLocalFile($path);
} }
/** public function hasUpdated($path, $time): bool {
* 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) {
return $this->getWrapperStorage()->hasUpdated($path, $time); return $this->getWrapperStorage()->hasUpdated($path, $time);
} }
public function getCache($path = '', $storage = null) { public function getCache($path = '', $storage = null): ICache {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
return $this->getWrapperStorage()->getCache($path, $storage); return $this->getWrapperStorage()->getCache($path, $storage);
} }
public function getScanner($path = '', $storage = null) { public function getScanner($path = '', $storage = null): IScanner {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
@ -371,66 +184,44 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $this->getWrapperStorage()->getOwner($path); return $this->getWrapperStorage()->getOwner($path);
} }
public function getWatcher($path = '', $storage = null) { public function getWatcher($path = '', $storage = null): IWatcher {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
return $this->getWrapperStorage()->getWatcher($path, $storage); return $this->getWrapperStorage()->getWatcher($path, $storage);
} }
public function getPropagator($storage = null) { public function getPropagator($storage = null): IPropagator {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
return $this->getWrapperStorage()->getPropagator($storage); return $this->getWrapperStorage()->getPropagator($storage);
} }
public function getUpdater($storage = null) { public function getUpdater($storage = null): IUpdater {
if (!$storage) { if (!$storage) {
$storage = $this; $storage = $this;
} }
return $this->getWrapperStorage()->getUpdater($storage); return $this->getWrapperStorage()->getUpdater($storage);
} }
public function getStorageCache() { public function getStorageCache(): \OC\Files\Cache\Storage {
return $this->getWrapperStorage()->getStorageCache(); return $this->getWrapperStorage()->getStorageCache();
} }
/** public function getETag($path): string|false {
* get the ETag for a file or folder
*
* @param string $path
* @return string|false
*/
public function getETag($path) {
return $this->getWrapperStorage()->getETag($path); return $this->getWrapperStorage()->getETag($path);
} }
/** public function test(): bool {
* Returns true
*
* @return true
*/
public function test() {
return $this->getWrapperStorage()->test(); return $this->getWrapperStorage()->test();
} }
/** public function isLocal(): bool {
* Returns the wrapped storage's value for isLocal()
*
* @return bool wrapped storage's isLocal() value
*/
public function isLocal() {
return $this->getWrapperStorage()->isLocal(); return $this->getWrapperStorage()->isLocal();
} }
/** public function instanceOfStorage($class): bool {
* 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) {
if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') { if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
// FIXME Temporary fix to keep existing checks working // FIXME Temporary fix to keep existing checks working
$class = '\OCA\Files_Sharing\SharedStorage'; $class = '\OCA\Files_Sharing\SharedStorage';
@ -443,7 +234,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
* @psalm-param class-string<T> $class * @psalm-param class-string<T> $class
* @psalm-return T|null * @psalm-return T|null
*/ */
public function getInstanceOfStorage(string $class) { public function getInstanceOfStorage(string $class): ?IStorage {
$storage = $this; $storage = $this;
while ($storage instanceof Wrapper) { while ($storage instanceof Wrapper) {
if ($storage instanceof $class) { if ($storage instanceof $class) {
@ -468,53 +259,23 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return call_user_func_array([$this->getWrapperStorage(), $method], $args); return call_user_func_array([$this->getWrapperStorage(), $method], $args);
} }
/** public function getDirectDownload($path): array|false {
* 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) {
return $this->getWrapperStorage()->getDirectDownload($path); return $this->getWrapperStorage()->getDirectDownload($path);
} }
/** public function getAvailability(): array {
* Get availability of the storage
*
* @return array [ available, last_checked ]
*/
public function getAvailability() {
return $this->getWrapperStorage()->getAvailability(); return $this->getWrapperStorage()->getAvailability();
} }
/** public function setAvailability($isAvailable): void {
* Set availability of the storage
*
* @param bool $isAvailable
*/
public function setAvailability($isAvailable) {
$this->getWrapperStorage()->setAvailability($isAvailable); $this->getWrapperStorage()->setAvailability($isAvailable);
} }
/** public function verifyPath($path, $fileName): void {
* @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) {
$this->getWrapperStorage()->verifyPath($path, $fileName); $this->getWrapperStorage()->verifyPath($path, $fileName);
} }
/** public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
return $this->copy($sourceInternalPath, $targetInternalPath); return $this->copy($sourceInternalPath, $targetInternalPath);
} }
@ -522,13 +283,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
} }
/** public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if ($sourceStorage === $this) { if ($sourceStorage === $this) {
return $this->rename($sourceInternalPath, $targetInternalPath); return $this->rename($sourceInternalPath, $targetInternalPath);
} }
@ -536,32 +291,29 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
} }
public function getMetaData($path) { public function getMetaData($path): ?array {
return $this->getWrapperStorage()->getMetaData($path); return $this->getWrapperStorage()->getMetaData($path);
} }
public function acquireLock($path, $type, ILockingProvider $provider) { public function acquireLock($path, $type, ILockingProvider $provider): void {
if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->getWrapperStorage()->acquireLock($path, $type, $provider); $this->getWrapperStorage()->acquireLock($path, $type, $provider);
} }
} }
public function releaseLock($path, $type, ILockingProvider $provider) { public function releaseLock($path, $type, ILockingProvider $provider): void {
if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->getWrapperStorage()->releaseLock($path, $type, $provider); $this->getWrapperStorage()->releaseLock($path, $type, $provider);
} }
} }
public function changeLock($path, $type, ILockingProvider $provider) { public function changeLock($path, $type, ILockingProvider $provider): void {
if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->getWrapperStorage()->changeLock($path, $type, $provider); $this->getWrapperStorage()->changeLock($path, $type, $provider);
} }
} }
/** public function needsPartFile(): bool {
* @return bool
*/
public function needsPartFile() {
return $this->getWrapperStorage()->needsPartFile(); return $this->getWrapperStorage()->needsPartFile();
} }
@ -579,11 +331,11 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
} }
} }
public function getDirectoryContent($directory): \Traversable { public function getDirectoryContent($directory): \Traversable|false {
return $this->getWrapperStorage()->getDirectoryContent($directory); return $this->getWrapperStorage()->getDirectoryContent($directory);
} }
public function isWrapperOf(IStorage $storage) { public function isWrapperOf(IStorage $storage): bool {
$wrapped = $this->getWrapperStorage(); $wrapped = $this->getWrapperStorage();
if ($wrapped === $storage) { if ($wrapped === $storage) {
return true; return true;

@ -23,7 +23,7 @@ class Quota extends Wrapper {
/** /**
* @param resource $stream * @param resource $stream
* @param int $limit * @param int $limit
* @return bool|resource * @return resource|false
*/ */
public static function wrap($stream, $limit) { public static function wrap($stream, $limit) {
$context = stream_context_create([ $context = stream_context_create([

@ -106,6 +106,7 @@ class Scanner extends PublicEmitter {
* @param \OC\Files\Mount\MountPoint $mount * @param \OC\Files\Mount\MountPoint $mount
*/ */
protected function attachListener($mount) { protected function attachListener($mount) {
/** @var \OC\Files\Cache\Scanner $scanner */
$scanner = $mount->getStorage()->getScanner(); $scanner = $mount->getStorage()->getScanner();
$scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function ($path) use ($mount) { $scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function ($path) use ($mount) {
$this->emit('\OC\Files\Utils\Scanner', 'scanFile', [$mount->getMountPoint() . $path]); $this->emit('\OC\Files\Utils\Scanner', 'scanFile', [$mount->getMountPoint() . $path]);
@ -145,6 +146,7 @@ class Scanner extends PublicEmitter {
continue; continue;
} }
/** @var \OC\Files\Cache\Scanner $scanner */
$scanner = $storage->getScanner(); $scanner = $storage->getScanner();
$this->attachListener($mount); $this->attachListener($mount);
@ -221,6 +223,7 @@ class Scanner extends PublicEmitter {
continue; continue;
} }
$relativePath = $mount->getInternalPath($dir); $relativePath = $mount->getInternalPath($dir);
/** @var \OC\Files\Cache\Scanner $scanner */
$scanner = $storage->getScanner(); $scanner = $storage->getScanner();
$scanner->setUseTransactions(false); $scanner->setUseTransactions(false);
$this->attachListener($mount); $this->attachListener($mount);

@ -8,6 +8,7 @@ namespace OC\Lockdown\Filesystem;
use Icewind\Streams\IteratorDirectory; use Icewind\Streams\IteratorDirectory;
use OC\Files\FileInfo; use OC\Files\FileInfo;
use OC\Files\Storage\Common; use OC\Files\Storage\Common;
use OCP\Files\Cache\ICache;
use OCP\Files\Storage\IStorage; use OCP\Files\Storage\IStorage;
class NullStorage extends Common { class NullStorage extends Common {
@ -15,143 +16,143 @@ class NullStorage extends Common {
parent::__construct($parameters); parent::__construct($parameters);
} }
public function getId() { public function getId(): string {
return 'null'; return 'null';
} }
public function mkdir($path) { public function mkdir($path): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function rmdir($path) { public function rmdir($path): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function opendir($path) { public function opendir($path): IteratorDirectory {
return new IteratorDirectory([]); return new IteratorDirectory([]);
} }
public function is_dir($path) { public function is_dir($path): bool {
return $path === ''; return $path === '';
} }
public function is_file($path) { public function is_file($path): bool {
return false; return false;
} }
public function stat($path) { public function stat($path): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function filetype($path) { public function filetype($path): string|false {
return ($path === '') ? 'dir' : false; return ($path === '') ? 'dir' : false;
} }
public function filesize($path): false|int|float { public function filesize($path): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function isCreatable($path) { public function isCreatable($path): bool {
return false; return false;
} }
public function isReadable($path) { public function isReadable($path): bool {
return $path === ''; return $path === '';
} }
public function isUpdatable($path) { public function isUpdatable($path): bool {
return false; return false;
} }
public function isDeletable($path) { public function isDeletable($path): bool {
return false; return false;
} }
public function isSharable($path) { public function isSharable($path): bool {
return false; return false;
} }
public function getPermissions($path) { public function getPermissions($path): int {
return null; return 0;
} }
public function file_exists($path) { public function file_exists($path): bool {
return $path === ''; return $path === '';
} }
public function filemtime($path) { public function filemtime($path): int|false {
return ($path === '') ? time() : false; return ($path === '') ? time() : false;
} }
public function file_get_contents($path) { public function file_get_contents($path): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function file_put_contents($path, $data) { public function file_put_contents($path, $data): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function unlink($path) { public function unlink($path): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function rename($source, $target) { public function rename($source, $target): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function copy($source, $target) { public function copy($source, $target): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function fopen($path, $mode) { public function fopen($path, $mode): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function getMimeType($path) { public function getMimeType($path): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function hash($type, $path, $raw = false) { public function hash($type, $path, $raw = false): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function free_space($path) { public function free_space($path): int {
return FileInfo::SPACE_UNKNOWN; return FileInfo::SPACE_UNKNOWN;
} }
public function touch($path, $mtime = null) { public function touch($path, $mtime = null): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function getLocalFile($path) { public function getLocalFile($path): string|false {
return false; return false;
} }
public function hasUpdated($path, $time) { public function hasUpdated($path, $time): bool {
return false; return false;
} }
public function getETag($path) { public function getETag($path): string {
return ''; return '';
} }
public function isLocal() { public function isLocal(): bool {
return false; return false;
} }
public function getDirectDownload($path) { public function getDirectDownload($path): array|false {
return false; return false;
} }
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): never {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem'); throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
} }
public function test() { public function test(): bool {
return true; return true;
} }
@ -159,7 +160,7 @@ class NullStorage extends Common {
return false; return false;
} }
public function getCache($path = '', $storage = null) { public function getCache($path = '', $storage = null): ICache {
return new NullCache(); return new NullCache();
} }
} }