aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/Files
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav/lib/Files')
-rw-r--r--apps/dav/lib/Files/FileSearchBackend.php4
-rw-r--r--apps/dav/lib/Files/LazySearchBackend.php1
-rw-r--r--apps/dav/lib/Files/Sharing/FilesDropPlugin.php116
3 files changed, 77 insertions, 44 deletions
diff --git a/apps/dav/lib/Files/FileSearchBackend.php b/apps/dav/lib/Files/FileSearchBackend.php
index ace367e4490..eb548bbd55c 100644
--- a/apps/dav/lib/Files/FileSearchBackend.php
+++ b/apps/dav/lib/Files/FileSearchBackend.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -15,6 +16,7 @@ use OCA\DAV\Connector\Sabre\CachingTree;
use OCA\DAV\Connector\Sabre\Directory;
use OCA\DAV\Connector\Sabre\File;
use OCA\DAV\Connector\Sabre\FilesPlugin;
+use OCA\DAV\Connector\Sabre\Server;
use OCA\DAV\Connector\Sabre\TagsPlugin;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Folder;
@@ -44,6 +46,7 @@ class FileSearchBackend implements ISearchBackend {
public const OPERATOR_LIMIT = 100;
public function __construct(
+ private Server $server,
private CachingTree $tree,
private IUser $user,
private IRootFolder $rootFolder,
@@ -133,6 +136,7 @@ class FileSearchBackend implements ISearchBackend {
* @param string[] $requestProperties
*/
public function preloadPropertyFor(array $nodes, array $requestProperties): void {
+ $this->server->emit('preloadProperties', [$nodes, $requestProperties]);
}
private function getFolderForPath(?string $path = null): Folder {
diff --git a/apps/dav/lib/Files/LazySearchBackend.php b/apps/dav/lib/Files/LazySearchBackend.php
index a0ad730ff2b..6ba539ddd87 100644
--- a/apps/dav/lib/Files/LazySearchBackend.php
+++ b/apps/dav/lib/Files/LazySearchBackend.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php
index ad7648795da..a3dbd32ce6b 100644
--- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php
+++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php
@@ -1,12 +1,15 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Files\Sharing;
-use OC\Files\View;
+use OCP\Files\Folder;
+use OCP\Files\NotFoundException;
use OCP\Share\IShare;
+use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAV\ServerPlugin;
use Sabre\HTTP\RequestInterface;
@@ -17,14 +20,9 @@ use Sabre\HTTP\ResponseInterface;
*/
class FilesDropPlugin extends ServerPlugin {
- private ?View $view = null;
private ?IShare $share = null;
private bool $enabled = false;
- public function setView(View $view): void {
- $this->view = $view;
- }
-
public function setShare(IShare $share): void {
$this->share = $share;
}
@@ -33,7 +31,6 @@ class FilesDropPlugin extends ServerPlugin {
$this->enabled = true;
}
-
/**
* This initializes the plugin.
* It is ONLY initialized by the server on a file drop request.
@@ -45,7 +42,12 @@ class FilesDropPlugin extends ServerPlugin {
}
public function onMkcol(RequestInterface $request, ResponseInterface $response) {
- if (!$this->enabled || $this->share === null || $this->view === null) {
+ if (!$this->enabled || $this->share === null) {
+ return;
+ }
+
+ $node = $this->share->getNode();
+ if (!($node instanceof Folder)) {
return;
}
@@ -57,7 +59,12 @@ class FilesDropPlugin extends ServerPlugin {
}
public function beforeMethod(RequestInterface $request, ResponseInterface $response) {
- if (!$this->enabled || $this->share === null || $this->view === null) {
+ if (!$this->enabled || $this->share === null) {
+ return;
+ }
+
+ $node = $this->share->getNode();
+ if (!($node instanceof Folder)) {
return;
}
@@ -66,13 +73,12 @@ class FilesDropPlugin extends ServerPlugin {
? trim(urldecode($request->getHeader('X-NC-Nickname')))
: null;
- //
if ($request->getMethod() !== 'PUT') {
// If uploading subfolders we need to ensure they get created
// within the nickname folder
if ($request->getMethod() === 'MKCOL') {
if (!$nickname) {
- throw new MethodNotAllowed('A nickname header is required when uploading subfolders');
+ throw new BadRequest('A nickname header is required when uploading subfolders');
}
} else {
throw new MethodNotAllowed('Only PUT is allowed on files drop');
@@ -108,7 +114,7 @@ class FilesDropPlugin extends ServerPlugin {
// We need a valid nickname for file requests
if ($isFileRequest && !$nickname) {
- throw new MethodNotAllowed('A nickname header is required for file requests');
+ throw new BadRequest('A nickname header is required for file requests');
}
// We're only allowing the upload of
@@ -116,56 +122,78 @@ class FilesDropPlugin extends ServerPlugin {
// This prevents confusion when uploading files and help
// classify them by uploaders.
if (!$nickname && !$isRootUpload) {
- throw new MethodNotAllowed('A nickname header is required when uploading subfolders');
+ throw new BadRequest('A nickname header is required when uploading subfolders');
}
- // If we have a nickname, let's put everything inside
if ($nickname) {
- // Put all files in the subfolder
+ try {
+ $node->verifyPath($nickname);
+ } catch (\Exception $e) {
+ // If the path is not valid, we throw an exception
+ throw new BadRequest('Invalid nickname: ' . $nickname);
+ }
+
+ // Forbid nicknames starting with a dot
+ if (str_starts_with($nickname, '.')) {
+ throw new BadRequest('Invalid nickname: ' . $nickname);
+ }
+
+ // If we have a nickname, let's put
+ // all files in the subfolder
$relativePath = '/' . $nickname . '/' . $relativePath;
$relativePath = str_replace('//', '/', $relativePath);
}
// Create the folders along the way
- $folders = $this->getPathSegments(dirname($relativePath));
- foreach ($folders as $folder) {
- if ($folder === '') {
+ $folder = $node;
+ $pathSegments = $this->getPathSegments(dirname($relativePath));
+ foreach ($pathSegments as $pathSegment) {
+ if ($pathSegment === '') {
continue;
- } // skip empty parts
- if (!$this->view->file_exists($folder)) {
- $this->view->mkdir($folder);
+ }
+
+ try {
+ // get the current folder
+ $currentFolder = $folder->get($pathSegment);
+ // check target is a folder
+ if ($currentFolder instanceof Folder) {
+ $folder = $currentFolder;
+ } else {
+ // otherwise look in the parent folder if we already create an unique folder name
+ foreach ($folder->getDirectoryListing() as $child) {
+ // we look for folders which match "NAME (SUFFIX)"
+ if ($child instanceof Folder && str_starts_with($child->getName(), $pathSegment)) {
+ $suffix = substr($child->getName(), strlen($pathSegment));
+ if (preg_match('/^ \(\d+\)$/', $suffix)) {
+ // we found the unique folder name and can use it
+ $folder = $child;
+ break;
+ }
+ }
+ }
+ // no folder found so we need to create a new unique folder name
+ if (!isset($child) || $child !== $folder) {
+ $folder = $folder->newFolder($folder->getNonExistingName($pathSegment));
+ }
+ }
+ } catch (NotFoundException) {
+ // the folder does simply not exist so we create it
+ $folder = $folder->newFolder($pathSegment);
}
}
// Finally handle conflicts on the end files
- $noConflictPath = \OC_Helper::buildNotExistingFileNameForView(dirname($relativePath), basename($relativePath), $this->view);
- $path = '/files/' . $token . '/' . $noConflictPath;
- $url = $request->getBaseUrl() . str_replace('//', '/', $path);
+ $uniqueName = $folder->getNonExistingName(basename($relativePath));
+ $relativePath = substr($folder->getPath(), strlen($node->getPath()));
+ $path = '/files/' . $token . '/' . $relativePath . '/' . $uniqueName;
+ $url = rtrim($request->getBaseUrl(), '/') . str_replace('//', '/', $path);
$request->setUrl($url);
}
private function getPathSegments(string $path): array {
// Normalize slashes and remove trailing slash
- $path = rtrim(str_replace('\\', '/', $path), '/');
-
- // Handle absolute paths starting with /
- $isAbsolute = str_starts_with($path, '/');
-
- $segments = explode('/', $path);
-
- // Add back the leading slash for the first segment if needed
- $result = [];
- $current = $isAbsolute ? '/' : '';
-
- foreach ($segments as $segment) {
- if ($segment === '') {
- // skip empty parts
- continue;
- }
- $current = rtrim($current, '/') . '/' . $segment;
- $result[] = $current;
- }
+ $path = trim(str_replace('\\', '/', $path), '/');
- return $result;
+ return explode('/', $path);
}
}