summaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/Connector/Sabre/Directory.php
diff options
context:
space:
mode:
authorRoeland Jago Douma <rullzer@users.noreply.github.com>2017-04-28 09:37:40 +0200
committerGitHub <noreply@github.com>2017-04-28 09:37:40 +0200
commit9da697b11af2928a1470dcedc7ebf77e4a5f0730 (patch)
tree84a599e4a27d332dd59dcbffabbc7a9b3504e65a /apps/dav/lib/Connector/Sabre/Directory.php
parent3fd75e288cf62551d4e7a300f178a763bd3d406f (diff)
parent5f6153168f89f14c0ada0c98a205cae5eb504d70 (diff)
downloadnextcloud-server-9da697b11af2928a1470dcedc7ebf77e4a5f0730.tar.gz
nextcloud-server-9da697b11af2928a1470dcedc7ebf77e4a5f0730.zip
Merge pull request #4524 from nextcloud/downstream-27508
Keep file id on move
Diffstat (limited to 'apps/dav/lib/Connector/Sabre/Directory.php')
-rw-r--r--apps/dav/lib/Connector/Sabre/Directory.php145
1 files changed, 137 insertions, 8 deletions
diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php
index 25cca40a889..435f47ee561 100644
--- a/apps/dav/lib/Connector/Sabre/Directory.php
+++ b/apps/dav/lib/Connector/Sabre/Directory.php
@@ -34,12 +34,20 @@ use OCA\DAV\Connector\Sabre\Exception\Forbidden;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
use OCP\Files\ForbiddenException;
+use OCP\Files\InvalidPathException;
+use OCP\Files\StorageNotAvailableException;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
use Sabre\DAV\Exception\Locked;
+use Sabre\DAV\Exception\ServiceUnavailable;
+use Sabre\DAV\INode;
+use Sabre\DAV\Exception\BadRequest;
+use OC\Files\Mount\MoveableMount;
+use Sabre\DAV\IFile;
+use Sabre\DAV\Exception\NotFound;
class Directory extends \OCA\DAV\Connector\Sabre\Node
- implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota {
+ implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota, \Sabre\DAV\IMoveTarget {
/**
* Cached directory content
@@ -113,9 +121,9 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
// exit if we can't create a new file and we don't updatable existing file
- $info = \OC_FileChunking::decodeName($name);
+ $chunkInfo = \OC_FileChunking::decodeName($name);
if (!$this->fileView->isCreatable($this->path) &&
- !$this->fileView->isUpdatable($this->path . '/' . $info['name'])
+ !$this->fileView->isUpdatable($this->path . '/' . $chunkInfo['name'])
) {
throw new \Sabre\DAV\Exception\Forbidden();
}
@@ -130,14 +138,18 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
$this->fileView->verifyPath($this->path, $name);
$path = $this->fileView->getAbsolutePath($this->path) . '/' . $name;
- // using a dummy FileInfo is acceptable here since it will be refreshed after the put is complete
- $info = new \OC\Files\FileInfo($path, null, null, array(), null);
+ // in case the file already exists/overwriting
+ $info = $this->fileView->getFileInfo($this->path . '/' . $name);
+ if (!$info) {
+ // use a dummy FileInfo which is acceptable here since it will be refreshed after the put is complete
+ $info = new \OC\Files\FileInfo($path, null, null, [], null);
+ }
$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info);
$node->acquireLock(ILockingProvider::LOCK_SHARED);
return $node->put($data);
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
- } catch (\OCP\Files\InvalidPathException $ex) {
+ } catch (InvalidPathException $ex) {
throw new InvalidPath($ex->getMessage());
} catch (ForbiddenException $ex) {
throw new Forbidden($ex->getMessage(), $ex->getRetry());
@@ -168,7 +180,7 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
}
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
- } catch (\OCP\Files\InvalidPathException $ex) {
+ } catch (InvalidPathException $ex) {
throw new InvalidPath($ex->getMessage());
} catch (ForbiddenException $ex) {
throw new Forbidden($ex->getMessage(), $ex->getRetry());
@@ -188,6 +200,11 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
* @throws \Sabre\DAV\Exception\ServiceUnavailable
*/
public function getChild($name, $info = null) {
+ if (!$this->info->isReadable()) {
+ // avoid detecting files through this way
+ throw new NotFound();
+ }
+
$path = $this->path . '/' . $name;
if (is_null($info)) {
try {
@@ -195,7 +212,7 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
$info = $this->fileView->getFileInfo($path);
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
- } catch (\OCP\Files\InvalidPathException $ex) {
+ } catch (InvalidPathException $ex) {
throw new InvalidPath($ex->getMessage());
} catch (ForbiddenException $e) {
throw new \Sabre\DAV\Exception\Forbidden();
@@ -221,12 +238,19 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
* Returns an array with all the child nodes
*
* @return \Sabre\DAV\INode[]
+ * @throws \Sabre\DAV\Exception\Locked
+ * @throws \OCA\DAV\Connector\Sabre\Exception\Forbidden
*/
public function getChildren() {
if (!is_null($this->dirContent)) {
return $this->dirContent;
}
try {
+ if (!$this->info->isReadable()) {
+ // return 403 instead of 404 because a 404 would make
+ // the caller believe that the collection itself does not exist
+ throw new Forbidden('No read permissions');
+ }
$folderContent = $this->fileView->getDirectoryContent($this->path);
} catch (LockedException $e) {
throw new Locked();
@@ -311,4 +335,109 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
}
}
+ /**
+ * Moves a node into this collection.
+ *
+ * It is up to the implementors to:
+ * 1. Create the new resource.
+ * 2. Remove the old resource.
+ * 3. Transfer any properties or other data.
+ *
+ * Generally you should make very sure that your collection can easily move
+ * the move.
+ *
+ * If you don't, just return false, which will trigger sabre/dav to handle
+ * the move itself. If you return true from this function, the assumption
+ * is that the move was successful.
+ *
+ * @param string $targetName New local file/collection name.
+ * @param string $fullSourcePath Full path to source node
+ * @param INode $sourceNode Source node itself
+ * @return bool
+ * @throws BadRequest
+ * @throws ServiceUnavailable
+ * @throws Forbidden
+ * @throws FileLocked
+ * @throws \Sabre\DAV\Exception\Forbidden
+ */
+ public function moveInto($targetName, $fullSourcePath, INode $sourceNode) {
+ if (!$sourceNode instanceof Node) {
+ // it's a file of another kind, like FutureFile
+ if ($sourceNode instanceof IFile) {
+ // fallback to default copy+delete handling
+ return false;
+ }
+ throw new BadRequest('Incompatible node types');
+ }
+
+ if (!$this->fileView) {
+ throw new ServiceUnavailable('filesystem not setup');
+ }
+
+ $destinationPath = $this->getPath() . '/' . $targetName;
+
+
+ $targetNodeExists = $this->childExists($targetName);
+
+ // at getNodeForPath we also check the path for isForbiddenFileOrDir
+ // with that we have covered both source and destination
+ if ($sourceNode instanceof Directory && $targetNodeExists) {
+ throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode->getName() . ', target exists');
+ }
+
+ list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($sourceNode->getPath());
+ $destinationDir = $this->getPath();
+
+ $sourcePath = $sourceNode->getPath();
+
+ $isMovableMount = false;
+ $sourceMount = \OC::$server->getMountManager()->find($this->fileView->getAbsolutePath($sourcePath));
+ $internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath));
+ if ($sourceMount instanceof MoveableMount && $internalPath === '') {
+ $isMovableMount = true;
+ }
+
+ try {
+ $sameFolder = ($sourceDir === $destinationDir);
+ // if we're overwriting or same folder
+ if ($targetNodeExists || $sameFolder) {
+ // note that renaming a share mount point is always allowed
+ if (!$this->fileView->isUpdatable($destinationDir) && !$isMovableMount) {
+ throw new \Sabre\DAV\Exception\Forbidden();
+ }
+ } else {
+ if (!$this->fileView->isCreatable($destinationDir)) {
+ throw new \Sabre\DAV\Exception\Forbidden();
+ }
+ }
+
+ if (!$sameFolder) {
+ // moving to a different folder, source will be gone, like a deletion
+ // note that moving a share mount point is always allowed
+ if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) {
+ throw new \Sabre\DAV\Exception\Forbidden();
+ }
+ }
+
+ $fileName = basename($destinationPath);
+ try {
+ $this->fileView->verifyPath($destinationDir, $fileName);
+ } catch (InvalidPathException $ex) {
+ throw new InvalidPath($ex->getMessage());
+ }
+
+ $renameOkay = $this->fileView->rename($sourcePath, $destinationPath);
+ if (!$renameOkay) {
+ throw new \Sabre\DAV\Exception\Forbidden('');
+ }
+ } catch (StorageNotAvailableException $e) {
+ throw new ServiceUnavailable($e->getMessage());
+ } catch (ForbiddenException $ex) {
+ throw new Forbidden($ex->getMessage(), $ex->getRetry());
+ } catch (LockedException $e) {
+ throw new FileLocked($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return true;
+ }
}