diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index 1b4de841ec6..d01ea6b223e 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -28,6 +28,7 @@ use OCP\Files\IFilenameValidator; use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountManager; use OCP\IConfig; +use OCP\IDateTimeZone; use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IL10N; @@ -108,6 +109,7 @@ class ServerFactory { $tree, $this->logger, $this->eventDispatcher, + \OCP\Server::get(IDateTimeZone::class), )); // Some WebDAV clients do require Class 2 WebDAV support (locking), since diff --git a/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php b/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php index f198519b454..de802a3cd50 100644 --- a/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php +++ b/apps/dav/lib/Connector/Sabre/ZipFolderPlugin.php @@ -15,6 +15,7 @@ use OCP\Files\Events\BeforeZipCreatedEvent; use OCP\Files\File as NcFile; use OCP\Files\Folder as NcFolder; use OCP\Files\Node as NcNode; +use OCP\IDateTimeZone; use Psr\Log\LoggerInterface; use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; @@ -41,6 +42,7 @@ class ZipFolderPlugin extends ServerPlugin { private Tree $tree, private LoggerInterface $logger, private IEventDispatcher $eventDispatcher, + private IDateTimeZone $timezoneFactory, ) { } @@ -163,7 +165,7 @@ class ZipFolderPlugin extends ServerPlugin { // Full folder is loaded to rename the archive to the folder name $archiveName = $folder->getName(); } - $streamer = new Streamer($tarRequest, -1, count($content)); + $streamer = new Streamer($tarRequest, -1, count($content), $this->timezoneFactory); $streamer->sendHeaders($archiveName); // For full folder downloads we also add the folder itself to the archive if (empty($files)) { diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 9b4a1b3d33c..d2bd3e6077b 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -83,6 +83,7 @@ use OCP\FilesMetadata\IFilesMetadataManager; use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IConfig; +use OCP\IDateTimeZone; use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IPreview; @@ -249,6 +250,7 @@ class Server { $this->server->tree, $logger, $eventDispatcher, + \OCP\Server::get(IDateTimeZone::class), )); $this->server->addPlugin(\OCP\Server::get(PaginatePlugin::class)); $this->server->addPlugin(new PropFindPreloadNotifyPlugin()); diff --git a/lib/private/Streamer.php b/lib/private/Streamer.php index e579c42c0d7..7ebb66bf03a 100644 --- a/lib/private/Streamer.php +++ b/lib/private/Streamer.php @@ -14,6 +14,7 @@ use OCP\Files\InvalidPathException; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\IDateTimeZone; use OCP\IRequest; use ownCloud\TarStreamer\TarStreamer; use Psr\Log\LoggerInterface; @@ -40,7 +41,12 @@ class Streamer { * @param int $numberOfFiles The number of files (and directories) that will * be included in the streamed file */ - public function __construct(IRequest|bool $preferTar, int|float $size, int $numberOfFiles) { + public function __construct( + IRequest|bool $preferTar, + int|float $size, + int $numberOfFiles, + private IDateTimeZone $timezoneFactory, + ) { if ($preferTar instanceof IRequest) { $preferTar = self::isUserAgentPreferTar($preferTar); } @@ -156,7 +162,7 @@ class Streamer { $options = []; if ($time) { $options = [ - 'timestamp' => $time + 'timestamp' => $this->fixTimestamp($time), ]; } @@ -176,7 +182,7 @@ class Streamer { public function addEmptyDir(string $dirName, int $timestamp = 0): bool { $options = null; if ($timestamp > 0) { - $options = ['timestamp' => $timestamp]; + $options = ['timestamp' => $this->fixTimestamp($timestamp)]; } return $this->streamerInstance->addEmptyDir($dirName, $options); @@ -191,4 +197,14 @@ class Streamer { public function finalize() { return $this->streamerInstance->finalize(); } + + private function fixTimestamp(int $timestamp): int { + if ($this->streamerInstance instanceof ZipStreamer) { + // Zip does not support any timezone information + // while tar is interpreted as Unix time the Zip time is interpreted as local time of the user... + $zone = $this->timezoneFactory->getTimeZone($timestamp); + $timestamp += $zone->getOffset(new \DateTimeImmutable('@' . (string)$timestamp)); + } + return $timestamp; + } } diff --git a/lib/public/AppFramework/Http/ZipResponse.php b/lib/public/AppFramework/Http/ZipResponse.php index a552eb1294f..f0c6577f0d4 100644 --- a/lib/public/AppFramework/Http/ZipResponse.php +++ b/lib/public/AppFramework/Http/ZipResponse.php @@ -9,6 +9,7 @@ namespace OCP\AppFramework\Http; use OC\Streamer; use OCP\AppFramework\Http; +use OCP\IDateTimeZone; use OCP\IRequest; /** @@ -65,7 +66,7 @@ class ZipResponse extends Response implements ICallbackResponse { $size += $resource['size']; } - $zip = new Streamer($this->request, $size, $files); + $zip = new Streamer($this->request, $size, $files, \OCP\Server::get(IDateTimeZone::class)); $zip->sendHeaders($this->name); foreach ($this->resources as $resource) {