From abf0b5332b215631d1da7737b69e21301aaafbae Mon Sep 17 00:00:00 2001 From: Tamino Bauknecht Date: Wed, 15 Nov 2023 20:38:08 +0100 Subject: [PATCH] First draft for metadata-only symlinks --- apps/dav/lib/BulkUpload/BulkUploadPlugin.php | 21 ++++++++------------ apps/dav/lib/Connector/Sabre/FilesPlugin.php | 13 ++++++------ apps/dav/lib/Upload/ChunkingV2Plugin.php | 19 +++++++----------- lib/public/Files/FileInfo.php | 4 ++++ 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/apps/dav/lib/BulkUpload/BulkUploadPlugin.php b/apps/dav/lib/BulkUpload/BulkUploadPlugin.php index 471568a107299..f4f25e55dbd8e 100644 --- a/apps/dav/lib/BulkUpload/BulkUploadPlugin.php +++ b/apps/dav/lib/BulkUpload/BulkUploadPlugin.php @@ -100,21 +100,16 @@ public function httpPost(RequestInterface $request, ResponseInterface $response) } if (isset($headers['oc-file-type']) && $headers['oc-file-type'] == 1) { - // TODO: store default value in global location - $allowSymlinks = \OC::$server->get(\OC\AllConfig::class)->getSystemValueBool( - 'localstorage.allowsymlinks', false); - if (!$allowSymlinks) { - throw new Forbidden("Server does not allow the creation of symlinks!"); - } $symlinkPath = $headers['x-file-path']; - $parentNode = $this->server->tree->getNodeForPath(dirname($symlinkPath)); - if(!$parentNode instanceof \OCA\DAV\Connector\Sabre\Directory) { - throw new Exception("Unable to upload '$symlinkPath' because the remote directory does not support symlink creation!"); - } - $etag = $parentNode->createSymlink(basename($symlinkPath), $content); - $writtenFiles[$headers['x-file-path']] = [ + $newEtag = "'$symlinkPath'->'$content'"; + $infoData = [ + 'type' => \OC\Files\FileInfo::TYPE_SYMLINK, + 'etag' => $newEtag, + ]; + \OC\Files\Filesystem::getView()->putFileInfo($symlinkPath, $infoData); + $writtenFiles[$symlinkPath] = [ "error" => false, - "etag" => $etag, + "etag" => $newEtag, ]; continue; } diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php index 3a5b71ec7d76f..ad77f58d16845 100644 --- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php @@ -236,17 +236,18 @@ public function handleDownloadToken(RequestInterface $request, ResponseInterface public function httpGet(RequestInterface $request, ResponseInterface $response) { // only handle symlinks - // TODO(taminob): does not work if not in cache (which it is currently not because the path here is /files/root/path/to/symlink (request path) and the path in cache is only /root/files/path/to/symlink (internal path)); to make it work without cache, e.g. \Sabre\DAV\Server::getResourceTypeForNode would have to be extended to handle symlinks - $node = $this->tree->getNodeForPath($request->getPath()); - if (!($node instanceof \OCA\DAV\Connector\Sabre\File)) { + $symlinkPath = $request->getPath(); + $fileInfo = \OC\Files\Filesystem::getView()->getFileInfo($symlinkPath); + if (!$fileInfo || $fileInfo->getType() !== \OC\Files\FileInfo::TYPE_SYMLINK) { return; } - if ($node->getFileInfo()->getType() !== \OCP\Files\FileInfo::TYPE_SYMLINK) { - return; + $symlinkTarget = $fileInfo->getMetadata()['symlinkTarget']; + if (isset($symlinkTarget)) { + throw new NotFound("Symlink has no target!"); } $response->addHeader('OC-File-Type', '1'); - $response->setBody($node->readlink()); + $response->setBody($symlinkTarget); // do not continue processing this request return false; } diff --git a/apps/dav/lib/Upload/ChunkingV2Plugin.php b/apps/dav/lib/Upload/ChunkingV2Plugin.php index 5c95cf1490635..108b10b050503 100644 --- a/apps/dav/lib/Upload/ChunkingV2Plugin.php +++ b/apps/dav/lib/Upload/ChunkingV2Plugin.php @@ -145,20 +145,15 @@ public function afterMkcol(RequestInterface $request, ResponseInterface $respons public function beforePut(RequestInterface $request, ResponseInterface $response): bool { if ($request->getHeader('OC-File-Type') == 1) { - // TODO: store default value in global location - $allowSymlinks = \OC::$server->get(\OC\AllConfig::class)->getSystemValueBool( - 'localstorage.allowsymlinks', false); - if (!$allowSymlinks) { - throw new Forbidden("Server does not allow the creation of symlinks!"); - } $symlinkPath = $request->getPath(); $symlinkTarget = $request->getBodyAsString(); - $parentNode = $this->server->tree->getNodeForPath(dirname($symlinkPath)); - if(!$parentNode instanceof \OCA\DAV\Connector\Sabre\Directory) { - throw new Exception("Unable to upload '$symlinkPath' because the remote directory does not support symlink creation!"); - } - $etag = $parentNode->createSymlink(basename($symlinkPath), $symlinkTarget); - $response->setHeader("OC-ETag", $etag); + $newEtag = "'$symlinkPath'->'$symlinkTarget'"; + $infoData = [ + 'type' => \OC\Files\FileInfo::TYPE_SYMLINK, + 'etag' => $newEtag, + ]; + \OC\Files\Filesystem::getView()->putFileInfo($symlinkPath, $infoData); + $response->setHeader("OC-ETag", $newEtag); $response->setStatus(201); $this->server->sapi->sendResponse($response); return false; diff --git a/lib/public/Files/FileInfo.php b/lib/public/Files/FileInfo.php index 817b03dfc65f1..6d843bccd78a7 100644 --- a/lib/public/Files/FileInfo.php +++ b/lib/public/Files/FileInfo.php @@ -45,6 +45,10 @@ interface FileInfo { * @since 7.0.0 */ public const TYPE_FOLDER = 'dir'; + /** + * @since TODO + */ + public const TYPE_SYMLINK = 'symlink'; /** * @const \OCP\Files\FileInfo::SPACE_NOT_COMPUTED Return value for a not computed space value