Merge pull request #12426 from owncloud/jail-mask-wrappers

Add Jail and PermissionsMask storage wrappers
This commit is contained in:
Robin Appelman 2014-11-27 16:00:14 +01:00
commit 05a069c101
11 changed files with 1384 additions and 5 deletions

View File

@ -585,7 +585,7 @@ class Cache {
/**
* find a folder in the cache which has not been fully scanned
*
* If multiply incomplete folders are in the cache, the one with the highest id will be returned,
* If multiple incomplete folders are in the cache, the one with the highest id will be returned,
* use the one with the highest id gives the best result with the background scanner, since that is most
* likely the folder where we stopped scanning previously
*

View File

@ -0,0 +1,255 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Cache\Wrapper;
/**
* Jail to a subdirectory of the wrapped cache
*/
class CacheJail extends CacheWrapper {
/**
* @var string
*/
protected $root;
/**
* @param \OC\Files\Cache\Cache $cache
* @param string $root
*/
public function __construct($cache, $root) {
parent::__construct($cache);
$this->root = $root;
}
protected function getSourcePath($path) {
if ($path === '') {
return $this->root;
} else {
return $this->root . '/' . $path;
}
}
/**
* @param string $path
* @return null|string the jailed path or null if the path is outside the jail
*/
protected function getJailedPath($path) {
$rootLength = strlen($this->root) + 1;
if ($path === $this->root) {
return '';
} else if (substr($path, 0, $rootLength) === $this->root . '/') {
return substr($path, $rootLength);
} else {
return null;
}
}
/**
* @param array $entry
* @return array
*/
protected function formatCacheEntry($entry) {
if (isset($entry['path'])) {
$entry['path'] = $this->getJailedPath($entry['path']);
}
return $entry;
}
protected function filterCacheEntry($entry) {
$rootLength = strlen($this->root) + 1;
return ($entry['path'] === $this->root) or (substr($entry['path'], 0, $rootLength) === $this->root . '/');
}
/**
* get the stored metadata of a file or folder
*
* @param string /int $file
* @return array|false
*/
public function get($file) {
if (is_string($file) or $file == '') {
$file = $this->getSourcePath($file);
}
return parent::get($file);
}
/**
* store meta data for a file or folder
*
* @param string $file
* @param array $data
*
* @return int file id
*/
public function put($file, array $data) {
return $this->cache->put($this->getSourcePath($file), $data);
}
/**
* update the metadata in the cache
*
* @param int $id
* @param array $data
*/
public function update($id, array $data) {
$this->cache->update($this->getSourcePath($id), $data);
}
/**
* get the file id for a file
*
* @param string $file
* @return int
*/
public function getId($file) {
return $this->cache->getId($this->getSourcePath($file));
}
/**
* get the id of the parent folder of a file
*
* @param string $file
* @return int
*/
public function getParentId($file) {
if ($file === '') {
return -1;
} else {
return $this->cache->getParentId($this->getSourcePath($file));
}
}
/**
* check if a file is available in the cache
*
* @param string $file
* @return bool
*/
public function inCache($file) {
return $this->cache->inCache($this->getSourcePath($file));
}
/**
* remove a file or folder from the cache
*
* @param string $file
*/
public function remove($file) {
$this->cache->remove($this->getSourcePath($file));
}
/**
* Move a file or folder in the cache
*
* @param string $source
* @param string $target
*/
public function move($source, $target) {
$this->cache->move($this->getSourcePath($source), $this->getSourcePath($target));
}
/**
* remove all entries for files that are stored on the storage from the cache
*/
public function clear() {
$this->cache->remove($this->root);
}
/**
* @param string $file
*
* @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
*/
public function getStatus($file) {
return $this->cache->getStatus($this->getSourcePath($file));
}
private function formatSearchResults($results) {
$results = array_filter($results, array($this, 'filterCacheEntry'));
$results = array_values($results);
return array_map(array($this, 'formatCacheEntry'), $results);
}
/**
* search for files matching $pattern
*
* @param string $pattern
* @return array an array of file data
*/
public function search($pattern) {
$results = $this->cache->search($pattern);
return $this->formatSearchResults($results);
}
/**
* search for files by mimetype
*
* @param string $mimetype
* @return array
*/
public function searchByMime($mimetype) {
$results = $this->cache->searchByMime($mimetype);
return $this->formatSearchResults($results);
}
/**
* update the folder size and the size of all parent folders
*
* @param string|boolean $path
* @param array $data (optional) meta data of the folder
*/
public function correctFolderSize($path, $data = null) {
$this->cache->correctFolderSize($this->getSourcePath($path), $data);
}
/**
* get the size of a folder and set it in the cache
*
* @param string $path
* @param array $entry (optional) meta data of the folder
* @return int
*/
public function calculateFolderSize($path, $entry = null) {
return $this->cache->calculateFolderSize($this->getSourcePath($path), $entry);
}
/**
* get all file ids on the files on the storage
*
* @return int[]
*/
public function getAll() {
// not supported
return array();
}
/**
* find a folder in the cache which has not been fully scanned
*
* If multiply incomplete folders are in the cache, the one with the highest id will be returned,
* use the one with the highest id gives the best result with the background scanner, since that is most
* likely the folder where we stopped scanning previously
*
* @return string|bool the path of the folder or false when no folder matched
*/
public function getIncomplete() {
// not supported
return false;
}
/**
* get the path of a file on this storage by it's id
*
* @param int $id
* @return string|null
*/
public function getPathById($id) {
$path = $this->cache->getPathById($id);
return $this->getJailedPath($path);
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Cache\Wrapper;
class CachePermissionsMask extends CacheWrapper {
/**
* @var int
*/
protected $mask;
/**
* @param \OC\Files\Cache\Cache $cache
* @param int $mask
*/
public function __construct($cache, $mask) {
parent::__construct($cache);
$this->mask = $mask;
}
protected function formatCacheEntry($entry) {
if (isset($entry['permissions'])) {
$entry['permissions'] &= $this->mask;
}
return $entry;
}
}

View File

@ -0,0 +1,247 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Cache\Wrapper;
use OC\Files\Cache\Cache;
class CacheWrapper extends Cache {
/**
* @var \OC\Files\Cache\Cache
*/
protected $cache;
/**
* @param \OC\Files\Cache\Cache $cache
*/
public function __construct($cache) {
$this->cache = $cache;
}
/**
* Make it easy for wrappers to modify every returned cache entry
*
* @param array $entry
* @return array
*/
protected function formatCacheEntry($entry) {
return $entry;
}
/**
* get the stored metadata of a file or folder
*
* @param string /int $file
* @return array|false
*/
public function get($file) {
$result = $this->cache->get($file);
if ($result) {
$result = $this->formatCacheEntry($result);
}
return $result;
}
/**
* get the metadata of all files stored in $folder
*
* @param string $folder
* @return array
*/
public function getFolderContents($folder) {
// cant do a simple $this->cache->.... call here since getFolderContentsById needs to be called on this
// and not the wrapped cache
$fileId = $this->getId($folder);
return $this->getFolderContentsById($fileId);
}
/**
* get the metadata of all files stored in $folder
*
* @param int $fileId the file id of the folder
* @return array
*/
public function getFolderContentsById($fileId) {
$results = $this->cache->getFolderContentsById($fileId);
return array_map(array($this, 'formatCacheEntry'), $results);
}
/**
* store meta data for a file or folder
*
* @param string $file
* @param array $data
*
* @return int file id
*/
public function put($file, array $data) {
return $this->cache->put($file, $data);
}
/**
* update the metadata in the cache
*
* @param int $id
* @param array $data
*/
public function update($id, array $data) {
$this->cache->update($id, $data);
}
/**
* get the file id for a file
*
* @param string $file
* @return int
*/
public function getId($file) {
return $this->cache->getId($file);
}
/**
* get the id of the parent folder of a file
*
* @param string $file
* @return int
*/
public function getParentId($file) {
return $this->cache->getParentId($file);
}
/**
* check if a file is available in the cache
*
* @param string $file
* @return bool
*/
public function inCache($file) {
return $this->cache->inCache($file);
}
/**
* remove a file or folder from the cache
*
* @param string $file
*/
public function remove($file) {
$this->cache->remove($file);
}
/**
* Move a file or folder in the cache
*
* @param string $source
* @param string $target
*/
public function move($source, $target) {
$this->cache->move($source, $target);
}
/**
* remove all entries for files that are stored on the storage from the cache
*/
public function clear() {
$this->cache->clear();
}
/**
* @param string $file
*
* @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
*/
public function getStatus($file) {
return $this->cache->getStatus($file);
}
/**
* search for files matching $pattern
*
* @param string $pattern
* @return array an array of file data
*/
public function search($pattern) {
$results = $this->cache->search($pattern);
return array_map(array($this, 'formatCacheEntry'), $results);
}
/**
* search for files by mimetype
*
* @param string $mimetype
* @return array
*/
public function searchByMime($mimetype) {
$results = $this->cache->searchByMime($mimetype);
return array_map(array($this, 'formatCacheEntry'), $results);
}
/**
* update the folder size and the size of all parent folders
*
* @param string|boolean $path
* @param array $data (optional) meta data of the folder
*/
public function correctFolderSize($path, $data = null) {
$this->cache->correctFolderSize($path, $data);
}
/**
* get the size of a folder and set it in the cache
*
* @param string $path
* @param array $entry (optional) meta data of the folder
* @return int
*/
public function calculateFolderSize($path, $entry = null) {
return $this->cache->calculateFolderSize($path, $entry);
}
/**
* get all file ids on the files on the storage
*
* @return int[]
*/
public function getAll() {
return $this->cache->getAll();
}
/**
* find a folder in the cache which has not been fully scanned
*
* If multiple incomplete folders are in the cache, the one with the highest id will be returned,
* use the one with the highest id gives the best result with the background scanner, since that is most
* likely the folder where we stopped scanning previously
*
* @return string|bool the path of the folder or false when no folder matched
*/
public function getIncomplete() {
return $this->cache->getIncomplete();
}
/**
* get the path of a file on this storage by it's id
*
* @param int $id
* @return string|null
*/
public function getPathById($id) {
return $this->cache->getPathById($id);
}
/**
* get the storage id of the storage for a file and the internal path of the file
* unlike getPathById this does not limit the search to files on this storage and
* instead does a global search in the cache table
*
* @param int $id
* @return array, first element holding the storage id, second the path
*/
static public function getById($id) {
return parent::getById($id);
}
}

View File

@ -0,0 +1,413 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Storage\Wrapper;
use OC\Files\Cache\Wrapper\CacheJail;
/**
* Jail to a subdirectory of the wrapped storage
*
* This restricts access to a subfolder of the wrapped storage with the subfolder becoming the root folder new storage
*/
class Jail extends Wrapper {
/**
* @var string
*/
protected $rootPath;
/**
* @param array $arguments ['storage' => $storage, 'mask' => $root]
*
* $storage: The storage that will be wrapper
* $root: The folder in the wrapped storage that will become the root folder of the wrapped storage
*/
public function __construct($arguments) {
parent::__construct($arguments);
$this->rootPath = $arguments['root'];
}
protected function getSourcePath($path) {
if ($path === '') {
return $this->rootPath;
} else {
return $this->rootPath . '/' . $path;
}
}
public function getId() {
return 'link:' . parent::getId() . ':' . $this->rootPath;
}
/**
* see http://php.net/manual/en/function.mkdir.php
*
* @param string $path
* @return bool
*/
public function mkdir($path) {
return $this->storage->mkdir($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.rmdir.php
*
* @param string $path
* @return bool
*/
public function rmdir($path) {
return $this->storage->rmdir($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.opendir.php
*
* @param string $path
* @return resource
*/
public function opendir($path) {
return $this->storage->opendir($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.is_dir.php
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
return $this->storage->is_dir($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.is_file.php
*
* @param string $path
* @return bool
*/
public function is_file($path) {
return $this->storage->is_file($this->getSourcePath($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) {
return $this->storage->stat($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.filetype.php
*
* @param string $path
* @return bool
*/
public function filetype($path) {
return $this->storage->filetype($this->getSourcePath($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) {
return $this->storage->filesize($this->getSourcePath($path));
}
/**
* check if a file can be created in $path
*
* @param string $path
* @return bool
*/
public function isCreatable($path) {
return $this->storage->isCreatable($this->getSourcePath($path));
}
/**
* check if a file can be read
*
* @param string $path
* @return bool
*/
public function isReadable($path) {
return $this->storage->isReadable($this->getSourcePath($path));
}
/**
* check if a file can be written to
*
* @param string $path
* @return bool
*/
public function isUpdatable($path) {
return $this->storage->isUpdatable($this->getSourcePath($path));
}
/**
* check if a file can be deleted
*
* @param string $path
* @return bool
*/
public function isDeletable($path) {
return $this->storage->isDeletable($this->getSourcePath($path));
}
/**
* check if a file can be shared
*
* @param string $path
* @return bool
*/
public function isSharable($path) {
return $this->storage->isSharable($this->getSourcePath($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) {
return $this->storage->getPermissions($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.file_exists.php
*
* @param string $path
* @return bool
*/
public function file_exists($path) {
return $this->storage->file_exists($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.filemtime.php
*
* @param string $path
* @return int
*/
public function filemtime($path) {
return $this->storage->filemtime($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.file_get_contents.php
*
* @param string $path
* @return string
*/
public function file_get_contents($path) {
return $this->storage->file_get_contents($this->getSourcePath($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) {
return $this->storage->file_put_contents($this->getSourcePath($path), $data);
}
/**
* see http://php.net/manual/en/function.unlink.php
*
* @param string $path
* @return bool
*/
public function unlink($path) {
return $this->storage->unlink($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @return bool
*/
public function rename($path1, $path2) {
return $this->storage->rename($this->getSourcePath($path1), $this->getSourcePath($path2));
}
/**
* see http://php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @return bool
*/
public function copy($path1, $path2) {
return $this->storage->copy($this->getSourcePath($path1), $this->getSourcePath($path2));
}
/**
* see http://php.net/manual/en/function.fopen.php
*
* @param string $path
* @param string $mode
* @return resource
*/
public function fopen($path, $mode) {
return $this->storage->fopen($this->getSourcePath($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) {
return $this->storage->getMimeType($this->getSourcePath($path));
}
/**
* see http://php.net/manual/en/function.hash.php
*
* @param string $type
* @param string $path
* @param bool $raw
* @return string
*/
public function hash($type, $path, $raw = false) {
return $this->storage->hash($type, $this->getSourcePath($path), $raw);
}
/**
* see http://php.net/manual/en/function.free_space.php
*
* @param string $path
* @return int
*/
public function free_space($path) {
return $this->storage->free_space($this->getSourcePath($path));
}
/**
* search for occurrences of $query in file names
*
* @param string $query
* @return array
*/
public function search($query) {
return $this->storage->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) {
return $this->storage->touch($this->getSourcePath($path), $mtime);
}
/**
* 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) {
return $this->storage->getLocalFile($this->getSourcePath($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) {
return $this->storage->getLocalFolder($this->getSourcePath($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) {
return $this->storage->hasUpdated($this->getSourcePath($path), $time);
}
/**
* get a cache instance for the storage
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
* @return \OC\Files\Cache\Cache
*/
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
$sourceCache = $this->storage->getCache($this->getSourcePath($path), $storage);
return new CacheJail($sourceCache, $this->rootPath);
}
/**
* get the user id of the owner of a file or folder
*
* @param string $path
* @return string
*/
public function getOwner($path) {
return $this->storage->getOwner($this->getSourcePath($path));
}
/**
* get a watcher instance for the cache
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
* @return \OC\Files\Cache\Watcher
*/
public function getWatcher($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return $this->storage->getWatcher($this->getSourcePath($path), $storage);
}
/**
* get the ETag for a file or folder
*
* @param string $path
* @return string
*/
public function getETag($path) {
return $this->storage->getETag($this->getSourcePath($path));
}
}

View File

@ -0,0 +1,111 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Storage\Wrapper;
use OC\Files\Cache\Wrapper\CachePermissionsMask;
use OCP\Constants;
/**
* Mask the permissions of a storage
*
* This can be used to restrict update, create, delete and/or share permissions of a storage
*
* Note that the read permissions cant be masked
*/
class PermissionsMask extends Wrapper {
/**
* @var int the permissions bits we want to keep
*/
private $mask;
/**
* @param array $arguments ['storage' => $storage, 'mask' => $mask]
*
* $storage: The storage the permissions mask should be applied on
* $mask: The permission bits that should be kept, a combination of the \OCP\Constant::PERMISSION_ constants
*/
public function __construct($arguments) {
parent::__construct($arguments);
$this->mask = $arguments['mask'];
}
private function checkMask($permissions) {
return ($this->mask & $permissions) === $permissions;
}
public function isUpdatable($path) {
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::isUpdatable($path);
}
public function isCreatable($path) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::isCreatable($path);
}
public function isDeletable($path) {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::isDeletable($path);
}
public function getPermissions($path) {
return $this->storage->getPermissions($path) & $this->mask;
}
public function rename($path1, $path2) {
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($path1, $path2);
}
public function copy($path1, $path2) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($path1, $path2);
}
public function touch($path, $mtime = null) {
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE;
return $this->checkMask($permissions) and parent::touch($path, $mtime);
}
public function mkdir($path) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::mkdir($path);
}
public function rmdir($path) {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::rmdir($path);
}
public function unlink($path) {
return $this->checkMask(Constants::PERMISSION_DELETE) and parent::unlink($path);
}
public function file_put_contents($path, $data) {
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE;
return $this->checkMask($permissions) and parent::file_put_contents($path, $data);
}
public function fopen($path, $mode) {
if ($mode === 'r' or $mode === 'rb') {
return parent::fopen($path, $mode);
} else {
$permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE;
return $this->checkMask($permissions) ? parent::fopen($path, $mode) : false;
}
}
/**
* get a cache instance for the storage
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
* @return \OC\Files\Cache\Cache
*/
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
$sourceCache = parent::getCache($path, $storage);
return new CachePermissionsMask($sourceCache, $this->mask);
}
}

View File

@ -20,20 +20,20 @@ class Cache extends \Test\TestCase {
/**
* @var \OC\Files\Storage\Temporary $storage ;
*/
private $storage;
protected $storage;
/**
* @var \OC\Files\Storage\Temporary $storage2 ;
*/
private $storage2;
protected $storage2;
/**
* @var \OC\Files\Cache\Cache $cache
*/
private $cache;
protected $cache;
/**
* @var \OC\Files\Cache\Cache $cache2
*/
private $cache2;
protected $cache2;
public function testSimple() {
$file1 = 'foo';

View File

@ -0,0 +1,67 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace Test\Files\Cache\Wrapper;
use Test\Files\Cache\Cache;
class CacheJail extends Cache {
/**
* @var \OC\Files\Cache\Cache $sourceCache
*/
protected $sourceCache;
public function setUp() {
parent::setUp();
$this->storage->mkdir('foo');
$this->sourceCache = $this->cache;
$this->cache = new \OC\Files\Cache\Wrapper\CacheJail($this->sourceCache, 'foo');
}
function testSearchOutsideJail() {
$file1 = 'foo/foobar';
$file2 = 'folder/foobar';
$data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder');
$this->sourceCache->put($file1, $data1);
$this->sourceCache->put($file2, $data1);
$this->assertCount(2, $this->sourceCache->search('%foobar'));
$result = $this->cache->search('%foobar%');
$this->assertCount(1, $result);
$this->assertEquals('foobar', $result[0]['path']);
}
function testClearKeepEntriesOutsideJail() {
$file1 = 'foo/foobar';
$file2 = 'foo/foobar/asd';
$file3 = 'folder/foobar';
$data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
$this->sourceCache->put('foo', $data1);
$this->sourceCache->put($file1, $data1);
$this->sourceCache->put($file2, $data1);
$this->sourceCache->put($file3, $data1);
$this->cache->clear();
$this->assertFalse($this->cache->inCache('foobar'));
$this->assertTrue($this->sourceCache->inCache('folder/foobar'));
}
function testGetById() {
//not supported
$this->assertTrue(true);
}
function testGetIncomplete() {
//not supported
$this->assertTrue(true);
}
}

View File

@ -0,0 +1,94 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace Test\Files\Cache\Wrapper;
use OCP\Constants;
use Test\Files\Cache\Cache;
class CachePermissionsMask extends Cache {
/**
* @var \OC\Files\Cache\Cache $sourceCache
*/
protected $sourceCache;
public function setUp() {
parent::setUp();
$this->storage->mkdir('foo');
$this->sourceCache = $this->cache;
$this->cache = $this->getMaskedCached(Constants::PERMISSION_ALL);
}
protected function getMaskedCached($mask) {
return new \OC\Files\Cache\Wrapper\CachePermissionsMask($this->sourceCache, $mask);
}
public function maskProvider() {
return array(
array(Constants::PERMISSION_ALL),
array(Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE),
array(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE),
array(Constants::PERMISSION_READ)
);
}
/**
* @dataProvider maskProvider
* @param int $mask
*/
public function testGetMasked($mask) {
$cache = $this->getMaskedCached($mask);
$data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain', 'permissions' => Constants::PERMISSION_ALL);
$this->sourceCache->put('foo', $data);
$result = $cache->get('foo');
$this->assertEquals($mask, $result['permissions']);
$data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain', 'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE);
$this->sourceCache->put('bar', $data);
$result = $cache->get('bar');
$this->assertEquals($mask & ~Constants::PERMISSION_DELETE, $result['permissions']);
}
/**
* @dataProvider maskProvider
* @param int $mask
*/
public function testGetFolderContentMasked($mask) {
$this->storage->mkdir('foo');
$this->storage->file_put_contents('foo/bar', 'asd');
$this->storage->file_put_contents('foo/asd', 'bar');
$this->storage->getScanner()->scan('');
$cache = $this->getMaskedCached($mask);
$files = $cache->getFolderContents('foo');
$this->assertCount(2, $files);
foreach ($files as $file) {
$this->assertEquals($mask & ~Constants::PERMISSION_CREATE, $file['permissions']);
}
}
/**
* @dataProvider maskProvider
* @param int $mask
*/
public function testSearchMasked($mask) {
$this->storage->mkdir('foo');
$this->storage->file_put_contents('foo/bar', 'asd');
$this->storage->file_put_contents('foo/foobar', 'bar');
$this->storage->getScanner()->scan('');
$cache = $this->getMaskedCached($mask);
$files = $cache->search('%bar');
$this->assertCount(2, $files);
foreach ($files as $file) {
$this->assertEquals($mask & ~Constants::PERMISSION_CREATE, $file['permissions']);
}
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace Test\Files\Storage\Wrapper;
class Jail extends \Test\Files\Storage\Storage {
/**
* @var string tmpDir
*/
private $tmpDir;
/**
* @var \OC\Files\Storage\Temporary
*/
private $sourceStorage;
public function setUp() {
parent::setUp();
$this->sourceStorage = new \OC\Files\Storage\Temporary(array());
$this->sourceStorage->mkdir('foo');
$this->instance = new \OC\Files\Storage\Wrapper\Jail(array(
'storage' => $this->sourceStorage,
'root' => 'foo'
));
}
public function tearDown() {
// test that nothing outside our jail is touched
$contents = array();
$dh = $this->sourceStorage->opendir('');
while ($file = readdir($dh)) {
if ($file !== '.' and $file !== '..') {
$contents[] = $file;
}
}
$this->assertEquals(array('foo'), $contents);
$this->sourceStorage->cleanUp();
parent::tearDown();
}
public function testMkDirRooted() {
$this->instance->mkdir('bar');
$this->assertTrue($this->sourceStorage->is_dir('foo/bar'));
}
public function testFilePutContentsRooted() {
$this->instance->file_put_contents('bar', 'asd');
$this->assertEquals('asd', $this->sourceStorage->file_get_contents('foo/bar'));
}
}

View File

@ -0,0 +1,105 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace Test\Files\Storage\Wrapper;
use OCP\Constants;
class PermissionsMask extends \Test\Files\Storage\Storage {
/**
* @var \OC\Files\Storage\Temporary
*/
private $sourceStorage;
public function setUp() {
parent::setUp();
$this->sourceStorage = new \OC\Files\Storage\Temporary(array());
$this->instance = $this->getMaskedStorage(Constants::PERMISSION_ALL);
}
public function tearDown() {
$this->sourceStorage->cleanUp();
parent::tearDown();
}
protected function getMaskedStorage($mask) {
return new \OC\Files\Storage\Wrapper\PermissionsMask(array(
'storage' => $this->sourceStorage,
'mask' => $mask
));
}
public function testMkdirNoCreate() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE);
$this->assertFalse($storage->mkdir('foo'));
$this->assertFalse($storage->file_exists('foo'));
}
public function testRmdirNoDelete() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE);
$this->assertTrue($storage->mkdir('foo'));
$this->assertTrue($storage->file_exists('foo'));
$this->assertFalse($storage->rmdir('foo'));
$this->assertTrue($storage->file_exists('foo'));
}
public function testTouchNewFileNoCreate() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE);
$this->assertFalse($storage->touch('foo'));
$this->assertFalse($storage->file_exists('foo'));
}
public function testTouchNewFileNoUpdate() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE);
$this->assertTrue($storage->touch('foo'));
$this->assertTrue($storage->file_exists('foo'));
}
public function testTouchExistingFileNoUpdate() {
$this->sourceStorage->touch('foo');
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE);
$this->assertFalse($storage->touch('foo'));
}
public function testUnlinkNoDelete() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE);
$this->assertTrue($storage->touch('foo'));
$this->assertTrue($storage->file_exists('foo'));
$this->assertFalse($storage->unlink('foo'));
$this->assertTrue($storage->file_exists('foo'));
}
public function testPutContentsNewFileNoUpdate() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE);
$this->assertTrue($storage->file_put_contents('foo', 'bar'));
$this->assertEquals('bar', $storage->file_get_contents('foo'));
}
public function testPutContentsNewFileNoCreate() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE);
$this->assertFalse($storage->file_put_contents('foo', 'bar'));
}
public function testPutContentsExistingFileNoUpdate() {
$this->sourceStorage->touch('foo');
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE);
$this->assertFalse($storage->file_put_contents('foo', 'bar'));
}
public function testFopenExistingFileNoUpdate() {
$this->sourceStorage->touch('foo');
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE);
$this->assertFalse($storage->fopen('foo', 'w'));
}
public function testFopenNewFileNoCreate() {
$storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE);
$this->assertFalse($storage->fopen('foo', 'w'));
}
}