From d861c1da3b5506115974d8f38bbbb1cacb955d82 Mon Sep 17 00:00:00 2001 From: Julius Knorr Date: Fri, 31 Oct 2025 12:57:50 +0100 Subject: [PATCH] perf: Optimize downloading directories as zip to avoid counting files for zip64 Signed-off-by: Julius Knorr --- apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php | 13 +++++-------- lib/private/Streamer.php | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php b/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php index 1807ce16047..25755e2299b 100644 --- a/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php +++ b/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php @@ -150,13 +150,6 @@ class ZipFolderPlugin extends ServerPlugin { throw new Forbidden($errorMessage); } - $content = empty($files) ? $folder->getDirectoryListing() : []; - foreach ($files as $path) { - $child = $node->getChild($path); - assert($child instanceof Node); - $content[] = $child->getNode(); - } - $archiveName = $folder->getName(); if (count(explode('/', trim($folder->getPath(), '/'), 3)) === 2) { // this is a download of the root folder @@ -169,13 +162,17 @@ class ZipFolderPlugin extends ServerPlugin { $rootPath = dirname($folder->getPath()); } - $streamer = new Streamer($tarRequest, -1, count($content), $this->timezoneFactory); + + $streamer = new Streamer($tarRequest, -1, -1, $this->timezoneFactory); $streamer->sendHeaders($archiveName); // For full folder downloads we also add the folder itself to the archive if (empty($files)) { $streamer->addEmptyDir($archiveName); } + + $content = empty($files) ? $folder->getDirectoryListing() : array_map(fn (string $path) => $folder->get($path), $files); foreach ($content as $node) { + assert($node instanceof NcNode); $this->streamNode($streamer, $node, $rootPath); } $streamer->finalize(); diff --git a/lib/private/Streamer.php b/lib/private/Streamer.php index 7ebb66bf03a..933a12bf9c0 100644 --- a/lib/private/Streamer.php +++ b/lib/private/Streamer.php @@ -39,7 +39,7 @@ class Streamer { * please migrate to `Streamer::isUserAgentPreferTar()` instead. * @param int|float $size The size of the files in bytes * @param int $numberOfFiles The number of files (and directories) that will - * be included in the streamed file + * be included in the streamed file, used to detect if zip32 or zip64 should be used, can be set to -1 to enforce zip64 */ public function __construct( IRequest|bool $preferTar, @@ -80,7 +80,7 @@ class Streamer { if ($preferTar) { // If TAR ball is preferred use it $this->streamerInstance = new TarStreamer(); - } elseif ($size > 0 && $size < 4 * 1000 * 1000 * 1000 && $numberOfFiles < 65536) { + } elseif ($size > 0 && $size < 4 * 1000 * 1000 * 1000 && $numberOfFiles < 65536 && $numberOfFiles >= 0) { $this->streamerInstance = new ZipStreamer(['zip64' => false]); } else { $this->streamerInstance = new ZipStreamer(['zip64' => true]);