aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Files
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Files')
-rw-r--r--lib/private/Files/Cache/Cache.php109
-rw-r--r--lib/private/Files/Cache/FailedCache.php2
-rw-r--r--lib/private/Files/Cache/QuerySearchHelper.php2
-rw-r--r--lib/private/Files/Cache/Storage.php2
-rw-r--r--lib/private/Files/Cache/Updater.php4
-rw-r--r--lib/private/Files/Config/MountProviderCollection.php6
-rw-r--r--lib/private/Files/Config/UserMountCache.php2
-rw-r--r--lib/private/Files/FileInfo.php12
-rw-r--r--lib/private/Files/FilenameValidator.php6
-rw-r--r--lib/private/Files/Filesystem.php2
-rw-r--r--lib/private/Files/Mount/Manager.php4
-rw-r--r--lib/private/Files/Mount/RootMountProvider.php2
-rw-r--r--lib/private/Files/Node/Folder.php2
-rw-r--r--lib/private/Files/Node/LazyUserFolder.php2
-rw-r--r--lib/private/Files/Node/Node.php15
-rw-r--r--lib/private/Files/Node/NonExistingFile.php8
-rw-r--r--lib/private/Files/Node/NonExistingFolder.php8
-rw-r--r--lib/private/Files/Node/Root.php2
-rw-r--r--lib/private/Files/ObjectStore/Azure.php4
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php27
-rw-r--r--lib/private/Files/ObjectStore/S3ConnectionTrait.php6
-rw-r--r--lib/private/Files/ObjectStore/S3ObjectTrait.php18
-rw-r--r--lib/private/Files/ObjectStore/S3Signature.php2
-rw-r--r--lib/private/Files/ObjectStore/SwiftFactory.php2
-rw-r--r--lib/private/Files/Search/SearchQuery.php8
-rw-r--r--lib/private/Files/SetupManager.php8
-rw-r--r--lib/private/Files/Storage/Common.php24
-rw-r--r--lib/private/Files/Storage/DAV.php26
-rw-r--r--lib/private/Files/Storage/Home.php2
-rw-r--r--lib/private/Files/Storage/StorageFactory.php2
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php4
-rw-r--r--lib/private/Files/Storage/Wrapper/Quota.php2
-rw-r--r--lib/private/Files/Storage/Wrapper/Wrapper.php2
-rw-r--r--lib/private/Files/Stream/Encryption.php2
-rw-r--r--lib/private/Files/Stream/SeekableHttpStream.php2
-rw-r--r--lib/private/Files/Type/Loader.php6
-rw-r--r--lib/private/Files/View.php31
37 files changed, 264 insertions, 104 deletions
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php
index a4290549dd9..a8d9067050d 100644
--- a/lib/private/Files/Cache/Cache.php
+++ b/lib/private/Files/Cache/Cache.php
@@ -9,6 +9,7 @@ namespace OC\Files\Cache;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OC\DB\Exceptions\DbalException;
+use OC\DB\QueryBuilder\Sharded\ShardDefinition;
use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchQuery;
use OC\Files\Storage\Wrapper\Encryption;
@@ -284,6 +285,7 @@ class Cache implements ICache {
if (count($extensionValues)) {
$query = $this->getQueryBuilder();
$query->insert('filecache_extended');
+ $query->hintShardKey('storage', $storageId);
$query->setValue('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT));
foreach ($extensionValues as $column => $value) {
@@ -357,6 +359,7 @@ class Cache implements ICache {
try {
$query = $this->getQueryBuilder();
$query->insert('filecache_extended');
+ $query->hintShardKey('storage', $this->getNumericStorageId());
$query->setValue('fileid', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT));
foreach ($extensionValues as $column => $value) {
@@ -368,6 +371,7 @@ class Cache implements ICache {
$query = $this->getQueryBuilder();
$query->update('filecache_extended')
->whereFileId($id)
+ ->hintShardKey('storage', $this->getNumericStorageId())
->andWhere($query->expr()->orX(...array_map(function ($key, $value) use ($query) {
return $query->expr()->orX(
$query->expr()->neq($key, $query->createNamedParameter($value)),
@@ -520,7 +524,8 @@ class Cache implements ICache {
$query = $this->getQueryBuilder();
$query->delete('filecache_extended')
- ->whereFileId($entry->getId());
+ ->whereFileId($entry->getId())
+ ->hintShardKey('storage', $this->getNumericStorageId());
$query->execute();
if ($entry->getMimeType() == FileInfo::MIMETYPE_FOLDER) {
@@ -564,7 +569,8 @@ class Cache implements ICache {
$query = $this->getQueryBuilder();
$query->delete('filecache_extended')
- ->where($query->expr()->in('fileid', $query->createParameter('childIds')));
+ ->where($query->expr()->in('fileid', $query->createParameter('childIds')))
+ ->hintShardKey('storage', $this->getNumericStorageId());
foreach (array_chunk($childIds, 1000) as $childIdChunk) {
$query->setParameter('childIds', $childIdChunk, IQueryBuilder::PARAM_INT_ARRAY);
@@ -652,6 +658,15 @@ class Cache implements ICache {
throw new \Exception('Invalid source storage path: ' . $sourcePath);
}
+ $shardDefinition = $this->connection->getShardDefinition('filecache');
+ if (
+ $shardDefinition &&
+ $shardDefinition->getShardForKey($sourceCache->getNumericStorageId()) !== $shardDefinition->getShardForKey($this->getNumericStorageId())
+ ) {
+ $this->moveFromStorageSharded($shardDefinition, $sourceCache, $sourceData, $targetPath);
+ return;
+ }
+
$sourceId = $sourceData['fileid'];
$newParentId = $this->getParentId($targetPath);
@@ -673,7 +688,7 @@ class Cache implements ICache {
$childChunks = array_chunk($childIds, 1000);
- $query = $this->connection->getQueryBuilder();
+ $query = $this->getQueryBuilder();
$fun = $query->func();
$newPathFunction = $fun->concat(
@@ -681,12 +696,15 @@ class Cache implements ICache {
$fun->substring('path', $query->createNamedParameter($sourceLength + 1, IQueryBuilder::PARAM_INT))// +1 for the leading slash
);
$query->update('filecache')
- ->set('storage', $query->createNamedParameter($targetStorageId, IQueryBuilder::PARAM_INT))
->set('path_hash', $fun->md5($newPathFunction))
->set('path', $newPathFunction)
- ->where($query->expr()->eq('storage', $query->createNamedParameter($sourceStorageId, IQueryBuilder::PARAM_INT)))
+ ->whereStorageId($sourceStorageId)
->andWhere($query->expr()->in('fileid', $query->createParameter('files')));
+ if ($sourceStorageId !== $targetStorageId) {
+ $query->set('storage', $query->createNamedParameter($targetStorageId), IQueryBuilder::PARAM_INT);
+ }
+
// when moving from an encrypted storage to a non-encrypted storage remove the `encrypted` mark
if ($sourceCache->hasEncryptionWrapper() && !$this->hasEncryptionWrapper()) {
$query->set('encrypted', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT));
@@ -728,13 +746,17 @@ class Cache implements ICache {
$query = $this->getQueryBuilder();
$query->update('filecache')
- ->set('storage', $query->createNamedParameter($targetStorageId))
->set('path', $query->createNamedParameter($targetPath))
->set('path_hash', $query->createNamedParameter(md5($targetPath)))
->set('name', $query->createNamedParameter(basename($targetPath)))
->set('parent', $query->createNamedParameter($newParentId, IQueryBuilder::PARAM_INT))
+ ->whereStorageId($sourceStorageId)
->whereFileId($sourceId);
+ if ($sourceStorageId !== $targetStorageId) {
+ $query->set('storage', $query->createNamedParameter($targetStorageId), IQueryBuilder::PARAM_INT);
+ }
+
// when moving from an encrypted storage to a non-encrypted storage remove the `encrypted` mark
if ($sourceCache->hasEncryptionWrapper() && !$this->hasEncryptionWrapper()) {
$query->set('encrypted', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT));
@@ -839,7 +861,7 @@ class Cache implements ICache {
* search for files by mimetype
*
* @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image')
- * where it will search for all mimetypes in the group ('image/*')
+ * where it will search for all mimetypes in the group ('image/*')
* @return ICacheEntry[] an array of cache entries where the mimetype matches the search
*/
public function searchByMime($mimetype) {
@@ -891,6 +913,7 @@ class Cache implements ICache {
$query->select($query->func()->count())
->from('filecache')
->whereParent($fileId)
+ ->whereStorageId($this->getNumericStorageId())
->andWhere($query->expr()->lt('size', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
$result = $query->execute();
@@ -1133,7 +1156,7 @@ class Cache implements ICache {
*/
public function copyFromCache(ICache $sourceCache, ICacheEntry $sourceEntry, string $targetPath): int {
if ($sourceEntry->getId() < 0) {
- throw new \RuntimeException("Invalid source cache entry on copyFromCache");
+ throw new \RuntimeException('Invalid source cache entry on copyFromCache');
}
$data = $this->cacheEntryToArray($sourceEntry);
@@ -1144,7 +1167,7 @@ class Cache implements ICache {
$fileId = $this->put($targetPath, $data);
if ($fileId <= 0) {
- throw new \RuntimeException("Failed to copy to " . $targetPath . " from cache with source data " . json_encode($data) . " ");
+ throw new \RuntimeException('Failed to copy to ' . $targetPath . ' from cache with source data ' . json_encode($data) . ' ');
}
if ($sourceEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) {
$folderContent = $sourceCache->getFolderContentsById($sourceEntry->getId());
@@ -1183,4 +1206,72 @@ class Cache implements ICache {
return null;
}
}
+
+ private function moveFromStorageSharded(ShardDefinition $shardDefinition, ICache $sourceCache, ICacheEntry $sourceEntry, $targetPath) {
+ if ($sourceEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) {
+ $fileIds = $this->getChildIds($sourceCache->getNumericStorageId(), $sourceEntry->getPath());
+ } else {
+ $fileIds = [];
+ }
+ $fileIds[] = $sourceEntry->getId();
+
+ $helper = $this->connection->getCrossShardMoveHelper();
+
+ $sourceConnection = $helper->getConnection($shardDefinition, $sourceCache->getNumericStorageId());
+ $targetConnection = $helper->getConnection($shardDefinition, $this->getNumericStorageId());
+
+ $cacheItems = $helper->loadItems($sourceConnection, 'filecache', 'fileid', $fileIds);
+ $extendedItems = $helper->loadItems($sourceConnection, 'filecache_extended', 'fileid', $fileIds);
+ $metadataItems = $helper->loadItems($sourceConnection, 'files_metadata', 'file_id', $fileIds);
+
+ // when moving from an encrypted storage to a non-encrypted storage remove the `encrypted` mark
+ $removeEncryptedFlag = ($sourceCache instanceof Cache && $sourceCache->hasEncryptionWrapper()) && !$this->hasEncryptionWrapper();
+
+ $sourcePathLength = strlen($sourceEntry->getPath());
+ foreach ($cacheItems as &$cacheItem) {
+ if ($cacheItem['path'] === $sourceEntry->getPath()) {
+ $cacheItem['path'] = $targetPath;
+ $cacheItem['parent'] = $this->getParentId($targetPath);
+ $cacheItem['name'] = basename($cacheItem['path']);
+ } else {
+ $cacheItem['path'] = $targetPath . '/' . substr($cacheItem['path'], $sourcePathLength + 1); // +1 for the leading slash
+ }
+ $cacheItem['path_hash'] = md5($cacheItem['path']);
+ $cacheItem['storage'] = $this->getNumericStorageId();
+ if ($removeEncryptedFlag) {
+ $cacheItem['encrypted'] = 0;
+ }
+ }
+
+ $targetConnection->beginTransaction();
+
+ try {
+ $helper->saveItems($targetConnection, 'filecache', $cacheItems);
+ $helper->saveItems($targetConnection, 'filecache_extended', $extendedItems);
+ $helper->saveItems($targetConnection, 'files_metadata', $metadataItems);
+ } catch (\Exception $e) {
+ $targetConnection->rollback();
+ throw $e;
+ }
+
+ $sourceConnection->beginTransaction();
+
+ try {
+ $helper->deleteItems($sourceConnection, 'filecache', 'fileid', $fileIds);
+ $helper->deleteItems($sourceConnection, 'filecache_extended', 'fileid', $fileIds);
+ $helper->deleteItems($sourceConnection, 'files_metadata', 'file_id', $fileIds);
+ } catch (\Exception $e) {
+ $targetConnection->rollback();
+ $sourceConnection->rollBack();
+ throw $e;
+ }
+
+ try {
+ $sourceConnection->commit();
+ } catch (\Exception $e) {
+ $targetConnection->rollback();
+ throw $e;
+ }
+ $targetConnection->commit();
+ }
}
diff --git a/lib/private/Files/Cache/FailedCache.php b/lib/private/Files/Cache/FailedCache.php
index 8ba2ac491bf..44c1016ca8e 100644
--- a/lib/private/Files/Cache/FailedCache.php
+++ b/lib/private/Files/Cache/FailedCache.php
@@ -125,7 +125,7 @@ class FailedCache implements ICache {
}
public function copyFromCache(ICache $sourceCache, ICacheEntry $sourceEntry, string $targetPath): int {
- throw new \Exception("Invalid cache");
+ throw new \Exception('Invalid cache');
}
public function getQueryFilterForStorage(): ISearchOperator {
diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php
index 0b164912301..82f9ec3be66 100644
--- a/lib/private/Files/Cache/QuerySearchHelper.php
+++ b/lib/private/Files/Cache/QuerySearchHelper.php
@@ -194,7 +194,7 @@ class QuerySearchHelper {
protected function requireUser(ISearchQuery $searchQuery): IUser {
$user = $searchQuery->getUser();
if ($user === null) {
- throw new \InvalidArgumentException("This search operation requires the user to be set in the query");
+ throw new \InvalidArgumentException('This search operation requires the user to be set in the query');
}
return $user;
}
diff --git a/lib/private/Files/Cache/Storage.php b/lib/private/Files/Cache/Storage.php
index 0929907fcff..8d99a268dc0 100644
--- a/lib/private/Files/Cache/Storage.php
+++ b/lib/private/Files/Cache/Storage.php
@@ -80,7 +80,7 @@ class Storage {
* Adjusts the storage id to use md5 if too long
* @param string $storageId storage id
* @return string unchanged $storageId if its length is less than 64 characters,
- * else returns the md5 of $storageId
+ * else returns the md5 of $storageId
*/
public static function adjustStorageId($storageId) {
if (strlen($storageId) > 64) {
diff --git a/lib/private/Files/Cache/Updater.php b/lib/private/Files/Cache/Updater.php
index e8c6d32599e..eab68b4f545 100644
--- a/lib/private/Files/Cache/Updater.php
+++ b/lib/private/Files/Cache/Updater.php
@@ -114,7 +114,7 @@ class Updater implements IUpdater {
}
// encryption is a pita and touches the cache itself
- if (isset($data['encrypted']) && !!$data['encrypted']) {
+ if (isset($data['encrypted']) && (bool)$data['encrypted']) {
$sizeDifference = null;
}
@@ -246,7 +246,7 @@ class Updater implements IUpdater {
// ignore the failure.
// with failures concurrent updates, someone else would have already done it.
// in the worst case the `storage_mtime` isn't updated, which should at most only trigger an extra rescan
- $this->logger->warning("Error while updating parent storage_mtime, should be safe to ignore", ['exception' => $e]);
+ $this->logger->warning('Error while updating parent storage_mtime, should be safe to ignore', ['exception' => $e]);
}
}
}
diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php
index 0e103690b6b..1dbc469c8c3 100644
--- a/lib/private/Files/Config/MountProviderCollection.php
+++ b/lib/private/Files/Config/MountProviderCollection.php
@@ -131,9 +131,9 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
}
$lateMounts = $this->filterMounts($user, $lateMounts);
- $this->eventLogger->start("fs:setup:add-mounts", "Add mounts to the filesystem");
+ $this->eventLogger->start('fs:setup:add-mounts', 'Add mounts to the filesystem');
array_walk($lateMounts, [$mountManager, 'addMount']);
- $this->eventLogger->end("fs:setup:add-mounts");
+ $this->eventLogger->end('fs:setup:add-mounts');
return array_merge($lateMounts, $firstMounts);
}
@@ -223,7 +223,7 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
}, []);
if (count($mounts) === 0) {
- throw new \Exception("No root mounts provided by any provider");
+ throw new \Exception('No root mounts provided by any provider');
}
return $mounts;
diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php
index 67b2cad7ea2..94da770b63f 100644
--- a/lib/private/Files/Config/UserMountCache.php
+++ b/lib/private/Files/Config/UserMountCache.php
@@ -477,7 +477,7 @@ class UserMountCache implements IUserMountCache {
}
}
- throw new NotFoundException("No cached mount for path " . $path);
+ throw new NotFoundException('No cached mount for path ' . $path);
}
public function getMountsInPath(IUser $user, string $path): array {
diff --git a/lib/private/Files/FileInfo.php b/lib/private/Files/FileInfo.php
index c3dcb531342..c47b8b1d1a7 100644
--- a/lib/private/Files/FileInfo.php
+++ b/lib/private/Files/FileInfo.php
@@ -134,7 +134,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @return int|null
*/
public function getId() {
- return isset($this->data['fileid']) ? (int) $this->data['fileid'] : null;
+ return isset($this->data['fileid']) ? (int)$this->data['fileid'] : null;
}
/**
@@ -196,7 +196,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
*/
public function getMTime() {
$this->updateEntryfromSubMounts();
- return (int) $this->data['mtime'];
+ return (int)$this->data['mtime'];
}
/**
@@ -210,14 +210,14 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* Return the current version used for the HMAC in the encryption app
*/
public function getEncryptedVersion(): int {
- return isset($this->data['encryptedVersion']) ? (int) $this->data['encryptedVersion'] : 1;
+ return isset($this->data['encryptedVersion']) ? (int)$this->data['encryptedVersion'] : 1;
}
/**
* @return int
*/
public function getPermissions() {
- return (int) $this->data['permissions'];
+ return (int)$this->data['permissions'];
}
/**
@@ -379,11 +379,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
}
public function getCreationTime(): int {
- return (int) $this->data['creation_time'];
+ return (int)$this->data['creation_time'];
}
public function getUploadTime(): int {
- return (int) $this->data['upload_time'];
+ return (int)$this->data['upload_time'];
}
public function getParentId(): int {
diff --git a/lib/private/Files/FilenameValidator.php b/lib/private/Files/FilenameValidator.php
index 2fe3c93d026..fde45068df7 100644
--- a/lib/private/Files/FilenameValidator.php
+++ b/lib/private/Files/FilenameValidator.php
@@ -25,6 +25,8 @@ use Psr\Log\LoggerInterface;
*/
class FilenameValidator implements IFilenameValidator {
+ public const INVALID_FILE_TYPE = 100;
+
private IL10N $l10n;
/**
@@ -269,12 +271,12 @@ class FilenameValidator implements IFilenameValidator {
*/
protected function checkForbiddenExtension(string $filename): void {
$filename = mb_strtolower($filename);
- // Check for forbidden filename exten<sions
+ // Check for forbidden filename extensions
$forbiddenExtensions = $this->getForbiddenExtensions();
foreach ($forbiddenExtensions as $extension) {
if (str_ends_with($filename, $extension)) {
if (str_starts_with($extension, '.')) {
- throw new InvalidPathException($this->l10n->t('"%1$s" is a forbidden file type.', [$extension]));
+ throw new InvalidPathException($this->l10n->t('"%1$s" is a forbidden file type.', [$extension]), self::INVALID_FILE_TYPE);
} else {
throw new InvalidPathException($this->l10n->t('Filenames must not end with "%1$s".', [$extension]));
}
diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php
index db7420c3c4c..48c069de0b9 100644
--- a/lib/private/Files/Filesystem.php
+++ b/lib/private/Files/Filesystem.php
@@ -674,7 +674,7 @@ class Filesystem {
*
* @param string $path
* @param bool|string $includeMountPoints whether to add mountpoint sizes,
- * defaults to true
+ * defaults to true
* @return \OC\Files\FileInfo|false False if file does not exist
*/
public static function getFileInfo($path, $includeMountPoints = true) {
diff --git a/lib/private/Files/Mount/Manager.php b/lib/private/Files/Mount/Manager.php
index c2267af3c96..d118021afa2 100644
--- a/lib/private/Files/Mount/Manager.php
+++ b/lib/private/Files/Mount/Manager.php
@@ -84,7 +84,7 @@ class Manager implements IMountManager {
if (count($this->mounts) === 0) {
$this->setupManager->setupRoot();
if (count($this->mounts) === 0) {
- throw new \Exception("No mounts even after explicitly setting up the root mounts");
+ throw new \Exception('No mounts even after explicitly setting up the root mounts');
}
}
@@ -104,7 +104,7 @@ class Manager implements IMountManager {
}
}
- throw new NotFoundException("No mount for path " . $path . " existing mounts (" . count($this->mounts) ."): " . implode(",", array_keys($this->mounts)));
+ throw new NotFoundException('No mount for path ' . $path . ' existing mounts (' . count($this->mounts) .'): ' . implode(',', array_keys($this->mounts)));
}
/**
diff --git a/lib/private/Files/Mount/RootMountProvider.php b/lib/private/Files/Mount/RootMountProvider.php
index 7ad7a7f059c..86f8188978f 100644
--- a/lib/private/Files/Mount/RootMountProvider.php
+++ b/lib/private/Files/Mount/RootMountProvider.php
@@ -56,7 +56,7 @@ class RootMountProvider implements IRootMountProvider {
}
private function getLocalRootMount(IStorageFactory $loader): MountPoint {
- $configDataDirectory = $this->config->getSystemValue("datadirectory", OC::$SERVERROOT . "/data");
+ $configDataDirectory = $this->config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data');
return new MountPoint(LocalRootStorage::class, '/', ['datadir' => $configDataDirectory], $loader, null, null, self::class);
}
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index 9936487abb3..ca256b09d33 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -422,7 +422,7 @@ class Folder extends Node implements \OCP\Files\Folder {
$filterNonRecentFiles = new SearchComparison(
ISearchComparison::COMPARE_GREATER_THAN,
'mtime',
- strtotime("-2 week")
+ strtotime('-2 week')
);
if ($offset === 0 && $limit <= 100) {
$query = new SearchQuery(
diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php
index f9908b9b7b6..77479c2fa5e 100644
--- a/lib/private/Files/Node/LazyUserFolder.php
+++ b/lib/private/Files/Node/LazyUserFolder.php
@@ -59,7 +59,7 @@ class LazyUserFolder extends LazyFolder {
}
$mountPoint = $this->mountManager->find('/' . $this->user->getUID());
if (is_null($mountPoint)) {
- throw new \Exception("No mountpoint for user folder");
+ throw new \Exception('No mountpoint for user folder');
}
return $mountPoint;
}
diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php
index e7f533e73a9..5dbdc4054bf 100644
--- a/lib/private/Files/Node/Node.php
+++ b/lib/private/Files/Node/Node.php
@@ -158,7 +158,7 @@ class Node implements INode {
public function getStorage() {
$storage = $this->getMountPoint()->getStorage();
if (!$storage) {
- throw new \Exception("No storage for node");
+ throw new \Exception('No storage for node');
}
return $storage;
}
@@ -432,11 +432,14 @@ class Node implements INode {
$targetPath = $this->normalizePath($targetPath);
$parent = $this->root->get(dirname($targetPath));
if (
- $parent instanceof Folder and
- $this->isValidPath($targetPath) and
- (
- $parent->isCreatable() ||
- ($parent->getInternalPath() === '' && $parent->getMountPoint() instanceof MoveableMount)
+ ($parent instanceof Folder)
+ && $this->isValidPath($targetPath)
+ && (
+ $parent->isCreatable()
+ || (
+ $parent->getInternalPath() === ''
+ && ($parent->getMountPoint() instanceof MoveableMount)
+ )
)
) {
$nonExisting = $this->createNonExistingNode($targetPath);
diff --git a/lib/private/Files/Node/NonExistingFile.php b/lib/private/Files/Node/NonExistingFile.php
index d154876432e..66ec2e6c040 100644
--- a/lib/private/Files/Node/NonExistingFile.php
+++ b/lib/private/Files/Node/NonExistingFile.php
@@ -38,6 +38,14 @@ class NonExistingFile extends File {
}
}
+ public function getInternalPath() {
+ if ($this->fileInfo) {
+ return parent::getInternalPath();
+ } else {
+ return $this->getParent()->getMountPoint()->getInternalPath($this->getPath());
+ }
+ }
+
public function stat() {
throw new NotFoundException();
}
diff --git a/lib/private/Files/Node/NonExistingFolder.php b/lib/private/Files/Node/NonExistingFolder.php
index 5650c99fe73..4489fdaf010 100644
--- a/lib/private/Files/Node/NonExistingFolder.php
+++ b/lib/private/Files/Node/NonExistingFolder.php
@@ -38,6 +38,14 @@ class NonExistingFolder extends Folder {
}
}
+ public function getInternalPath() {
+ if ($this->fileInfo) {
+ return parent::getInternalPath();
+ } else {
+ return $this->getParent()->getMountPoint()->getInternalPath($this->getPath());
+ }
+ }
+
public function stat() {
throw new NotFoundException();
}
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php
index 5fb4013cfc9..416adc7f374 100644
--- a/lib/private/Files/Node/Root.php
+++ b/lib/private/Files/Node/Root.php
@@ -459,7 +459,7 @@ class Root extends Folder implements IRootFolder {
if ($folder instanceof Folder) {
return $folder->getByIdInRootMount($id);
} else {
- throw new \Exception("getByIdInPath with non folder");
+ throw new \Exception('getByIdInPath with non folder');
}
}
return [];
diff --git a/lib/private/Files/ObjectStore/Azure.php b/lib/private/Files/ObjectStore/Azure.php
index 55400d4131c..2dacdac1f8d 100644
--- a/lib/private/Files/ObjectStore/Azure.php
+++ b/lib/private/Files/ObjectStore/Azure.php
@@ -21,7 +21,7 @@ class Azure implements IObjectStore {
private $blobClient = null;
/** @var string|null */
private $endpoint = null;
- /** @var bool */
+ /** @var bool */
private $autoCreate = false;
/**
@@ -45,7 +45,7 @@ class Azure implements IObjectStore {
private function getBlobClient() {
if (!$this->blobClient) {
$protocol = $this->endpoint ? substr($this->endpoint, 0, strpos($this->endpoint, ':')) : 'https';
- $connectionString = "DefaultEndpointsProtocol=" . $protocol . ";AccountName=" . $this->accountName . ";AccountKey=" . $this->accountKey;
+ $connectionString = 'DefaultEndpointsProtocol=' . $protocol . ';AccountName=' . $this->accountName . ';AccountKey=' . $this->accountKey;
if ($this->endpoint) {
$connectionString .= ';BlobEndpoint=' . $this->endpoint;
}
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
index 389f744eab4..228fc516677 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -594,6 +594,31 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
}
+ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, ?ICacheEntry $sourceCacheEntry = null): bool {
+ $sourceCache = $sourceStorage->getCache();
+ if (!$sourceCacheEntry) {
+ $sourceCacheEntry = $sourceCache->get($sourceInternalPath);
+ }
+ if ($sourceCacheEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
+ foreach ($sourceCache->getFolderContents($sourceInternalPath) as $child) {
+ $this->moveFromStorage($sourceStorage, $child->getPath(), $targetInternalPath . '/' . $child->getName());
+ }
+ $sourceStorage->rmdir($sourceInternalPath);
+ } else {
+ // move the cache entry before the contents so that we have the correct fileid/urn for the target
+ $this->getCache()->moveFromCache($sourceCache, $sourceInternalPath, $targetInternalPath);
+ try {
+ $this->writeStream($targetInternalPath, $sourceStorage->fopen($sourceInternalPath, 'r'), $sourceCacheEntry->getSize());
+ } catch (\Exception $e) {
+ // restore the cache entry
+ $sourceCache->moveFromCache($this->getCache(), $targetInternalPath, $sourceInternalPath);
+ throw $e;
+ }
+ $sourceStorage->unlink($sourceInternalPath);
+ }
+ return true;
+ }
+
public function copy($source, $target) {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);
@@ -632,7 +657,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$sourceUrn = $this->getURN($sourceEntry->getId());
if (!$cache instanceof Cache) {
- throw new \Exception("Invalid source cache for object store copy");
+ throw new \Exception('Invalid source cache for object store copy');
}
$targetId = $cache->copyFromCache($cache, $sourceEntry, $to);
diff --git a/lib/private/Files/ObjectStore/S3ConnectionTrait.php b/lib/private/Files/ObjectStore/S3ConnectionTrait.php
index 0506eb35353..9de85f00620 100644
--- a/lib/private/Files/ObjectStore/S3ConnectionTrait.php
+++ b/lib/private/Files/ObjectStore/S3ConnectionTrait.php
@@ -28,7 +28,7 @@ trait S3ConnectionTrait {
protected function parseParams($params) {
if (empty($params['bucket'])) {
- throw new \Exception("Bucket has to be configured.");
+ throw new \Exception('Bucket has to be configured.');
}
$this->id = 'amazon::' . $params['bucket'];
@@ -132,7 +132,7 @@ trait S3ConnectionTrait {
try {
$logger->info('Bucket "' . $this->bucket . '" does not exist - creating it.', ['app' => 'objectstore']);
if (!$this->connection::isBucketDnsCompatible($this->bucket)) {
- throw new \Exception("The bucket will not be created because the name is not dns compatible, please correct it: " . $this->bucket);
+ throw new \Exception('The bucket will not be created because the name is not dns compatible, please correct it: ' . $this->bucket);
}
$this->connection->createBucket(['Bucket' => $this->bucket]);
$this->testTimeout();
@@ -197,7 +197,7 @@ trait S3ConnectionTrait {
}
protected function getCertificateBundlePath(): ?string {
- if ((int)($this->params['use_nextcloud_bundle'] ?? "0")) {
+ if ((int)($this->params['use_nextcloud_bundle'] ?? '0')) {
// since we store the certificate bundles on the primary storage, we can't get the bundle while setting up the primary storage
if (!isset($this->params['primary_storage'])) {
/** @var ICertificateManager $certManager */
diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php
index 5d00c184ca7..2e625033751 100644
--- a/lib/private/Files/ObjectStore/S3ObjectTrait.php
+++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php
@@ -127,7 +127,7 @@ trait S3ObjectTrait {
if ($e->getState()->isInitiated() && (array_key_exists('UploadId', $uploadInfo))) {
$this->getConnection()->abortMultipartUpload($uploadInfo);
}
- throw new \OCA\DAV\Connector\Sabre\Exception\BadGateway("Error while uploading to S3 bucket", 0, $e);
+ throw new \OCA\DAV\Connector\Sabre\Exception\BadGateway('Error while uploading to S3 bucket', 0, $e);
}
}
@@ -144,7 +144,7 @@ trait S3ObjectTrait {
// ($psrStream->isSeekable() && $psrStream->getSize() !== null) evaluates to true for a On-Seekable stream
// so the optimisation does not apply
- $buffer = new Psr7\Stream(fopen("php://memory", 'rwb+'));
+ $buffer = new Psr7\Stream(fopen('php://memory', 'rwb+'));
Utils::copyToStream($psrStream, $buffer, $this->putSizeLimit);
$buffer->seek(0);
if ($buffer->getSize() < $this->putSizeLimit) {
@@ -183,14 +183,14 @@ trait S3ObjectTrait {
if ($this->useMultipartCopy && $size > $this->copySizeLimit) {
$copy = new MultipartCopy($this->getConnection(), [
- "source_bucket" => $this->getBucket(),
- "source_key" => $from
+ 'source_bucket' => $this->getBucket(),
+ 'source_key' => $from
], array_merge([
- "bucket" => $this->getBucket(),
- "key" => $to,
- "acl" => "private",
- "params" => $this->getSSECParameters() + $this->getSSECParameters(true),
- "source_metadata" => $sourceMetadata
+ 'bucket' => $this->getBucket(),
+ 'key' => $to,
+ 'acl' => 'private',
+ 'params' => $this->getSSECParameters() + $this->getSSECParameters(true),
+ 'source_metadata' => $sourceMetadata
], $options));
$copy->copy();
} else {
diff --git a/lib/private/Files/ObjectStore/S3Signature.php b/lib/private/Files/ObjectStore/S3Signature.php
index e3a522b6581..4e9784ee81a 100644
--- a/lib/private/Files/ObjectStore/S3Signature.php
+++ b/lib/private/Files/ObjectStore/S3Signature.php
@@ -99,7 +99,7 @@ class S3Signature implements SignatureInterface {
}
/**
- * @param RequestInterface $request
+ * @param RequestInterface $request
* @param CredentialsInterface $creds
*
* @return RequestInterface
diff --git a/lib/private/Files/ObjectStore/SwiftFactory.php b/lib/private/Files/ObjectStore/SwiftFactory.php
index 0db5c9762d2..a2e22e45de2 100644
--- a/lib/private/Files/ObjectStore/SwiftFactory.php
+++ b/lib/private/Files/ObjectStore/SwiftFactory.php
@@ -170,7 +170,7 @@ class SwiftFactory {
try {
/** @var \OpenStack\Identity\v2\Models\Token $token */
$token = $authService->model(\OpenStack\Identity\v2\Models\Token::class, $cachedToken['token']);
- $now = new \DateTimeImmutable("now");
+ $now = new \DateTimeImmutable('now');
if ($token->expires > $now) {
$hasValidCachedToken = true;
$this->params['v2cachedToken'] = $token;
diff --git a/lib/private/Files/Search/SearchQuery.php b/lib/private/Files/Search/SearchQuery.php
index e7cb031da3e..3c8711facd8 100644
--- a/lib/private/Files/Search/SearchQuery.php
+++ b/lib/private/Files/Search/SearchQuery.php
@@ -11,13 +11,13 @@ use OCP\Files\Search\ISearchQuery;
use OCP\IUser;
class SearchQuery implements ISearchQuery {
- /** @var ISearchOperator */
+ /** @var ISearchOperator */
private $searchOperation;
- /** @var integer */
+ /** @var integer */
private $limit;
- /** @var integer */
+ /** @var integer */
private $offset;
- /** @var ISearchOrder[] */
+ /** @var ISearchOrder[] */
private $order;
/** @var ?IUser */
private $user;
diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php
index 3a3f7ba9c11..e74dd1042d6 100644
--- a/lib/private/Files/SetupManager.php
+++ b/lib/private/Files/SetupManager.php
@@ -382,7 +382,7 @@ class SetupManager {
}
// for the user's home folder, and includes children we need everything always
- if (rtrim($path) === "/" . $user->getUID() . "/files" && $includeChildren) {
+ if (rtrim($path) === '/' . $user->getUID() . '/files' && $includeChildren) {
$this->setupForUser($user);
return;
}
@@ -412,7 +412,7 @@ class SetupManager {
$setupProviders[] = $cachedMount->getMountProvider();
$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
} else {
- $this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
+ $this->logger->debug('mount at ' . $cachedMount->getMountPoint() . ' has no provider set, performing full setup');
$this->eventLogger->end('fs:setup:user:path:find');
$this->setupForUser($user);
$this->eventLogger->end('fs:setup:user:path');
@@ -429,7 +429,7 @@ class SetupManager {
}, false);
if ($needsFullSetup) {
- $this->logger->debug("mount has no provider set, performing full setup");
+ $this->logger->debug('mount has no provider set, performing full setup');
$this->setupForUser($user);
$this->eventLogger->end('fs:setup:user:path');
return;
@@ -491,7 +491,7 @@ class SetupManager {
return;
}
- $this->eventLogger->start('fs:setup:user:providers', "Setup filesystem for " . implode(', ', $providers));
+ $this->eventLogger->start('fs:setup:user:providers', 'Setup filesystem for ' . implode(', ', $providers));
$this->oneTimeUserSetup($user);
diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php
index 823ff65474b..9541ba7c746 100644
--- a/lib/private/Files/Storage/Common.php
+++ b/lib/private/Files/Storage/Common.php
@@ -13,6 +13,7 @@ use OC\Files\Cache\Propagator;
use OC\Files\Cache\Scanner;
use OC\Files\Cache\Updater;
use OC\Files\Cache\Watcher;
+use OC\Files\FilenameValidator;
use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\Jail;
use OC\Files\Storage\Wrapper\Wrapper;
@@ -159,7 +160,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
}
public function file_get_contents($path) {
- $handle = $this->fopen($path, "r");
+ $handle = $this->fopen($path, 'r');
if (!$handle) {
return false;
}
@@ -169,7 +170,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
}
public function file_put_contents($path, $data) {
- $handle = $this->fopen($path, "w");
+ $handle = $this->fopen($path, 'w');
if (!$handle) {
return false;
}
@@ -430,11 +431,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
if ($this->stat('')) {
return true;
}
- \OC::$server->get(LoggerInterface::class)->info("External storage not available: stat() failed");
+ \OC::$server->get(LoggerInterface::class)->info('External storage not available: stat() failed');
return false;
} catch (\Exception $e) {
\OC::$server->get(LoggerInterface::class)->warning(
- "External storage not available: " . $e->getMessage(),
+ 'External storage not available: ' . $e->getMessage(),
['exception' => $e]
);
return false;
@@ -494,7 +495,18 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
$this->getFilenameValidator()
->validateFilename($fileName);
- // NOTE: $path will remain unverified for now
+ // verify also the path is valid
+ if ($path && $path !== '/' && $path !== '.') {
+ try {
+ $this->verifyPath(dirname($path), basename($path));
+ } catch (InvalidPathException $e) {
+ // Ignore invalid file type exceptions on directories
+ if ($e->getCode() !== FilenameValidator::INVALID_FILE_TYPE) {
+ $l = \OCP\Util::getL10N('lib');
+ throw new InvalidPathException($l->t('Invalid parent path'), previous: $e);
+ }
+ }
+ }
}
/**
@@ -816,7 +828,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
try {
[$count, $result] = \OC_Helper::streamCopy($stream, $target);
if (!$result) {
- throw new GenericFileException("Failed to copy stream");
+ throw new GenericFileException('Failed to copy stream');
}
} finally {
fclose($target);
diff --git a/lib/private/Files/Storage/DAV.php b/lib/private/Files/Storage/DAV.php
index 63ef1399a69..7abc0ccc182 100644
--- a/lib/private/Files/Storage/DAV.php
+++ b/lib/private/Files/Storage/DAV.php
@@ -90,9 +90,9 @@ class DAV extends Common {
if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
$host = $params['host'];
//remove leading http[s], will be generated in createBaseUri()
- if (str_starts_with($host, "https://")) {
+ if (str_starts_with($host, 'https://')) {
$host = substr($host, 8);
- } elseif (str_starts_with($host, "http://")) {
+ } elseif (str_starts_with($host, 'http://')) {
$host = substr($host, 7);
}
$this->host = $host;
@@ -162,13 +162,13 @@ class DAV extends Common {
$lastRequestStart = 0;
$this->client->on('beforeRequest', function (RequestInterface $request) use (&$lastRequestStart) {
- $this->logger->debug("sending dav " . $request->getMethod() . " request to external storage: " . $request->getAbsoluteUrl(), ['app' => 'dav']);
+ $this->logger->debug('sending dav ' . $request->getMethod() . ' request to external storage: ' . $request->getAbsoluteUrl(), ['app' => 'dav']);
$lastRequestStart = microtime(true);
- $this->eventLogger->start('fs:storage:dav:request', "Sending dav request to external storage");
+ $this->eventLogger->start('fs:storage:dav:request', 'Sending dav request to external storage');
});
$this->client->on('afterRequest', function (RequestInterface $request) use (&$lastRequestStart) {
$elapsed = microtime(true) - $lastRequestStart;
- $this->logger->debug("dav " . $request->getMethod() . " request to external storage: " . $request->getAbsoluteUrl() . " took " . round($elapsed * 1000, 1) . "ms", ['app' => 'dav']);
+ $this->logger->debug('dav ' . $request->getMethod() . ' request to external storage: ' . $request->getAbsoluteUrl() . ' took ' . round($elapsed * 1000, 1) . 'ms', ['app' => 'dav']);
$this->eventLogger->end('fs:storage:dav:request');
});
}
@@ -283,11 +283,11 @@ class DAV extends Common {
return false;
}
$responseType = [];
- if (isset($response["{DAV:}resourcetype"])) {
+ if (isset($response['{DAV:}resourcetype'])) {
/** @var ResourceType[] $response */
- $responseType = $response["{DAV:}resourcetype"]->getValue();
+ $responseType = $response['{DAV:}resourcetype']->getValue();
}
- return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
+ return (count($responseType) > 0 and $responseType[0] == '{DAV:}collection') ? 'dir' : 'file';
} catch (\Exception $e) {
$this->convertException($e, $path);
}
@@ -582,11 +582,11 @@ class DAV extends Common {
}
$responseType = [];
- if (isset($response["{DAV:}resourcetype"])) {
+ if (isset($response['{DAV:}resourcetype'])) {
/** @var ResourceType[] $response */
- $responseType = $response["{DAV:}resourcetype"]->getValue();
+ $responseType = $response['{DAV:}resourcetype']->getValue();
}
- $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
+ $type = (count($responseType) > 0 and $responseType[0] == '{DAV:}collection') ? 'dir' : 'file';
if ($type === 'dir') {
$mimeType = 'httpd/unix-directory';
} elseif (isset($response['{DAV:}getcontenttype'])) {
@@ -832,9 +832,9 @@ class DAV extends Common {
* @param string $path optional path from the operation
*
* @throws StorageInvalidException if the storage is invalid, for example
- * when the authentication expired or is invalid
+ * when the authentication expired or is invalid
* @throws StorageNotAvailableException if the storage is not available,
- * which might be temporary
+ * which might be temporary
* @throws ForbiddenException if the action is not allowed
*/
protected function convertException(Exception $e, $path = '') {
diff --git a/lib/private/Files/Storage/Home.php b/lib/private/Files/Storage/Home.php
index 9a336d2efcc..a8d1f82b987 100644
--- a/lib/private/Files/Storage/Home.php
+++ b/lib/private/Files/Storage/Home.php
@@ -28,7 +28,7 @@ class Home extends Local implements \OCP\Files\IHomeStorage {
* Construct a Home storage instance
*
* @param array $arguments array with "user" containing the
- * storage owner
+ * storage owner
*/
public function __construct($arguments) {
$this->user = $arguments['user'];
diff --git a/lib/private/Files/Storage/StorageFactory.php b/lib/private/Files/Storage/StorageFactory.php
index 18fca1d28e3..612592e2d3a 100644
--- a/lib/private/Files/Storage/StorageFactory.php
+++ b/lib/private/Files/Storage/StorageFactory.php
@@ -26,7 +26,7 @@ class StorageFactory implements IStorageFactory {
* @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
+ * name registered
*/
public function addStorageWrapper($wrapperName, $callback, $priority = 50, $existingMounts = []) {
if (isset($this->storageWrappers[$wrapperName])) {
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index 09048c239ee..1ead1c342b0 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -65,7 +65,7 @@ class Encryption extends Wrapper {
/** @var array remember for which path we execute the repair step to avoid recursions */
private $fixUnencryptedSizeOf = [];
- /** @var ArrayCache */
+ /** @var ArrayCache */
private $arrayCache;
/** @var CappedMemoryCache<bool> */
@@ -204,7 +204,7 @@ class Encryption extends Wrapper {
$encryptionModule = $this->getEncryptionModule($path);
if ($encryptionModule) {
- $handle = $this->fopen($path, "r");
+ $handle = $this->fopen($path, 'r');
if (!$handle) {
return false;
}
diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php
index 8c6799fdd2d..b642c438266 100644
--- a/lib/private/Files/Storage/Wrapper/Quota.php
+++ b/lib/private/Files/Storage/Wrapper/Quota.php
@@ -40,7 +40,7 @@ class Quota extends Wrapper {
if ($this->quota === null) {
$quotaCallback = $this->quotaCallback;
if ($quotaCallback === null) {
- throw new \Exception("No quota or quota callback provider");
+ throw new \Exception('No quota or quota callback provider');
}
$this->quota = $quotaCallback();
}
diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php
index 29acc9ad1c2..f8aa9d963dc 100644
--- a/lib/private/Files/Storage/Wrapper/Wrapper.php
+++ b/lib/private/Files/Storage/Wrapper/Wrapper.php
@@ -40,7 +40,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
*/
public function getWrapperStorage() {
if (!$this->storage) {
- $message = "storage wrapper " . get_class($this) . " doesn't have a wrapped storage set";
+ $message = 'storage wrapper ' . get_class($this) . " doesn't have a wrapped storage set";
$logger = Server::get(LoggerInterface::class);
$logger->error($message);
$this->storage = new FailedStorage(['exception' => new \Exception($message)]);
diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php
index 32c0021cd23..8f08f925da0 100644
--- a/lib/private/Files/Stream/Encryption.php
+++ b/lib/private/Files/Stream/Encryption.php
@@ -55,7 +55,7 @@ class Encryption extends Wrapper {
/** @var string */
protected $fullPath;
- /** @var bool */
+ /** @var bool */
protected $signed;
/**
diff --git a/lib/private/Files/Stream/SeekableHttpStream.php b/lib/private/Files/Stream/SeekableHttpStream.php
index 02ed1470fbd..5ed04ed9066 100644
--- a/lib/private/Files/Stream/SeekableHttpStream.php
+++ b/lib/private/Files/Stream/SeekableHttpStream.php
@@ -90,7 +90,7 @@ class SeekableHttpStream implements File {
continue 2;
}
}
- throw new \Exception("Failed to get source stream from stream wrapper of " . get_class($responseHead));
+ throw new \Exception('Failed to get source stream from stream wrapper of ' . get_class($responseHead));
}
$rangeHeaders = array_values(array_filter($responseHead, function ($v) {
diff --git a/lib/private/Files/Type/Loader.php b/lib/private/Files/Type/Loader.php
index 247acf0141a..407df59b2e2 100644
--- a/lib/private/Files/Type/Loader.php
+++ b/lib/private/Files/Type/Loader.php
@@ -115,7 +115,7 @@ class Loader implements IMimeTypeLoader {
throw new \Exception("Database threw an unique constraint on inserting a new mimetype, but couldn't return the ID for this very mimetype");
}
- $mimetypeId = (int) $id;
+ $mimetypeId = (int)$id;
}
$this->mimetypes[$mimetypeId] = $mimetype;
@@ -136,8 +136,8 @@ class Loader implements IMimeTypeLoader {
$result->closeCursor();
foreach ($results as $row) {
- $this->mimetypes[(int) $row['id']] = $row['mimetype'];
- $this->mimetypeIds[$row['mimetype']] = (int) $row['id'];
+ $this->mimetypes[(int)$row['id']] = $row['mimetype'];
+ $this->mimetypeIds[$row['mimetype']] = (int)$row['id'];
}
}
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index 09e2ba39c10..2241bc02ae6 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -221,7 +221,7 @@ class View {
$relPath = '/' . $pathParts[3];
$this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
\OC_Hook::emit(
- Filesystem::CLASSNAME, "umount",
+ Filesystem::CLASSNAME, 'umount',
[Filesystem::signal_param_path => $relPath]
);
$this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true);
@@ -229,7 +229,7 @@ class View {
$this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true);
if ($result) {
\OC_Hook::emit(
- Filesystem::CLASSNAME, "post_umount",
+ Filesystem::CLASSNAME, 'post_umount',
[Filesystem::signal_param_path => $relPath]
);
}
@@ -697,7 +697,7 @@ class View {
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($target));
if (str_starts_with($absolutePath2, $absolutePath1 . '/')) {
- throw new ForbiddenException("Moving a folder into a child folder is forbidden", false);
+ throw new ForbiddenException('Moving a folder into a child folder is forbidden', false);
}
$targetParts = explode('/', $absolutePath2);
@@ -1330,7 +1330,7 @@ class View {
*
* @param string $path
* @param bool|string $includeMountPoints true to add mountpoint sizes,
- * 'ext' to add only ext storage mount point sizes. Defaults to true.
+ * 'ext' to add only ext storage mount point sizes. Defaults to true.
* @return \OC\Files\FileInfo|false False if file does not exist
*/
public function getFileInfo($path, $includeMountPoints = true) {
@@ -1835,28 +1835,39 @@ class View {
/**
* @param string $path
* @param string $fileName
+ * @param bool $readonly Check only if the path is allowed for read-only access
* @throws InvalidPathException
*/
- public function verifyPath($path, $fileName): void {
+ public function verifyPath($path, $fileName, $readonly = false): void {
// All of the view's functions disallow '..' in the path so we can short cut if the path is invalid
if (!Filesystem::isValidPath($path ?: '/')) {
$l = \OCP\Util::getL10N('lib');
throw new InvalidPathException($l->t('Path contains invalid segments'));
}
+ // Short cut for read-only validation
+ if ($readonly) {
+ $validator = \OCP\Server::get(FilenameValidator::class);
+ if ($validator->isForbidden($fileName)) {
+ $l = \OCP\Util::getL10N('lib');
+ throw new InvalidPathException($l->t('Filename is a reserved word'));
+ }
+ return;
+ }
+
try {
/** @type \OCP\Files\Storage $storage */
[$storage, $internalPath] = $this->resolvePath($path);
$storage->verifyPath($internalPath, $fileName);
} catch (ReservedWordException $ex) {
$l = \OCP\Util::getL10N('lib');
- throw new InvalidPathException($l->t('File name is a reserved word'));
+ throw new InvalidPathException($ex->getMessage() ?: $l->t('Filename is a reserved word'));
} catch (InvalidCharacterInPathException $ex) {
$l = \OCP\Util::getL10N('lib');
- throw new InvalidPathException($l->t('File name contains at least one invalid character'));
+ throw new InvalidPathException($ex->getMessage() ?: $l->t('Filename contains at least one invalid character'));
} catch (FileNameTooLongException $ex) {
$l = \OCP\Util::getL10N('lib');
- throw new InvalidPathException($l->t('File name is too long'));
+ throw new InvalidPathException($l->t('Filename is too long'));
} catch (InvalidDirectoryException $ex) {
$l = \OCP\Util::getL10N('lib');
throw new InvalidPathException($l->t('Dot files are not allowed'));
@@ -1898,7 +1909,7 @@ class View {
*
* @param string $absolutePath absolute path
* @param bool $useParentMount true to return parent mount instead of whatever
- * is mounted directly on the given path, false otherwise
+ * is mounted directly on the given path, false otherwise
* @return IMountPoint mount point for which to apply locks
*/
private function getMountForLock(string $absolutePath, bool $useParentMount = false): IMountPoint {
@@ -2112,7 +2123,7 @@ class View {
* @param string $absolutePath absolute path which is under "files"
*
* @return string path relative to "files" with trimmed slashes or null
- * if the path was NOT relative to files
+ * if the path was NOT relative to files
*
* @throws \InvalidArgumentException if the given path was not under "files"
* @since 8.1.0