@ -17,6 +17,11 @@ use OC\Files\FilenameValidator;
use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\Jail;
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\GenericFileException;
use OCP\Files\IFilenameValidator;
@ -66,9 +71,8 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
* Remove a file or folder
*
* @param string $path
* @return bool
*/
protected function remove($path) {
protected function remove($path): bool {
if ($this->is_dir($path)) {
return $this->rmdir($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';
}
public function is_file($path) {
public function is_file($path): bool {
return $this->filetype($path) === 'file';
}
public function filesize($path): false| int|float {
public function filesize($path): int|float|false {
if ($this->is_dir($path)) {
return 0; //by definition
} 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
// subclasses might want to implement this more thoroughly
return $this->file_exists($path);
}
public function isUpdatable($path) {
public function isUpdatable($path): bool {
// at least check whether it exists
// subclasses might want to implement this more thoroughly
// a non-existing file/folder isn't updatable
return $this->file_exists($path);
}
public function isCreatable($path) {
public function isCreatable($path): bool {
if ($this->is_dir($path) & & $this->isUpdatable($path)) {
return true;
}
return false;
}
public function isDeletable($path) {
public function isDeletable($path): bool {
if ($path === '' || $path === '/') {
return $this->isUpdatable($path);
}
@ -127,11 +131,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->isUpdatable($parent) & & $this->isUpdatable($path);
}
public function isSharable($path) {
public function isSharable($path): bool {
return $this->isReadable($path);
}
public function getPermissions($path) {
public function getPermissions($path): int {
$permissions = 0;
if ($this->isCreatable($path)) {
$permissions |= \OCP\Constants::PERMISSION_CREATE;
@ -151,7 +155,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $permissions;
}
public function filemtime($path) {
public function filemtime($path): int|false {
$stat = $this->stat($path);
if (isset($stat['mtime']) & & $stat['mtime'] > 0) {
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');
if (!$handle) {
return false;
@ -170,7 +174,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $data;
}
public function file_put_contents($path, $data) {
public function file_put_contents($path, $data): int|float|false {
$handle = $this->fopen($path, 'w');
if (!$handle) {
return false;
@ -181,14 +185,14 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $count;
}
public function rename($source, $target) {
public function rename($source, $target): bool {
$this->remove($target);
$this->removeCachedFile($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)) {
$this->remove($target);
$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)) {
return 'httpd/unix-directory';
} 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');
$ctx = hash_init($type);
hash_update_stream($ctx, $fh);
@ -233,15 +237,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return hash_final($ctx, $raw);
}
public function getLocalFile($path) {
public function getLocalFile($path): string|false {
return $this->getCachedFile($path);
}
/**
* @param string $path
* @param string $target
*/
private function addLocalFolder($path, $target) {
private function addLocalFolder($path, $target): void {
$dh = $this->opendir($path);
if (is_resource($dh)) {
while (($file = readdir($dh)) !== false) {
@ -258,12 +258,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
}
}
/**
* @param string $query
* @param string $dir
* @return array
*/
protected function searchInDir($query, $dir = '') {
protected function searchInDir($query, $dir = ''): array {
$files = [];
$dh = $this->opendir($dir);
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
*
* 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
* exclusive access to the backend and will not pick up files that have been added in a way that circumvents
* 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;
}
@ -307,23 +299,18 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $dependencies;
}
/**
* @return Cache
*/
public function getCache($path = '', $storage = null) {
public function getCache($path = '', $storage = null): ICache {
if (!$storage) {
$storage = $this;
}
/** @psalm-suppress NoInterfaceProperties The isset check is saf e */
/** @var self $storag e */
if (!isset($storage->cache)) {
$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;
}
public function getScanner($path = '', $storage = null) {
public function getScanner($path = '', $storage = null): IScanner {
if (!$storage) {
$storage = $this;
}
@ -336,7 +323,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $storage->scanner;
}
public function getWatcher($path = '', $storage = null) {
public function getWatcher($path = '', $storage = null): IWatcher {
if (!$storage) {
$storage = $this;
}
@ -348,7 +335,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->watcher;
}
public function getPropagator($storage = null) {
public function getPropagator($storage = null): IPropagator {
if (!$storage) {
$storage = $this;
}
@ -363,27 +350,24 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $storage->propagator;
}
/**
* 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) {
public function getUpdater($storage = null): IUpdater {
if (!$storage) {
$storage = $this;
}
if (!$storage->instanceOfStorage(self::class)) {
throw new \InvalidArgumentException('Storage is not of the correct class');
}
/** @var self $storage */
if (!isset($storage->updater)) {
$storage->updater = new Updater($storage);
}
return $storage->updater;
}
public function getStorageCache($storage = null) {
return $this->getCache($storage)->getStorageCache();
public function getStorageCache($storage = null): \OC\Files\Cache\Storage {
/** @var Cache $cache */
$cache = $this->getCache($storage);
return $cache->getStorageCache();
}
public function getOwner($path): string|false {
@ -394,13 +378,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->owner;
}
/**
* get the ETag for a file or folder
*
* @param string $path
* @return string|false
*/
public function getETag($path) {
public function getETag($path): string|false {
return uniqid();
}
@ -411,7 +389,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
* @param string $path The path to clean
* @return string cleaned path
*/
public function cleanPath($path) {
public function cleanPath($path): string {
if (strlen($path) == 0 or $path[0] != '/') {
$path = '/' . $path;
}
@ -430,10 +408,8 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
/**
* Test a storage for availability
*
* @return bool
*/
public function test() {
public function test(): bool {
try {
if ($this->stat('')) {
return true;
@ -449,20 +425,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
}
}
/**
* get the free space in the storage
*
* @param string $path
* @return int|float|false
*/
public function free_space($path) {
public function free_space($path): int|float|false {
return \OCP\Files\FileInfo::SPACE_UNKNOWN;
}
/**
* {@inheritdoc}
*/
public function isLocal() {
public function isLocal(): bool {
// the common implementation returns a temporary file by
// default, which is not local
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
*
* @param string $class
* @return bool
*/
public function instanceOfStorage($class) {
public function instanceOfStorage($class): bool {
if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
// FIXME Temporary fix to keep existing checks working
$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.
*
* @param string $path
* @return array|false
*/
public function getDirectDownload($path) {
public function getDirectDownload($path): array|false {
return [];
}
/**
* @inheritdoc
* @throws InvalidPathException
*/
public function verifyPath($path, $fileName) {
public function verifyPath($path, $fileName): void {
$this->getFilenameValidator()
->validateFilename($fileName);
@ -527,30 +488,24 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $this->filenameValidator;
}
/**
* @param array $options
*/
public function setMountOptions(array $options) {
public function setMountOptions(array $options): void {
$this->mountOptions = $options;
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function getMountOption($name, $default = null) {
public function getMountOption($name, $default = null): mixed {
return $this->mountOptions[$name] ?? $default;
}
/**
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @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) {
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
*
* @param IStorage $storage
* @return bool
*/
private function isSameStorage(IStorage $storage): bool {
while ($storage->instanceOfStorage(Wrapper::class)) {
@ -611,12 +563,10 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
}
/**
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
*/
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath): bool {
if ($this->isSameStorage($sourceStorage)) {
// resolve any jailed paths
while ($sourceStorage->instanceOfStorage(Jail::class)) {
@ -645,7 +595,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $result;
}
public function getMetaData($path) {
public function getMetaData($path): ?array {
if (Filesystem::isFileBlacklisted($path)) {
throw new ForbiddenException('Invalid path: ' . $path, false);
}
@ -675,7 +625,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $data;
}
public function acquireLock($path, $type, ILockingProvider $provider) {
public function acquireLock($path, $type, ILockingProvider $provider): void {
$logger = $this->getLockLogger();
if ($logger) {
$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();
if ($logger) {
$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();
if ($logger) {
$typeString = ($type === ILockingProvider::LOCK_SHARED) ? 'shared' : 'exclusive';
@ -767,45 +717,22 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
/**
* @return array [ available, last_checked ]
*/
public function getAvailability() {
public function getAvailability(): array {
return $this->getStorageCache()->getAvailability();
}
/**
* @param bool $isAvailable
*/
public function setAvailability($isAvailable) {
public function setAvailability($isAvailable): void {
$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 {
$this->owner = $user;
}
/**
* @return bool
*/
public function needsPartFile() {
public function needsPartFile(): bool {
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 {
$target = $this->fopen($path, 'w');
if (!$target) {
@ -823,7 +750,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
return $count;
}
public function getDirectoryContent($directory): \Traversable {
public function getDirectoryContent($directory): \Traversable|false {
$dh = $this->opendir($directory);
if ($dh === false) {