From a22f9ff301312bb24332edaacfb65c280cd8fcd8 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 1 Sep 2013 19:47:48 +0200 Subject: [PATCH 01/11] Provide an implementation of the fileapi for oc6 build on top of the old api --- lib/files/exceptions.php | 21 + lib/files/node/file.php | 155 +++++++ lib/files/node/folder.php | 382 +++++++++++++++ lib/files/node/node.php | 247 ++++++++++ lib/files/node/nonexistingfile.php | 89 ++++ lib/files/node/nonexistingfolder.php | 113 +++++ lib/files/node/root.php | 337 ++++++++++++++ lib/files/view.php | 2 +- tests/lib/files/node/file.php | 664 +++++++++++++++++++++++++++ tests/lib/files/node/folder.php | 479 +++++++++++++++++++ tests/lib/files/node/integration.php | 121 +++++ tests/lib/files/node/node.php | 330 +++++++++++++ tests/lib/files/node/root.php | 106 +++++ 13 files changed, 3045 insertions(+), 1 deletion(-) create mode 100644 lib/files/exceptions.php create mode 100644 lib/files/node/file.php create mode 100644 lib/files/node/folder.php create mode 100644 lib/files/node/node.php create mode 100644 lib/files/node/nonexistingfile.php create mode 100644 lib/files/node/nonexistingfolder.php create mode 100644 lib/files/node/root.php create mode 100644 tests/lib/files/node/file.php create mode 100644 tests/lib/files/node/folder.php create mode 100644 tests/lib/files/node/integration.php create mode 100644 tests/lib/files/node/node.php create mode 100644 tests/lib/files/node/root.php diff --git a/lib/files/exceptions.php b/lib/files/exceptions.php new file mode 100644 index 0000000000..8a3c40ab0c --- /dev/null +++ b/lib/files/exceptions.php @@ -0,0 +1,21 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files; + +class NotFoundException extends \Exception { +} + +class NotPermittedException extends \Exception { +} + +class AlreadyExistsException extends \Exception { +} + +class NotEnoughSpaceException extends \Exception { +} diff --git a/lib/files/node/file.php b/lib/files/node/file.php new file mode 100644 index 0000000000..0ad5d68ec6 --- /dev/null +++ b/lib/files/node/file.php @@ -0,0 +1,155 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\NotPermittedException; + +class File extends Node { + /** + * @return string + * @throws \OC\Files\NotPermittedException + */ + public function getContent() { + if ($this->checkPermissions(\OCP\PERMISSION_READ)) { + /** + * @var \OC\Files\Storage\Storage $storage; + */ + return $this->view->file_get_contents($this->path); + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $data + * @throws \OC\Files\NotPermittedException + */ + public function putContent($data) { + if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { + $this->sendHooks(array('preWrite')); + $this->view->file_put_contents($this->path, $data); + $this->sendHooks(array('postWrite')); + } else { + throw new NotPermittedException(); + } + } + + /** + * @return string + */ + public function getMimeType() { + return $this->view->getMimeType($this->path); + } + + /** + * @param string $mode + * @return resource + * @throws \OC\Files\NotPermittedException + */ + public function fopen($mode) { + $preHooks = array(); + $postHooks = array(); + $requiredPermissions = \OCP\PERMISSION_READ; + switch ($mode) { + case 'r+': + case 'rb+': + case 'w+': + case 'wb+': + case 'x+': + case 'xb+': + case 'a+': + case 'ab+': + case 'w': + case 'wb': + case 'x': + case 'xb': + case 'a': + case 'ab': + $preHooks[] = 'preWrite'; + $postHooks[] = 'postWrite'; + $requiredPermissions |= \OCP\PERMISSION_UPDATE; + break; + } + + if ($this->checkPermissions($requiredPermissions)) { + $this->sendHooks($preHooks); + $result = $this->view->fopen($this->path, $mode); + $this->sendHooks($postHooks); + return $result; + } else { + throw new NotPermittedException(); + } + } + + public function delete() { + if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { + $this->sendHooks(array('preDelete')); + $this->view->unlink($this->path); + $nonExisting = new NonExistingFile($this->root, $this->view, $this->path); + $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); + $this->exists = false; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->copy($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + return $targetNode; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function move($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->rename($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + $this->path = $targetPath; + return $targetNode; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $type + * @param bool $raw + * @return string + */ + public function hash($type, $raw = false) { + return $this->view->hash($type, $this->path, $raw); + } +} diff --git a/lib/files/node/folder.php b/lib/files/node/folder.php new file mode 100644 index 0000000000..f710ae5ae9 --- /dev/null +++ b/lib/files/node/folder.php @@ -0,0 +1,382 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OC\Files\NotFoundException; +use OC\Files\NotPermittedException; + +class Folder extends Node { + /** + * @param string $path path relative to the folder + * @return string + * @throws \OC\Files\NotPermittedException + */ + public function getFullPath($path) { + if (!$this->isValidPath($path)) { + throw new NotPermittedException(); + } + return $this->path . $this->normalizePath($path); + } + + /** + * @param string $path + * @throws \OC\Files\NotFoundException + * @return string + */ + public function getRelativePath($path) { + if ($this->path === '' or $this->path === '/') { + return $this->normalizePath($path); + } + if (strpos($path, $this->path) !== 0) { + throw new NotFoundException(); + } else { + $path = substr($path, strlen($this->path)); + if (strlen($path) === 0) { + return '/'; + } else { + return $this->normalizePath($path); + } + } + } + + /** + * check if a node is a (grand-)child of the folder + * + * @param \OC\Files\Node\Node $node + * @return bool + */ + public function isSubNode($node) { + return strpos($node->getPath(), $this->path . '/') === 0; + } + + /** + * get the content of this directory + * + * @throws \OC\Files\NotFoundException + * @return Node[] + */ + public function getDirectoryListing() { + $result = array(); + + /** + * @var \OC\Files\Storage\Storage $storage + */ + list($storage, $internalPath) = $this->view->resolvePath($this->path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $permissionsCache = $storage->getPermissionsCache($internalPath); + + //trigger cache update check + $this->view->getFileInfo($this->path); + + $files = $cache->getFolderContents($internalPath); + $permissions = $permissionsCache->getDirectoryPermissions($this->getId(), $this->root->getUser()->getUID()); + } else { + $files = array(); + } + + //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders + $mounts = $this->root->getMountsIn($this->path); + $dirLength = strlen($this->path); + foreach ($mounts as $mount) { + $subStorage = $mount->getStorage(); + if ($subStorage) { + $subCache = $subStorage->getCache(''); + + if ($subCache->getStatus('') === Cache::NOT_FOUND) { + $subScanner = $subStorage->getScanner(''); + $subScanner->scanFile(''); + } + + $rootEntry = $subCache->get(''); + if ($rootEntry) { + $relativePath = trim(substr($mount->getMountPoint(), $dirLength), '/'); + if ($pos = strpos($relativePath, '/')) { + //mountpoint inside subfolder add size to the correct folder + $entryName = substr($relativePath, 0, $pos); + foreach ($files as &$entry) { + if ($entry['name'] === $entryName) { + if ($rootEntry['size'] >= 0) { + $entry['size'] += $rootEntry['size']; + } else { + $entry['size'] = -1; + } + } + } + } else { //mountpoint in this folder, add an entry for it + $rootEntry['name'] = $relativePath; + $rootEntry['storageObject'] = $subStorage; + + //remove any existing entry with the same name + foreach ($files as $i => $file) { + if ($file['name'] === $rootEntry['name']) { + $files[$i] = null; + break; + } + } + $files[] = $rootEntry; + } + } + } + } + + foreach ($files as $file) { + if ($file) { + if (isset($permissions[$file['fileid']])) { + $file['permissions'] = $permissions[$file['fileid']]; + } + $node = $this->createNode($this->path . '/' . $file['name'], $file); + $result[] = $node; + } + } + + return $result; + } + + /** + * @param string $path + * @param array $info + * @return File|Folder + */ + protected function createNode($path, $info = array()) { + if (!isset($info['mimetype'])) { + $isDir = $this->view->is_dir($path); + } else { + $isDir = $info['mimetype'] === 'httpd/unix-directory'; + } + if ($isDir) { + return new Folder($this->root, $this->view, $path); + } else { + return new File($this->root, $this->view, $path); + } + } + + /** + * Get the node at $path + * + * @param string $path + * @return \OC\Files\Node\Node + * @throws \OC\Files\NotFoundException + */ + public function get($path) { + return $this->root->get($this->getFullPath($path)); + } + + /** + * @param string $path + * @return bool + */ + public function nodeExists($path) { + try { + $this->get($path); + return true; + } catch (NotFoundException $e) { + return false; + } + } + + /** + * @param string $path + * @return Folder + * @throws NotPermittedException + */ + public function newFolder($path) { + if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { + $fullPath = $this->getFullPath($path); + $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->root->emit('\OC\Files', 'preCreate', array($nonExisting)); + $this->view->mkdir($fullPath); + $node = new Folder($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'postWrite', array($node)); + $this->root->emit('\OC\Files', 'postCreate', array($node)); + return $node; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $path + * @return File + * @throws NotPermittedException + */ + public function newFile($path) { + if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { + $fullPath = $this->getFullPath($path); + $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->root->emit('\OC\Files', 'preCreate', array($nonExisting)); + $this->view->touch($fullPath); + $node = new File($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'postWrite', array($node)); + $this->root->emit('\OC\Files', 'postCreate', array($node)); + return $node; + } else { + throw new NotPermittedException(); + } + } + + /** + * search for files with the name matching $query + * + * @param string $query + * @return Node[] + */ + public function search($query) { + return $this->searchCommon('%' . $query . '%', 'search'); + } + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return Node[] + */ + public function searchByMime($mimetype) { + return $this->searchCommon($mimetype, 'searchByMime'); + } + + /** + * @param string $query + * @param string $method + * @return Node[] + */ + private function searchCommon($query, $method) { + $files = array(); + $rootLength = strlen($this->path); + /** + * @var \OC\Files\Storage\Storage $storage + */ + list($storage, $internalPath) = $this->view->resolvePath($this->path); + $internalRootLength = strlen($internalPath); + + $cache = $storage->getCache(''); + + $results = $cache->$method($query); + foreach ($results as $result) { + if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) { + $result['internalPath'] = $result['path']; + $result['path'] = substr($result['path'], $internalRootLength); + $result['storage'] = $storage; + $files[] = $result; + } + } + + $mounts = $this->root->getMountsIn($this->path); + foreach ($mounts as $mount) { + $storage = $mount->getStorage(); + if ($storage) { + $cache = $storage->getCache(''); + + $relativeMountPoint = substr($mount->getMountPoint(), $rootLength); + $results = $cache->$method($query); + foreach ($results as $result) { + $result['internalPath'] = $result['path']; + $result['path'] = $relativeMountPoint . $result['path']; + $result['storage'] = $storage; + $files[] = $result; + } + } + } + + $result = array(); + foreach ($files as $file) { + $result[] = $this->createNode($this->normalizePath($this->path . '/' . $file['path']), $file); + } + + return $result; + } + + /** + * @param $id + * @return Node[] + */ + public function getById($id) { + $nodes = $this->root->getById($id); + $result = array(); + foreach ($nodes as $node) { + $pathPart = substr($node->getPath(), 0, strlen($this->getPath()) + 1); + if ($this->path === '/' or $pathPart === $this->getPath() . '/') { + $result[] = $node; + } + } + return $result; + } + + public function getFreeSpace() { + return $this->view->free_space($this->path); + } + + /** + * @return bool + */ + public function isCreatable() { + return $this->checkPermissions(\OCP\PERMISSION_CREATE); + } + + public function delete() { + if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { + $this->sendHooks(array('preDelete')); + $this->view->rmdir($this->path); + $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path); + $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); + $this->exists = false; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->copy($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + return $targetNode; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function move($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->rename($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + $this->path = $targetPath; + return $targetNode; + } else { + throw new NotPermittedException(); + } + } +} diff --git a/lib/files/node/node.php b/lib/files/node/node.php new file mode 100644 index 0000000000..a71f787506 --- /dev/null +++ b/lib/files/node/node.php @@ -0,0 +1,247 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OC\Files\NotFoundException; +use OC\Files\NotPermittedException; + +require_once 'files/exceptions.php'; + +class Node { + /** + * @var \OC\Files\View $view + */ + protected $view; + + /** + * @var \OC\Files\Node\Root $root + */ + protected $root; + + /** + * @var string $path + */ + protected $path; + + /** + * @param \OC\Files\View $view + * @param \OC\Files\Node\Root Root $root + * @param string $path + */ + public function __construct($root, $view, $path) { + $this->view = $view; + $this->root = $root; + $this->path = $path; + } + + /** + * @param string[] $hooks + */ + protected function sendHooks($hooks) { + foreach ($hooks as $hook) { + $this->root->emit('\OC\Files', $hook, array($this)); + } + } + + /** + * @param int $permissions + * @return bool + */ + protected function checkPermissions($permissions) { + return ($this->getPermissions() & $permissions) == $permissions; + } + + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function move($targetPath) { + return; + } + + public function delete() { + return; + } + + /** + * @param string $targetPath + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + return; + } + + /** + * @param int $mtime + * @throws \OC\Files\NotPermittedException + */ + public function touch($mtime = null) { + if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { + $this->sendHooks(array('preTouch')); + $this->view->touch($this->path, $mtime); + $this->sendHooks(array('postTouch')); + } else { + throw new NotPermittedException(); + } + } + + /** + * @return \OC\Files\Storage\Storage + * @throws \OC\Files\NotFoundException + */ + public function getStorage() { + list($storage,) = $this->view->resolvePath($this->path); + return $storage; + } + + /** + * @return string + */ + public function getPath() { + return $this->path; + } + + /** + * @return string + */ + public function getInternalPath() { + list(, $internalPath) = $this->view->resolvePath($this->path); + return $internalPath; + } + + /** + * @return int + */ + public function getId() { + $info = $this->view->getFileInfo($this->path); + return $info['fileid']; + } + + /** + * @return array + */ + public function stat() { + return $this->view->stat($this->path); + } + + /** + * @return int + */ + public function getMTime() { + return $this->view->filemtime($this->path); + } + + /** + * @return int + */ + public function getSize() { + return $this->view->filesize($this->path); + } + + /** + * @return string + */ + public function getEtag() { + $info = $this->view->getFileInfo($this->path); + return $info['etag']; + } + + /** + * @return int + */ + public function getPermissions() { + $info = $this->view->getFileInfo($this->path); + return $info['permissions']; + } + + /** + * @return bool + */ + public function isReadable() { + return $this->checkPermissions(\OCP\PERMISSION_READ); + } + + /** + * @return bool + */ + public function isUpdateable() { + return $this->checkPermissions(\OCP\PERMISSION_UPDATE); + } + + /** + * @return bool + */ + public function isDeletable() { + return $this->checkPermissions(\OCP\PERMISSION_DELETE); + } + + /** + * @return bool + */ + public function isShareable() { + return $this->checkPermissions(\OCP\PERMISSION_SHARE); + } + + /** + * @return Node + */ + public function getParent() { + return $this->root->get(dirname($this->path)); + } + + /** + * @return string + */ + public function getName() { + return basename($this->path); + } + + /** + * @param string $path + * @return string + */ + protected function normalizePath($path) { + if ($path === '' or $path === '/') { + return '/'; + } + //no windows style slashes + $path = str_replace('\\', '/', $path); + //add leading slash + if ($path[0] !== '/') { + $path = '/' . $path; + } + //remove duplicate slashes + while (strpos($path, '//') !== false) { + $path = str_replace('//', '/', $path); + } + //remove trailing slash + $path = rtrim($path, '/'); + + return $path; + } + + /** + * check if the requested path is valid + * + * @param string $path + * @return bool + */ + public function isValidPath($path) { + if (!$path || $path[0] !== '/') { + $path = '/' . $path; + } + if (strstr($path, '/../') || strrchr($path, '/') === '/..') { + return false; + } + return true; + } +} diff --git a/lib/files/node/nonexistingfile.php b/lib/files/node/nonexistingfile.php new file mode 100644 index 0000000000..6f18450efe --- /dev/null +++ b/lib/files/node/nonexistingfile.php @@ -0,0 +1,89 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\NotFoundException; + +class NonExistingFile extends File { + /** + * @param string $newPath + * @throws \OC\Files\NotFoundException + */ + public function rename($newPath) { + throw new NotFoundException(); + } + + public function delete() { + throw new NotFoundException(); + } + + public function copy($newPath) { + throw new NotFoundException(); + } + + public function touch($mtime = null) { + throw new NotFoundException(); + } + + public function getId() { + throw new NotFoundException(); + } + + public function stat() { + throw new NotFoundException(); + } + + public function getMTime() { + throw new NotFoundException(); + } + + public function getSize() { + throw new NotFoundException(); + } + + public function getEtag() { + throw new NotFoundException(); + } + + public function getPermissions() { + throw new NotFoundException(); + } + + public function isReadable() { + throw new NotFoundException(); + } + + public function isUpdateable() { + throw new NotFoundException(); + } + + public function isDeletable() { + throw new NotFoundException(); + } + + public function isShareable() { + throw new NotFoundException(); + } + + public function getContent() { + throw new NotFoundException(); + } + + public function putContent($data) { + throw new NotFoundException(); + } + + public function getMimeType() { + throw new NotFoundException(); + } + + public function fopen($mode) { + throw new NotFoundException(); + } +} diff --git a/lib/files/node/nonexistingfolder.php b/lib/files/node/nonexistingfolder.php new file mode 100644 index 0000000000..0249a02624 --- /dev/null +++ b/lib/files/node/nonexistingfolder.php @@ -0,0 +1,113 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\NotFoundException; + +class NonExistingFolder extends Folder { + /** + * @param string $newPath + * @throws \OC\Files\NotFoundException + */ + public function rename($newPath) { + throw new NotFoundException(); + } + + public function delete() { + throw new NotFoundException(); + } + + public function copy($newPath) { + throw new NotFoundException(); + } + + public function touch($mtime = null) { + throw new NotFoundException(); + } + + public function getId() { + throw new NotFoundException(); + } + + public function stat() { + throw new NotFoundException(); + } + + public function getMTime() { + throw new NotFoundException(); + } + + public function getSize() { + throw new NotFoundException(); + } + + public function getEtag() { + throw new NotFoundException(); + } + + public function getPermissions() { + throw new NotFoundException(); + } + + public function isReadable() { + throw new NotFoundException(); + } + + public function isUpdateable() { + throw new NotFoundException(); + } + + public function isDeletable() { + throw new NotFoundException(); + } + + public function isShareable() { + throw new NotFoundException(); + } + + public function get($path) { + throw new NotFoundException(); + } + + public function getDirectoryListing() { + throw new NotFoundException(); + } + + public function nodeExists($path) { + return false; + } + + public function newFolder($path) { + throw new NotFoundException(); + } + + public function newFile($path) { + throw new NotFoundException(); + } + + public function search($pattern) { + throw new NotFoundException(); + } + + public function searchByMime($mime) { + throw new NotFoundException(); + } + + public function getById($id) { + throw new NotFoundException(); + } + + public function getFreeSpace() { + throw new NotFoundException(); + } + + public function isCreatable() { + throw new NotFoundException(); + } +} diff --git a/lib/files/node/root.php b/lib/files/node/root.php new file mode 100644 index 0000000000..f88d8c294c --- /dev/null +++ b/lib/files/node/root.php @@ -0,0 +1,337 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OC\Files\Mount\Manager; +use OC\Files\Mount\Mount; +use OC\Files\NotFoundException; +use OC\Files\NotPermittedException; +use OC\Hooks\Emitter; +use OC\Hooks\PublicEmitter; + +/** + * Class Root + * + * Hooks available in scope \OC\Files + * - preWrite(\OC\Files\Node\Node $node) + * - postWrite(\OC\Files\Node\Node $node) + * - preCreate(\OC\Files\Node\Node $node) + * - postCreate(\OC\Files\Node\Node $node) + * - preDelete(\OC\Files\Node\Node $node) + * - postDelete(\OC\Files\Node\Node $node) + * - preTouch(\OC\Files\Node\Node $node, int $mtime) + * - postTouch(\OC\Files\Node\Node $node) + * - preCopy(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) + * - postCopy(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) + * - preRename(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) + * - postRename(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) + * + * @package OC\Files\Node + */ +class Root extends Folder implements Emitter { + + /** + * @var \OC\Files\Mount\Manager $mountManager + */ + private $mountManager; + + /** + * @var \OC\Hooks\PublicEmitter + */ + private $emitter; + + /** + * @var \OC\User\User $user + */ + private $user; + + /** + * @param \OC\Files\Mount\Manager $manager + * @param \OC\Files\View $view + * @param \OC\User\User $user + */ + public function __construct($manager, $view, $user) { + parent::__construct($this, $view, ''); + $this->mountManager = $manager; + $this->user = $user; + $this->emitter = new PublicEmitter(); + } + + /** + * Get the user for which the filesystem is setup + * + * @return \OC\User\User + */ + public function getUser() { + return $this->user; + } + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback) { + $this->emitter->listen($scope, $method, $callback); + } + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, $callback = null) { + $this->emitter->removeListener($scope, $method, $callback); + } + + /** + * @param string $scope + * @param string $method + * @param array $arguments + */ + public function emit($scope, $method, $arguments = array()) { + $this->emitter->emit($scope, $method, $arguments); + } + + /** + * @param \OC\Files\Storage\Storage $storage + * @param string $mountPoint + * @param array $arguments + */ + public function mount($storage, $mountPoint, $arguments = array()) { + $mount = new Mount($storage, $mountPoint, $arguments); + $this->mountManager->addMount($mount); + } + + /** + * @param string $mountPoint + * @return \OC\Files\Mount\Mount + */ + public function getMount($mountPoint) { + return $this->mountManager->find($mountPoint); + } + + /** + * @param string $mountPoint + * @return \OC\Files\Mount\Mount[] + */ + public function getMountsIn($mountPoint) { + return $this->mountManager->findIn($mountPoint); + } + + /** + * @param string $storageId + * @return \OC\Files\Mount\Mount[] + */ + public function getMountByStorageId($storageId) { + return $this->mountManager->findByStorageId($storageId); + } + + /** + * @param int $numericId + * @return Mount[] + */ + public function getMountByNumericStorageId($numericId) { + return $this->mountManager->findByNumericId($numericId); + } + + /** + * @param \OC\Files\Mount\Mount $mount + */ + public function unMount($mount) { + $this->mountManager->remove($mount); + } + + /** + * @param string $path + * @throws \OC\Files\NotFoundException + * @throws \OC\Files\NotPermittedException + * @return Node + */ + public function get($path) { + $path = $this->normalizePath($path); + if ($this->isValidPath($path)) { + $fullPath = $this->getFullPath($path); + if ($this->view->file_exists($fullPath)) { + return $this->createNode($fullPath); + } else { + throw new NotFoundException(); + } + } else { + throw new NotPermittedException(); + } + } + + /** + * search file by id + * + * An array is returned because in the case where a single storage is mounted in different places the same file + * can exist in different places + * + * @param int $id + * @throws \OC\Files\NotFoundException + * @return Node[] + */ + public function getById($id) { + $result = Cache::getById($id); + if (is_null($result)) { + throw new NotFoundException(); + } else { + list($storageId, $internalPath) = $result; + $nodes = array(); + $mounts = $this->mountManager->findByStorageId($storageId); + foreach ($mounts as $mount) { + $nodes[] = $this->get($mount->getMountPoint() . $internalPath); + } + return $nodes; + } + + } + + //most operations cant be done on the root + + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function rename($targetPath) { + throw new NotPermittedException(); + } + + public function delete() { + throw new NotPermittedException(); + } + + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + throw new NotPermittedException(); + } + + /** + * @param int $mtime + * @throws \OC\Files\NotPermittedException + */ + public function touch($mtime = null) { + throw new NotPermittedException(); + } + + /** + * @return \OC\Files\Storage\Storage + * @throws \OC\Files\NotFoundException + */ + public function getStorage() { + throw new NotFoundException(); + } + + /** + * @return string + */ + public function getPath() { + return '/'; + } + + /** + * @return string + */ + public function getInternalPath() { + return ''; + } + + /** + * @return int + */ + public function getId() { + return null; + } + + /** + * @return array + */ + public function stat() { + return null; + } + + /** + * @return int + */ + public function getMTime() { + return null; + } + + /** + * @return int + */ + public function getSize() { + return null; + } + + /** + * @return string + */ + public function getEtag() { + return null; + } + + /** + * @return int + */ + public function getPermissions() { + return \OCP\PERMISSION_CREATE; + } + + /** + * @return bool + */ + public function isReadable() { + return false; + } + + /** + * @return bool + */ + public function isUpdateable() { + return false; + } + + /** + * @return bool + */ + public function isDeletable() { + return false; + } + + /** + * @return bool + */ + public function isShareable() { + return false; + } + + /** + * @return Node + * @throws \OC\Files\NotFoundException + */ + public function getParent() { + throw new NotFoundException(); + } + + /** + * @return string + */ + public function getName() { + return ''; + } +} diff --git a/lib/files/view.php b/lib/files/view.php index 8aee12bf6f..3a1fdd415b 100644 --- a/lib/files/view.php +++ b/lib/files/view.php @@ -30,7 +30,7 @@ class View { private $internal_path_cache = array(); private $storage_cache = array(); - public function __construct($root) { + public function __construct($root = '') { $this->fakeRoot = $root; } diff --git a/tests/lib/files/node/file.php b/tests/lib/files/node/file.php new file mode 100644 index 0000000000..707106373b --- /dev/null +++ b/tests/lib/files/node/file.php @@ -0,0 +1,664 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Node; + +use OC\Files\NotFoundException; +use OC\Files\NotPermittedException; +use OC\Files\View; + +class File extends \PHPUnit_Framework_TestCase { + private $user; + + public function setUp() { + $this->user = new \OC\User\User('', new \OC_User_Dummy); + } + + public function testDelete() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->exactly(2)) + ->method('emit') + ->will($this->returnValue(true)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $view->expects($this->once()) + ->method('unlink') + ->with('/bar/foo') + ->will($this->returnValue(true)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->delete(); + } + + public function testDeleteHooks() { + $test = $this; + $hooksRun = 0; + /** + * @param \OC\Files\Node\File $node + */ + $preListener = function ($node) use (&$test, &$hooksRun) { + $test->assertInstanceOf('\OC\Files\Node\File', $node); + $test->assertEquals('foo', $node->getInternalPath()); + $test->assertEquals('/bar/foo', $node->getPath()); + $test->assertEquals(1, $node->getId()); + $hooksRun++; + }; + + /** + * @param \OC\Files\Node\File $node + */ + $postListener = function ($node) use (&$test, &$hooksRun) { + $test->assertInstanceOf('\OC\Files\Node\NonExistingFile', $node); + $test->assertEquals('foo', $node->getInternalPath()); + $test->assertEquals('/bar/foo', $node->getPath()); + $hooksRun++; + }; + + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + $root->listen('\OC\Files', 'preDelete', $preListener); + $root->listen('\OC\Files', 'postDelete', $postListener); + + $view->expects($this->any()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 1))); + + $view->expects($this->once()) + ->method('unlink') + ->with('/bar/foo') + ->will($this->returnValue(true)); + + $view->expects($this->any()) + ->method('resolvePath') + ->with('/bar/foo') + ->will($this->returnValue(array(null, 'foo'))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->delete(); + $this->assertEquals(2, $hooksRun); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testDeleteNotPermitted() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->delete(); + } + + public function testGetContent() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $hook = function ($file) { + throw new \Exception('Hooks are not supposed to be called'); + }; + + $root->listen('\OC\Files', 'preWrite', $hook); + $root->listen('\OC\Files', 'postWrite', $hook); + + $view->expects($this->once()) + ->method('file_get_contents') + ->with('/bar/foo') + ->will($this->returnValue('bar')); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals('bar', $node->getContent()); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testGetContentNotPermitted() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => 0))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->getContent(); + } + + public function testPutContent() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $view->expects($this->once()) + ->method('file_put_contents') + ->with('/bar/foo', 'bar') + ->will($this->returnValue(true)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->putContent('bar'); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testPutContentNotPermitted() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->putContent('bar'); + } + + public function testGetMimeType() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->once()) + ->method('getMimeType') + ->with('/bar/foo') + ->will($this->returnValue('text/plain')); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals('text/plain', $node->getMimeType()); + } + + public function testFOpenRead() { + $stream = fopen('php://memory', 'w+'); + fwrite($stream, 'bar'); + rewind($stream); + + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $hook = function ($file) { + throw new \Exception('Hooks are not supposed to be called'); + }; + + $root->listen('\OC\Files', 'preWrite', $hook); + $root->listen('\OC\Files', 'postWrite', $hook); + + $view->expects($this->once()) + ->method('fopen') + ->with('/bar/foo', 'r') + ->will($this->returnValue($stream)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $fh = $node->fopen('r'); + $this->assertEquals($stream, $fh); + $this->assertEquals('bar', fread($fh, 3)); + } + + public function testFOpenWrite() { + $stream = fopen('php://memory', 'w+'); + + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, new $view, $this->user); + + $hooksCalled = 0; + $hook = function ($file) use (&$hooksCalled) { + $hooksCalled++; + }; + + $root->listen('\OC\Files', 'preWrite', $hook); + $root->listen('\OC\Files', 'postWrite', $hook); + + $view->expects($this->once()) + ->method('fopen') + ->with('/bar/foo', 'w') + ->will($this->returnValue($stream)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $fh = $node->fopen('w'); + $this->assertEquals($stream, $fh); + fwrite($fh, 'bar'); + rewind($fh); + $this->assertEquals('bar', fread($stream, 3)); + $this->assertEquals(2, $hooksCalled); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testFOpenReadNotPermitted() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $hook = function ($file) { + throw new \Exception('Hooks are not supposed to be called'); + }; + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => 0))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->fopen('r'); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testFOpenReadWriteNoReadPermissions() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $hook = function () { + throw new \Exception('Hooks are not supposed to be called'); + }; + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_UPDATE))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->fopen('w'); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testFOpenReadWriteNoWritePermissions() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, new $view, $this->user); + + $hook = function () { + throw new \Exception('Hooks are not supposed to be called'); + }; + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $node->fopen('w'); + } + + public function testCopySameStorage() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->any()) + ->method('copy') + ->with('/bar/foo', '/bar/asd'); + + $view->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 3))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar'); + $newNode = new \OC\Files\Node\File($root, $view, '/bar/asd'); + + $root->expects($this->exactly(2)) + ->method('get') + ->will($this->returnValueMap(array( + array('/bar/asd', $newNode), + array('/bar', $parentNode) + ))); + + $target = $node->copy('/bar/asd'); + $this->assertInstanceOf('\OC\Files\Node\File', $target); + $this->assertEquals(3, $target->getId()); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testCopyNotPermitted() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + /** + * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + + $root->expects($this->never()) + ->method('getMount'); + + $storage->expects($this->never()) + ->method('copy'); + + $view->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ, 'fileid' => 3))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar'); + + $root->expects($this->once()) + ->method('get') + ->will($this->returnValueMap(array( + array('/bar', $parentNode) + ))); + + $node->copy('/bar/asd'); + } + + /** + * @expectedException \OC\Files\NotFoundException + */ + public function testCopyNoParent() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->never()) + ->method('copy'); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + + $root->expects($this->once()) + ->method('get') + ->with('/bar/asd') + ->will($this->throwException(new NotFoundException())); + + $node->copy('/bar/asd/foo'); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testCopyParentIsFile() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->never()) + ->method('copy'); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $parentNode = new \OC\Files\Node\File($root, $view, '/bar'); + + $root->expects($this->once()) + ->method('get') + ->will($this->returnValueMap(array( + array('/bar', $parentNode) + ))); + + $node->copy('/bar/asd'); + } + + public function testMoveSameStorage() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->any()) + ->method('rename') + ->with('/bar/foo', '/bar/asd'); + + $view->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 1))); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar'); + + $root->expects($this->any()) + ->method('get') + ->will($this->returnValueMap(array(array('/bar', $parentNode), array('/bar/asd', $node)))); + + $target = $node->move('/bar/asd'); + $this->assertInstanceOf('\OC\Files\Node\File', $target); + $this->assertEquals(1, $target->getId()); + $this->assertEquals('/bar/asd', $node->getPath()); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testMoveNotPermitted() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $view->expects($this->never()) + ->method('rename'); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar'); + + $root->expects($this->once()) + ->method('get') + ->with('/bar') + ->will($this->returnValue($parentNode)); + + $node->move('/bar/asd'); + } + + /** + * @expectedException \OC\Files\NotFoundException + */ + public function testMoveNoParent() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + /** + * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + + $storage->expects($this->never()) + ->method('rename'); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar'); + + $root->expects($this->once()) + ->method('get') + ->with('/bar') + ->will($this->throwException(new NotFoundException())); + + $node->move('/bar/asd'); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testMoveParentIsFile() { + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + + $view->expects($this->never()) + ->method('rename'); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $parentNode = new \OC\Files\Node\File($root, $view, '/bar'); + + $root->expects($this->once()) + ->method('get') + ->with('/bar') + ->will($this->returnValue($parentNode)); + + $node->move('/bar/asd'); + } +} diff --git a/tests/lib/files/node/folder.php b/tests/lib/files/node/folder.php new file mode 100644 index 0000000000..691aa612c7 --- /dev/null +++ b/tests/lib/files/node/folder.php @@ -0,0 +1,479 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Node\Node; +use OC\Files\NotFoundException; +use OC\Files\NotPermittedException; +use OC\Files\View; + +class Folder extends \PHPUnit_Framework_TestCase { + private $user; + + public function setUp() { + $this->user = new \OC\User\User('', new \OC_User_Dummy); + } + + public function testDelete() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + $root->expects($this->exactly(2)) + ->method('emit') + ->will($this->returnValue(true)); + + $view->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $view->expects($this->once()) + ->method('rmdir') + ->with('/bar/foo') + ->will($this->returnValue(true)); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $node->delete(); + } + + public function testDeleteHooks() { + $test = $this; + $hooksRun = 0; + /** + * @param \OC\Files\Node\File $node + */ + $preListener = function ($node) use (&$test, &$hooksRun) { + $test->assertInstanceOf('\OC\Files\Node\Folder', $node); + $test->assertEquals('foo', $node->getInternalPath()); + $test->assertEquals('/bar/foo', $node->getPath()); + $hooksRun++; + }; + + /** + * @param \OC\Files\Node\File $node + */ + $postListener = function ($node) use (&$test, &$hooksRun) { + $test->assertInstanceOf('\OC\Files\Node\NonExistingFolder', $node); + $test->assertEquals('foo', $node->getInternalPath()); + $test->assertEquals('/bar/foo', $node->getPath()); + $hooksRun++; + }; + + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + $root->listen('\OC\Files', 'preDelete', $preListener); + $root->listen('\OC\Files', 'postDelete', $postListener); + + $view->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 1))); + + $view->expects($this->once()) + ->method('rmdir') + ->with('/bar/foo') + ->will($this->returnValue(true)); + + $view->expects($this->any()) + ->method('resolvePath') + ->with('/bar/foo') + ->will($this->returnValue(array(null, 'foo'))); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $node->delete(); + $this->assertEquals(2, $hooksRun); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testDeleteNotPermitted() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $node->delete(); + } + + public function testGetDirectoryContent() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + /** + * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + + $cache = $this->getMock('\OC\Files\Cache\Cache', array(), array('')); + $cache->expects($this->any()) + ->method('getStatus') + ->with('foo') + ->will($this->returnValue(Cache::COMPLETE)); + + $cache->expects($this->once()) + ->method('getFolderContents') + ->with('foo') + ->will($this->returnValue(array( + array('fileid' => 2, 'path' => '/bar/foo/asd', 'name' => 'asd', 'size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain'), + array('fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory') + ))); + + $permissionsCache = $this->getMock('\OC\Files\Cache\Permissions', array(), array('/')); + $permissionsCache->expects($this->once()) + ->method('getDirectoryPermissions') + ->will($this->returnValue(array(2 => \OCP\PERMISSION_ALL))); + + $root->expects($this->once()) + ->method('getMountsIn') + ->with('/bar/foo') + ->will($this->returnValue(array())); + + $storage->expects($this->any()) + ->method('getPermissionsCache') + ->will($this->returnValue($permissionsCache)); + $storage->expects($this->any()) + ->method('getCache') + ->will($this->returnValue($cache)); + + $view->expects($this->any()) + ->method('resolvePath') + ->with('/bar/foo') + ->will($this->returnValue(array($storage, 'foo'))); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $children = $node->getDirectoryListing(); + $this->assertEquals(2, count($children)); + $this->assertInstanceOf('\OC\Files\Node\File', $children[0]); + $this->assertInstanceOf('\OC\Files\Node\Folder', $children[1]); + $this->assertEquals('asd', $children[0]->getName()); + $this->assertEquals('qwerty', $children[1]->getName()); + } + + public function testGet() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $root->expects($this->once()) + ->method('get') + ->with('/bar/foo/asd'); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $node->get('asd'); + } + + public function testNodeExists() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $child = new \OC\Files\Node\Folder($root, $view, '/bar/foo/asd'); + + $root->expects($this->once()) + ->method('get') + ->with('/bar/foo/asd') + ->will($this->returnValue($child)); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $this->assertTrue($node->nodeExists('asd')); + } + + public function testNodeExistsNotExists() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $root->expects($this->once()) + ->method('get') + ->with('/bar/foo/asd') + ->will($this->throwException(new NotFoundException())); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $this->assertFalse($node->nodeExists('asd')); + } + + public function testNewFolder() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $view->expects($this->once()) + ->method('mkdir') + ->with('/bar/foo/asd') + ->will($this->returnValue(true)); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $child = new \OC\Files\Node\Folder($root, $view, '/bar/foo/asd'); + $result = $node->newFolder('asd'); + $this->assertEquals($child, $result); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testNewFolderNotPermitted() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $node->newFolder('asd'); + } + + public function testNewFile() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $view->expects($this->once()) + ->method('touch') + ->with('/bar/foo/asd') + ->will($this->returnValue(true)); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $child = new \OC\Files\Node\File($root, $view, '/bar/foo/asd'); + $result = $node->newFile('asd'); + $this->assertEquals($child, $result); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testNewFileNotPermitted() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $node->newFile('asd'); + } + + public function testGetFreeSpace() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('free_space') + ->with('/bar/foo') + ->will($this->returnValue(100)); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $this->assertEquals(100, $node->getFreeSpace()); + } + + public function testSearch() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + $storage = $this->getMock('\OC\Files\Storage\Storage'); + $cache = $this->getMock('\OC\Files\Cache\Cache', array(), array('')); + + $storage->expects($this->once()) + ->method('getCache') + ->will($this->returnValue($cache)); + + $cache->expects($this->once()) + ->method('search') + ->with('%qw%') + ->will($this->returnValue(array( + array('fileid' => 3, 'path' => 'foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain') + ))); + + $root->expects($this->once()) + ->method('getMountsIn') + ->with('/bar/foo') + ->will($this->returnValue(array())); + + $view->expects($this->once()) + ->method('resolvePath') + ->will($this->returnValue(array($storage, 'foo'))); + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $result = $node->search('qw'); + $this->assertEquals(1, count($result)); + $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath()); + } + + public function testSearchSubStorages() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + $storage = $this->getMock('\OC\Files\Storage\Storage'); + $cache = $this->getMock('\OC\Files\Cache\Cache', array(), array('')); + $subCache = $this->getMock('\OC\Files\Cache\Cache', array(), array('')); + $subStorage = $this->getMock('\OC\Files\Storage\Storage'); + $subMount = $this->getMock('\OC\Files\Mount\Mount', array(), array(null, '')); + + $subMount->expects($this->once()) + ->method('getStorage') + ->will($this->returnValue($subStorage)); + + $subMount->expects($this->once()) + ->method('getMountPoint') + ->will($this->returnValue('/bar/foo/bar/')); + + $storage->expects($this->once()) + ->method('getCache') + ->will($this->returnValue($cache)); + + $subStorage->expects($this->once()) + ->method('getCache') + ->will($this->returnValue($subCache)); + + $cache->expects($this->once()) + ->method('search') + ->with('%qw%') + ->will($this->returnValue(array( + array('fileid' => 3, 'path' => 'foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain') + ))); + + $subCache->expects($this->once()) + ->method('search') + ->with('%qw%') + ->will($this->returnValue(array( + array('fileid' => 4, 'path' => 'asd/qweasd', 'name' => 'qweasd', 'size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain') + ))); + + $root->expects($this->once()) + ->method('getMountsIn') + ->with('/bar/foo') + ->will($this->returnValue(array($subMount))); + + $view->expects($this->once()) + ->method('resolvePath') + ->will($this->returnValue(array($storage, 'foo'))); + + + $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo'); + $result = $node->search('qw'); + $this->assertEquals(2, count($result)); + } + + public function testIsSubNode() { + $file = new Node(null, null, '/foo/bar'); + $folder = new \OC\Files\Node\Folder(null, null, '/foo'); + $this->assertTrue($folder->isSubNode($file)); + $this->assertFalse($folder->isSubNode($folder)); + + $file = new Node(null, null, '/foobar'); + $this->assertFalse($folder->isSubNode($file)); + } +} diff --git a/tests/lib/files/node/integration.php b/tests/lib/files/node/integration.php new file mode 100644 index 0000000000..c99b6f99eb --- /dev/null +++ b/tests/lib/files/node/integration.php @@ -0,0 +1,121 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Mount\Manager; +use OC\Files\Node\Root; +use OC\Files\NotFoundException; +use OC\Files\NotPermittedException; +use OC\Files\Storage\Temporary; +use OC\Files\View; +use OC\User\User; + +class IntegrationTests extends \PHPUnit_Framework_TestCase { + /** + * @var \OC\Files\Node\Root $root + */ + private $root; + + /** + * @var \OC\Files\Storage\Storage[] + */ + private $storages; + + /** + * @var \OC\Files\View $view + */ + private $view; + + public function setUp() { + \OC\Files\Filesystem::init('', ''); + \OC\Files\Filesystem::clearMounts(); + $manager = \OC\Files\Filesystem::getMountManager(); + + \OC_Hook::clear('OC_Filesystem'); + + \OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook'); + \OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook'); + \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook'); + \OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook'); + + $user = new User('', new \OC_User_Dummy); + $this->view = new View(); + $this->root = new Root($manager, $this->view, $user); + $storage = new Temporary(array()); + $subStorage = new Temporary(array()); + $this->storages[] = $storage; + $this->storages[] = $subStorage; + $this->root->mount($storage, '/'); + $this->root->mount($subStorage, '/substorage/'); + } + + public function tearDown() { + foreach ($this->storages as $storage) { + $storage->getCache()->clear(); + } + \OC\Files\Filesystem::clearMounts(); + } + + public function testBasicFile() { + $file = $this->root->newFile('/foo.txt'); + $this->assertCount(2, $this->root->getDirectoryListing()); + $this->assertTrue($this->root->nodeExists('/foo.txt')); + $id = $file->getId(); + $this->assertInstanceOf('\OC\Files\Node\File', $file); + $file->putContent('qwerty'); + $this->assertEquals('text/plain', $file->getMimeType()); + $this->assertEquals('qwerty', $file->getContent()); + $this->assertFalse($this->root->nodeExists('/bar.txt')); + $file->move('/bar.txt'); + $this->assertFalse($this->root->nodeExists('/foo.txt')); + $this->assertTrue($this->root->nodeExists('/bar.txt')); + $this->assertEquals('bar.txt', $file->getName()); + $this->assertEquals('bar.txt', $file->getInternalPath()); + + $file->move('/substorage/bar.txt'); + $this->assertNotEquals($id, $file->getId()); + $this->assertEquals('qwerty', $file->getContent()); + } + + public function testBasicFolder() { + $folder = $this->root->newFolder('/foo'); + $this->assertTrue($this->root->nodeExists('/foo')); + $file = $folder->newFile('/bar'); + $this->assertTrue($this->root->nodeExists('/foo/bar')); + $file->putContent('qwerty'); + + $listing = $folder->getDirectoryListing(); + $this->assertEquals(1, count($listing)); + $this->assertEquals($file->getId(), $listing[0]->getId()); + $this->assertEquals($file->getStorage(), $listing[0]->getStorage()); + + + $rootListing = $this->root->getDirectoryListing(); + $this->assertEquals(2, count($rootListing)); + + $folder->move('/asd'); + /** + * @var \OC\Files\Node\File $file + */ + $file = $folder->get('/bar'); + $this->assertInstanceOf('\OC\Files\Node\File', $file); + $this->assertFalse($this->root->nodeExists('/foo/bar')); + $this->assertTrue($this->root->nodeExists('/asd/bar')); + $this->assertEquals('qwerty', $file->getContent()); + $folder->move('/substorage/foo'); + /** + * @var \OC\Files\Node\File $file + */ + $file = $folder->get('/bar'); + $this->assertInstanceOf('\OC\Files\Node\File', $file); + $this->assertTrue($this->root->nodeExists('/substorage/foo/bar')); + $this->assertEquals('qwerty', $file->getContent()); + } +} diff --git a/tests/lib/files/node/node.php b/tests/lib/files/node/node.php new file mode 100644 index 0000000000..aa9d2a382e --- /dev/null +++ b/tests/lib/files/node/node.php @@ -0,0 +1,330 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Node; + +class Node extends \PHPUnit_Framework_TestCase { + private $user; + + public function setUp() { + $this->user = new \OC\User\User('', new \OC_User_Dummy); + } + + public function testStat() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $stat = array( + 'fileid' => 1, + 'size' => 100, + 'etag' => 'qwerty', + 'mtime' => 50, + 'permissions' => 0 + ); + + $view->expects($this->once()) + ->method('stat') + ->with('/bar/foo') + ->will($this->returnValue($stat)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals($stat, $node->stat()); + } + + public function testGetId() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $stat = array( + 'fileid' => 1, + 'size' => 100, + 'etag' => 'qwerty', + 'mtime' => 50 + ); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue($stat)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals(1, $node->getId()); + } + + public function testGetSize() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('filesize') + ->with('/bar/foo') + ->will($this->returnValue(100)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals(100, $node->getSize()); + } + + public function testGetEtag() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $stat = array( + 'fileid' => 1, + 'size' => 100, + 'etag' => 'qwerty', + 'mtime' => 50 + ); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue($stat)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals('qwerty', $node->getEtag()); + } + + public function testGetMTime() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + /** + * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + + $view->expects($this->once()) + ->method('filemtime') + ->with('/bar/foo') + ->will($this->returnValue(50)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals(50, $node->getMTime()); + } + + public function testGetStorage() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + /** + * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + + $view->expects($this->once()) + ->method('resolvePath') + ->with('/bar/foo') + ->will($this->returnValue(array($storage, 'foo'))); + + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals($storage, $node->getStorage()); + } + + public function testGetPath() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals('/bar/foo', $node->getPath()); + } + + public function testGetInternalPath() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + /** + * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + + $view->expects($this->once()) + ->method('resolvePath') + ->with('/bar/foo') + ->will($this->returnValue(array($storage, 'foo'))); + + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals('foo', $node->getInternalPath()); + } + + public function testGetName() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $node = new \OC\Files\Node\File($root, $view, '/bar/foo'); + $this->assertEquals('foo', $node->getName()); + } + + public function testTouchSetMTime() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->once()) + ->method('touch') + ->with('/bar/foo', 100) + ->will($this->returnValue(true)); + + $view->expects($this->once()) + ->method('filemtime') + ->with('/bar/foo') + ->will($this->returnValue(100)); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $node = new \OC\Files\Node\Node($root, $view, '/bar/foo'); + $node->touch(100); + $this->assertEquals(100, $node->getMTime()); + } + + public function testTouchHooks() { + $test = $this; + $hooksRun = 0; + /** + * @param \OC\Files\Node\File $node + */ + $preListener = function ($node) use (&$test, &$hooksRun) { + $test->assertEquals('foo', $node->getInternalPath()); + $test->assertEquals('/bar/foo', $node->getPath()); + $hooksRun++; + }; + + /** + * @param \OC\Files\Node\File $node + */ + $postListener = function ($node) use (&$test, &$hooksRun) { + $test->assertEquals('foo', $node->getInternalPath()); + $test->assertEquals('/bar/foo', $node->getPath()); + $hooksRun++; + }; + + /** + * @var \OC\Files\Mount\Manager $manager + */ + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + $root->listen('\OC\Files', 'preTouch', $preListener); + $root->listen('\OC\Files', 'postTouch', $postListener); + + $view->expects($this->once()) + ->method('touch') + ->with('/bar/foo', 100) + ->will($this->returnValue(true)); + + $view->expects($this->any()) + ->method('resolvePath') + ->with('/bar/foo') + ->will($this->returnValue(array(null, 'foo'))); + + $view->expects($this->any()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL))); + + $node = new \OC\Files\Node\Node($root, $view, '/bar/foo'); + $node->touch(100); + $this->assertEquals(2, $hooksRun); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testTouchNotPermitted() { + $manager = $this->getMock('\OC\Files\Mount\Manager'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user)); + $root->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($this->user)); + + $view->expects($this->any()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ))); + + $node = new \OC\Files\Node\Node($root, $view, '/bar/foo'); + $node->touch(100); + } +} diff --git a/tests/lib/files/node/root.php b/tests/lib/files/node/root.php new file mode 100644 index 0000000000..0b356ec6d9 --- /dev/null +++ b/tests/lib/files/node/root.php @@ -0,0 +1,106 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\NotPermittedException; +use OC\Files\Mount\Manager; + +class Root extends \PHPUnit_Framework_TestCase { + private $user; + + public function setUp() { + $this->user = new \OC\User\User('', new \OC_User_Dummy); + } + + public function testGet() { + $manager = new Manager(); + /** + * @var \OC\Files\Storage\Storage $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $view->expects($this->once()) + ->method('getFileInfo') + ->with('/bar/foo') + ->will($this->returnValue(array('fileid' => 10, 'path' => 'bar/foo', 'name', 'mimetype' => 'text/plain'))); + + $view->expects($this->once()) + ->method('is_dir') + ->with('/bar/foo') + ->will($this->returnValue(false)); + + $view->expects($this->once()) + ->method('file_exists') + ->with('/bar/foo') + ->will($this->returnValue(true)); + + $root->mount($storage, ''); + $node = $root->get('/bar/foo'); + $this->assertEquals(10, $node->getId()); + $this->assertInstanceOf('\OC\Files\Node\File', $node); + } + + /** + * @expectedException \OC\Files\NotFoundException + */ + public function testGetNotFound() { + $manager = new Manager(); + /** + * @var \OC\Files\Storage\Storage $storage + */ + $storage = $this->getMock('\OC\Files\Storage\Storage'); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $view->expects($this->once()) + ->method('file_exists') + ->with('/bar/foo') + ->will($this->returnValue(false)); + + $root->mount($storage, ''); + $root->get('/bar/foo'); + } + + /** + * @expectedException \OC\Files\NotPermittedException + */ + public function testGetInvalidPath() { + $manager = new Manager(); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $root->get('/../foo'); + } + + /** + * @expectedException \OC\Files\NotFoundException + */ + public function testGetNoStorages() { + $manager = new Manager(); + /** + * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view + */ + $view = $this->getMock('\OC\Files\View'); + $root = new \OC\Files\Node\Root($manager, $view, $this->user); + + $root->get('/bar/foo'); + } +} From 1cfd03771f3ba8a91b5600cf71c6f455d288bbe0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 6 Sep 2013 20:20:17 +0200 Subject: [PATCH 02/11] use === --- lib/files/node/node.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/files/node/node.php b/lib/files/node/node.php index a71f787506..a1db042c25 100644 --- a/lib/files/node/node.php +++ b/lib/files/node/node.php @@ -56,7 +56,7 @@ class Node { * @return bool */ protected function checkPermissions($permissions) { - return ($this->getPermissions() & $permissions) == $permissions; + return ($this->getPermissions() & $permissions) === $permissions; } /** From 0131a3202597fe2cfefbb72e1a20fd266d48451a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 6 Sep 2013 20:38:59 +0200 Subject: [PATCH 03/11] extract interfaces from fileapi for public namespace --- lib/files/node/file.php | 2 +- lib/files/node/folder.php | 2 +- lib/files/node/node.php | 2 +- lib/public/files/node/file.php | 44 +++++++++++++ lib/public/files/node/folder.php | 104 +++++++++++++++++++++++++++++ lib/public/files/node/node.php | 108 +++++++++++++++++++++++++++++++ 6 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 lib/public/files/node/file.php create mode 100644 lib/public/files/node/folder.php create mode 100644 lib/public/files/node/node.php diff --git a/lib/files/node/file.php b/lib/files/node/file.php index 0ad5d68ec6..f13b474aa6 100644 --- a/lib/files/node/file.php +++ b/lib/files/node/file.php @@ -10,7 +10,7 @@ namespace OC\Files\Node; use OC\Files\NotPermittedException; -class File extends Node { +class File extends Node implements \OCP\Files\Node\File { /** * @return string * @throws \OC\Files\NotPermittedException diff --git a/lib/files/node/folder.php b/lib/files/node/folder.php index f710ae5ae9..daf75d7c23 100644 --- a/lib/files/node/folder.php +++ b/lib/files/node/folder.php @@ -13,7 +13,7 @@ use OC\Files\Cache\Scanner; use OC\Files\NotFoundException; use OC\Files\NotPermittedException; -class Folder extends Node { +class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param string $path path relative to the folder * @return string diff --git a/lib/files/node/node.php b/lib/files/node/node.php index a1db042c25..5ee9f23161 100644 --- a/lib/files/node/node.php +++ b/lib/files/node/node.php @@ -15,7 +15,7 @@ use OC\Files\NotPermittedException; require_once 'files/exceptions.php'; -class Node { +class Node implements \OCP\Files\Node\Node { /** * @var \OC\Files\View $view */ diff --git a/lib/public/files/node/file.php b/lib/public/files/node/file.php new file mode 100644 index 0000000000..193663f60b --- /dev/null +++ b/lib/public/files/node/file.php @@ -0,0 +1,44 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files\Node; + +use OC\Files\NotPermittedException; + +interface File extends Node { + /** + * @return string + * @throws \OC\Files\NotPermittedException + */ + public function getContent(); + + /** + * @param string $data + * @throws \OC\Files\NotPermittedException + */ + public function putContent($data); + + /** + * @return string + */ + public function getMimeType(); + + /** + * @param string $mode + * @return resource + * @throws \OC\Files\NotPermittedException + */ + public function fopen($mode); + + /** + * @param string $type + * @param bool $raw + * @return string + */ + public function hash($type, $raw = false); +} diff --git a/lib/public/files/node/folder.php b/lib/public/files/node/folder.php new file mode 100644 index 0000000000..7b3ae80f0d --- /dev/null +++ b/lib/public/files/node/folder.php @@ -0,0 +1,104 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OC\Files\NotFoundException; +use OC\Files\NotPermittedException; + +interface Folder extends Node { + /** + * @param string $path path relative to the folder + * @return string + * @throws \OC\Files\NotPermittedException + */ + public function getFullPath($path); + + /** + * @param string $path + * @throws \OC\Files\NotFoundException + * @return string + */ + public function getRelativePath($path); + + /** + * check if a node is a (grand-)child of the folder + * + * @param \OC\Files\Node\Node $node + * @return bool + */ + public function isSubNode($node); + + /** + * get the content of this directory + * + * @throws \OC\Files\NotFoundException + * @return Node[] + */ + public function getDirectoryListing(); + + /** + * Get the node at $path + * + * @param string $path + * @return \OC\Files\Node\Node + * @throws \OC\Files\NotFoundException + */ + public function get($path); + + /** + * @param string $path + * @return bool + */ + public function nodeExists($path); + + /** + * @param string $path + * @return Folder + * @throws NotPermittedException + */ + public function newFolder($path); + + /** + * @param string $path + * @return File + * @throws NotPermittedException + */ + public function newFile($path); + + /** + * search for files with the name matching $query + * + * @param string $query + * @return Node[] + */ + public function search($query); + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return Node[] + */ + public function searchByMime($mimetype); + + /** + * @param $id + * @return Node[] + */ + public function getById($id); + + public function getFreeSpace(); + + /** + * @return bool + */ + public function isCreatable(); +} diff --git a/lib/public/files/node/node.php b/lib/public/files/node/node.php new file mode 100644 index 0000000000..085e880e37 --- /dev/null +++ b/lib/public/files/node/node.php @@ -0,0 +1,108 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files\Node; + +interface Node { + /** + * @param string $targetPath + * @throws \OC\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function move($targetPath); + + public function delete(); + + /** + * @param string $targetPath + * @return \OC\Files\Node\Node + */ + public function copy($targetPath); + + /** + * @param int $mtime + * @throws \OC\Files\NotPermittedException + */ + public function touch($mtime = null); + + /** + * @return \OC\Files\Storage\Storage + * @throws \OC\Files\NotFoundException + */ + public function getStorage(); + + /** + * @return string + */ + public function getPath(); + + /** + * @return string + */ + public function getInternalPath(); + + /** + * @return int + */ + public function getId(); + + /** + * @return array + */ + public function stat(); + + /** + * @return int + */ + public function getMTime(); + + /** + * @return int + */ + public function getSize(); + + /** + * @return string + */ + public function getEtag(); + + /** + * @return int + */ + public function getPermissions(); + + /** + * @return bool + */ + public function isReadable(); + + /** + * @return bool + */ + public function isUpdateable(); + + /** + * @return bool + */ + public function isDeletable(); + + /** + * @return bool + */ + public function isShareable(); + + /** + * @return Node + */ + public function getParent(); + + /** + * @return string + */ + public function getName(); +} From 2e1b534957460ac39bfe1f5f14148164df148e5a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 6 Sep 2013 20:55:47 +0200 Subject: [PATCH 04/11] update phpdoc for public fileapi --- lib/public/files/node/folder.php | 16 ++++++++-------- lib/public/files/node/node.php | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/public/files/node/folder.php b/lib/public/files/node/folder.php index 7b3ae80f0d..af53bc9e58 100644 --- a/lib/public/files/node/folder.php +++ b/lib/public/files/node/folder.php @@ -31,7 +31,7 @@ interface Folder extends Node { /** * check if a node is a (grand-)child of the folder * - * @param \OC\Files\Node\Node $node + * @param \OCP\Files\Node\Node $node * @return bool */ public function isSubNode($node); @@ -40,7 +40,7 @@ interface Folder extends Node { * get the content of this directory * * @throws \OC\Files\NotFoundException - * @return Node[] + * @return \OCP\Files\Node\Node[] */ public function getDirectoryListing(); @@ -48,7 +48,7 @@ interface Folder extends Node { * Get the node at $path * * @param string $path - * @return \OC\Files\Node\Node + * @return \OCP\Files\Node\Node * @throws \OC\Files\NotFoundException */ public function get($path); @@ -61,14 +61,14 @@ interface Folder extends Node { /** * @param string $path - * @return Folder + * @return \OCP\Files\Node\Folder * @throws NotPermittedException */ public function newFolder($path); /** * @param string $path - * @return File + * @return \OCP\Files\Node\File * @throws NotPermittedException */ public function newFile($path); @@ -77,7 +77,7 @@ interface Folder extends Node { * search for files with the name matching $query * * @param string $query - * @return Node[] + * @return \OCP\Files\Node\Node[] */ public function search($query); @@ -85,13 +85,13 @@ interface Folder extends Node { * search for files by mimetype * * @param string $mimetype - * @return Node[] + * @return \OCP\Files\Node\Node[] */ public function searchByMime($mimetype); /** * @param $id - * @return Node[] + * @return \OCP\Files\Node\Node[] */ public function getById($id); diff --git a/lib/public/files/node/node.php b/lib/public/files/node/node.php index 085e880e37..b85f37e69a 100644 --- a/lib/public/files/node/node.php +++ b/lib/public/files/node/node.php @@ -12,7 +12,7 @@ interface Node { /** * @param string $targetPath * @throws \OC\Files\NotPermittedException - * @return \OC\Files\Node\Node + * @return \OCP\Files\Node\Node */ public function move($targetPath); @@ -20,7 +20,7 @@ interface Node { /** * @param string $targetPath - * @return \OC\Files\Node\Node + * @return \OCP\Files\Node\Node */ public function copy($targetPath); From 315344eb9cc58dda23bfe52c1413ad963265a9cb Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 10 Sep 2013 19:34:38 +0200 Subject: [PATCH 05/11] move public files api to a clearer namespace --- lib/public/files/{node => }/file.php | 2 +- lib/public/files/{node => }/folder.php | 18 +++++++++--------- lib/public/files/{node => }/node.php | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) rename lib/public/files/{node => }/file.php (96%) rename lib/public/files/{node => }/folder.php (84%) rename lib/public/files/{node => }/node.php (94%) diff --git a/lib/public/files/node/file.php b/lib/public/files/file.php similarity index 96% rename from lib/public/files/node/file.php rename to lib/public/files/file.php index 193663f60b..c571e184ce 100644 --- a/lib/public/files/node/file.php +++ b/lib/public/files/file.php @@ -6,7 +6,7 @@ * See the COPYING-README file. */ -namespace OCP\Files\Node; +namespace OCP\Files; use OC\Files\NotPermittedException; diff --git a/lib/public/files/node/folder.php b/lib/public/files/folder.php similarity index 84% rename from lib/public/files/node/folder.php rename to lib/public/files/folder.php index af53bc9e58..a8e57f7ae2 100644 --- a/lib/public/files/node/folder.php +++ b/lib/public/files/folder.php @@ -6,7 +6,7 @@ * See the COPYING-README file. */ -namespace OCP\Files\Node; +namespace OCP\Files; use OC\Files\Cache\Cache; use OC\Files\Cache\Scanner; @@ -31,7 +31,7 @@ interface Folder extends Node { /** * check if a node is a (grand-)child of the folder * - * @param \OCP\Files\Node\Node $node + * @param \OCP\Files\Node $node * @return bool */ public function isSubNode($node); @@ -40,7 +40,7 @@ interface Folder extends Node { * get the content of this directory * * @throws \OC\Files\NotFoundException - * @return \OCP\Files\Node\Node[] + * @return \OCP\Files\Node[] */ public function getDirectoryListing(); @@ -48,7 +48,7 @@ interface Folder extends Node { * Get the node at $path * * @param string $path - * @return \OCP\Files\Node\Node + * @return \OCP\Files\Node * @throws \OC\Files\NotFoundException */ public function get($path); @@ -61,14 +61,14 @@ interface Folder extends Node { /** * @param string $path - * @return \OCP\Files\Node\Folder + * @return \OCP\Files\Folder * @throws NotPermittedException */ public function newFolder($path); /** * @param string $path - * @return \OCP\Files\Node\File + * @return \OCP\Files\File * @throws NotPermittedException */ public function newFile($path); @@ -77,7 +77,7 @@ interface Folder extends Node { * search for files with the name matching $query * * @param string $query - * @return \OCP\Files\Node\Node[] + * @return \OCP\Files\Node[] */ public function search($query); @@ -85,13 +85,13 @@ interface Folder extends Node { * search for files by mimetype * * @param string $mimetype - * @return \OCP\Files\Node\Node[] + * @return \OCP\Files\Node[] */ public function searchByMime($mimetype); /** * @param $id - * @return \OCP\Files\Node\Node[] + * @return \OCP\Files\Node[] */ public function getById($id); diff --git a/lib/public/files/node/node.php b/lib/public/files/node.php similarity index 94% rename from lib/public/files/node/node.php rename to lib/public/files/node.php index b85f37e69a..d3b71803f5 100644 --- a/lib/public/files/node/node.php +++ b/lib/public/files/node.php @@ -6,13 +6,13 @@ * See the COPYING-README file. */ -namespace OCP\Files\Node; +namespace OCP\Files; interface Node { /** * @param string $targetPath * @throws \OC\Files\NotPermittedException - * @return \OCP\Files\Node\Node + * @return \OCP\Files\Node */ public function move($targetPath); @@ -20,7 +20,7 @@ interface Node { /** * @param string $targetPath - * @return \OCP\Files\Node\Node + * @return \OCP\Files\Node */ public function copy($targetPath); From e271a55783dafd605791d02ca718b463fa19d58d Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 10 Sep 2013 19:44:23 +0200 Subject: [PATCH 06/11] move filesystem expceptions to global namespace --- lib/files/node/file.php | 14 +++---- lib/files/node/folder.php | 32 +++++++------- lib/files/node/node.php | 14 +++---- lib/files/node/nonexistingfile.php | 4 +- lib/files/node/nonexistingfolder.php | 4 +- lib/files/node/root.php | 44 ++++++++++---------- lib/public/files/alreadyexistsexception.php | 11 +++++ lib/public/files/notenoughspaceexception.php | 11 +++++ lib/public/files/notfoundexception.php | 11 +++++ lib/public/files/notpermittedexception.php | 11 +++++ 10 files changed, 99 insertions(+), 57 deletions(-) create mode 100644 lib/public/files/alreadyexistsexception.php create mode 100644 lib/public/files/notenoughspaceexception.php create mode 100644 lib/public/files/notfoundexception.php create mode 100644 lib/public/files/notpermittedexception.php diff --git a/lib/files/node/file.php b/lib/files/node/file.php index f13b474aa6..75d5e0166b 100644 --- a/lib/files/node/file.php +++ b/lib/files/node/file.php @@ -8,12 +8,12 @@ namespace OC\Files\Node; -use OC\Files\NotPermittedException; +use OCP\Files\NotPermittedException; -class File extends Node implements \OCP\Files\Node\File { +class File extends Node implements \OCP\Files\File { /** * @return string - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function getContent() { if ($this->checkPermissions(\OCP\PERMISSION_READ)) { @@ -28,7 +28,7 @@ class File extends Node implements \OCP\Files\Node\File { /** * @param string $data - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function putContent($data) { if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { @@ -50,7 +50,7 @@ class File extends Node implements \OCP\Files\Node\File { /** * @param string $mode * @return resource - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function fopen($mode) { $preHooks = array(); @@ -101,7 +101,7 @@ class File extends Node implements \OCP\Files\Node\File { /** * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException * @return \OC\Files\Node\Node */ public function copy($targetPath) { @@ -123,7 +123,7 @@ class File extends Node implements \OCP\Files\Node\File { /** * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException * @return \OC\Files\Node\Node */ public function move($targetPath) { diff --git a/lib/files/node/folder.php b/lib/files/node/folder.php index daf75d7c23..923f53821b 100644 --- a/lib/files/node/folder.php +++ b/lib/files/node/folder.php @@ -10,14 +10,14 @@ namespace OC\Files\Node; use OC\Files\Cache\Cache; use OC\Files\Cache\Scanner; -use OC\Files\NotFoundException; -use OC\Files\NotPermittedException; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; -class Folder extends Node implements \OCP\Files\Node\Folder { +class Folder extends Node implements \OCP\Files\Folder { /** * @param string $path path relative to the folder * @return string - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function getFullPath($path) { if (!$this->isValidPath($path)) { @@ -28,7 +28,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param string $path - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException * @return string */ public function getRelativePath($path) { @@ -60,7 +60,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * get the content of this directory * - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException * @return Node[] */ public function getDirectoryListing() { @@ -164,7 +164,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { * * @param string $path * @return \OC\Files\Node\Node - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function get($path) { return $this->root->get($this->getFullPath($path)); @@ -185,8 +185,8 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param string $path - * @return Folder - * @throws NotPermittedException + * @return \OC\Files\Node\Folder + * @throws \OCP\Files\NotPermittedException */ public function newFolder($path) { if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { @@ -206,8 +206,8 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param string $path - * @return File - * @throws NotPermittedException + * @return \OC\Files\Node\File + * @throws \OCP\Files\NotPermittedException */ public function newFile($path) { if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { @@ -229,7 +229,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { * search for files with the name matching $query * * @param string $query - * @return Node[] + * @return \OC\Files\Node\Node[] */ public function search($query) { return $this->searchCommon('%' . $query . '%', 'search'); @@ -248,7 +248,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param string $query * @param string $method - * @return Node[] + * @return \OC\Files\Node\Node[] */ private function searchCommon($query, $method) { $files = array(); @@ -298,7 +298,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param $id - * @return Node[] + * @return \OC\Files\Node\Node[] */ public function getById($id) { $nodes = $this->root->getById($id); @@ -337,7 +337,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException * @return \OC\Files\Node\Node */ public function copy($targetPath) { @@ -359,7 +359,7 @@ class Folder extends Node implements \OCP\Files\Node\Folder { /** * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException * @return \OC\Files\Node\Node */ public function move($targetPath) { diff --git a/lib/files/node/node.php b/lib/files/node/node.php index 5ee9f23161..063e2424a6 100644 --- a/lib/files/node/node.php +++ b/lib/files/node/node.php @@ -10,12 +10,10 @@ namespace OC\Files\Node; use OC\Files\Cache\Cache; use OC\Files\Cache\Scanner; -use OC\Files\NotFoundException; -use OC\Files\NotPermittedException; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; -require_once 'files/exceptions.php'; - -class Node implements \OCP\Files\Node\Node { +class Node implements \OCP\Files\Node { /** * @var \OC\Files\View $view */ @@ -61,7 +59,7 @@ class Node implements \OCP\Files\Node\Node { /** * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException * @return \OC\Files\Node\Node */ public function move($targetPath) { @@ -82,7 +80,7 @@ class Node implements \OCP\Files\Node\Node { /** * @param int $mtime - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function touch($mtime = null) { if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { @@ -96,7 +94,7 @@ class Node implements \OCP\Files\Node\Node { /** * @return \OC\Files\Storage\Storage - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function getStorage() { list($storage,) = $this->view->resolvePath($this->path); diff --git a/lib/files/node/nonexistingfile.php b/lib/files/node/nonexistingfile.php index 6f18450efe..d45076f7fe 100644 --- a/lib/files/node/nonexistingfile.php +++ b/lib/files/node/nonexistingfile.php @@ -8,12 +8,12 @@ namespace OC\Files\Node; -use OC\Files\NotFoundException; +use OCP\Files\NotFoundException; class NonExistingFile extends File { /** * @param string $newPath - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function rename($newPath) { throw new NotFoundException(); diff --git a/lib/files/node/nonexistingfolder.php b/lib/files/node/nonexistingfolder.php index 0249a02624..0346cbf1e2 100644 --- a/lib/files/node/nonexistingfolder.php +++ b/lib/files/node/nonexistingfolder.php @@ -8,12 +8,12 @@ namespace OC\Files\Node; -use OC\Files\NotFoundException; +use OCP\Files\NotFoundException; class NonExistingFolder extends Folder { /** * @param string $newPath - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function rename($newPath) { throw new NotFoundException(); diff --git a/lib/files/node/root.php b/lib/files/node/root.php index f88d8c294c..e3d58476e9 100644 --- a/lib/files/node/root.php +++ b/lib/files/node/root.php @@ -12,8 +12,8 @@ use OC\Files\Cache\Cache; use OC\Files\Cache\Scanner; use OC\Files\Mount\Manager; use OC\Files\Mount\Mount; -use OC\Files\NotFoundException; -use OC\Files\NotPermittedException; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; use OC\Hooks\Emitter; use OC\Hooks\PublicEmitter; @@ -21,18 +21,18 @@ use OC\Hooks\PublicEmitter; * Class Root * * Hooks available in scope \OC\Files - * - preWrite(\OC\Files\Node\Node $node) - * - postWrite(\OC\Files\Node\Node $node) - * - preCreate(\OC\Files\Node\Node $node) - * - postCreate(\OC\Files\Node\Node $node) - * - preDelete(\OC\Files\Node\Node $node) - * - postDelete(\OC\Files\Node\Node $node) - * - preTouch(\OC\Files\Node\Node $node, int $mtime) - * - postTouch(\OC\Files\Node\Node $node) - * - preCopy(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) - * - postCopy(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) - * - preRename(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) - * - postRename(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target) + * - preWrite(\OCP\Files\Node $node) + * - postWrite(\OCP\Files\Node $node) + * - preCreate(\OCP\Files\Node $node) + * - postCreate(\OCP\Files\Node $node) + * - preDelete(\OCP\Files\Node $node) + * - postDelete(\OCP\Files\Node $node) + * - preTouch(\OC\FilesP\Node $node, int $mtime) + * - postTouch(\OCP\Files\Node $node) + * - preCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) + * - postCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) + * - preRename(\OCP\Files\Node $source, \OCP\Files\Node $target) + * - postRename(\OCP\Files\Node $source, \OCP\Files\Node $target) * * @package OC\Files\Node */ @@ -152,8 +152,8 @@ class Root extends Folder implements Emitter { /** * @param string $path - * @throws \OC\Files\NotFoundException - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotFoundException + * @throws \OCP\Files\NotPermittedException * @return Node */ public function get($path) { @@ -177,7 +177,7 @@ class Root extends Folder implements Emitter { * can exist in different places * * @param int $id - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException * @return Node[] */ public function getById($id) { @@ -200,7 +200,7 @@ class Root extends Folder implements Emitter { /** * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException * @return \OC\Files\Node\Node */ public function rename($targetPath) { @@ -213,7 +213,7 @@ class Root extends Folder implements Emitter { /** * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException * @return \OC\Files\Node\Node */ public function copy($targetPath) { @@ -222,7 +222,7 @@ class Root extends Folder implements Emitter { /** * @param int $mtime - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function touch($mtime = null) { throw new NotPermittedException(); @@ -230,7 +230,7 @@ class Root extends Folder implements Emitter { /** * @return \OC\Files\Storage\Storage - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function getStorage() { throw new NotFoundException(); @@ -322,7 +322,7 @@ class Root extends Folder implements Emitter { /** * @return Node - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function getParent() { throw new NotFoundException(); diff --git a/lib/public/files/alreadyexistsexception.php b/lib/public/files/alreadyexistsexception.php new file mode 100644 index 0000000000..32947c7a5c --- /dev/null +++ b/lib/public/files/alreadyexistsexception.php @@ -0,0 +1,11 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files; + +class AlreadyExistsException extends \Exception {} diff --git a/lib/public/files/notenoughspaceexception.php b/lib/public/files/notenoughspaceexception.php new file mode 100644 index 0000000000..e51806666a --- /dev/null +++ b/lib/public/files/notenoughspaceexception.php @@ -0,0 +1,11 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files; + +class NotEnoughSpaceException extends \Exception {} diff --git a/lib/public/files/notfoundexception.php b/lib/public/files/notfoundexception.php new file mode 100644 index 0000000000..1ff426a40c --- /dev/null +++ b/lib/public/files/notfoundexception.php @@ -0,0 +1,11 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files; + +class NotFoundException extends \Exception {} diff --git a/lib/public/files/notpermittedexception.php b/lib/public/files/notpermittedexception.php new file mode 100644 index 0000000000..0509de7e82 --- /dev/null +++ b/lib/public/files/notpermittedexception.php @@ -0,0 +1,11 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files; + +class NotPermittedException extends \Exception {} From 9ad7891b4e7ddf1c4420f485c5d3cf4477835087 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 10 Sep 2013 20:02:15 +0200 Subject: [PATCH 07/11] improve phpdoc for the public files interface --- lib/files/exceptions.php | 21 ------------ lib/public/files/file.php | 19 ++++++++--- lib/public/files/folder.php | 51 +++++++++++++++++++---------- lib/public/files/node.php | 65 +++++++++++++++++++++++++++++++++---- 4 files changed, 105 insertions(+), 51 deletions(-) delete mode 100644 lib/files/exceptions.php diff --git a/lib/files/exceptions.php b/lib/files/exceptions.php deleted file mode 100644 index 8a3c40ab0c..0000000000 --- a/lib/files/exceptions.php +++ /dev/null @@ -1,21 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files; - -class NotFoundException extends \Exception { -} - -class NotPermittedException extends \Exception { -} - -class AlreadyExistsException extends \Exception { -} - -class NotEnoughSpaceException extends \Exception { -} diff --git a/lib/public/files/file.php b/lib/public/files/file.php index c571e184ce..916b2edd6c 100644 --- a/lib/public/files/file.php +++ b/lib/public/files/file.php @@ -8,34 +8,43 @@ namespace OCP\Files; -use OC\Files\NotPermittedException; - interface File extends Node { /** + * Get the content of the file as string + * * @return string - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function getContent(); /** + * Write to the file from string data + * * @param string $data - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function putContent($data); /** + * Get the mimetype of the file + * * @return string */ public function getMimeType(); /** + * Open the file as stream, resulting resource can be operated as stream like the result from php's own fopen + * * @param string $mode * @return resource - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function fopen($mode); /** + * Compute the hash of the file + * Type of hash is set with $type and can be anything supported by php's hash_file + * * @param string $type * @param bool $raw * @return string diff --git a/lib/public/files/folder.php b/lib/public/files/folder.php index a8e57f7ae2..da7f20fd36 100644 --- a/lib/public/files/folder.php +++ b/lib/public/files/folder.php @@ -8,22 +8,21 @@ namespace OCP\Files; -use OC\Files\Cache\Cache; -use OC\Files\Cache\Scanner; -use OC\Files\NotFoundException; -use OC\Files\NotPermittedException; - interface Folder extends Node { /** - * @param string $path path relative to the folder + * Get the full path of an item in the folder within owncloud's filesystem + * + * @param string $path relative path of an item in the folder * @return string - * @throws \OC\Files\NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function getFullPath($path); /** - * @param string $path - * @throws \OC\Files\NotFoundException + * Get the path of an item in the folder relative to the folder + * + * @param string $path absolute path of an item in the folder + * @throws \OCP\Files\NotFoundException * @return string */ public function getRelativePath($path); @@ -39,7 +38,7 @@ interface Folder extends Node { /** * get the content of this directory * - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException * @return \OCP\Files\Node[] */ public function getDirectoryListing(); @@ -47,29 +46,35 @@ interface Folder extends Node { /** * Get the node at $path * - * @param string $path + * @param string $path relative path of the file or folder * @return \OCP\Files\Node - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function get($path); /** - * @param string $path + * Check if a file or folder exists in the folder + * + * @param string $path relative path of the file or folder * @return bool */ public function nodeExists($path); /** - * @param string $path + * Create a new folder + * + * @param string $path relative path of the new folder * @return \OCP\Files\Folder - * @throws NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function newFolder($path); /** - * @param string $path + * Create a new file + * + * @param string $path relative path of the new file * @return \OCP\Files\File - * @throws NotPermittedException + * @throws \OCP\Files\NotPermittedException */ public function newFile($path); @@ -83,6 +88,7 @@ interface Folder extends Node { /** * search for files by mimetype + * $mimetype can either be a full mimetype (image/png) or a wildcard mimetype (image) * * @param string $mimetype * @return \OCP\Files\Node[] @@ -90,14 +96,23 @@ interface Folder extends Node { public function searchByMime($mimetype); /** - * @param $id + * get a file or folder inside the folder by it's internal id + * + * @param int $id * @return \OCP\Files\Node[] */ public function getById($id); + /** + * Get the amount of free space inside the folder + * + * @return int + */ public function getFreeSpace(); /** + * Check if new files or folders can be created within the folder + * * @return bool */ public function isCreatable(); diff --git a/lib/public/files/node.php b/lib/public/files/node.php index d3b71803f5..42dd910871 100644 --- a/lib/public/files/node.php +++ b/lib/public/files/node.php @@ -10,98 +10,149 @@ namespace OCP\Files; interface Node { /** - * @param string $targetPath - * @throws \OC\Files\NotPermittedException + * Move the file or folder to a new location + * + * @param string $targetPath the absolute target path + * @throws \OCP\Files\NotPermittedException * @return \OCP\Files\Node */ public function move($targetPath); + /** + * Delete the file or folder + */ public function delete(); /** - * @param string $targetPath + * Cope the file or folder to a new location + * + * @param string $targetPath the absolute target path * @return \OCP\Files\Node */ public function copy($targetPath); /** - * @param int $mtime - * @throws \OC\Files\NotPermittedException + * Change the modified date of the file or folder + * If $mtime is omitted the current time will be used + * + * @param int $mtime (optional) modified date as unix timestamp + * @throws \OCP\Files\NotPermittedException */ public function touch($mtime = null); /** + * Get the storage backend the file or folder is stored on + * * @return \OC\Files\Storage\Storage - * @throws \OC\Files\NotFoundException + * @throws \OCP\Files\NotFoundException */ public function getStorage(); /** + * Get the full path of the file or folder + * * @return string */ public function getPath(); /** + * Get the path of the file or folder relative to the mountpoint of it's storage + * * @return string */ public function getInternalPath(); /** + * Get the internal file id for the file or folder + * * @return int */ public function getId(); /** + * Get metadata of the file or folder + * The returned array contains the following values: + * - mtime + * - size + * * @return array */ public function stat(); /** + * Get the modified date of the file or folder as unix timestamp + * * @return int */ public function getMTime(); /** + * Get the size of the file or folder in bytes + * * @return int */ public function getSize(); /** + * Get the Etag of the file or folder + * The Etag is an string id used to detect changes to a file or folder, + * every time the file or folder is changed the Etag will change to + * * @return string */ public function getEtag(); + /** + * Get the permissions of the file or folder as a combination of one or more of the following constants: + * - \OCP\PERMISSION_READ + * - \OCP\PERMISSION_UPDATE + * - \OCP\PERMISSION_CREATE + * - \OCP\PERMISSION_DELETE + * - \OCP\PERMISSION_SHARE + * * @return int */ public function getPermissions(); /** + * Check if the file or folder is readable + * * @return bool */ public function isReadable(); /** + * Check if the file or folder is writable + * * @return bool */ public function isUpdateable(); /** + * Check if the file or folder is deletable + * * @return bool */ public function isDeletable(); /** + * Check if the file or folder is shareable + * * @return bool */ public function isShareable(); /** - * @return Node + * Get the parent folder of the file or folder + * + * @return Folder */ public function getParent(); /** + * Get the filename of the file or folder + * * @return string */ public function getName(); From 2e5ce091f037f0f1b2d5f97ad8866a82c9118f58 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 10 Sep 2013 20:13:47 +0200 Subject: [PATCH 08/11] add storage backend interface to public namespace --- lib/files/storage/storage.php | 2 +- lib/public/files/node.php | 2 +- lib/public/files/storage.php | 343 ++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 lib/public/files/storage.php diff --git a/lib/files/storage/storage.php b/lib/files/storage/storage.php index c96caebf4a..b673bb9a32 100644 --- a/lib/files/storage/storage.php +++ b/lib/files/storage/storage.php @@ -13,7 +13,7 @@ namespace OC\Files\Storage; * * All paths passed to the storage are relative to the storage and should NOT have a leading slash. */ -interface Storage { +interface Storage extends \OCP\Files\Storage { /** * $parameters is a free form array with the configuration options needed to construct the storage * diff --git a/lib/public/files/node.php b/lib/public/files/node.php index 42dd910871..b3ddf6de62 100644 --- a/lib/public/files/node.php +++ b/lib/public/files/node.php @@ -43,7 +43,7 @@ interface Node { /** * Get the storage backend the file or folder is stored on * - * @return \OC\Files\Storage\Storage + * @return \OCP\Files\Storage * @throws \OCP\Files\NotFoundException */ public function getStorage(); diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php new file mode 100644 index 0000000000..e794662a43 --- /dev/null +++ b/lib/public/files/storage.php @@ -0,0 +1,343 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Files; + +/** + * Provide a common interface to all different storage options + * + * All paths passed to the storage are relative to the storage and should NOT have a leading slash. + */ +interface Storage { + /** + * $parameters is a free form array with the configuration options needed to construct the storage + * + * @param array $parameters + */ + public function __construct($parameters); + + /** + * Get the identifier for the storage, + * the returned id should be the same for every storage object that is created with the same parameters + * and two storage objects with the same id should refer to two storages that display the same files. + * + * @return string + */ + public function getId(); + + /** + * see http://php.net/manual/en/function.mkdir.php + * + * @param string $path + * @return bool + */ + public function mkdir($path); + + /** + * see http://php.net/manual/en/function.rmdir.php + * + * @param string $path + * @return bool + */ + public function rmdir($path); + + /** + * see http://php.net/manual/en/function.opendir.php + * + * @param string $path + * @return resource + */ + public function opendir($path); + + /** + * see http://php.net/manual/en/function.is_dir.php + * + * @param string $path + * @return bool + */ + public function is_dir($path); + + /** + * see http://php.net/manual/en/function.is_file.php + * + * @param string $path + * @return bool + */ + public function is_file($path); + + /** + * see http://php.net/manual/en/function.stat.php + * only the following keys are required in the result: size and mtime + * + * @param string $path + * @return array + */ + public function stat($path); + + /** + * see http://php.net/manual/en/function.filetype.php + * + * @param string $path + * @return bool + */ + public function filetype($path); + + /** + * see http://php.net/manual/en/function.filesize.php + * The result for filesize when called on a folder is required to be 0 + * + * @param string $path + * @return int + */ + public function filesize($path); + + /** + * check if a file can be created in $path + * + * @param string $path + * @return bool + */ + public function isCreatable($path); + + /** + * check if a file can be read + * + * @param string $path + * @return bool + */ + public function isReadable($path); + + /** + * check if a file can be written to + * + * @param string $path + * @return bool + */ + public function isUpdatable($path); + + /** + * check if a file can be deleted + * + * @param string $path + * @return bool + */ + public function isDeletable($path); + + /** + * check if a file can be shared + * + * @param string $path + * @return bool + */ + public function isSharable($path); + + /** + * get the full permissions of a path. + * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php + * + * @param string $path + * @return int + */ + public function getPermissions($path); + + /** + * see http://php.net/manual/en/function.file_exists.php + * + * @param string $path + * @return bool + */ + public function file_exists($path); + + /** + * see http://php.net/manual/en/function.filemtime.php + * + * @param string $path + * @return int + */ + public function filemtime($path); + + /** + * see http://php.net/manual/en/function.file_get_contents.php + * + * @param string $path + * @return string + */ + public function file_get_contents($path); + + /** + * see http://php.net/manual/en/function.file_put_contents.php + * + * @param string $path + * @param string $data + * @return bool + */ + public function file_put_contents($path, $data); + + /** + * see http://php.net/manual/en/function.unlink.php + * + * @param string $path + * @return bool + */ + public function unlink($path); + + /** + * see http://php.net/manual/en/function.rename.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function rename($path1, $path2); + + /** + * see http://php.net/manual/en/function.copy.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function copy($path1, $path2); + + /** + * see http://php.net/manual/en/function.fopen.php + * + * @param string $path + * @param string $mode + * @return resource + */ + public function fopen($path, $mode); + + /** + * get the mimetype for a file or folder + * The mimetype for a folder is required to be "httpd/unix-directory" + * + * @param string $path + * @return string + */ + public function getMimeType($path); + + /** + * see http://php.net/manual/en/function.hash-file.php + * + * @param string $type + * @param string $path + * @param bool $raw + * @return string + */ + public function hash($type, $path, $raw = false); + + /** + * see http://php.net/manual/en/function.free_space.php + * + * @param string $path + * @return int + */ + public function free_space($path); + + /** + * search for occurrences of $query in file names + * + * @param string $query + * @return array + */ + public function search($query); + + /** + * see http://php.net/manual/en/function.touch.php + * If the backend does not support the operation, false should be returned + * + * @param string $path + * @param int $mtime + * @return bool + */ + public function touch($path, $mtime = null); + + /** + * get the path to a local version of the file. + * The local version of the file can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFile($path); + + /** + * get the path to a local version of the folder. + * The local version of the folder can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFolder($path); + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + public function hasUpdated($path, $time); + + /** + * get a cache instance for the storage + * + * @param string $path + * @return \OC\Files\Cache\Cache + */ + public function getCache($path = ''); + + /** + * get a scanner instance for the storage + * + * @param string $path + * @return \OC\Files\Cache\Scanner + */ + public function getScanner($path = ''); + + + /** + * get the user id of the owner of a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path); + + /** + * get a permissions cache instance for the cache + * + * @param string $path + * @return \OC\Files\Cache\Permissions + */ + public function getPermissionsCache($path = ''); + + /** + * get a watcher instance for the cache + * + * @param string $path + * @return \OC\Files\Cache\Watcher + */ + public function getWatcher($path = ''); + + /** + * @return \OC\Files\Cache\Storage + */ + public function getStorageCache(); + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path); +} From b9167196fb331d7197210e4a130e03d32d839b8a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 10 Sep 2013 22:21:49 +0200 Subject: [PATCH 09/11] adjust test cases to namespace changes --- tests/lib/files/node/file.php | 28 ++++++++++++++-------------- tests/lib/files/node/folder.php | 10 +++++----- tests/lib/files/node/integration.php | 4 ++-- tests/lib/files/node/node.php | 2 +- tests/lib/files/node/root.php | 8 ++++---- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/lib/files/node/file.php b/tests/lib/files/node/file.php index 707106373b..76938a0dcc 100644 --- a/tests/lib/files/node/file.php +++ b/tests/lib/files/node/file.php @@ -8,8 +8,8 @@ namespace Test\Files\Node; -use OC\Files\NotFoundException; -use OC\Files\NotPermittedException; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; use OC\Files\View; class File extends \PHPUnit_Framework_TestCase { @@ -106,7 +106,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testDeleteNotPermitted() { $manager = $this->getMock('\OC\Files\Mount\Manager'); @@ -162,7 +162,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testGetContentNotPermitted() { $manager = $this->getMock('\OC\Files\Mount\Manager'); @@ -212,7 +212,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testPutContentNotPermitted() { $manager = $this->getMock('\OC\Files\Mount\Manager'); @@ -327,7 +327,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testFOpenReadNotPermitted() { /** @@ -354,7 +354,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testFOpenReadWriteNoReadPermissions() { /** @@ -381,7 +381,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testFOpenReadWriteNoWritePermissions() { /** @@ -443,7 +443,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testCopyNotPermitted() { /** @@ -483,7 +483,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotFoundException + * @expectedException \OCP\Files\NotFoundException */ public function testCopyNoParent() { /** @@ -510,7 +510,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testCopyParentIsFile() { /** @@ -571,7 +571,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testMoveNotPermitted() { /** @@ -603,7 +603,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotFoundException + * @expectedException \OCP\Files\NotFoundException */ public function testMoveNoParent() { /** @@ -635,7 +635,7 @@ class File extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testMoveParentIsFile() { /** diff --git a/tests/lib/files/node/folder.php b/tests/lib/files/node/folder.php index 691aa612c7..b1589a276b 100644 --- a/tests/lib/files/node/folder.php +++ b/tests/lib/files/node/folder.php @@ -10,8 +10,8 @@ namespace Test\Files\Node; use OC\Files\Cache\Cache; use OC\Files\Node\Node; -use OC\Files\NotFoundException; -use OC\Files\NotPermittedException; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; use OC\Files\View; class Folder extends \PHPUnit_Framework_TestCase { @@ -103,7 +103,7 @@ class Folder extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testDeleteNotPermitted() { $manager = $this->getMock('\OC\Files\Mount\Manager'); @@ -275,7 +275,7 @@ class Folder extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testNewFolderNotPermitted() { $manager = $this->getMock('\OC\Files\Mount\Manager'); @@ -325,7 +325,7 @@ class Folder extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testNewFileNotPermitted() { $manager = $this->getMock('\OC\Files\Mount\Manager'); diff --git a/tests/lib/files/node/integration.php b/tests/lib/files/node/integration.php index c99b6f99eb..bc439c1aa0 100644 --- a/tests/lib/files/node/integration.php +++ b/tests/lib/files/node/integration.php @@ -11,8 +11,8 @@ namespace Test\Files\Node; use OC\Files\Cache\Cache; use OC\Files\Mount\Manager; use OC\Files\Node\Root; -use OC\Files\NotFoundException; -use OC\Files\NotPermittedException; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; use OC\Files\Storage\Temporary; use OC\Files\View; use OC\User\User; diff --git a/tests/lib/files/node/node.php b/tests/lib/files/node/node.php index aa9d2a382e..cf5fec3052 100644 --- a/tests/lib/files/node/node.php +++ b/tests/lib/files/node/node.php @@ -306,7 +306,7 @@ class Node extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testTouchNotPermitted() { $manager = $this->getMock('\OC\Files\Mount\Manager'); diff --git a/tests/lib/files/node/root.php b/tests/lib/files/node/root.php index 0b356ec6d9..97eaf7f716 100644 --- a/tests/lib/files/node/root.php +++ b/tests/lib/files/node/root.php @@ -9,7 +9,7 @@ namespace Test\Files\Node; use OC\Files\Cache\Cache; -use OC\Files\NotPermittedException; +use OCP\Files\NotPermittedException; use OC\Files\Mount\Manager; class Root extends \PHPUnit_Framework_TestCase { @@ -53,7 +53,7 @@ class Root extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotFoundException + * @expectedException \OCP\Files\NotFoundException */ public function testGetNotFound() { $manager = new Manager(); @@ -77,7 +77,7 @@ class Root extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotPermittedException + * @expectedException \OCP\Files\NotPermittedException */ public function testGetInvalidPath() { $manager = new Manager(); @@ -91,7 +91,7 @@ class Root extends \PHPUnit_Framework_TestCase { } /** - * @expectedException \OC\Files\NotFoundException + * @expectedException \OCP\Files\NotFoundException */ public function testGetNoStorages() { $manager = new Manager(); From 58ed78aa9eb3c6b7986c7eb84668bdb5e65c0b13 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 12 Sep 2013 21:58:32 +0200 Subject: [PATCH 10/11] cleanup public storage interface a bit --- lib/public/files/storage.php | 46 ------------------------------------ 1 file changed, 46 deletions(-) diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index e794662a43..f32f207348 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -287,52 +287,6 @@ interface Storage { */ public function hasUpdated($path, $time); - /** - * get a cache instance for the storage - * - * @param string $path - * @return \OC\Files\Cache\Cache - */ - public function getCache($path = ''); - - /** - * get a scanner instance for the storage - * - * @param string $path - * @return \OC\Files\Cache\Scanner - */ - public function getScanner($path = ''); - - - /** - * get the user id of the owner of a file or folder - * - * @param string $path - * @return string - */ - public function getOwner($path); - - /** - * get a permissions cache instance for the cache - * - * @param string $path - * @return \OC\Files\Cache\Permissions - */ - public function getPermissionsCache($path = ''); - - /** - * get a watcher instance for the cache - * - * @param string $path - * @return \OC\Files\Cache\Watcher - */ - public function getWatcher($path = ''); - - /** - * @return \OC\Files\Cache\Storage - */ - public function getStorageCache(); - /** * get the ETag for a file or folder * From 6eeb4d165c5a0eb0c49375aa4141c59d6a63f164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 13 Sep 2013 21:44:31 +0200 Subject: [PATCH 11/11] - giving the user a new id for each test run in order to prevent reuse of e.g. permissions data in the database - setting the current user id because \OC\FilesView relies on \OC_User::getUser() --- tests/lib/files/node/integration.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/files/node/integration.php b/tests/lib/files/node/integration.php index bc439c1aa0..14e1d05853 100644 --- a/tests/lib/files/node/integration.php +++ b/tests/lib/files/node/integration.php @@ -45,7 +45,8 @@ class IntegrationTests extends \PHPUnit_Framework_TestCase { \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook'); \OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook'); - $user = new User('', new \OC_User_Dummy); + $user = new User(uniqid('user'), new \OC_User_Dummy); + \OC_User::setUserId($user->getUID()); $this->view = new View(); $this->root = new Root($manager, $this->view, $user); $storage = new Temporary(array());