/** * Copies a file or directory. * * This method must work recursively and delete the destination * if it exists * * @param string $source * @param string $destination * @throws \Sabre\DAV\Exception\ServiceUnavailable * @return void */ public function copy($source, $destination) { if (!$this->fileView) { throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); } // this will trigger existence check $this->getNodeForPath($source); list($destinationDir, $destinationName) = \Sabre\HTTP\URLUtil::splitPath($destination); try { $this->fileView->verifyPath($destinationDir, $destinationName); } catch (\OCP\Files\InvalidPathException $ex) { throw new InvalidPath($ex->getMessage()); } try { $this->fileView->copy($source, $destination); } catch (StorageNotAvailableException $e) { throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); } catch (ForbiddenException $ex) { throw new Forbidden($ex->getMessage(), $ex->getRetry()); } catch (LockedException $e) { throw new FileLocked($e->getMessage(), $e->getCode(), $e); } list($destinationDir, ) = \Sabre\HTTP\URLUtil::splitPath($destination); $this->markDirty($destinationDir); }
protected function verifyPath() { try { $fileName = basename($this->info->getPath()); $this->fileView->verifyPath($this->path, $fileName); } catch (\OCP\Files\InvalidPathException $ex) { throw new InvalidPath($ex->getMessage()); } }
/** * Moves a file from one location to another * * @param string $sourcePath The path to the file which should be moved * @param string $destinationPath The full destination path, so not just the destination parent node * @throws \Sabre\DAV\Exception\BadRequest * @throws \Sabre\DAV\Exception\ServiceUnavailable * @throws \Sabre\DAV\Exception\Forbidden * @return int */ public function move($sourcePath, $destinationPath) { if (!$this->fileView) { throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup'); } $targetNodeExists = $this->nodeExists($destinationPath); $sourceNode = $this->getNodeForPath($sourcePath); if ($sourceNode instanceof \Sabre\DAV\ICollection && $targetNodeExists) { throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists'); } list($sourceDir, ) = \Sabre\HTTP\URLUtil::splitPath($sourcePath); list($destinationDir, ) = \Sabre\HTTP\URLUtil::splitPath($destinationPath); $isMovableMount = false; $sourceMount = $this->mountManager->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 (\OCP\Files\InvalidPathException $ex) { throw new InvalidPath($ex->getMessage()); } $renameOkay = $this->fileView->rename($sourcePath, $destinationPath); if (!$renameOkay) { throw new \Sabre\DAV\Exception\Forbidden(''); } } catch (\OCP\Files\StorageNotAvailableException $e) { throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); } $this->markDirty($sourceDir); $this->markDirty($destinationDir); }
/** * rename a file * * @param string $dir * @param string $oldname * @param string $newname * @return array */ public function rename($dir, $oldname, $newname) { $result = array('success' => false, 'data' => NULL); try { // check if the new name is conform to file name restrictions $this->view->verifyPath($dir, $newname); } catch (\OCP\Files\InvalidPathException $ex) { $result['data'] = array('message' => $this->l10n->t($ex->getMessage()), 'code' => 'invalidname'); return $result; } $normalizedOldPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $oldname); $normalizedNewPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $newname); // rename to non-existing folder is denied if (!$this->view->file_exists($normalizedOldPath)) { $result['data'] = array('message' => $this->l10n->t('%s could not be renamed as it has been deleted', array($oldname)), 'code' => 'sourcenotfound', 'oldname' => $oldname, 'newname' => $newname); } else { if (!$this->view->file_exists($dir)) { $result['data'] = array('message' => (string) $this->l10n->t('The target folder has been moved or deleted.', array($dir)), 'code' => 'targetnotfound'); // rename to existing file is denied } else { if ($this->view->file_exists($normalizedNewPath)) { $result['data'] = array('message' => $this->l10n->t("The name %s is already used in the folder %s. Please choose a different name.", array($newname, $dir))); } else { if ($newname !== '.' and $this->view->rename($normalizedOldPath, $normalizedNewPath)) { // successful rename $meta = $this->view->getFileInfo($normalizedNewPath); $meta = \OCA\Files\Helper::populateTags(array($meta)); $fileInfo = \OCA\Files\Helper::formatFileInfo(current($meta)); $fileInfo['path'] = dirname($normalizedNewPath); $result['success'] = true; $result['data'] = $fileInfo; } else { // rename failed $result['data'] = array('message' => $this->l10n->t('%s could not be renamed', array($oldname))); } } } } return $result; }
/** * @dataProvider providesAstralPlane * @expectedException \OCP\Files\InvalidPathException * @expectedExceptionMessage 4-byte characters are not supported in file names */ public function testPathVerificationAstralPlane($fileName) { $this->view->verifyPath('', $fileName); }