summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2014-11-10 16:00:08 +0100
committerRobin Appelman <icewind@owncloud.com>2014-11-27 15:25:53 +0100
commitabb6e89c5d83102c2838bd6a48b5bf6e73e9660d (patch)
treeb2fab37864f6f904c4560bf111dcbf6d72e69401 /lib
parenta2172786a8cbdcac58906df03713f21a98694119 (diff)
downloadnextcloud-server-abb6e89c5d83102c2838bd6a48b5bf6e73e9660d.tar.gz
nextcloud-server-abb6e89c5d83102c2838bd6a48b5bf6e73e9660d.zip
Add storage and cache wrappers to jail a storage to a subfolder
Diffstat (limited to 'lib')
-rw-r--r--lib/private/files/cache/cache.php2
-rw-r--r--lib/private/files/cache/wrapper/cachejail.php255
-rw-r--r--lib/private/files/cache/wrapper/cachewrapper.php247
-rw-r--r--lib/private/files/storage/wrapper/jail.php413
-rw-r--r--lib/private/files/storage/wrapper/permissionsmask.php102
5 files changed, 1018 insertions, 1 deletions
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php
index 2c12f834518..4157da2281c 100644
--- a/lib/private/files/cache/cache.php
+++ b/lib/private/files/cache/cache.php
@@ -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
*
diff --git a/lib/private/files/cache/wrapper/cachejail.php b/lib/private/files/cache/wrapper/cachejail.php
new file mode 100644
index 00000000000..7982293f5ed
--- /dev/null
+++ b/lib/private/files/cache/wrapper/cachejail.php
@@ -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);
+ }
+}
diff --git a/lib/private/files/cache/wrapper/cachewrapper.php b/lib/private/files/cache/wrapper/cachewrapper.php
new file mode 100644
index 00000000000..040358ec657
--- /dev/null
+++ b/lib/private/files/cache/wrapper/cachewrapper.php
@@ -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);
+ }
+}
diff --git a/lib/private/files/storage/wrapper/jail.php b/lib/private/files/storage/wrapper/jail.php
new file mode 100644
index 00000000000..22b96765757
--- /dev/null
+++ b/lib/private/files/storage/wrapper/jail.php
@@ -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));
+ }
+}
diff --git a/lib/private/files/storage/wrapper/permissionsmask.php b/lib/private/files/storage/wrapper/permissionsmask.php
new file mode 100644
index 00000000000..be5cb6bbaa3
--- /dev/null
+++ b/lib/private/files/storage/wrapper/permissionsmask.php
@@ -0,0 +1,102 @@
+<?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;
+
+/**
+ * Mask the permissions of a storage
+ *
+ * Note that the read permissions cant be masked
+ */
+class PermissionsMask extends Wrapper {
+ /**
+ * @var int
+ */
+ private $mask;
+
+ 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(\OCP\PERMISSION_UPDATE) and parent::isUpdatable($path);
+ }
+
+ public function isCreatable($path) {
+ return $this->checkMask(\OCP\PERMISSION_CREATE) and parent::isCreatable($path);
+ }
+
+ public function isDeletable($path) {
+ return $this->checkMask(\OCP\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(\OCP\PERMISSION_UPDATE) and parent::rename($path1, $path2);
+ }
+
+ public function copy($path1, $path2) {
+ return $this->checkMask(\OCP\PERMISSION_CREATE) and parent::copy($path1, $path2);
+ }
+
+ public function touch($path, $mtime = null) {
+ $permissions = $this->file_exists($path) ? \OCP\PERMISSION_UPDATE : \OCP\PERMISSION_CREATE;
+ return $this->checkMask($permissions) and parent::touch($path, $mtime);
+ }
+
+ public function mkdir($path) {
+ return $this->checkMask(\OCP\PERMISSION_CREATE) and parent::mkdir($path);
+ }
+
+ public function rmdir($path) {
+ return $this->checkMask(\OCP\PERMISSION_DELETE) and parent::rmdir($path);
+ }
+
+ public function unlink($path) {
+ return $this->checkMask(\OCP\PERMISSION_DELETE) and parent::unlink($path);
+ }
+
+ public function file_put_contents($path, $data) {
+ $permissions = $this->file_exists($path) ? \OCP\PERMISSION_UPDATE : \OCP\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) ? \OCP\PERMISSION_UPDATE : \OCP\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);
+ }
+}
n> : "Válido hasta %s", "Import root certificate" : "Importar certificado raíz", "Administrator documentation" : "Documentación del adminsitrador", "Documentation" : "Documentación", "Forum" : "Foro", "None" : "Ninguno", "Login" : "Iniciar sesión", "Plain" : "Plano", "NT LAN Manager" : "Administrador de LAN NT", "SSL/TLS" : "SSL/TLS", "STARTTLS" : "STARTTLS", "Email server" : "Servidor de correo electrónico", "Open documentation" : "Abrir documentación", "It is important to set up this server to be able to send emails, like for password reset and notifications." : "Es importante preparar este servidor para poder enviar correos electrónicos, como para restablecer contraseñas y notificaciones. ", "Send mode" : "Modo de envío", "Encryption" : "Encripción", "From address" : "De la dirección", "mail" : "correo", "Authentication method" : "Método de autenticación", "Authentication required" : "Autenticación requerida", "Server address" : "Dirección del servidor", "Port" : "Puerto", "Credentials" : "Credenciales", "SMTP Username" : "Usuario SMTP", "SMTP Password" : "Contraseña SMTP", "Save" : "Guardar", "Test email settings" : "Probar las configuraciones de correo electrónico", "Send email" : "Enviar correo electrónico", "Security & setup warnings" : "Advertencias de seguridad y configuración", "All checks passed." : "Pasaron todas las verificaciones. ", "Version" : "Versión", "Server-side encryption" : "Encripción del lado del servidor", "Server-side encryption makes it possible to encrypt files which are uploaded to this server. This comes with limitations like a performance penalty, so enable this only if needed." : "La encripción del lado del servidor hace posible encriptar archivos que serán cargados a este servidor. Esto trae consigo algunas limitaciónes como penalizaciones en el desemeño, asi que habilítalo sólo si es necesario. ", "Enable server-side encryption" : "Habilitar encripción del lado del servidor", "Please read carefully before activating server-side encryption: " : "Por favor lee detenidamente antes de activar la encripción del lado de servidor:", "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Una vez que la encripción se encuentre habilitada, todos lo archivos cargados al servidor desde ese momento en tiempo, se encriptarán en el servidor. Sólo será posible deshabilitar la encripción en una fecha posterior si el modulo de encripción activo soporta esa funcionalidad y si todas las preciondiciones están satisfechas (ejem. establecer una llave de recuperación).", "Encryption alone does not guarantee security of the system. Please see documentation for more information about how the encryption app works, and the supported use cases." : "La encripción por sí sola no garantiza la seguridad del sistema. Por favor consulta la documentación para mayores informes de cómo funciona la aplicación de encripción y de los casos de uso soportados. ", "Be aware that encryption always increases the file size." : "Por favor considera que la encripción siempre aumenta el tamaño de los archivos. ", "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Siempre es una buena idea generar respaldos de tus datos, en caso de tener encripción asegúrate de respaldar las llaves de encripción junto con tus datos. ", "This is the final warning: Do you really want to enable encryption?" : "Esta es la advertencia final: ¿Realmente deseas habilitar la encripción?", "Enable encryption" : "Habilitar encripción", "No encryption module loaded, please enable an encryption module in the app menu." : "No se ha cargado un módulo de encripción, por favor habilita un módulo de encripción en el menú de la aplicación. ", "Select default encryption module:" : "Selecciona el modulo de encripción predeterminado:", "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"Default encryption module\" and run 'occ encryption:migrate'" : "Necesitas migrar tus llaves de encripción de la encripción anterior (ownCloud <= 8.0) a la actual. Por favor habilita el \"Módulo de encripción predeterminado\" y ejecuta el comando 'occ encryption:migrate'", "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : "Necesitas migar tus llaves de encripción de la encripción anterior (ownCloud <=8.0) a la actual. ", "Start migration" : "Iniciar migración", "Background jobs" : "Trabajos en segundo plano", "Last job ran %s." : "El último trabajo corrió %s.", "Last job execution ran %s. Something seems wrong." : "La última ejecución del trabajo corrió %s. Algo parece estar mal. ", "Background job didn’t run yet!" : "¡El trabajo de segundo plano aún no ha corrido!", "For optimal performance it's important to configure background jobs correctly. For bigger instances 'Cron' is the recommended setting. Please see the documentation for more information." : "Para un desempeño ideal, es importante configurar los trabajos de fondo correctamente. Para instancias más grandes 'Cron' es la configuración recomendada. Por favor consulta la documentación para más información. ", "Execute one task with each page loaded" : "Ejecutar una tarea con cada página cargada", "The cron.php needs to be executed by the system user \"%s\"." : "El cron.php necesita ser ejecutado por el usuario de sistema \"%s\".", "To run this you need the PHP POSIX extension. See {linkstart}PHP documentation{linkend} for more details." : "Para correr esto necesitas la extensión POSIX de PHP. Por favor ve la {linkstart}documentación de PHP{linkend} para más detalles. ", "Sharing" : "Compartiendo", "As admin you can fine-tune the sharing behavior. Please see the documentation for more information." : "Como administrador, puedes hacer ajustes finos al comportamiento de compartir. Por favor consulta la documentación para más información. ", "Allow apps to use the Share API" : "Permitir que las aplicaciones usen el API para Compartir", "Expire after " : "Expirar después de", "days" : "días", "Enforce expiration date" : "Forzar fecha de expiración", "Allow users to share via link" : "Permitir a los usuarios compartir mediante ligas", "Allow public uploads" : "Permitir cargas públicas", "Always ask for a password" : "Siempre pedir una contraseña", "Enforce password protection" : "Forzar protección de contraseñas", "Allow resharing" : "Permitir volver a compartir", "Allow sharing with groups" : "Permitir compartir con grupos", "Restrict users to only share with users in their groups" : "Limitar a los usuarios a sólo compartir con otros usuarios en sus grupos", "Exclude groups from sharing" : "Evitar que los grupos compartan", "These groups will still be able to receive shares, but not to initiate them." : "Estos grupos aún podrán recibir elementos compartidos, pero no los podrán iniciar.", "Allow username autocompletion in share dialog. If this is disabled the full username or email address needs to be entered." : "Permitir el autocompletado de usuarios en la ventana de diálogo de compartir. Si esto está deshabilitado, se deberá ingresar el correo electrónico o nombre completo. ", "Show disclaimer text on the public link upload page. (Only shown when the file list is hidden.)" : "Mostrar el texto de exención de responsabilidad legal en la página de carga de ligas públicas. (Sólo se muestra cuando la lista de archivos está oculta.)", "This text will be shown on the public link upload page when the file list is hidden." : "Este texto se mostrará en la página de carga de la liga pública cuando la lista de archivos esté oculta. ", "Personal" : "Personal", "Administration" : "Administración", "Developed by the {communityopen}Nextcloud community{linkclose}, the {githubopen}source code{linkclose} is licensed under the {licenseopen}AGPL{linkclose}." : "Desarrollado por la {communityopen}comunidad Nextcloud {linkclose}, el {githubopen}código fuente {linkclose} está licenciado bajo {licenseopen}AGPL{linkclose}.", "Like our Facebook page" : "Da un Like a nuestra página de Facebook", "Follow us on Twitter" : "Síguenos en Twitter", "Check out our blog" : "Visita nuestro blog", "Subscribe to our newsletter" : "Suscribete a nuestro boletín", "Profile picture" : "Foto de perfil", "Upload new" : "Cargar nuevo", "Select from Files" : "Seleccionar desde Archivos", "Remove image" : "Eliminar imagen", "png or jpg, max. 20 MB" : "png o jpg max. 20 MB", "Picture provided by original account" : "Imagen proporcionada por la cuenta original ", "Choose as profile picture" : "Seleccionar como foto del perfil", "Details" : "Detalles", "Full name" : "Nombre completo", "No display name set" : "No se ha establecido el nombre a desplegar", "Your email address" : "Tu dirección de correo electrónico", "No email address set" : "No se ha establecido la dirección de correo electrónico", "For password reset and notifications" : "Para restablecer contraseña y notificaciones", "Phone number" : "Número de teléfono", "Your phone number" : "Su número telefónico", "Address" : "Dirección", "Your postal address" : "Tu dirección postal", "Website" : "Sitio web", "It can take up to 24 hours before the account is displayed as verified." : "Puede tomar hasta 24 horas antes de que la cuenta se muestre como verificada. ", "Link https://…" : "Liga https:// ...", "Twitter" : "Twitter", "Twitter handle @…" : "Cuenta de twitter @...", "Help translate" : "Ayuda a traducir", "Current password" : "Contraseña actual", "New password" : "Nueva contraseña", "Change password" : "Cambiar contraseña", "Disconnect" : "Desconectar", "Not supported!" : "¡No soportado!", "Press ⌘-C to copy." : "Presiona ⌘-C para copiar.", "Press Ctrl-C to copy." : "Presiona Ctrl-C para copiar.", "Error while loading browser sessions and device tokens" : "Se presentó un error al cargar las sesiones de tu navegador y las fichas de los dispositivos.", "Official apps are developed by and within the community. They offer central functionality and are ready for production use." : "Las aplicaciones oficiales son desarrolladas por y dentro de la comunidad. Ofrecen una funcionalidad centralizada y se encuentran listas para ser usadas en producción. ", "Official" : "Oficial", "Store credentials" : "Almacenar credenciales", "cron.php is registered at a webcron service to call cron.php every 15 minutes over HTTP." : "cron.php está registrado en un servicio webcron para llamar a cron.php cada 15 minutos a través de HTTP. ", "Use system cron service to call the cron.php file every 15 minutes." : "Usar el servicio cron del sistema para llamar al archivo cron.php cada 15 minutos. ", "Set default expiration date" : "Establecer la fecha de expiración predeterminada", "Follow us on Google+" : "Síguenos en Google+", "Share" : "Compartir" }, "nplurals=2; plural=(n != 1);");