Review of 1.0.3: names a snapshot cannot hold, restore-directory errors under salvage, browse speed

- Leave out and report a file or folder whose name a snapshot cannot hold
- A staging write failure stops a full restore under --salvage
- Browse reuses its repository; empty folders read along with the entries
- Keep leases alive while empty folders are created; exact-prefix empty folder is the target
- Clean up tables that were partly created or before the transaction started
- Bin: no empty message after a read error; longer pages
This commit is contained in:
2026-11-06 19:44:52 +01:00
parent c7a651f269
commit 1736005648
9 changed files with 68 additions and 19 deletions
+2
View File
@@ -209,6 +209,8 @@ final class RestoreFullService {
try {
/** @var array<string, mixed> $backupConfig */
$backupConfig = $this->fetchBackupConfig($target, $snapshotId, $salvage);
} catch (\OCA\NgBackup\Repository\RestoreTargetException $e) {
throw $e; // nowhere to put it: not a config.php that cannot be read
} catch (\Throwable $e) {
if (!$salvage) {
throw $e;
+7 -3
View File
@@ -61,7 +61,8 @@ final class RestoreService {
$prefix = trim($path, '/');
$prefix = $prefix === '' ? '' : $prefix . '/';
$children = [];
foreach ($this->targets->repository($target)->entries($snapshotId) as $e) {
$repo = $this->targets->repository($target);
foreach ($repo->entries($snapshotId) as $e) {
if ($prefix !== '' && !str_starts_with($e['p'], $prefix)) {
continue;
}
@@ -75,7 +76,7 @@ final class RestoreService {
}
$children[$name] = $c;
}
foreach ($this->targets->repository($target)->emptyDirs($snapshotId) as [$dir]) {
foreach ($repo->emptyDirs($snapshotId) as [$dir]) { // read along with the entries
if ($prefix === '' || str_starts_with($dir, $prefix)) {
$name = explode('/', substr($dir, strlen($prefix)), 2)[0];
$children[$name] ??= ['name' => $name, 'type' => 'dir', 'size' => 0, 'mtime' => null, 'files' => 0];
@@ -180,6 +181,9 @@ final class RestoreService {
if (!$existed) {
$folder->touch($mtime);
}
if ($progress !== null) {
$progress($restored, count($names), $dir); // keeps the lease alive too
}
}
$trashed = 0;
@@ -204,7 +208,7 @@ final class RestoreService {
throw new \InvalidArgumentException('Invalid path: ' . $prefix);
}
if (!is_dir($directory) && !mkdir($directory, 0750, true) && !is_dir($directory)) {
throw new \RuntimeException("Cannot create $directory");
throw new \OCA\NgBackup\Repository\RestoreTargetException("Cannot create $directory (disk full, or no permission?)");
}
return $this->withSharedLock($target, function (callable $refresh) use ($target, $snapshotId, $prefix, $directory, $stripPrefix, $heartbeat, &$skipped, $keepUnchanged): int {
$own = LeaseService::throttled($refresh);