diff options
author | Robin Appelman <robin@icewind.nl> | 2025-04-25 18:35:12 +0200 |
---|---|---|
committer | Robin Appelman <robin@icewind.nl> | 2025-05-13 14:06:15 +0200 |
commit | a4a5bcaacb54e56c79ad13c5dd8e52ac19eb6f11 (patch) | |
tree | a0f0cc1398b40411ea57a13d47d64680979bdcf0 | |
parent | f6c9cdcf6aa13e9a12087639264213f53194991d (diff) | |
download | nextcloud-server-backport/52441/stable31.tar.gz nextcloud-server-backport/52441/stable31.zip |
fix: better error message when trying to scan a folder that is already being scannedbackport/52441/stable31
Signed-off-by: Robin Appelman <robin@icewind.nl>
-rw-r--r-- | apps/files/lib/Command/Scan.php | 7 | ||||
-rw-r--r-- | apps/files_external/lib/Command/Scan.php | 15 | ||||
-rw-r--r-- | lib/private/Files/Cache/Scanner.php | 10 | ||||
-rw-r--r-- | lib/private/Files/Utils/Scanner.php | 11 | ||||
-rw-r--r-- | lib/public/Lock/LockedException.php | 12 |
5 files changed, 48 insertions, 7 deletions
diff --git a/apps/files/lib/Command/Scan.php b/apps/files/lib/Command/Scan.php index cf1cb04b9af..89018e4191a 100644 --- a/apps/files/lib/Command/Scan.php +++ b/apps/files/lib/Command/Scan.php @@ -24,6 +24,7 @@ use OCP\Files\NotFoundException; use OCP\Files\StorageNotAvailableException; use OCP\FilesMetadata\IFilesMetadataManager; use OCP\IUserManager; +use OCP\Lock\LockedException; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; @@ -164,6 +165,12 @@ class Scan extends Base { } catch (NotFoundException $e) { $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>'); ++$this->errorsCounter; + } catch (LockedException $e) { + if (str_starts_with($e->getPath(), 'scanner::')) { + $output->writeln('<error>Another process is already scanning \'' . substr($e->getPath(), strlen('scanner::')) . '\'</error>'); + } else { + throw $e; + } } catch (\Exception $e) { $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>'); $output->writeln('<error>' . $e->getTraceAsString() . '</error>'); diff --git a/apps/files_external/lib/Command/Scan.php b/apps/files_external/lib/Command/Scan.php index bd54415df55..4f29dae1ce0 100644 --- a/apps/files_external/lib/Command/Scan.php +++ b/apps/files_external/lib/Command/Scan.php @@ -11,6 +11,7 @@ namespace OCA\Files_External\Command; use OC\Files\Cache\Scanner; use OCA\Files_External\Service\GlobalStoragesService; use OCP\IUserManager; +use OCP\Lock\LockedException; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -82,7 +83,19 @@ class Scan extends StorageAuthBase { $this->abortIfInterrupted(); }); - $scanner->scan($path); + try { + $scanner->scan($path); + } catch (LockedException $e) { + if (is_string($e->getReadablePath()) && str_starts_with($e->getReadablePath(), 'scanner::')) { + if ($e->getReadablePath() === 'scanner::') { + $output->writeln('<error>Another process is already scanning this storage</error>'); + } else { + $output->writeln('<error>Another process is already scanning \'' . substr($e->getReadablePath(), strlen('scanner::')) . '\' in this storage</error>'); + } + } else { + throw $e; + } + } $this->presentStats($output); diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php index 1fb408a0655..b067f70b8cb 100644 --- a/lib/private/Files/Cache/Scanner.php +++ b/lib/private/Files/Cache/Scanner.php @@ -210,7 +210,7 @@ class Scanner extends BasicEmitter implements IScanner { * @var \OC\Files\Cache\CacheEntry $cacheData */ $newData = $this->array_diff_assoc_multi($data, $cacheData->getData()); - + // make it known to the caller that etag has been changed and needs propagation if (isset($newData['etag'])) { $data['etag_changed'] = true; @@ -351,23 +351,23 @@ class Scanner extends BasicEmitter implements IScanner { * */ protected function array_diff_assoc_multi(array $array1, array $array2) { - + $result = []; foreach ($array1 as $key => $value) { - + // if $array2 doesn't have the same key, that's a result if (!array_key_exists($key, $array2)) { $result[$key] = $value; continue; } - + // if $array2's value for the same key is different, that's a result if ($array2[$key] !== $value && !is_array($value)) { $result[$key] = $value; continue; } - + if (is_array($value)) { $nestedDiff = $this->array_diff_assoc_multi($value, $array2[$key]); if (!empty($nestedDiff)) { diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php index 4d94629443f..e9ed351b27b 100644 --- a/lib/private/Files/Utils/Scanner.php +++ b/lib/private/Files/Utils/Scanner.php @@ -29,6 +29,7 @@ use OCP\Files\Storage\IStorage; use OCP\Files\StorageNotAvailableException; use OCP\IDBConnection; use OCP\Lock\ILockingProvider; +use OCP\Lock\LockedException; use Psr\Log\LoggerInterface; /** @@ -260,7 +261,15 @@ class Scanner extends PublicEmitter { try { $propagator = $storage->getPropagator(); $propagator->beginBatch(); - $scanner->scan($relativePath, $recursive, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE); + try { + $scanner->scan($relativePath, $recursive, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE); + } catch (LockedException $e) { + if (is_string($e->getReadablePath()) && str_starts_with($e->getReadablePath(), 'scanner::')) { + throw new LockedException("scanner::$dir", $e, $e->getExistingLock()); + } else { + throw $e; + } + } $cache = $storage->getCache(); if ($cache instanceof Cache) { // only re-calculate for the root folder we scanned, anything below that is taken care of by the scanner diff --git a/lib/public/Lock/LockedException.php b/lib/public/Lock/LockedException.php index ce41d2d7242..799886a2dbb 100644 --- a/lib/public/Lock/LockedException.php +++ b/lib/public/Lock/LockedException.php @@ -24,6 +24,8 @@ class LockedException extends \Exception { /** @var string|null */ private $existingLock; + private ?string $readablePath; + /** * LockedException constructor. * @@ -34,6 +36,7 @@ class LockedException extends \Exception { * @since 8.1.0 */ public function __construct(string $path, ?\Exception $previous = null, ?string $existingLock = null, ?string $readablePath = null) { + $this->readablePath = $readablePath; if ($readablePath) { $message = "\"$path\"(\"$readablePath\") is locked"; } else { @@ -62,4 +65,13 @@ class LockedException extends \Exception { public function getExistingLock(): ?string { return $this->existingLock; } + + /** + * @return ?string + * @since 32.0.0 + */ + public function getReadablePath(): ?string { + return $this->readablePath; + } + } |