aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2025-04-25 18:35:12 +0200
committerRobin Appelman <robin@icewind.nl>2025-05-13 14:06:15 +0200
commita4a5bcaacb54e56c79ad13c5dd8e52ac19eb6f11 (patch)
treea0f0cc1398b40411ea57a13d47d64680979bdcf0
parentf6c9cdcf6aa13e9a12087639264213f53194991d (diff)
downloadnextcloud-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.php7
-rw-r--r--apps/files_external/lib/Command/Scan.php15
-rw-r--r--lib/private/Files/Cache/Scanner.php10
-rw-r--r--lib/private/Files/Utils/Scanner.php11
-rw-r--r--lib/public/Lock/LockedException.php12
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;
+ }
+
}