diff options
author | Roeland Jago Douma <rullzer@owncloud.com> | 2016-04-24 19:45:43 +0200 |
---|---|---|
committer | Roeland Jago Douma <rullzer@owncloud.com> | 2016-04-24 21:37:35 +0200 |
commit | dedf392751e1b27163f9dd49b2a54f410727c823 (patch) | |
tree | 2d4d0265d7c574caed62dfe25cd718d79141be04 /lib/private/files | |
parent | dc5c570d7caa3095a3cb4ab2b5a51bf772d7de4c (diff) | |
download | nextcloud-server-dedf392751e1b27163f9dd49b2a54f410727c823.tar.gz nextcloud-server-dedf392751e1b27163f9dd49b2a54f410727c823.zip |
Move \OC\Files to PSR-4
Diffstat (limited to 'lib/private/files')
65 files changed, 0 insertions, 18273 deletions
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php deleted file mode 100644 index 53467c278d2..00000000000 --- a/lib/private/files/cache/cache.php +++ /dev/null @@ -1,837 +0,0 @@ -<?php -/** - * @author Andreas Fischer <bantu@owncloud.com> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Florin Peter <github@florin-peter.de> - * @author Jens-Christian Fischer <jens-christian.fischer@switch.ch> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author TheSFReader <TheSFReader@gmail.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -use OCP\Files\Cache\ICache; -use OCP\Files\Cache\ICacheEntry; -use \OCP\Files\IMimeTypeLoader; -use OCP\IDBConnection; - -/** - * Metadata cache for a storage - * - * The cache stores the metadata for all files and folders in a storage and is kept up to date trough the following mechanisms: - * - * - Scanner: scans the storage and updates the cache where needed - * - Watcher: checks for changes made to the filesystem outside of the ownCloud instance and rescans files and folder when a change is detected - * - Updater: listens to changes made to the filesystem inside of the ownCloud instance and updates the cache where needed - * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater - */ -class Cache implements ICache { - use MoveFromCacheTrait { - MoveFromCacheTrait::moveFromCache as moveFromCacheFallback; - } - - /** - * @var array partial data for the cache - */ - protected $partial = array(); - - /** - * @var string - */ - protected $storageId; - - /** - * @var Storage $storageCache - */ - protected $storageCache; - - /** @var IMimeTypeLoader */ - protected $mimetypeLoader; - - /** - * @var IDBConnection - */ - protected $connection; - - /** - * @param \OC\Files\Storage\Storage|string $storage - */ - public function __construct($storage) { - if ($storage instanceof \OC\Files\Storage\Storage) { - $this->storageId = $storage->getId(); - } else { - $this->storageId = $storage; - } - if (strlen($this->storageId) > 64) { - $this->storageId = md5($this->storageId); - } - - $this->storageCache = new Storage($storage); - $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); - $this->connection = \OC::$server->getDatabaseConnection(); - } - - /** - * Get the numeric storage id for this cache's storage - * - * @return int - */ - public function getNumericStorageId() { - return $this->storageCache->getNumericId(); - } - - /** - * get the stored metadata of a file or folder - * - * @param string | int $file either the path of a file or folder or the file id for a file or folder - * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache - */ - public function get($file) { - if (is_string($file) or $file == '') { - // normalize file - $file = $this->normalize($file); - - $where = 'WHERE `storage` = ? AND `path_hash` = ?'; - $params = array($this->getNumericStorageId(), md5($file)); - } else { //file id - $where = 'WHERE `fileid` = ?'; - $params = array($file); - } - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, - `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum` - FROM `*PREFIX*filecache` ' . $where; - $result = $this->connection->executeQuery($sql, $params); - $data = $result->fetch(); - - //FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO - //PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false - if ($data === null) { - $data = false; - } - - //merge partial data - if (!$data and is_string($file)) { - if (isset($this->partial[$file])) { - $data = $this->partial[$file]; - } - return $data; - } else { - //fix types - $data['fileid'] = (int)$data['fileid']; - $data['parent'] = (int)$data['parent']; - $data['size'] = 0 + $data['size']; - $data['mtime'] = (int)$data['mtime']; - $data['storage_mtime'] = (int)$data['storage_mtime']; - $data['encryptedVersion'] = (int)$data['encrypted']; - $data['encrypted'] = (bool)$data['encrypted']; - $data['storage'] = $this->storageId; - $data['mimetype'] = $this->mimetypeLoader->getMimetypeById($data['mimetype']); - $data['mimepart'] = $this->mimetypeLoader->getMimetypeById($data['mimepart']); - if ($data['storage_mtime'] == 0) { - $data['storage_mtime'] = $data['mtime']; - } - $data['permissions'] = (int)$data['permissions']; - return new CacheEntry($data); - } - } - - /** - * get the metadata of all files stored in $folder - * - * @param string $folder - * @return ICacheEntry[] - */ - public function getFolderContents($folder) { - $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 ICacheEntry[] - */ - public function getFolderContentsById($fileId) { - if ($fileId > -1) { - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, - `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum` - FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC'; - $result = $this->connection->executeQuery($sql, [$fileId]); - $files = $result->fetchAll(); - foreach ($files as &$file) { - $file['mimetype'] = $this->mimetypeLoader->getMimetypeById($file['mimetype']); - $file['mimepart'] = $this->mimetypeLoader->getMimetypeById($file['mimepart']); - if ($file['storage_mtime'] == 0) { - $file['storage_mtime'] = $file['mtime']; - } - $file['permissions'] = (int)$file['permissions']; - $file['mtime'] = (int)$file['mtime']; - $file['storage_mtime'] = (int)$file['storage_mtime']; - $file['size'] = 0 + $file['size']; - } - return array_map(function (array $data) { - return new CacheEntry($data); - }, $files); - } else { - return array(); - } - } - - /** - * insert or update meta data for a file or folder - * - * @param string $file - * @param array $data - * - * @return int file id - * @throws \RuntimeException - */ - public function put($file, array $data) { - if (($id = $this->getId($file)) > -1) { - $this->update($id, $data); - return $id; - } else { - return $this->insert($file, $data); - } - } - - /** - * insert meta data for a new file or folder - * - * @param string $file - * @param array $data - * - * @return int file id - * @throws \RuntimeException - */ - public function insert($file, array $data) { - // normalize file - $file = $this->normalize($file); - - if (isset($this->partial[$file])) { //add any saved partial data - $data = array_merge($this->partial[$file], $data); - unset($this->partial[$file]); - } - - $requiredFields = array('size', 'mtime', 'mimetype'); - foreach ($requiredFields as $field) { - if (!isset($data[$field])) { //data not complete save as partial and return - $this->partial[$file] = $data; - return -1; - } - } - - $data['path'] = $file; - $data['parent'] = $this->getParentId($file); - $data['name'] = \OC_Util::basename($file); - - list($queryParts, $params) = $this->buildParts($data); - $queryParts[] = '`storage`'; - $params[] = $this->getNumericStorageId(); - - $queryParts = array_map(function ($item) { - return trim($item, "`"); - }, $queryParts); - $values = array_combine($queryParts, $params); - if (\OC::$server->getDatabaseConnection()->insertIfNotExist('*PREFIX*filecache', $values, [ - 'storage', - 'path_hash', - ]) - ) { - return (int)$this->connection->lastInsertId('*PREFIX*filecache'); - } - - // The file was created in the mean time - if (($id = $this->getId($file)) > -1) { - $this->update($id, $data); - return $id; - } else { - throw new \RuntimeException('File entry could not be inserted with insertIfNotExist() but could also not be selected with getId() in order to perform an update. Please try again.'); - } - } - - /** - * update the metadata of an existing file or folder in the cache - * - * @param int $id the fileid of the existing file or folder - * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged - */ - public function update($id, array $data) { - - if (isset($data['path'])) { - // normalize path - $data['path'] = $this->normalize($data['path']); - } - - if (isset($data['name'])) { - // normalize path - $data['name'] = $this->normalize($data['name']); - } - - list($queryParts, $params) = $this->buildParts($data); - // duplicate $params because we need the parts twice in the SQL statement - // once for the SET part, once in the WHERE clause - $params = array_merge($params, $params); - $params[] = $id; - - // don't update if the data we try to set is the same as the one in the record - // some databases (Postgres) don't like superfluous updates - $sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' . - 'WHERE (' . - implode(' <> ? OR ', $queryParts) . ' <> ? OR ' . - implode(' IS NULL OR ', $queryParts) . ' IS NULL' . - ') AND `fileid` = ? '; - $this->connection->executeQuery($sql, $params); - - } - - /** - * extract query parts and params array from data array - * - * @param array $data - * @return array [$queryParts, $params] - * $queryParts: string[], the (escaped) column names to be set in the query - * $params: mixed[], the new values for the columns, to be passed as params to the query - */ - protected function buildParts(array $data) { - $fields = array( - 'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', - 'etag', 'permissions', 'checksum'); - - $doNotCopyStorageMTime = false; - if (array_key_exists('mtime', $data) && $data['mtime'] === null) { - // this horrific magic tells it to not copy storage_mtime to mtime - unset($data['mtime']); - $doNotCopyStorageMTime = true; - } - - $params = array(); - $queryParts = array(); - foreach ($data as $name => $value) { - if (array_search($name, $fields) !== false) { - if ($name === 'path') { - $params[] = md5($value); - $queryParts[] = '`path_hash`'; - } elseif ($name === 'mimetype') { - $params[] = $this->mimetypeLoader->getId(substr($value, 0, strpos($value, '/'))); - $queryParts[] = '`mimepart`'; - $value = $this->mimetypeLoader->getId($value); - } elseif ($name === 'storage_mtime') { - if (!$doNotCopyStorageMTime && !isset($data['mtime'])) { - $params[] = $value; - $queryParts[] = '`mtime`'; - } - } elseif ($name === 'encrypted') { - if(isset($data['encryptedVersion'])) { - $value = $data['encryptedVersion']; - } else { - // Boolean to integer conversion - $value = $value ? 1 : 0; - } - } - $params[] = $value; - $queryParts[] = '`' . $name . '`'; - } - } - return array($queryParts, $params); - } - - /** - * get the file id for a file - * - * A file id is a numeric id for a file or folder that's unique within an owncloud instance which stays the same for the lifetime of a file - * - * File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing - * - * @param string $file - * @return int - */ - public function getId($file) { - // normalize file - $file = $this->normalize($file); - - $pathHash = md5($file); - - $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'; - $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash)); - if ($row = $result->fetch()) { - return $row['fileid']; - } else { - return -1; - } - } - - /** - * get the id of the parent folder of a file - * - * @param string $file - * @return int - */ - public function getParentId($file) { - if ($file === '') { - return -1; - } else { - $parent = $this->getParentPath($file); - return (int)$this->getId($parent); - } - } - - private function getParentPath($path) { - $parent = dirname($path); - if ($parent === '.') { - $parent = ''; - } - return $parent; - } - - /** - * check if a file is available in the cache - * - * @param string $file - * @return bool - */ - public function inCache($file) { - return $this->getId($file) != -1; - } - - /** - * remove a file or folder from the cache - * - * when removing a folder from the cache all files and folders inside the folder will be removed as well - * - * @param string $file - */ - public function remove($file) { - $entry = $this->get($file); - $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?'; - $this->connection->executeQuery($sql, array($entry['fileid'])); - if ($entry['mimetype'] === 'httpd/unix-directory') { - $this->removeChildren($entry); - } - } - - /** - * Get all sub folders of a folder - * - * @param array $entry the cache entry of the folder to get the subfolders for - * @return array[] the cache entries for the subfolders - */ - private function getSubFolders($entry) { - $children = $this->getFolderContentsById($entry['fileid']); - return array_filter($children, function ($child) { - return $child['mimetype'] === 'httpd/unix-directory'; - }); - } - - /** - * Recursively remove all children of a folder - * - * @param array $entry the cache entry of the folder to remove the children of - * @throws \OC\DatabaseException - */ - private function removeChildren($entry) { - $subFolders = $this->getSubFolders($entry); - foreach ($subFolders as $folder) { - $this->removeChildren($folder); - } - $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `parent` = ?'; - $this->connection->executeQuery($sql, array($entry['fileid'])); - } - - /** - * Move a file or folder in the cache - * - * @param string $source - * @param string $target - */ - public function move($source, $target) { - $this->moveFromCache($this, $source, $target); - } - - /** - * Get the storage id and path needed for a move - * - * @param string $path - * @return array [$storageId, $internalPath] - */ - protected function getMoveInfo($path) { - return [$this->getNumericStorageId(), $path]; - } - - /** - * Move a file or folder in the cache - * - * @param \OCP\Files\Cache\ICache $sourceCache - * @param string $sourcePath - * @param string $targetPath - * @throws \OC\DatabaseException - */ - public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { - if ($sourceCache instanceof Cache) { - // normalize source and target - $sourcePath = $this->normalize($sourcePath); - $targetPath = $this->normalize($targetPath); - - $sourceData = $sourceCache->get($sourcePath); - $sourceId = $sourceData['fileid']; - $newParentId = $this->getParentId($targetPath); - - list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath); - list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath); - - // sql for final update - $moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?'; - - if ($sourceData['mimetype'] === 'httpd/unix-directory') { - //find all child entries - $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?'; - $result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']); - $childEntries = $result->fetchAll(); - $sourceLength = strlen($sourcePath); - $this->connection->beginTransaction(); - $query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); - - foreach ($childEntries as $child) { - $newTargetPath = $targetPath . substr($child['path'], $sourceLength); - $query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]); - } - $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]); - $this->connection->commit(); - } else { - $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]); - } - } else { - $this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath); - } - } - - /** - * remove all entries for files that are stored on the storage from the cache - */ - public function clear() { - $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?'; - $this->connection->executeQuery($sql, array($this->getNumericStorageId())); - - $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'; - $this->connection->executeQuery($sql, array($this->storageId)); - } - - /** - * Get the scan status of a file - * - * - Cache::NOT_FOUND: File is not in the cache - * - Cache::PARTIAL: File is not stored in the cache but some incomplete data is known - * - Cache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned - * - Cache::COMPLETE: The file or folder, with all it's children) are fully scanned - * - * @param string $file - * - * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE - */ - public function getStatus($file) { - // normalize file - $file = $this->normalize($file); - - $pathHash = md5($file); - $sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'; - $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash)); - if ($row = $result->fetch()) { - if ((int)$row['size'] === -1) { - return self::SHALLOW; - } else { - return self::COMPLETE; - } - } else { - if (isset($this->partial[$file])) { - return self::PARTIAL; - } else { - return self::NOT_FOUND; - } - } - } - - /** - * search for files matching $pattern - * - * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%') - * @return ICacheEntry[] an array of cache entries where the name matches the search pattern - */ - public function search($pattern) { - // normalize pattern - $pattern = $this->normalize($pattern); - - - $sql = ' - SELECT `fileid`, `storage`, `path`, `parent`, `name`, - `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, - `etag`, `permissions`, `checksum` - FROM `*PREFIX*filecache` - WHERE `storage` = ? AND `name` ILIKE ?'; - $result = $this->connection->executeQuery($sql, - [$this->getNumericStorageId(), $pattern] - ); - - $files = []; - while ($row = $result->fetch()) { - $row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']); - $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']); - $files[] = $row; - } - return array_map(function(array $data) { - return new CacheEntry($data); - }, $files); - } - - /** - * search for files by mimetype - * - * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image') - * where it will search for all mimetypes in the group ('image/*') - * @return ICacheEntry[] an array of cache entries where the mimetype matches the search - */ - public function searchByMime($mimetype) { - if (strpos($mimetype, '/')) { - $where = '`mimetype` = ?'; - } else { - $where = '`mimepart` = ?'; - } - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum` - FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'; - $mimetype = $this->mimetypeLoader->getId($mimetype); - $result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId())); - $files = array(); - while ($row = $result->fetch()) { - $row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']); - $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']); - $files[] = $row; - } - return array_map(function (array $data) { - return new CacheEntry($data); - }, $files); - } - - /** - * Search for files by tag of a given users. - * - * Note that every user can tag files differently. - * - * @param string|int $tag name or tag id - * @param string $userId owner of the tags - * @return ICacheEntry[] file data - */ - public function searchByTag($tag, $userId) { - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' . - '`mimetype`, `mimepart`, `size`, `mtime`, ' . - '`encrypted`, `etag`, `permissions`, `checksum` ' . - 'FROM `*PREFIX*filecache` `file`, ' . - '`*PREFIX*vcategory_to_object` `tagmap`, ' . - '`*PREFIX*vcategory` `tag` ' . - // JOIN filecache to vcategory_to_object - 'WHERE `file`.`fileid` = `tagmap`.`objid` ' . - // JOIN vcategory_to_object to vcategory - 'AND `tagmap`.`type` = `tag`.`type` ' . - 'AND `tagmap`.`categoryid` = `tag`.`id` ' . - // conditions - 'AND `file`.`storage` = ? ' . - 'AND `tag`.`type` = \'files\' ' . - 'AND `tag`.`uid` = ? '; - if (is_int($tag)) { - $sql .= 'AND `tag`.`id` = ? '; - } else { - $sql .= 'AND `tag`.`category` = ? '; - } - $result = $this->connection->executeQuery( - $sql, - [ - $this->getNumericStorageId(), - $userId, - $tag - ] - ); - $files = array(); - while ($row = $result->fetch()) { - $files[] = $row; - } - return array_map(function (array $data) { - return new CacheEntry($data); - }, $files); - } - - /** - * Re-calculate 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->calculateFolderSize($path, $data); - if ($path !== '') { - $parent = dirname($path); - if ($parent === '.' or $parent === '/') { - $parent = ''; - } - $this->correctFolderSize($parent); - } - } - - /** - * calculate 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) { - $totalSize = 0; - if (is_null($entry) or !isset($entry['fileid'])) { - $entry = $this->get($path); - } - if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') { - $id = $entry['fileid']; - $sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' . - 'FROM `*PREFIX*filecache` ' . - 'WHERE `parent` = ? AND `storage` = ?'; - $result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId())); - if ($row = $result->fetch()) { - $result->closeCursor(); - list($sum, $min) = array_values($row); - $sum = 0 + $sum; - $min = 0 + $min; - if ($min === -1) { - $totalSize = $min; - } else { - $totalSize = $sum; - } - $update = array(); - if ($entry['size'] !== $totalSize) { - $update['size'] = $totalSize; - } - if (count($update) > 0) { - $this->update($id, $update); - } - } else { - $result->closeCursor(); - } - } - return $totalSize; - } - - /** - * get all file ids on the files on the storage - * - * @return int[] - */ - public function getAll() { - $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?'; - $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId())); - $ids = array(); - while ($row = $result->fetch()) { - $ids[] = $row['fileid']; - } - return $ids; - } - - /** - * 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() { - $query = $this->connection->prepare('SELECT `path` FROM `*PREFIX*filecache`' - . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC', 1); - $query->execute([$this->getNumericStorageId()]); - if ($row = $query->fetch()) { - return $row['path']; - } else { - return false; - } - } - - /** - * get the path of a file on this storage by it's file id - * - * @param int $id the file id of the file or folder to search - * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache - */ - public function getPathById($id) { - $sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?'; - $result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId())); - if ($row = $result->fetch()) { - // Oracle stores empty strings as null... - if ($row['path'] === null) { - return ''; - } - return $row['path']; - } else { - return null; - } - } - - /** - * 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 - * @deprecated use getPathById() instead - * @return array first element holding the storage id, second the path - */ - static public function getById($id) { - $connection = \OC::$server->getDatabaseConnection(); - $sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?'; - $result = $connection->executeQuery($sql, array($id)); - if ($row = $result->fetch()) { - $numericId = $row['storage']; - $path = $row['path']; - } else { - return null; - } - - if ($id = Storage::getStorageId($numericId)) { - return array($id, $path); - } else { - return null; - } - } - - /** - * normalize the given path - * - * @param string $path - * @return string - */ - public function normalize($path) { - - return trim(\OC_Util::normalizeUnicode($path), '/'); - } -} diff --git a/lib/private/files/cache/cacheentry.php b/lib/private/files/cache/cacheentry.php deleted file mode 100644 index 6d3c5d5b089..00000000000 --- a/lib/private/files/cache/cacheentry.php +++ /dev/null @@ -1,114 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -use OCP\Files\Cache\ICacheEntry; - -/** - * meta data for a file or folder - */ -class CacheEntry implements ICacheEntry, \ArrayAccess { - /** - * @var array - */ - private $data; - - public function __construct(array $data) { - $this->data = $data; - } - - public function offsetSet($offset, $value) { - $this->data[$offset] = $value; - } - - public function offsetExists($offset) { - return isset($this->data[$offset]); - } - - public function offsetUnset($offset) { - unset($this->data[$offset]); - } - - public function offsetGet($offset) { - if (isset($this->data[$offset])) { - return $this->data[$offset]; - } else { - return null; - } - } - - public function getId() { - return (int)$this->data['fileid']; - } - - public function getStorageId() { - return $this->data['storage']; - } - - - public function getPath() { - return $this->data['path']; - } - - - public function getName() { - return $this->data['name']; - } - - - public function getMimeType() { - return $this->data['mimetype']; - } - - - public function getMimePart() { - return $this->data['mimepart']; - } - - public function getSize() { - return $this->data['size']; - } - - public function getMTime() { - return $this->data['mtime']; - } - - public function getStorageMTime() { - return $this->data['storage_mtime']; - } - - public function getEtag() { - return $this->data['etag']; - } - - public function getPermissions() { - return $this->data['permissions']; - } - - public function isEncrypted() { - return isset($this->data['encrypted']) && $this->data['encrypted']; - } - - public function getData() { - return $this->data; - } -} diff --git a/lib/private/files/cache/failedcache.php b/lib/private/files/cache/failedcache.php deleted file mode 100644 index 0386ba3ca32..00000000000 --- a/lib/private/files/cache/failedcache.php +++ /dev/null @@ -1,142 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -use OCP\Constants; -use OCP\Files\Cache\ICache; - -/** - * Storage placeholder to represent a missing precondition, storage unavailable - */ -class FailedCache implements ICache { - /** @var bool whether to show the failed storage in the ui */ - private $visible; - - /** - * FailedCache constructor. - * - * @param bool $visible - */ - public function __construct($visible = true) { - $this->visible = $visible; - } - - - public function getNumericStorageId() { - return -1; - } - - public function get($file) { - if ($file === '') { - return new CacheEntry([ - 'fileid' => -1, - 'size' => 0, - 'mimetype' => 'httpd/unix-directory', - 'mimepart' => 'httpd', - 'permissions' => $this->visible ? Constants::PERMISSION_READ : 0, - 'mtime' => time() - ]); - } else { - return false; - } - } - - public function getFolderContents($folder) { - return []; - } - - public function getFolderContentsById($fileId) { - return []; - } - - public function put($file, array $data) { - return; - } - - public function insert($file, array $data) { - return; - } - - public function update($id, array $data) { - return; - } - - public function getId($file) { - return -1; - } - - public function getParentId($file) { - return -1; - } - - public function inCache($file) { - return false; - } - - public function remove($file) { - return; - } - - public function move($source, $target) { - return; - } - - public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { - return; - } - - public function clear() { - return; - } - - public function getStatus($file) { - return ICache::NOT_FOUND; - } - - public function search($pattern) { - return []; - } - - public function searchByMime($mimetype) { - return []; - } - - public function searchByTag($tag, $userId) { - return []; - } - - public function getAll() { - return []; - } - - public function getIncomplete() { - return []; - } - - public function getPathById($id) { - return null; - } - - public function normalize($path) { - return $path; - } -} diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php deleted file mode 100644 index ae92504ddd6..00000000000 --- a/lib/private/files/cache/homecache.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php -/** - * @author Andreas Fischer <bantu@owncloud.com> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -use OCP\Files\Cache\ICacheEntry; - -class HomeCache extends Cache { - /** - * 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) { - if ($path !== '/' and $path !== '' and $path !== 'files' and $path !== 'files_trashbin' and $path !== 'files_versions') { - return parent::calculateFolderSize($path, $entry); - } elseif ($path === '' or $path === '/') { - // since the size of / isn't used (the size of /files is used instead) there is no use in calculating it - return 0; - } - - $totalSize = 0; - if (is_null($entry)) { - $entry = $this->get($path); - } - if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { - $id = $entry['fileid']; - $sql = 'SELECT SUM(`size`) AS f1 ' . - 'FROM `*PREFIX*filecache` ' . - 'WHERE `parent` = ? AND `storage` = ? AND `size` >= 0'; - $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); - if ($row = $result->fetchRow()) { - $result->closeCursor(); - list($sum) = array_values($row); - $totalSize = 0 + $sum; - $entry['size'] += 0; - if ($entry['size'] !== $totalSize) { - $this->update($id, array('size' => $totalSize)); - } - } - } - return $totalSize; - } - - /** - * @param string $path - * @return ICacheEntry - */ - public function get($path) { - $data = parent::get($path); - if ($path === '' or $path === '/') { - // only the size of the "files" dir counts - $filesData = parent::get('files'); - - if (isset($filesData['size'])) { - $data['size'] = $filesData['size']; - } - } - return $data; - } -} diff --git a/lib/private/files/cache/homepropagator.php b/lib/private/files/cache/homepropagator.php deleted file mode 100644 index 8edca9c0c87..00000000000 --- a/lib/private/files/cache/homepropagator.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -class HomePropagator extends Propagator { - private $ignoredBaseFolders; - - /** - * @param \OC\Files\Storage\Storage $storage - */ - public function __construct(\OC\Files\Storage\Storage $storage) { - parent::__construct($storage); - $this->ignoredBaseFolders = ['files_encryption']; - } - - - /** - * @param string $internalPath - * @param int $time - * @param int $sizeDifference number of bytes the file has grown - * @return array[] all propagated entries - */ - public function propagateChange($internalPath, $time, $sizeDifference = 0) { - list($baseFolder) = explode('/', $internalPath, 2); - if (in_array($baseFolder, $this->ignoredBaseFolders)) { - return []; - } else { - return parent::propagateChange($internalPath, $time, $sizeDifference); - } - } -} diff --git a/lib/private/files/cache/movefromcachetrait.php b/lib/private/files/cache/movefromcachetrait.php deleted file mode 100644 index 7d8ed7b5d21..00000000000 --- a/lib/private/files/cache/movefromcachetrait.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -use OCP\Files\Cache\ICache; -use OCP\Files\Cache\ICacheEntry; - -/** - * Fallback implementation for moveFromCache - */ -trait MoveFromCacheTrait { - /** - * store meta data for a file or folder - * - * @param string $file - * @param array $data - * - * @return int file id - * @throws \RuntimeException - */ - abstract public function put($file, array $data); - - /** - * Move a file or folder in the cache - * - * @param \OCP\Files\Cache\ICache $sourceCache - * @param string $sourcePath - * @param string $targetPath - */ - public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { - $sourceEntry = $sourceCache->get($sourcePath); - - $this->copyFromCache($sourceCache, $sourceEntry, $targetPath); - - $sourceCache->remove($sourcePath); - } - - /** - * Copy a file or folder in the cache - * - * @param \OCP\Files\Cache\ICache $sourceCache - * @param ICacheEntry $sourceEntry - * @param string $targetPath - */ - public function copyFromCache(ICache $sourceCache, ICacheEntry $sourceEntry, $targetPath) { - $this->put($targetPath, $this->cacheEntryToArray($sourceEntry)); - if ($sourceEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) { - $folderContent = $sourceCache->getFolderContentsById($sourceEntry->getId()); - foreach ($folderContent as $subEntry) { - $subTargetPath = $targetPath . '/' . $subEntry->getName(); - $this->copyFromCache($sourceCache, $subEntry, $subTargetPath); - } - } - } - - private function cacheEntryToArray(ICacheEntry $entry) { - return [ - 'size' => $entry->getSize(), - 'mtime' => $entry->getMTime(), - 'storage_mtime' => $entry->getStorageMTime(), - 'mimetype' => $entry->getMimeType(), - 'mimepart' => $entry->getMimePart(), - 'etag' => $entry->getEtag(), - 'permissions' => $entry->getPermissions(), - 'encrypted' => $entry->isEncrypted() - ]; - } -} diff --git a/lib/private/files/cache/propagator.php b/lib/private/files/cache/propagator.php deleted file mode 100644 index 50264e54d44..00000000000 --- a/lib/private/files/cache/propagator.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -use OCP\Files\Cache\IPropagator; - -/** - * Propagate etags and mtimes within the storage - */ -class Propagator implements IPropagator { - /** - * @var \OC\Files\Storage\Storage - */ - protected $storage; - - /** - * @param \OC\Files\Storage\Storage $storage - */ - public function __construct(\OC\Files\Storage\Storage $storage) { - $this->storage = $storage; - } - - - /** - * @param string $internalPath - * @param int $time - * @param int $sizeDifference number of bytes the file has grown - * @return array[] all propagated entries - */ - public function propagateChange($internalPath, $time, $sizeDifference = 0) { - $cache = $this->storage->getCache($internalPath); - - $parentId = $cache->getParentId($internalPath); - $propagatedEntries = []; - while ($parentId !== -1) { - $entry = $cache->get($parentId); - $propagatedEntries[] = $entry; - if (!$entry) { - return $propagatedEntries; - } - $mtime = max($time, $entry['mtime']); - - if ($entry['size'] === -1) { - $newSize = -1; - } else { - $newSize = $entry['size'] + $sizeDifference; - } - $cache->update($parentId, ['mtime' => $mtime, 'etag' => $this->storage->getETag($entry['path']), 'size' => $newSize]); - - $parentId = $entry['parent']; - } - - return $propagatedEntries; - } -} diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php deleted file mode 100644 index 8730707f1c2..00000000000 --- a/lib/private/files/cache/scanner.php +++ /dev/null @@ -1,503 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Martin Mattel <martin.mattel@diemattels.at> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Owen Winkler <a_github@midnightcircus.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -use OC\Files\Filesystem; -use OC\Hooks\BasicEmitter; -use OCP\Config; -use OCP\Files\Cache\IScanner; -use OCP\Files\Storage\ILockingStorage; -use OCP\Lock\ILockingProvider; - -/** - * Class Scanner - * - * Hooks available in scope \OC\Files\Cache\Scanner: - * - scanFile(string $path, string $storageId) - * - scanFolder(string $path, string $storageId) - * - postScanFile(string $path, string $storageId) - * - postScanFolder(string $path, string $storageId) - * - * @package OC\Files\Cache - */ -class Scanner extends BasicEmitter implements IScanner { - /** - * @var \OC\Files\Storage\Storage $storage - */ - protected $storage; - - /** - * @var string $storageId - */ - protected $storageId; - - /** - * @var \OC\Files\Cache\Cache $cache - */ - protected $cache; - - /** - * @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache - */ - protected $cacheActive; - - /** - * @var bool $useTransactions whether to use transactions - */ - protected $useTransactions = true; - - /** - * @var \OCP\Lock\ILockingProvider - */ - protected $lockingProvider; - - public function __construct(\OC\Files\Storage\Storage $storage) { - $this->storage = $storage; - $this->storageId = $this->storage->getId(); - $this->cache = $storage->getCache(); - $this->cacheActive = !Config::getSystemValue('filesystem_cache_readonly', false); - $this->lockingProvider = \OC::$server->getLockingProvider(); - } - - /** - * Whether to wrap the scanning of a folder in a database transaction - * On default transactions are used - * - * @param bool $useTransactions - */ - public function setUseTransactions($useTransactions) { - $this->useTransactions = $useTransactions; - } - - /** - * get all the metadata of a file or folder - * * - * - * @param string $path - * @return array an array of metadata of the file - */ - protected function getData($path) { - $data = $this->storage->getMetaData($path); - if (is_null($data)) { - \OCP\Util::writeLog('OC\Files\Cache\Scanner', "!!! Path '$path' is not accessible or present !!!", \OCP\Util::DEBUG); - } - return $data; - } - - /** - * scan a single file and store it in the cache - * - * @param string $file - * @param int $reuseExisting - * @param int $parentId - * @param array | null $cacheData existing data in the cache for the file to be scanned - * @param bool $lock set to false to disable getting an additional read lock during scanning - * @return array an array of metadata of the scanned file - * @throws \OC\ServerNotAvailableException - * @throws \OCP\Lock\LockedException - */ - public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) { - - // only proceed if $file is not a partial file nor a blacklisted file - if (!self::isPartialFile($file) and !Filesystem::isFileBlacklisted($file)) { - - //acquire a lock - if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); - } - } - - $data = $this->getData($file); - - if ($data) { - - // pre-emit only if it was a file. By that we avoid counting/treating folders as files - if ($data['mimetype'] !== 'httpd/unix-directory') { - $this->emit('\OC\Files\Cache\Scanner', 'scanFile', array($file, $this->storageId)); - \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId)); - } - - $parent = dirname($file); - if ($parent === '.' or $parent === '/') { - $parent = ''; - } - if ($parentId === -1) { - $parentId = $this->cache->getId($parent); - } - - // scan the parent if it's not in the cache (id -1) and the current file is not the root folder - if ($file and $parentId === -1) { - $parentData = $this->scanFile($parent); - $parentId = $parentData['fileid']; - } - if ($parent) { - $data['parent'] = $parentId; - } - if (is_null($cacheData)) { - /** @var CacheEntry $cacheData */ - $cacheData = $this->cache->get($file); - } - if ($cacheData and $reuseExisting and isset($cacheData['fileid'])) { - // prevent empty etag - if (empty($cacheData['etag'])) { - $etag = $data['etag']; - } else { - $etag = $cacheData['etag']; - } - $fileId = $cacheData['fileid']; - $data['fileid'] = $fileId; - // only reuse data if the file hasn't explicitly changed - if (isset($data['storage_mtime']) && isset($cacheData['storage_mtime']) && $data['storage_mtime'] === $cacheData['storage_mtime']) { - $data['mtime'] = $cacheData['mtime']; - if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { - $data['size'] = $cacheData['size']; - } - if ($reuseExisting & self::REUSE_ETAG) { - $data['etag'] = $etag; - } - } - // Only update metadata that has changed - $newData = array_diff_assoc($data, $cacheData->getData()); - } else { - $newData = $data; - $fileId = -1; - } - if (!empty($newData)) { - // Reset the checksum if the data has changed - $newData['checksum'] = ''; - $data['fileid'] = $this->addToCache($file, $newData, $fileId); - } - if (isset($cacheData['size'])) { - $data['oldSize'] = $cacheData['size']; - } else { - $data['oldSize'] = 0; - } - - if (isset($cacheData['encrypted'])) { - $data['encrypted'] = $cacheData['encrypted']; - } - - // post-emit only if it was a file. By that we avoid counting/treating folders as files - if ($data['mimetype'] !== 'httpd/unix-directory') { - $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', array($file, $this->storageId)); - \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', array('path' => $file, 'storage' => $this->storageId)); - } - - } else { - $this->removeFromCache($file); - } - - //release the acquired lock - if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); - } - } - - if ($data && !isset($data['encrypted'])) { - $data['encrypted'] = false; - } - return $data; - } - - return null; - } - - protected function removeFromCache($path) { - \OC_Hook::emit('Scanner', 'removeFromCache', array('file' => $path)); - $this->emit('\OC\Files\Cache\Scanner', 'removeFromCache', array($path)); - if ($this->cacheActive) { - $this->cache->remove($path); - } - } - - /** - * @param string $path - * @param array $data - * @param int $fileId - * @return int the id of the added file - */ - protected function addToCache($path, $data, $fileId = -1) { - \OC_Hook::emit('Scanner', 'addToCache', array('file' => $path, 'data' => $data)); - $this->emit('\OC\Files\Cache\Scanner', 'addToCache', array($path, $this->storageId, $data)); - if ($this->cacheActive) { - if ($fileId !== -1) { - $this->cache->update($fileId, $data); - return $fileId; - } else { - return $this->cache->put($path, $data); - } - } else { - return -1; - } - } - - /** - * @param string $path - * @param array $data - * @param int $fileId - */ - protected function updateCache($path, $data, $fileId = -1) { - \OC_Hook::emit('Scanner', 'addToCache', array('file' => $path, 'data' => $data)); - $this->emit('\OC\Files\Cache\Scanner', 'updateCache', array($path, $this->storageId, $data)); - if ($this->cacheActive) { - if ($fileId !== -1) { - $this->cache->update($fileId, $data); - } else { - $this->cache->put($path, $data); - } - } - } - - /** - * scan a folder and all it's children - * - * @param string $path - * @param bool $recursive - * @param int $reuse - * @param bool $lock set to false to disable getting an additional read lock during scanning - * @return array an array of the meta data of the scanned file or folder - */ - public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) { - if ($reuse === -1) { - $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; - } - if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); - } - } - $data = $this->scanFile($path, $reuse, -1, null, $lock); - if ($data and $data['mimetype'] === 'httpd/unix-directory') { - $size = $this->scanChildren($path, $recursive, $reuse, $data, $lock); - $data['size'] = $size; - } - if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); - } - } - return $data; - } - - /** - * Get the children currently in the cache - * - * @param int $folderId - * @return array[] - */ - protected function getExistingChildren($folderId) { - $existingChildren = array(); - $children = $this->cache->getFolderContentsById($folderId); - foreach ($children as $child) { - $existingChildren[$child['name']] = $child; - } - return $existingChildren; - } - - /** - * Get the children from the storage - * - * @param string $folder - * @return string[] - */ - protected function getNewChildren($folder) { - $children = array(); - if ($dh = $this->storage->opendir($folder)) { - if (is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if (!Filesystem::isIgnoredDir($file)) { - $children[] = $file; - } - } - } - } - return $children; - } - - /** - * scan all the files and folders in a folder - * - * @param string $path - * @param bool $recursive - * @param int $reuse - * @param array $folderData existing cache data for the folder to be scanned - * @param bool $lock set to false to disable getting an additional read lock during scanning - * @return int the size of the scanned folder or -1 if the size is unknown at this stage - */ - protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderData = null, $lock = true) { - if ($reuse === -1) { - $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; - } - $this->emit('\OC\Files\Cache\Scanner', 'scanFolder', array($path, $this->storageId)); - $size = 0; - $childQueue = array(); - if (is_array($folderData) and isset($folderData['fileid'])) { - $folderId = $folderData['fileid']; - } else { - $folderId = $this->cache->getId($path); - } - $existingChildren = $this->getExistingChildren($folderId); - $newChildren = $this->getNewChildren($path); - - if ($this->useTransactions) { - \OC::$server->getDatabaseConnection()->beginTransaction(); - } - $exceptionOccurred = false; - foreach ($newChildren as $file) { - $child = ($path) ? $path . '/' . $file : $file; - try { - $existingData = isset($existingChildren[$file]) ? $existingChildren[$file] : null; - $data = $this->scanFile($child, $reuse, $folderId, $existingData, $lock); - if ($data) { - if ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE) { - $childQueue[$child] = $data; - } else if ($data['size'] === -1) { - $size = -1; - } else if ($size !== -1) { - $size += $data['size']; - } - } - } catch (\Doctrine\DBAL\DBALException $ex) { - // might happen if inserting duplicate while a scanning - // process is running in parallel - // log and ignore - \OCP\Util::writeLog('core', 'Exception while scanning file "' . $child . '": ' . $ex->getMessage(), \OCP\Util::DEBUG); - $exceptionOccurred = true; - } catch (\OCP\Lock\LockedException $e) { - if ($this->useTransactions) { - \OC::$server->getDatabaseConnection()->rollback(); - } - throw $e; - } - } - $removedChildren = \array_diff(array_keys($existingChildren), $newChildren); - foreach ($removedChildren as $childName) { - $child = ($path) ? $path . '/' . $childName : $childName; - $this->removeFromCache($child); - } - if ($this->useTransactions) { - \OC::$server->getDatabaseConnection()->commit(); - } - if ($exceptionOccurred) { - // It might happen that the parallel scan process has already - // inserted mimetypes but those weren't available yet inside the transaction - // To make sure to have the updated mime types in such cases, - // we reload them here - \OC::$server->getMimeTypeLoader()->reset(); - } - - foreach ($childQueue as $child => $childData) { - $childSize = $this->scanChildren($child, self::SCAN_RECURSIVE, $reuse, $childData, $lock); - if ($childSize === -1) { - $size = -1; - } else if ($size !== -1) { - $size += $childSize; - } - } - if (!is_array($folderData) or !isset($folderData['size']) or $folderData['size'] !== $size) { - $this->updateCache($path, array('size' => $size), $folderId); - } - $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', array($path, $this->storageId)); - return $size; - } - - /** - * check if the file should be ignored when scanning - * NOTE: files with a '.part' extension are ignored as well! - * prevents unfinished put requests to be scanned - * - * @param string $file - * @return boolean - */ - public static function isPartialFile($file) { - if (pathinfo($file, PATHINFO_EXTENSION) === 'part') { - return true; - } - if (strpos($file, '.part/') !== false) { - return true; - } - - return false; - } - - /** - * walk over any folders that are not fully scanned yet and scan them - */ - public function backgroundScan() { - if (!$this->cache->inCache('')) { - $this->runBackgroundScanJob(function () { - $this->scan('', self::SCAN_RECURSIVE, self::REUSE_ETAG); - }, ''); - } else { - $lastPath = null; - while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) { - $this->runBackgroundScanJob(function() use ($path) { - $this->scan($path, self::SCAN_RECURSIVE, self::REUSE_ETAG); - }, $path); - // FIXME: this won't proceed with the next item, needs revamping of getIncomplete() - // to make this possible - $lastPath = $path; - } - } - } - - private function runBackgroundScanJob(callable $callback, $path) { - try { - $callback(); - \OC_Hook::emit('Scanner', 'correctFolderSize', array('path' => $path)); - if ($this->cacheActive) { - $this->cache->correctFolderSize($path); - } - } catch (\OCP\Files\StorageInvalidException $e) { - // skip unavailable storages - } catch (\OCP\Files\StorageNotAvailableException $e) { - // skip unavailable storages - } catch (\OCP\Files\ForbiddenException $e) { - // skip forbidden storages - } catch (\OCP\Lock\LockedException $e) { - // skip unavailable storages - } - } - - /** - * Set whether the cache is affected by scan operations - * - * @param boolean $active The active state of the cache - */ - public function setCacheActive($active) { - $this->cacheActive = $active; - } -} diff --git a/lib/private/files/cache/storage.php b/lib/private/files/cache/storage.php deleted file mode 100644 index 90c451ecc21..00000000000 --- a/lib/private/files/cache/storage.php +++ /dev/null @@ -1,189 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; - -/** - * Handle the mapping between the string and numeric storage ids - * - * Each storage has 2 different ids - * a string id which is generated by the storage backend and reflects the configuration of the storage (e.g. 'smb://user@host/share') - * and a numeric storage id which is referenced in the file cache - * - * A mapping between the two storage ids is stored in the database and accessible trough this class - * - * @package OC\Files\Cache - */ -class Storage { - private $storageId; - private $numericId; - - /** - * @param \OC\Files\Storage\Storage|string $storage - * @param bool $isAvailable - * @throws \RuntimeException - */ - public function __construct($storage, $isAvailable = true) { - if ($storage instanceof \OC\Files\Storage\Storage) { - $this->storageId = $storage->getId(); - } else { - $this->storageId = $storage; - } - $this->storageId = self::adjustStorageId($this->storageId); - - if ($row = self::getStorageById($this->storageId)) { - $this->numericId = $row['numeric_id']; - } else { - $connection = \OC::$server->getDatabaseConnection(); - $available = $isAvailable ? 1 : 0; - if ($connection->insertIfNotExist('*PREFIX*storages', ['id' => $this->storageId, 'available' => $available])) { - $this->numericId = $connection->lastInsertId('*PREFIX*storages'); - } else { - if ($row = self::getStorageById($this->storageId)) { - $this->numericId = $row['numeric_id']; - } else { - throw new \RuntimeException('Storage could neither be inserted nor be selected from the database'); - } - } - } - } - - /** - * @param string $storageId - * @return array|null - */ - public static function getStorageById($storageId) { - $sql = 'SELECT * FROM `*PREFIX*storages` WHERE `id` = ?'; - $result = \OC_DB::executeAudited($sql, array($storageId)); - return $result->fetchRow(); - } - - /** - * Adjusts the storage id to use md5 if too long - * @param string $storageId storage id - * @return string unchanged $storageId if its length is less than 64 characters, - * else returns the md5 of $storageId - */ - public static function adjustStorageId($storageId) { - if (strlen($storageId) > 64) { - return md5($storageId); - } - return $storageId; - } - - /** - * Get the numeric id for the storage - * - * @return int - */ - public function getNumericId() { - return $this->numericId; - } - - /** - * Get the string id for the storage - * - * @param int $numericId - * @return string|null either the storage id string or null if the numeric id is not known - */ - public static function getStorageId($numericId) { - - $sql = 'SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?'; - $result = \OC_DB::executeAudited($sql, array($numericId)); - if ($row = $result->fetchRow()) { - return $row['id']; - } else { - return null; - } - } - - /** - * Get the numeric of the storage with the provided string id - * - * @param $storageId - * @return int|null either the numeric storage id or null if the storage id is not knwon - */ - public static function getNumericStorageId($storageId) { - $storageId = self::adjustStorageId($storageId); - - if ($row = self::getStorageById($storageId)) { - return $row['numeric_id']; - } else { - return null; - } - } - - /** - * @return array|null [ available, last_checked ] - */ - public function getAvailability() { - if ($row = self::getStorageById($this->storageId)) { - return [ - 'available' => ((int)$row['available'] === 1), - 'last_checked' => $row['last_checked'] - ]; - } else { - return null; - } - } - - /** - * @param bool $isAvailable - */ - public function setAvailability($isAvailable) { - $sql = 'UPDATE `*PREFIX*storages` SET `available` = ?, `last_checked` = ? WHERE `id` = ?'; - $available = $isAvailable ? 1 : 0; - \OC_DB::executeAudited($sql, array($available, time(), $this->storageId)); - } - - /** - * Check if a string storage id is known - * - * @param string $storageId - * @return bool - */ - public static function exists($storageId) { - return !is_null(self::getNumericStorageId($storageId)); - } - - /** - * remove the entry for the storage - * - * @param string $storageId - */ - public static function remove($storageId) { - $storageId = self::adjustStorageId($storageId); - $numericId = self::getNumericStorageId($storageId); - $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'; - \OC_DB::executeAudited($sql, array($storageId)); - - if (!is_null($numericId)) { - $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?'; - \OC_DB::executeAudited($sql, array($numericId)); - } - } -} diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php deleted file mode 100644 index 3f80f2b6167..00000000000 --- a/lib/private/files/cache/updater.php +++ /dev/null @@ -1,228 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; -use OCP\Files\Cache\IUpdater; -use OCP\Files\Storage\IStorage; - -/** - * Update the cache and propagate changes - * - */ -class Updater implements IUpdater { - /** - * @var bool - */ - protected $enabled = true; - - /** - * @var \OC\Files\Storage\Storage - */ - protected $storage; - - /** - * @var \OC\Files\Cache\Propagator - */ - protected $propagator; - - /** - * @var Scanner - */ - protected $scanner; - - /** - * @var Cache - */ - protected $cache; - - /** - * @param \OC\Files\Storage\Storage $storage - */ - public function __construct(\OC\Files\Storage\Storage $storage) { - $this->storage = $storage; - $this->propagator = $storage->getPropagator(); - $this->scanner = $storage->getScanner(); - $this->cache = $storage->getCache(); - } - - /** - * Disable updating the cache trough this updater - */ - public function disable() { - $this->enabled = false; - } - - /** - * Re-enable the updating of the cache trough this updater - */ - public function enable() { - $this->enabled = true; - } - - /** - * Get the propagator for etags and mtime for the view the updater works on - * - * @return Propagator - */ - public function getPropagator() { - return $this->propagator; - } - - /** - * Propagate etag and mtime changes for the parent folders of $path up to the root of the filesystem - * - * @param string $path the path of the file to propagate the changes for - * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used - */ - public function propagate($path, $time = null) { - if (Scanner::isPartialFile($path)) { - return; - } - $this->propagator->propagateChange($path, $time); - } - - /** - * Update the cache for $path and update the size, etag and mtime of the parent folders - * - * @param string $path - * @param int $time - */ - public function update($path, $time = null) { - if (!$this->enabled or Scanner::isPartialFile($path)) { - return; - } - if (is_null($time)) { - $time = time(); - } - - $data = $this->scanner->scan($path, Scanner::SCAN_SHALLOW, -1, false); - if ( - isset($data['oldSize']) && isset($data['size']) && - !$data['encrypted'] // encryption is a pita and touches the cache itself - ) { - $sizeDifference = $data['size'] - $data['oldSize']; - } else { - // scanner didn't provide size info, fallback to full size calculation - $sizeDifference = 0; - $this->cache->correctFolderSize($path, $data); - } - $this->correctParentStorageMtime($path); - $this->propagator->propagateChange($path, $time, $sizeDifference); - } - - /** - * Remove $path from the cache and update the size, etag and mtime of the parent folders - * - * @param string $path - */ - public function remove($path) { - if (!$this->enabled or Scanner::isPartialFile($path)) { - return; - } - - $parent = dirname($path); - if ($parent === '.') { - $parent = ''; - } - - $this->cache->remove($path); - $this->cache->correctFolderSize($parent); - $this->correctParentStorageMtime($path); - $this->propagator->propagateChange($path, time()); - } - - /** - * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders - * - * @param IStorage $sourceStorage - * @param string $source - * @param string $target - */ - public function renameFromStorage(IStorage $sourceStorage, $source, $target) { - if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) { - return; - } - - $time = time(); - - $sourceCache = $sourceStorage->getCache(); - $sourceUpdater = $sourceStorage->getUpdater(); - $sourcePropagator = $sourceStorage->getPropagator(); - - if ($sourceCache->inCache($source)) { - if ($this->cache->inCache($target)) { - $this->cache->remove($target); - } - - if ($sourceStorage === $this->storage) { - $this->cache->move($source, $target); - } else { - $this->cache->moveFromCache($sourceCache, $source, $target); - } - } - - if (pathinfo($source, PATHINFO_EXTENSION) !== pathinfo($target, PATHINFO_EXTENSION)) { - // handle mime type change - $mimeType = $this->storage->getMimeType($target); - $fileId = $this->cache->getId($target); - $this->cache->update($fileId, ['mimetype' => $mimeType]); - } - - $sourceCache->correctFolderSize($source); - $this->cache->correctFolderSize($target); - if ($sourceUpdater instanceof Updater) { - $sourceUpdater->correctParentStorageMtime($source); - } - $this->correctParentStorageMtime($target); - $this->updateStorageMTimeOnly($target); - $sourcePropagator->propagateChange($source, $time); - $this->propagator->propagateChange($target, $time); - } - - private function updateStorageMTimeOnly($internalPath) { - $fileId = $this->cache->getId($internalPath); - if ($fileId !== -1) { - $this->cache->update( - $fileId, [ - 'mtime' => null, // this magic tells it to not overwrite mtime - 'storage_mtime' => $this->storage->filemtime($internalPath) - ] - ); - } - } - - /** - * update the storage_mtime of the direct parent in the cache to the mtime from the storage - * - * @param string $internalPath - */ - private function correctParentStorageMtime($internalPath) { - $parentId = $this->cache->getParentId($internalPath); - $parent = dirname($internalPath); - if ($parentId != -1) { - $this->cache->update($parentId, array('storage_mtime' => $this->storage->filemtime($parent))); - } - } -} diff --git a/lib/private/files/cache/watcher.php b/lib/private/files/cache/watcher.php deleted file mode 100644 index a00e875a2d4..00000000000 --- a/lib/private/files/cache/watcher.php +++ /dev/null @@ -1,140 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache; -use OCP\Files\Cache\ICacheEntry; -use OCP\Files\Cache\IWatcher; - -/** - * check the storage backends for updates and change the cache accordingly - */ -class Watcher implements IWatcher { - - protected $watchPolicy = self::CHECK_ONCE; - - protected $checkedPaths = array(); - - /** - * @var \OC\Files\Storage\Storage $storage - */ - protected $storage; - - /** - * @var Cache $cache - */ - protected $cache; - - /** - * @var Scanner $scanner ; - */ - protected $scanner; - - /** - * @param \OC\Files\Storage\Storage $storage - */ - public function __construct(\OC\Files\Storage\Storage $storage) { - $this->storage = $storage; - $this->cache = $storage->getCache(); - $this->scanner = $storage->getScanner(); - } - - /** - * @param int $policy either \OC\Files\Cache\Watcher::CHECK_NEVER, \OC\Files\Cache\Watcher::CHECK_ONCE, \OC\Files\Cache\Watcher::CHECK_ALWAYS - */ - public function setPolicy($policy) { - $this->watchPolicy = $policy; - } - - /** - * @return int either \OC\Files\Cache\Watcher::CHECK_NEVER, \OC\Files\Cache\Watcher::CHECK_ONCE, \OC\Files\Cache\Watcher::CHECK_ALWAYS - */ - public function getPolicy() { - return $this->watchPolicy; - } - - /** - * check $path for updates and update if needed - * - * @param string $path - * @param ICacheEntry|null $cachedEntry - * @return boolean true if path was updated - */ - public function checkUpdate($path, $cachedEntry = null) { - if (is_null($cachedEntry)) { - $cachedEntry = $this->cache->get($path); - } - if ($this->needsUpdate($path, $cachedEntry)) { - $this->update($path, $cachedEntry); - return true; - } else { - return false; - } - } - - /** - * Update the cache for changes to $path - * - * @param string $path - * @param ICacheEntry $cachedData - */ - public function update($path, $cachedData) { - if ($this->storage->is_dir($path)) { - $this->scanner->scan($path, Scanner::SCAN_SHALLOW); - } else { - $this->scanner->scanFile($path); - } - if ($cachedData['mimetype'] === 'httpd/unix-directory') { - $this->cleanFolder($path); - } - $this->cache->correctFolderSize($path); - } - - /** - * Check if the cache for $path needs to be updated - * - * @param string $path - * @param ICacheEntry $cachedData - * @return bool - */ - public function needsUpdate($path, $cachedData) { - if ($this->watchPolicy === self::CHECK_ALWAYS or ($this->watchPolicy === self::CHECK_ONCE and array_search($path, $this->checkedPaths) === false)) { - $this->checkedPaths[] = $path; - return $this->storage->hasUpdated($path, $cachedData['storage_mtime']); - } - return false; - } - - /** - * remove deleted files in $path from the cache - * - * @param string $path - */ - public function cleanFolder($path) { - $cachedContent = $this->cache->getFolderContents($path); - foreach ($cachedContent as $entry) { - if (!$this->storage->file_exists($entry['path'])) { - $this->cache->remove($entry['path']); - } - } - } -} diff --git a/lib/private/files/cache/wrapper/cachejail.php b/lib/private/files/cache/wrapper/cachejail.php deleted file mode 100644 index 88b0f23a1fc..00000000000 --- a/lib/private/files/cache/wrapper/cachejail.php +++ /dev/null @@ -1,300 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache\Wrapper; - -/** - * Jail to a subdirectory of the wrapped cache - */ -class CacheJail extends CacheWrapper { - /** - * @var string - */ - protected $root; - - /** - * @param \OCP\Files\Cache\ICache $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 . '/' . ltrim($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); - } - - /** - * insert meta data for a new file or folder - * - * @param string $file - * @param array $data - * - * @return int file id - * @throws \RuntimeException - */ - public function insert($file, array $data) { - return $this->cache->insert($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($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); - } - - /** - * search for files by mimetype - * - * @param string|int $tag name or tag id - * @param string $userId owner of the tags - * @return array - */ - public function searchByTag($tag, $userId) { - $results = $this->cache->searchByTag($tag, $userId); - 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); - } - - /** - * Move a file or folder in the cache - * - * Note that this should make sure the entries are removed from the source cache - * - * @param \OCP\Files\Cache\ICache $sourceCache - * @param string $sourcePath - * @param string $targetPath - */ - public function moveFromCache(\OCP\Files\Cache\ICache $sourceCache, $sourcePath, $targetPath) { - if ($sourceCache === $this) { - return $this->move($sourcePath, $targetPath); - } - return $this->cache->moveFromCache($sourceCache, $sourcePath, $targetPath); - } -} diff --git a/lib/private/files/cache/wrapper/cachepermissionsmask.php b/lib/private/files/cache/wrapper/cachepermissionsmask.php deleted file mode 100644 index b3a7bcb3a73..00000000000 --- a/lib/private/files/cache/wrapper/cachepermissionsmask.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache\Wrapper; - -class CachePermissionsMask extends CacheWrapper { - /** - * @var int - */ - protected $mask; - - /** - * @param \OCP\Files\Cache\ICache $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; - } -} diff --git a/lib/private/files/cache/wrapper/cachewrapper.php b/lib/private/files/cache/wrapper/cachewrapper.php deleted file mode 100644 index 8c77e3c340e..00000000000 --- a/lib/private/files/cache/wrapper/cachewrapper.php +++ /dev/null @@ -1,309 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Cache\Wrapper; - -use OC\Files\Cache\Cache; -use OCP\Files\Cache\ICacheEntry; -use OCP\Files\Cache\ICache; - -class CacheWrapper extends Cache { - /** - * @var \OCP\Files\Cache\ICache - */ - protected $cache; - - /** - * @param \OCP\Files\Cache\ICache $cache - */ - public function __construct($cache) { - $this->cache = $cache; - } - - /** - * Make it easy for wrappers to modify every returned cache entry - * - * @param ICacheEntry $entry - * @return ICacheEntry - */ - protected function formatCacheEntry($entry) { - return $entry; - } - - /** - * get the stored metadata of a file or folder - * - * @param string|int $file - * @return ICacheEntry|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 ICacheEntry[] - */ - public function getFolderContents($folder) { - // can't 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); - } - - /** - * insert or update meta data for a file or folder - * - * @param string $file - * @param array $data - * - * @return int file id - * @throws \RuntimeException - */ - public function put($file, array $data) { - if (($id = $this->getId($file)) > -1) { - $this->update($id, $data); - return $id; - } else { - return $this->insert($file, $data); - } - } - - /** - * insert meta data for a new file or folder - * - * @param string $file - * @param array $data - * - * @return int file id - * @throws \RuntimeException - */ - public function insert($file, array $data) { - return $this->cache->insert($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); - } - - public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { - $this->cache->moveFromCache($sourceCache, $sourcePath, $targetPath); - } - - /** - * 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 ICacheEntry[] 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 ICacheEntry[] - */ - public function searchByMime($mimetype) { - $results = $this->cache->searchByMime($mimetype); - return array_map(array($this, 'formatCacheEntry'), $results); - } - - /** - * search for files by tag - * - * @param string|int $tag name or tag id - * @param string $userId owner of the tags - * @return ICacheEntry[] file data - */ - public function searchByTag($tag, $userId) { - $results = $this->cache->searchByTag($tag, $userId); - 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); - } - - /** - * Returns the numeric storage id - * - * @return int - */ - public function getNumericStorageId() { - return $this->cache->getNumericStorageId(); - } - - /** - * 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/config/cachedmountinfo.php b/lib/private/files/config/cachedmountinfo.php deleted file mode 100644 index ce75cb66896..00000000000 --- a/lib/private/files/config/cachedmountinfo.php +++ /dev/null @@ -1,107 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Config; - -use OC\Files\Filesystem; -use OCP\Files\Config\ICachedMountInfo; -use OCP\Files\Node; -use OCP\IUser; - -class CachedMountInfo implements ICachedMountInfo { - /** - * @var IUser - */ - protected $user; - - /** - * @var int - */ - protected $storageId; - - /** - * @var int - */ - protected $rootId; - - /** - * @var string - */ - protected $mountPoint; - - /** - * CachedMountInfo constructor. - * - * @param IUser $user - * @param int $storageId - * @param int $rootId - * @param string $mountPoint - */ - public function __construct(IUser $user, $storageId, $rootId, $mountPoint) { - $this->user = $user; - $this->storageId = $storageId; - $this->rootId = $rootId; - $this->mountPoint = $mountPoint; - } - - /** - * @return IUser - */ - public function getUser() { - return $this->user; - } - - /** - * @return int the numeric storage id of the mount - */ - public function getStorageId() { - return $this->storageId; - } - - /** - * @return int the fileid of the root of the mount - */ - public function getRootId() { - return $this->rootId; - } - - /** - * @return Node the root node of the mount - */ - public function getMountPointNode() { - // TODO injection etc - Filesystem::initMountPoints($this->getUser()->getUID()); - $userNode = \OC::$server->getUserFolder($this->getUser()->getUID()); - $nodes = $userNode->getById($this->getRootId()); - if (count($nodes) > 0) { - return $nodes[0]; - } else { - return null; - } - } - - /** - * @return string the mount point of the mount for the user - */ - public function getMountPoint() { - return $this->mountPoint; - } -} diff --git a/lib/private/files/config/lazystoragemountinfo.php b/lib/private/files/config/lazystoragemountinfo.php deleted file mode 100644 index 654c5b2b23e..00000000000 --- a/lib/private/files/config/lazystoragemountinfo.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Config; - -use OC\Files\Filesystem; -use OCP\Files\Config\ICachedMountInfo; -use OCP\Files\Mount\IMountPoint; -use OCP\Files\Node; -use OCP\IUser; - -class LazyStorageMountInfo extends CachedMountInfo { - /** @var IMountPoint */ - private $mount; - - /** - * CachedMountInfo constructor. - * - * @param IUser $user - * @param IMountPoint $mount - */ - public function __construct(IUser $user, IMountPoint $mount) { - $this->user = $user; - $this->mount = $mount; - } - - /** - * @return int the numeric storage id of the mount - */ - public function getStorageId() { - if (!$this->storageId) { - $this->storageId = $this->mount->getStorage()->getStorageCache()->getNumericId(); - } - return parent::getStorageId(); - } - - /** - * @return int the fileid of the root of the mount - */ - public function getRootId() { - if (!$this->rootId) { - $this->rootId = $this->mount->getStorageRootId(); - } - return parent::getRootId(); - } - - /** - * @return string the mount point of the mount for the user - */ - public function getMountPoint() { - if (!$this->mountPoint) { - $this->mountPoint = $this->mount->getMountPoint(); - } - return parent::getMountPoint(); - } -} diff --git a/lib/private/files/config/mountprovidercollection.php b/lib/private/files/config/mountprovidercollection.php deleted file mode 100644 index 499fa576fbc..00000000000 --- a/lib/private/files/config/mountprovidercollection.php +++ /dev/null @@ -1,108 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Config; - -use OC\Hooks\Emitter; -use OC\Hooks\EmitterTrait; -use OCP\Files\Config\IMountProviderCollection; -use OCP\Files\Config\IMountProvider; -use OCP\Files\Config\IUserMountCache; -use OCP\Files\Mount\IMountPoint; -use OCP\Files\Storage\IStorageFactory; -use OCP\IUser; - -class MountProviderCollection implements IMountProviderCollection, Emitter { - use EmitterTrait; - - /** - * @var \OCP\Files\Config\IMountProvider[] - */ - private $providers = array(); - - /** - * @var \OCP\Files\Storage\IStorageFactory - */ - private $loader; - - /** - * @var \OCP\Files\Config\IUserMountCache - */ - private $mountCache; - - /** - * @param \OCP\Files\Storage\IStorageFactory $loader - * @param IUserMountCache $mountCache - */ - public function __construct(IStorageFactory $loader, IUserMountCache $mountCache) { - $this->loader = $loader; - $this->mountCache = $mountCache; - } - - /** - * Get all configured mount points for the user - * - * @param \OCP\IUser $user - * @return \OCP\Files\Mount\IMountPoint[] - */ - public function getMountsForUser(IUser $user) { - $loader = $this->loader; - $mounts = array_map(function (IMountProvider $provider) use ($user, $loader) { - return $provider->getMountsForUser($user, $loader); - }, $this->providers); - $mounts = array_filter($mounts, function ($result) { - return is_array($result); - }); - return array_reduce($mounts, function (array $mounts, array $providerMounts) { - return array_merge($mounts, $providerMounts); - }, array()); - } - - /** - * Add a provider for mount points - * - * @param \OCP\Files\Config\IMountProvider $provider - */ - public function registerProvider(IMountProvider $provider) { - $this->providers[] = $provider; - $this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]); - } - - /** - * Cache mounts for user - * - * @param IUser $user - * @param IMountPoint[] $mountPoints - */ - public function registerMounts(IUser $user, array $mountPoints) { - $this->mountCache->registerMounts($user, $mountPoints); - } - - /** - * Get the mount cache which can be used to search for mounts without setting up the filesystem - * - * @return IUserMountCache - */ - public function getMountCache() { - return $this->mountCache; - } -} diff --git a/lib/private/files/config/usermountcache.php b/lib/private/files/config/usermountcache.php deleted file mode 100644 index 05ca146f4be..00000000000 --- a/lib/private/files/config/usermountcache.php +++ /dev/null @@ -1,290 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Config; - -use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use OC\Files\Filesystem; -use OCA\Files_Sharing\SharedMount; -use OCP\DB\QueryBuilder\IQueryBuilder; -use OCP\Files\Config\ICachedMountInfo; -use OCP\Files\Config\IUserMountCache; -use OCP\Files\Mount\IMountPoint; -use OCP\Files\NotFoundException; -use OCP\ICache; -use OCP\IDBConnection; -use OCP\ILogger; -use OCP\IUser; -use OCP\IUserManager; - -/** - * Cache mounts points per user in the cache so we can easilly look them up - */ -class UserMountCache implements IUserMountCache { - /** - * @var IDBConnection - */ - private $connection; - - /** - * @var IUserManager - */ - private $userManager; - - /** @var ICachedMountInfo[][] [$userId => [$cachedMountInfo, ....], ...] */ - private $mountsForUsers = []; - - /** - * @var ILogger - */ - private $logger; - - private $cacheInfoCache = []; - - /** - * UserMountCache constructor. - * - * @param IDBConnection $connection - * @param IUserManager $userManager - * @param ILogger $logger - */ - public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) { - $this->connection = $connection; - $this->userManager = $userManager; - $this->logger = $logger; - } - - public function registerMounts(IUser $user, array $mounts) { - // filter out non-proper storages coming from unit tests - $mounts = array_filter($mounts, function (IMountPoint $mount) { - return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache(); - }); - /** @var ICachedMountInfo[] $newMounts */ - $newMounts = array_map(function (IMountPoint $mount) use ($user) { - // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet) - if ($mount->getStorageRootId() === -1) { - return null; - } else { - return new LazyStorageMountInfo($user, $mount); - } - }, $mounts); - $newMounts = array_values(array_filter($newMounts)); - - $cachedMounts = $this->getMountsForUser($user); - $mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) { - // since we are only looking for mounts for a specific user comparing on root id is enough - return $mount1->getRootId() - $mount2->getRootId(); - }; - - /** @var ICachedMountInfo[] $addedMounts */ - $addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff); - /** @var ICachedMountInfo[] $removedMounts */ - $removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff); - - $changedMounts = array_uintersect($newMounts, $cachedMounts, function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) { - // filter mounts with the same root id and different mountpoints - if ($mount1->getRootId() !== $mount2->getRootId()) { - return -1; - } - return ($mount1->getMountPoint() !== $mount2->getMountPoint()) ? 0 : 1; - }); - - foreach ($addedMounts as $mount) { - $this->addToCache($mount); - $this->mountsForUsers[$user->getUID()][] = $mount; - } - foreach ($removedMounts as $mount) { - $this->removeFromCache($mount); - $index = array_search($mount, $this->mountsForUsers[$user->getUID()]); - unset($this->mountsForUsers[$user->getUID()][$index]); - } - foreach ($changedMounts as $mount) { - $this->setMountPoint($mount); - } - } - - private function addToCache(ICachedMountInfo $mount) { - $this->connection->insertIfNotExist('*PREFIX*mounts', [ - 'storage_id' => $mount->getStorageId(), - 'root_id' => $mount->getRootId(), - 'user_id' => $mount->getUser()->getUID(), - 'mount_point' => $mount->getMountPoint() - ], ['root_id', 'user_id']); - } - - private function setMountPoint(ICachedMountInfo $mount) { - $builder = $this->connection->getQueryBuilder(); - - $query = $builder->update('mounts') - ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint())) - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) - ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); - - $query->execute(); - } - - private function removeFromCache(ICachedMountInfo $mount) { - $builder = $this->connection->getQueryBuilder(); - - $query = $builder->delete('mounts') - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) - ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); - $query->execute(); - } - - private function dbRowToMountInfo(array $row) { - $user = $this->userManager->get($row['user_id']); - return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point']); - } - - /** - * @param IUser $user - * @return ICachedMountInfo[] - */ - public function getMountsForUser(IUser $user) { - if (!isset($this->mountsForUsers[$user->getUID()])) { - $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point') - ->from('mounts') - ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID()))); - - $rows = $query->execute()->fetchAll(); - - $this->mountsForUsers[$user->getUID()] = array_map([$this, 'dbRowToMountInfo'], $rows); - } - return $this->mountsForUsers[$user->getUID()]; - } - - /** - * @param int $numericStorageId - * @return CachedMountInfo[] - */ - public function getMountsForStorageId($numericStorageId) { - $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point') - ->from('mounts') - ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT))); - - $rows = $query->execute()->fetchAll(); - - return array_map([$this, 'dbRowToMountInfo'], $rows); - } - - /** - * @param int $rootFileId - * @return CachedMountInfo[] - */ - public function getMountsForRootId($rootFileId) { - $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point') - ->from('mounts') - ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT))); - - $rows = $query->execute()->fetchAll(); - - return array_map([$this, 'dbRowToMountInfo'], $rows); - } - - /** - * @param $fileId - * @return array - * @throws \OCP\Files\NotFoundException - */ - private function getCacheInfoFromFileId($fileId) { - if (!isset($this->cacheInfoCache[$fileId])) { - $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage', 'path') - ->from('filecache') - ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); - - $row = $query->execute()->fetch(); - if (is_array($row)) { - $this->cacheInfoCache[$fileId] = [ - (int)$row['storage'], - $row['path'] - ]; - } else { - throw new NotFoundException('File with id "' . $fileId . '" not found'); - } - } - return $this->cacheInfoCache[$fileId]; - } - - /** - * @param int $fileId - * @return ICachedMountInfo[] - * @since 9.0.0 - */ - public function getMountsForFileId($fileId) { - try { - list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId); - } catch (NotFoundException $e) { - return []; - } - $mountsForStorage = $this->getMountsForStorageId($storageId); - - // filter mounts that are from the same storage but a different directory - return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) { - if ($fileId === $mount->getRootId()) { - return true; - } - try { - list(, $internalMountPath) = $this->getCacheInfoFromFileId($mount->getRootId()); - } catch (NotFoundException $e) { - return false; - } - - return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/'; - }); - - } - - /** - * Remove all cached mounts for a user - * - * @param IUser $user - */ - public function removeUserMounts(IUser $user) { - $builder = $this->connection->getQueryBuilder(); - - $query = $builder->delete('mounts') - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID()))); - $query->execute(); - } - - public function removeUserStorageMount($storageId, $userId) { - $builder = $this->connection->getQueryBuilder(); - - $query = $builder->delete('mounts') - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId))) - ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); - $query->execute(); - } - - public function remoteStorageMounts($storageId) { - $builder = $this->connection->getQueryBuilder(); - - $query = $builder->delete('mounts') - ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); - $query->execute(); - } -} diff --git a/lib/private/files/config/usermountcachelistener.php b/lib/private/files/config/usermountcachelistener.php deleted file mode 100644 index 99673cf6285..00000000000 --- a/lib/private/files/config/usermountcachelistener.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Config; - -use OC\User\Manager; -use OCP\Files\Config\IUserMountCache; - -/** - * Listen to hooks and update the mount cache as needed - */ -class UserMountCacheListener { - /** - * @var IUserMountCache - */ - private $userMountCache; - - /** - * UserMountCacheListener constructor. - * - * @param IUserMountCache $userMountCache - */ - public function __construct(IUserMountCache $userMountCache) { - $this->userMountCache = $userMountCache; - } - - public function listen(Manager $manager) { - $manager->listen('\OC\User', 'postDelete', [$this->userMountCache, 'removeUserMounts']); - } -} diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php deleted file mode 100644 index 5f32ad34bb3..00000000000 --- a/lib/private/files/fileinfo.php +++ /dev/null @@ -1,346 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author tbartenstein <tbartenstein@users.noreply.github.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files; - -use OCP\Files\Cache\ICacheEntry; -use OCP\IUser; - -class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { - /** - * @var array $data - */ - private $data; - - /** - * @var string $path - */ - private $path; - - /** - * @var \OC\Files\Storage\Storage $storage - */ - private $storage; - - /** - * @var string $internalPath - */ - private $internalPath; - - /** - * @var \OCP\Files\Mount\IMountPoint - */ - private $mount; - - /** - * @var IUser - */ - private $owner; - - /** - * @var string[] - */ - private $childEtags = []; - - /** - * @param string|boolean $path - * @param Storage\Storage $storage - * @param string $internalPath - * @param array|ICacheEntry $data - * @param \OCP\Files\Mount\IMountPoint $mount - * @param \OCP\IUser|null $owner - */ - public function __construct($path, $storage, $internalPath, $data, $mount, $owner= null) { - $this->path = $path; - $this->storage = $storage; - $this->internalPath = $internalPath; - $this->data = $data; - $this->mount = $mount; - $this->owner = $owner; - } - - public function offsetSet($offset, $value) { - $this->data[$offset] = $value; - } - - public function offsetExists($offset) { - return isset($this->data[$offset]); - } - - public function offsetUnset($offset) { - unset($this->data[$offset]); - } - - public function offsetGet($offset) { - if ($offset === 'type') { - return $this->getType(); - } else if ($offset === 'etag') { - return $this->getEtag(); - } elseif ($offset === 'permissions') { - return $this->getPermissions(); - } elseif (isset($this->data[$offset])) { - return $this->data[$offset]; - } else { - return null; - } - } - - /** - * @return string - */ - public function getPath() { - return $this->path; - } - - /** - * @return \OCP\Files\Storage - */ - public function getStorage() { - return $this->storage; - } - - /** - * @return string - */ - public function getInternalPath() { - return $this->internalPath; - } - - /** - * @return int - */ - public function getId() { - return $this->data['fileid']; - } - - /** - * @return string - */ - public function getMimetype() { - return $this->data['mimetype']; - } - - /** - * @return string - */ - public function getMimePart() { - return $this->data['mimepart']; - } - - /** - * @return string - */ - public function getName() { - return basename($this->getPath()); - } - - /** - * @return string - */ - public function getEtag() { - if (count($this->childEtags) > 0) { - $combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags); - return md5($combinedEtag); - } else { - return $this->data['etag']; - } - } - - /** - * @return int - */ - public function getSize() { - return isset($this->data['size']) ? $this->data['size'] : 0; - } - - /** - * @return int - */ - public function getMTime() { - return $this->data['mtime']; - } - - /** - * @return bool - */ - public function isEncrypted() { - return $this->data['encrypted']; - } - - /** - * Return the currently version used for the HMAC in the encryption app - * - * @return int - */ - public function getEncryptedVersion() { - return isset($this->data['encryptedVersion']) ? (int) $this->data['encryptedVersion'] : 1; - } - - /** - * @return int - */ - public function getPermissions() { - $perms = $this->data['permissions']; - if (\OCP\Util::isSharingDisabledForUser() || ($this->isShared() && !\OC\Share\Share::isResharingAllowed())) { - $perms = $perms & ~\OCP\Constants::PERMISSION_SHARE; - } - return $perms; - } - - /** - * @return \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER - */ - public function getType() { - if (!isset($this->data['type'])) { - $this->data['type'] = ($this->getMimetype() === 'httpd/unix-directory') ? self::TYPE_FOLDER : self::TYPE_FILE; - } - return $this->data['type']; - } - - public function getData() { - return $this->data; - } - - /** - * @param int $permissions - * @return bool - */ - protected function checkPermissions($permissions) { - return ($this->getPermissions() & $permissions) === $permissions; - } - - /** - * @return bool - */ - public function isReadable() { - return $this->checkPermissions(\OCP\Constants::PERMISSION_READ); - } - - /** - * @return bool - */ - public function isUpdateable() { - return $this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE); - } - - /** - * Check whether new files or folders can be created inside this folder - * - * @return bool - */ - public function isCreatable() { - return $this->checkPermissions(\OCP\Constants::PERMISSION_CREATE); - } - - /** - * @return bool - */ - public function isDeletable() { - return $this->checkPermissions(\OCP\Constants::PERMISSION_DELETE); - } - - /** - * @return bool - */ - public function isShareable() { - return $this->checkPermissions(\OCP\Constants::PERMISSION_SHARE); - } - - /** - * Check if a file or folder is shared - * - * @return bool - */ - public function isShared() { - $sid = $this->getStorage()->getId(); - if (!is_null($sid)) { - $sid = explode(':', $sid); - return ($sid[0] === 'shared'); - } - - return false; - } - - public function isMounted() { - $sid = $this->getStorage()->getId(); - if (!is_null($sid)) { - $sid = explode(':', $sid); - return ($sid[0] !== 'home' and $sid[0] !== 'shared'); - } - - return false; - } - - /** - * Get the mountpoint the file belongs to - * - * @return \OCP\Files\Mount\IMountPoint - */ - public function getMountPoint() { - return $this->mount; - } - - /** - * Get the owner of the file - * - * @return \OCP\IUser - */ - public function getOwner() { - return $this->owner; - } - - /** - * Add a cache entry which is the child of this folder - * - * Sets the size, etag and size to for cross-storage childs - * - * @param array $data cache entry for the child - * @param string $entryPath full path of the child entry - */ - public function addSubEntry($data, $entryPath) { - $this->data['size'] += isset($data['size']) ? $data['size'] : 0; - if (isset($data['mtime'])) { - $this->data['mtime'] = max($this->data['mtime'], $data['mtime']); - } - if (isset($data['etag'])) { - // prefix the etag with the relative path of the subentry to propagate etag on mount moves - $relativeEntryPath = substr($entryPath, strlen($this->getPath())); - // attach the permissions to propagate etag on permision changes of submounts - $permissions = isset($data['permissions']) ? $data['permissions'] : 0; - $this->childEtags[] = $relativeEntryPath . '/' . $data['etag'] . $permissions; - } - } - - /** - * @inheritdoc - */ - public function getChecksum() { - return $this->data['checksum']; - } -} diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php deleted file mode 100644 index 7283c815c97..00000000000 --- a/lib/private/files/filesystem.php +++ /dev/null @@ -1,928 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Bart Visscher <bartv@thisnet.nl> - * @author Christopher Schäpers <kondou@ts.unde.re> - * @author Florin Peter <github@florin-peter.de> - * @author Georg Ehrke <georg@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Sam Tuke <mail@samtuke.com> - * @author Stephan Peijnik <speijnik@anexia-it.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -/** - * Class for abstraction of filesystem functions - * This class won't call any filesystem functions for itself but will pass them to the correct OC_Filestorage object - * this class should also handle all the file permission related stuff - * - * Hooks provided: - * read(path) - * write(path, &run) - * post_write(path) - * create(path, &run) (when a file is created, both create and write will be emitted in that order) - * post_create(path) - * delete(path, &run) - * post_delete(path) - * rename(oldpath,newpath, &run) - * post_rename(oldpath,newpath) - * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order) - * post_rename(oldpath,newpath) - * post_initMountPoints(user, user_dir) - * - * the &run parameter can be set to false to prevent the operation from occurring - */ - -namespace OC\Files; - -use OC\Files\Config\MountProviderCollection; -use OC\Files\Mount\MountPoint; -use OC\Files\Storage\StorageFactory; -use OCP\Files\Config\IMountProvider; -use OCP\Files\Mount\IMountPoint; -use OCP\Files\NotFoundException; -use OCP\IUserManager; - -class Filesystem { - - /** - * @var Mount\Manager $mounts - */ - private static $mounts; - - public static $loaded = false; - /** - * @var \OC\Files\View $defaultInstance - */ - static private $defaultInstance; - - static private $usersSetup = array(); - - static private $normalizedPathCache = array(); - - static private $listeningForProviders = false; - - /** - * classname which used for hooks handling - * used as signalclass in OC_Hooks::emit() - */ - const CLASSNAME = 'OC_Filesystem'; - - /** - * signalname emitted before file renaming - * - * @param string $oldpath - * @param string $newpath - */ - const signal_rename = 'rename'; - - /** - * signal emitted after file renaming - * - * @param string $oldpath - * @param string $newpath - */ - const signal_post_rename = 'post_rename'; - - /** - * signal emitted before file/dir creation - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_create = 'create'; - - /** - * signal emitted after file/dir creation - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_post_create = 'post_create'; - - /** - * signal emits before file/dir copy - * - * @param string $oldpath - * @param string $newpath - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_copy = 'copy'; - - /** - * signal emits after file/dir copy - * - * @param string $oldpath - * @param string $newpath - */ - const signal_post_copy = 'post_copy'; - - /** - * signal emits before file/dir save - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_write = 'write'; - - /** - * signal emits after file/dir save - * - * @param string $path - */ - const signal_post_write = 'post_write'; - - /** - * signal emitted before file/dir update - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_update = 'update'; - - /** - * signal emitted after file/dir update - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_post_update = 'post_update'; - - /** - * signal emits when reading file/dir - * - * @param string $path - */ - const signal_read = 'read'; - - /** - * signal emits when removing file/dir - * - * @param string $path - */ - const signal_delete = 'delete'; - - /** - * parameters definitions for signals - */ - const signal_param_path = 'path'; - const signal_param_oldpath = 'oldpath'; - const signal_param_newpath = 'newpath'; - - /** - * run - changing this flag to false in hook handler will cancel event - */ - const signal_param_run = 'run'; - - const signal_create_mount = 'create_mount'; - const signal_delete_mount = 'delete_mount'; - const signal_param_mount_type = 'mounttype'; - const signal_param_users = 'users'; - - /** - * @var \OC\Files\Storage\StorageFactory $loader - */ - private static $loader; - - /** - * @param string $wrapperName - * @param callable $wrapper - * @param int $priority - */ - public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) { - $mounts = self::getMountManager()->getAll(); - if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) { - // do not re-wrap if storage with this name already existed - return; - } - } - - /** - * Returns the storage factory - * - * @return \OCP\Files\Storage\IStorageFactory - */ - public static function getLoader() { - if (!self::$loader) { - self::$loader = new StorageFactory(); - } - return self::$loader; - } - - /** - * Returns the mount manager - * - * @return \OC\Files\Mount\Manager - */ - public static function getMountManager($user = '') { - if (!self::$mounts) { - \OC_Util::setupFS($user); - } - return self::$mounts; - } - - /** - * get the mountpoint of the storage object for a path - * ( note: because a storage is not always mounted inside the fakeroot, the - * returned mountpoint is relative to the absolute root of the filesystem - * and doesn't take the chroot into account ) - * - * @param string $path - * @return string - */ - static public function getMountPoint($path) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = self::$mounts->find($path); - if ($mount) { - return $mount->getMountPoint(); - } else { - return ''; - } - } - - /** - * get a list of all mount points in a directory - * - * @param string $path - * @return string[] - */ - static public function getMountPoints($path) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $result = array(); - $mounts = self::$mounts->findIn($path); - foreach ($mounts as $mount) { - $result[] = $mount->getMountPoint(); - } - return $result; - } - - /** - * get the storage mounted at $mountPoint - * - * @param string $mountPoint - * @return \OC\Files\Storage\Storage - */ - public static function getStorage($mountPoint) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = self::$mounts->find($mountPoint); - return $mount->getStorage(); - } - - /** - * @param string $id - * @return Mount\MountPoint[] - */ - public static function getMountByStorageId($id) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - return self::$mounts->findByStorageId($id); - } - - /** - * @param int $id - * @return Mount\MountPoint[] - */ - public static function getMountByNumericId($id) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - return self::$mounts->findByNumericId($id); - } - - /** - * resolve a path to a storage and internal path - * - * @param string $path - * @return array an array consisting of the storage and the internal path - */ - static public function resolvePath($path) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = self::$mounts->find($path); - if ($mount) { - return array($mount->getStorage(), rtrim($mount->getInternalPath($path), '/')); - } else { - return array(null, null); - } - } - - static public function init($user, $root) { - if (self::$defaultInstance) { - return false; - } - self::getLoader(); - self::$defaultInstance = new View($root); - - if (!self::$mounts) { - self::$mounts = \OC::$server->getMountManager(); - } - - //load custom mount config - self::initMountPoints($user); - - self::$loaded = true; - - return true; - } - - static public function initMountManager() { - if (!self::$mounts) { - self::$mounts = \OC::$server->getMountManager(); - } - } - - /** - * Initialize system and personal mount points for a user - * - * @param string $user - * @throws \OC\User\NoUserException if the user is not available - */ - public static function initMountPoints($user = '') { - if ($user == '') { - $user = \OC_User::getUser(); - } - if ($user === null || $user === false || $user === '') { - throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session'); - } - if (isset(self::$usersSetup[$user])) { - return; - } - $root = \OC_User::getHome($user); - - $userManager = \OC::$server->getUserManager(); - $userObject = $userManager->get($user); - - if (is_null($userObject)) { - \OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR); - throw new \OC\User\NoUserException('Backends provided no user object for ' . $user); - } - - self::$usersSetup[$user] = true; - - $homeStorage = \OC::$server->getConfig()->getSystemValue('objectstore'); - if (!empty($homeStorage)) { - // sanity checks - if (empty($homeStorage['class'])) { - \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR); - } - if (!isset($homeStorage['arguments'])) { - $homeStorage['arguments'] = array(); - } - // instantiate object store implementation - $homeStorage['arguments']['objectstore'] = new $homeStorage['class']($homeStorage['arguments']); - // mount with home object store implementation - $homeStorage['class'] = '\OC\Files\ObjectStore\HomeObjectStoreStorage'; - } else { - $homeStorage = array( - //default home storage configuration: - 'class' => '\OC\Files\Storage\Home', - 'arguments' => array() - ); - } - $homeStorage['arguments']['user'] = $userObject; - - // check for legacy home id (<= 5.0.12) - if (\OC\Files\Cache\Storage::exists('local::' . $root . '/')) { - $homeStorage['arguments']['legacy'] = true; - } - - $mount = new MountPoint($homeStorage['class'], '/' . $user, $homeStorage['arguments'], self::getLoader()); - self::getMountManager()->addMount($mount); - - $home = \OC\Files\Filesystem::getStorage($user); - - self::mountCacheDir($user); - - // Chance to mount for other storages - /** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */ - $mountConfigManager = \OC::$server->getMountProviderCollection(); - if ($userObject) { - $mounts = $mountConfigManager->getMountsForUser($userObject); - array_walk($mounts, array(self::$mounts, 'addMount')); - $mounts[] = $mount; - $mountConfigManager->registerMounts($userObject, $mounts); - } - - self::listenForNewMountProviders($mountConfigManager, $userManager); - \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root)); - } - - /** - * Get mounts from mount providers that are registered after setup - * - * @param MountProviderCollection $mountConfigManager - * @param IUserManager $userManager - */ - private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) { - if (!self::$listeningForProviders) { - self::$listeningForProviders = true; - $mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) { - foreach (Filesystem::$usersSetup as $user => $setup) { - $userObject = $userManager->get($user); - if ($userObject) { - $mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader()); - array_walk($mounts, array(self::$mounts, 'addMount')); - } - } - }); - } - } - - /** - * Mounts the cache directory - * - * @param string $user user name - */ - private static function mountCacheDir($user) { - $cacheBaseDir = \OC::$server->getConfig()->getSystemValue('cache_path', ''); - if ($cacheBaseDir !== '') { - $cacheDir = rtrim($cacheBaseDir, '/') . '/' . $user; - if (!file_exists($cacheDir)) { - mkdir($cacheDir, 0770, true); - } - // mount external cache dir to "/$user/cache" mount point - self::mount('\OC\Files\Storage\Local', array('datadir' => $cacheDir), '/' . $user . '/cache'); - } - } - - /** - * get the default filesystem view - * - * @return View - */ - static public function getView() { - return self::$defaultInstance; - } - - /** - * tear down the filesystem, removing all storage providers - */ - static public function tearDown() { - self::clearMounts(); - self::$defaultInstance = null; - } - - /** - * get the relative path of the root data directory for the current user - * - * @return string - * - * Returns path like /admin/files - */ - static public function getRoot() { - if (!self::$defaultInstance) { - return null; - } - return self::$defaultInstance->getRoot(); - } - - /** - * clear all mounts and storage backends - */ - public static function clearMounts() { - if (self::$mounts) { - self::$usersSetup = array(); - self::$mounts->clear(); - } - } - - /** - * mount an \OC\Files\Storage\Storage in our virtual filesystem - * - * @param \OC\Files\Storage\Storage|string $class - * @param array $arguments - * @param string $mountpoint - */ - static public function mount($class, $arguments, $mountpoint) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader()); - self::$mounts->addMount($mount); - } - - /** - * return the path to a local version of the file - * we need this because we can't know if a file is stored local or not from - * outside the filestorage and for some purposes a local file is needed - * - * @param string $path - * @return string - */ - static public function getLocalFile($path) { - return self::$defaultInstance->getLocalFile($path); - } - - /** - * @param string $path - * @return string - */ - static public function getLocalFolder($path) { - return self::$defaultInstance->getLocalFolder($path); - } - - /** - * return path to file which reflects one visible in browser - * - * @param string $path - * @return string - */ - static public function getLocalPath($path) { - $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files'; - $newpath = $path; - if (strncmp($newpath, $datadir, strlen($datadir)) == 0) { - $newpath = substr($path, strlen($datadir)); - } - return $newpath; - } - - /** - * check if the requested path is valid - * - * @param string $path - * @return bool - */ - static public function isValidPath($path) { - $path = self::normalizePath($path); - if (!$path || $path[0] !== '/') { - $path = '/' . $path; - } - if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') { - return false; - } - return true; - } - - /** - * checks if a file is blacklisted for storage in the filesystem - * Listens to write and rename hooks - * - * @param array $data from hook - */ - static public function isBlacklisted($data) { - if (isset($data['path'])) { - $path = $data['path']; - } else if (isset($data['newpath'])) { - $path = $data['newpath']; - } - if (isset($path)) { - if (self::isFileBlacklisted($path)) { - $data['run'] = false; - } - } - } - - /** - * @param string $filename - * @return bool - */ - static public function isFileBlacklisted($filename) { - $filename = self::normalizePath($filename); - - $blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', array('.htaccess')); - $filename = strtolower(basename($filename)); - return in_array($filename, $blacklist); - } - - /** - * check if the directory should be ignored when scanning - * NOTE: the special directories . and .. would cause never ending recursion - * - * @param String $dir - * @return boolean - */ - static public function isIgnoredDir($dir) { - if ($dir === '.' || $dir === '..') { - return true; - } - return false; - } - - /** - * following functions are equivalent to their php builtin equivalents for arguments/return values. - */ - static public function mkdir($path) { - return self::$defaultInstance->mkdir($path); - } - - static public function rmdir($path) { - return self::$defaultInstance->rmdir($path); - } - - static public function opendir($path) { - return self::$defaultInstance->opendir($path); - } - - static public function readdir($path) { - return self::$defaultInstance->readdir($path); - } - - static public function is_dir($path) { - return self::$defaultInstance->is_dir($path); - } - - static public function is_file($path) { - return self::$defaultInstance->is_file($path); - } - - static public function stat($path) { - return self::$defaultInstance->stat($path); - } - - static public function filetype($path) { - return self::$defaultInstance->filetype($path); - } - - static public function filesize($path) { - return self::$defaultInstance->filesize($path); - } - - static public function readfile($path) { - return self::$defaultInstance->readfile($path); - } - - static public function isCreatable($path) { - return self::$defaultInstance->isCreatable($path); - } - - static public function isReadable($path) { - return self::$defaultInstance->isReadable($path); - } - - static public function isUpdatable($path) { - return self::$defaultInstance->isUpdatable($path); - } - - static public function isDeletable($path) { - return self::$defaultInstance->isDeletable($path); - } - - static public function isSharable($path) { - return self::$defaultInstance->isSharable($path); - } - - static public function file_exists($path) { - return self::$defaultInstance->file_exists($path); - } - - static public function filemtime($path) { - return self::$defaultInstance->filemtime($path); - } - - static public function touch($path, $mtime = null) { - return self::$defaultInstance->touch($path, $mtime); - } - - /** - * @return string - */ - static public function file_get_contents($path) { - return self::$defaultInstance->file_get_contents($path); - } - - static public function file_put_contents($path, $data) { - return self::$defaultInstance->file_put_contents($path, $data); - } - - static public function unlink($path) { - return self::$defaultInstance->unlink($path); - } - - static public function rename($path1, $path2) { - return self::$defaultInstance->rename($path1, $path2); - } - - static public function copy($path1, $path2) { - return self::$defaultInstance->copy($path1, $path2); - } - - static public function fopen($path, $mode) { - return self::$defaultInstance->fopen($path, $mode); - } - - /** - * @return string - */ - static public function toTmpFile($path) { - return self::$defaultInstance->toTmpFile($path); - } - - static public function fromTmpFile($tmpFile, $path) { - return self::$defaultInstance->fromTmpFile($tmpFile, $path); - } - - static public function getMimeType($path) { - return self::$defaultInstance->getMimeType($path); - } - - static public function hash($type, $path, $raw = false) { - return self::$defaultInstance->hash($type, $path, $raw); - } - - static public function free_space($path = '/') { - return self::$defaultInstance->free_space($path); - } - - static public function search($query) { - return self::$defaultInstance->search($query); - } - - /** - * @param string $query - */ - static public function searchByMime($query) { - return self::$defaultInstance->searchByMime($query); - } - - /** - * @param string|int $tag name or tag id - * @param string $userId owner of the tags - * @return FileInfo[] array or file info - */ - static public function searchByTag($tag, $userId) { - return self::$defaultInstance->searchByTag($tag, $userId); - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - */ - static public function hasUpdated($path, $time) { - return self::$defaultInstance->hasUpdated($path, $time); - } - - /** - * Fix common problems with a file path - * - * @param string $path - * @param bool $stripTrailingSlash - * @param bool $isAbsolutePath - * @return string - */ - public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false) { - /** - * FIXME: This is a workaround for existing classes and files which call - * this function with another type than a valid string. This - * conversion should get removed as soon as all existing - * function calls have been fixed. - */ - $path = (string)$path; - - $cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath]); - - if (isset(self::$normalizedPathCache[$cacheKey])) { - return self::$normalizedPathCache[$cacheKey]; - } - - if ($path == '') { - return '/'; - } - - //normalize unicode if possible - $path = \OC_Util::normalizeUnicode($path); - - //no windows style slashes - $path = str_replace('\\', '/', $path); - - // When normalizing an absolute path, we need to ensure that the drive-letter - // is still at the beginning on windows - $windows_drive_letter = ''; - if ($isAbsolutePath && \OC_Util::runningOnWindows() && preg_match('#^([a-zA-Z])$#', $path[0]) && $path[1] == ':' && $path[2] == '/') { - $windows_drive_letter = substr($path, 0, 2); - $path = substr($path, 2); - } - - //add leading slash - if ($path[0] !== '/') { - $path = '/' . $path; - } - - // remove '/./' - // ugly, but str_replace() can't replace them all in one go - // as the replacement itself is part of the search string - // which will only be found during the next iteration - while (strpos($path, '/./') !== false) { - $path = str_replace('/./', '/', $path); - } - // remove sequences of slashes - $path = preg_replace('#/{2,}#', '/', $path); - - //remove trailing slash - if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') { - $path = substr($path, 0, -1); - } - - // remove trailing '/.' - if (substr($path, -2) == '/.') { - $path = substr($path, 0, -2); - } - - $normalizedPath = $windows_drive_letter . $path; - self::$normalizedPathCache[$cacheKey] = $normalizedPath; - - return $normalizedPath; - } - - /** - * get the filesystem info - * - * @param string $path - * @param boolean $includeMountPoints whether to add mountpoint sizes, - * defaults to true - * @return \OC\Files\FileInfo|bool False if file does not exist - */ - public static function getFileInfo($path, $includeMountPoints = true) { - return self::$defaultInstance->getFileInfo($path, $includeMountPoints); - } - - /** - * change file metadata - * - * @param string $path - * @param array $data - * @return int - * - * returns the fileid of the updated file - */ - public static function putFileInfo($path, $data) { - return self::$defaultInstance->putFileInfo($path, $data); - } - - /** - * get the content of a directory - * - * @param string $directory path under datadirectory - * @param string $mimetype_filter limit returned content to this mimetype or mimepart - * @return \OC\Files\FileInfo[] - */ - public static function getDirectoryContent($directory, $mimetype_filter = '') { - return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter); - } - - /** - * Get the path of a file by id - * - * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file - * - * @param int $id - * @throws NotFoundException - * @return string - */ - public static function getPath($id) { - return self::$defaultInstance->getPath($id); - } - - /** - * Get the owner for a file or folder - * - * @param string $path - * @return string - */ - public static function getOwner($path) { - return self::$defaultInstance->getOwner($path); - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - static public function getETag($path) { - return self::$defaultInstance->getETag($path); - } -} diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php deleted file mode 100644 index ba4a7f8d910..00000000000 --- a/lib/private/files/mount/manager.php +++ /dev/null @@ -1,165 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Mount; - -use \OC\Files\Filesystem; -use OCP\Files\Mount\IMountManager; -use OCP\Files\Mount\IMountPoint; - -class Manager implements IMountManager { - /** - * @var MountPoint[] - */ - private $mounts = array(); - - /** - * @param IMountPoint $mount - */ - public function addMount(IMountPoint $mount) { - $this->mounts[$mount->getMountPoint()] = $mount; - } - - /** - * @param string $mountPoint - */ - public function removeMount($mountPoint) { - $mountPoint = Filesystem::normalizePath($mountPoint); - if (strlen($mountPoint) > 1) { - $mountPoint .= '/'; - } - unset($this->mounts[$mountPoint]); - } - - /** - * @param string $mountPoint - * @param string $target - */ - public function moveMount($mountPoint, $target){ - $this->mounts[$target] = $this->mounts[$mountPoint]; - unset($this->mounts[$mountPoint]); - } - - /** - * Find the mount for $path - * - * @param string $path - * @return MountPoint - */ - public function find($path) { - \OC_Util::setupFS(); - $path = $this->formatPath($path); - if (isset($this->mounts[$path])) { - return $this->mounts[$path]; - } - - \OC_Hook::emit('OC_Filesystem', 'get_mountpoint', array('path' => $path)); - $foundMountPoint = ''; - $mountPoints = array_keys($this->mounts); - foreach ($mountPoints as $mountpoint) { - if (strpos($path, $mountpoint) === 0 and strlen($mountpoint) > strlen($foundMountPoint)) { - $foundMountPoint = $mountpoint; - } - } - if (isset($this->mounts[$foundMountPoint])) { - return $this->mounts[$foundMountPoint]; - } else { - return null; - } - } - - /** - * Find all mounts in $path - * - * @param string $path - * @return MountPoint[] - */ - public function findIn($path) { - \OC_Util::setupFS(); - $path = $this->formatPath($path); - $result = array(); - $pathLength = strlen($path); - $mountPoints = array_keys($this->mounts); - foreach ($mountPoints as $mountPoint) { - if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) { - $result[] = $this->mounts[$mountPoint]; - } - } - return $result; - } - - public function clear() { - $this->mounts = array(); - } - - /** - * Find mounts by storage id - * - * @param string $id - * @return MountPoint[] - */ - public function findByStorageId($id) { - \OC_Util::setupFS(); - if (strlen($id) > 64) { - $id = md5($id); - } - $result = array(); - foreach ($this->mounts as $mount) { - if ($mount->getStorageId() === $id) { - $result[] = $mount; - } - } - return $result; - } - - /** - * @return MountPoint[] - */ - public function getAll() { - return $this->mounts; - } - - /** - * Find mounts by numeric storage id - * - * @param int $id - * @return MountPoint[] - */ - public function findByNumericId($id) { - $storageId = \OC\Files\Cache\Storage::getStorageId($id); - return $this->findByStorageId($storageId); - } - - /** - * @param string $path - * @return string - */ - private function formatPath($path) { - $path = Filesystem::normalizePath($path); - if (strlen($path) > 1) { - $path .= '/'; - } - return $path; - } -} diff --git a/lib/private/files/mount/mountpoint.php b/lib/private/files/mount/mountpoint.php deleted file mode 100644 index 7b9294fc1e0..00000000000 --- a/lib/private/files/mount/mountpoint.php +++ /dev/null @@ -1,251 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Mount; - -use \OC\Files\Filesystem; -use OC\Files\Storage\StorageFactory; -use OC\Files\Storage\Storage; -use OCP\Files\Mount\IMountPoint; - -class MountPoint implements IMountPoint { - /** - * @var \OC\Files\Storage\Storage $storage - */ - protected $storage = null; - protected $class; - protected $storageId; - - /** - * Configuration options for the storage backend - * - * @var array - */ - protected $arguments = array(); - protected $mountPoint; - - /** - * Mount specific options - * - * @var array - */ - protected $mountOptions = array(); - - /** - * @var \OC\Files\Storage\StorageFactory $loader - */ - private $loader; - - /** - * Specified whether the storage is invalid after failing to - * instantiate it. - * - * @var bool - */ - private $invalidStorage = false; - - /** - * @param string|\OC\Files\Storage\Storage $storage - * @param string $mountpoint - * @param array $arguments (optional) configuration for the storage backend - * @param \OCP\Files\Storage\IStorageFactory $loader - * @param array $mountOptions mount specific options - */ - public function __construct($storage, $mountpoint, $arguments = null, $loader = null, $mountOptions = null) { - if (is_null($arguments)) { - $arguments = array(); - } - if (is_null($loader)) { - $this->loader = new StorageFactory(); - } else { - $this->loader = $loader; - } - - if (!is_null($mountOptions)) { - $this->mountOptions = $mountOptions; - } - - $mountpoint = $this->formatPath($mountpoint); - $this->mountPoint = $mountpoint; - if ($storage instanceof Storage) { - $this->class = get_class($storage); - $this->storage = $this->loader->wrap($this, $storage); - } else { - // Update old classes to new namespace - if (strpos($storage, 'OC_Filestorage_') !== false) { - $storage = '\OC\Files\Storage\\' . substr($storage, 15); - } - $this->class = $storage; - $this->arguments = $arguments; - } - } - - /** - * get complete path to the mount point, relative to data/ - * - * @return string - */ - public function getMountPoint() { - return $this->mountPoint; - } - - /** - * Sets the mount point path, relative to data/ - * - * @param string $mountPoint new mount point - */ - public function setMountPoint($mountPoint) { - $this->mountPoint = $this->formatPath($mountPoint); - } - - /** - * create the storage that is mounted - * - * @return \OC\Files\Storage\Storage - */ - private function createStorage() { - if ($this->invalidStorage) { - return null; - } - - if (class_exists($this->class)) { - try { - return $this->loader->getInstance($this, $this->class, $this->arguments); - } catch (\Exception $exception) { - $this->invalidStorage = true; - if ($this->mountPoint === '/') { - // the root storage could not be initialized, show the user! - throw new \Exception('The root storage could not be initialized. Please contact your local administrator.', $exception->getCode(), $exception); - } else { - \OCP\Util::writeLog('core', $exception->getMessage(), \OCP\Util::ERROR); - } - return null; - } - } else { - \OCP\Util::writeLog('core', 'storage backend ' . $this->class . ' not found', \OCP\Util::ERROR); - $this->invalidStorage = true; - return null; - } - } - - /** - * @return \OC\Files\Storage\Storage - */ - public function getStorage() { - if (is_null($this->storage)) { - $this->storage = $this->createStorage(); - } - return $this->storage; - } - - /** - * @return string - */ - public function getStorageId() { - if (!$this->storageId) { - if (is_null($this->storage)) { - $storage = $this->createStorage(); //FIXME: start using exceptions - if (is_null($storage)) { - return null; - } - - $this->storage = $storage; - } - $this->storageId = $this->storage->getId(); - if (strlen($this->storageId) > 64) { - $this->storageId = md5($this->storageId); - } - } - return $this->storageId; - } - - /** - * @param string $path - * @return string - */ - public function getInternalPath($path) { - if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) { - $internalPath = ''; - } else { - $internalPath = substr($path, strlen($this->mountPoint)); - } - // substr returns false instead of an empty string, we always want a string - return (string)$internalPath; - } - - /** - * @param string $path - * @return string - */ - private function formatPath($path) { - $path = Filesystem::normalizePath($path); - if (strlen($path) > 1) { - $path .= '/'; - } - return $path; - } - - /** - * @param callable $wrapper - */ - public function wrapStorage($wrapper) { - $storage = $this->getStorage(); - // storage can be null if it couldn't be initialized - if ($storage != null) { - $this->storage = $wrapper($this->mountPoint, $storage, $this); - } - } - - /** - * Get a mount option - * - * @param string $name Name of the mount option to get - * @param mixed $default Default value for the mount option - * @return mixed - */ - public function getOption($name, $default) { - return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; - } - - /** - * Get all options for the mount - * - * @return array - */ - public function getOptions() { - return $this->mountOptions; - } - - /** - * Get the file id of the root of the storage - * - * @return int - */ - public function getStorageRootId() { - return (int)$this->getStorage()->getCache()->getId(''); - } -} diff --git a/lib/private/files/mount/moveablemount.php b/lib/private/files/mount/moveablemount.php deleted file mode 100644 index 8a1bd7dd9c5..00000000000 --- a/lib/private/files/mount/moveablemount.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Mount; - -/** - * Defines the mount point to be (re)moved by the user - */ -interface MoveableMount { - /** - * Move the mount point to $target - * - * @param string $target the target mount point - * @return bool - */ - public function moveMount($target); - - /** - * Remove the mount points - * - * @return mixed - * @return bool - */ - public function removeMount(); -} diff --git a/lib/private/files/node/file.php b/lib/private/files/node/file.php deleted file mode 100644 index 9e0014abb0b..00000000000 --- a/lib/private/files/node/file.php +++ /dev/null @@ -1,176 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Node; - -use OCP\Files\NotPermittedException; - -class File extends Node implements \OCP\Files\File { - /** - * @return string - * @throws \OCP\Files\NotPermittedException - */ - public function getContent() { - if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) { - /** - * @var \OC\Files\Storage\Storage $storage; - */ - return $this->view->file_get_contents($this->path); - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $data - * @throws \OCP\Files\NotPermittedException - */ - public function putContent($data) { - if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) { - $this->sendHooks(array('preWrite')); - $this->view->file_put_contents($this->path, $data); - $this->fileInfo = null; - $this->sendHooks(array('postWrite')); - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $mode - * @return resource - * @throws \OCP\Files\NotPermittedException - */ - public function fopen($mode) { - $preHooks = array(); - $postHooks = array(); - $requiredPermissions = \OCP\Constants::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\Constants::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\Constants::PERMISSION_DELETE)) { - $this->sendHooks(array('preDelete')); - $fileInfo = $this->getFileInfo(); - $this->view->unlink($this->path); - $nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo); - $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); - $this->exists = false; - $this->fileInfo = null; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $targetPath - * @throws \OCP\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 \OCP\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; - $this->fileInfo = null; - 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); - } - - /** - * @inheritdoc - */ - public function getChecksum() { - return $this->getFileInfo()->getChecksum(); - } -} diff --git a/lib/private/files/node/folder.php b/lib/private/files/node/folder.php deleted file mode 100644 index f4d7dae20a3..00000000000 --- a/lib/private/files/node/folder.php +++ /dev/null @@ -1,360 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Node; - -use OCP\Files\FileInfo; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; - -class Folder extends Node implements \OCP\Files\Folder { - /** - * @param string $path path relative to the folder - * @return string - * @throws \OCP\Files\NotPermittedException - */ - public function getFullPath($path) { - if (!$this->isValidPath($path)) { - throw new NotPermittedException(); - } - return $this->path . $this->normalizePath($path); - } - - /** - * @param string $path - * @return string - */ - public function getRelativePath($path) { - if ($this->path === '' or $this->path === '/') { - return $this->normalizePath($path); - } - if ($path === $this->path) { - return '/'; - } else if (strpos($path, $this->path . '/') !== 0) { - return null; - } else { - $path = substr($path, strlen($this->path)); - 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 \OCP\Files\NotFoundException - * @return Node[] - */ - public function getDirectoryListing() { - $folderContent = $this->view->getDirectoryContent($this->path); - - return array_map(function(FileInfo $info) { - if ($info->getMimetype() === 'httpd/unix-directory') { - return new Folder($this->root, $this->view, $info->getPath(), $info); - } else { - return new File($this->root, $this->view, $info->getPath(), $info); - } - }, $folderContent); - } - - /** - * @param string $path - * @param FileInfo $info - * @return File|Folder - */ - protected function createNode($path, FileInfo $info = null) { - if (is_null($info)) { - $isDir = $this->view->is_dir($path); - } else { - $isDir = $info->getType() === FileInfo::TYPE_FOLDER; - } - if ($isDir) { - return new Folder($this->root, $this->view, $path, $info); - } else { - return new File($this->root, $this->view, $path, $info); - } - } - - /** - * Get the node at $path - * - * @param string $path - * @return \OC\Files\Node\Node - * @throws \OCP\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 \OC\Files\Node\Folder - * @throws \OCP\Files\NotPermittedException - */ - public function newFolder($path) { - if ($this->checkPermissions(\OCP\Constants::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 \OC\Files\Node\File - * @throws \OCP\Files\NotPermittedException - */ - public function newFile($path) { - if ($this->checkPermissions(\OCP\Constants::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 \OC\Files\Node\Node[] - */ - public function search($query) { - return $this->searchCommon('search', array('%' . $query . '%')); - } - - /** - * search for files by mimetype - * - * @param string $mimetype - * @return Node[] - */ - public function searchByMime($mimetype) { - return $this->searchCommon('searchByMime', array($mimetype)); - } - - /** - * search for files by tag - * - * @param string|int $tag name or tag id - * @param string $userId owner of the tags - * @return Node[] - */ - public function searchByTag($tag, $userId) { - return $this->searchCommon('searchByTag', array($tag, $userId)); - } - - /** - * @param string $method cache method - * @param array $args call args - * @return \OC\Files\Node\Node[] - */ - private function searchCommon($method, $args) { - $files = array(); - $rootLength = strlen($this->path); - $mount = $this->root->getMount($this->path); - $storage = $mount->getStorage(); - $internalPath = $mount->getInternalPath($this->path); - $internalPath = rtrim($internalPath, '/'); - if ($internalPath !== '') { - $internalPath = $internalPath . '/'; - } - $internalRootLength = strlen($internalPath); - - $cache = $storage->getCache(''); - - $results = call_user_func_array(array($cache, $method), $args); - 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[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount); - } - } - - $mounts = $this->root->getMountsIn($this->path); - foreach ($mounts as $mount) { - $storage = $mount->getStorage(); - if ($storage) { - $cache = $storage->getCache(''); - - $relativeMountPoint = substr($mount->getMountPoint(), $rootLength); - $results = call_user_func_array(array($cache, $method), $args); - foreach ($results as $result) { - $result['internalPath'] = $result['path']; - $result['path'] = $relativeMountPoint . $result['path']; - $result['storage'] = $storage; - $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount); - } - } - } - - return array_map(function(FileInfo $file) { - return $this->createNode($file->getPath(), $file); - }, $files); - } - - /** - * @param int $id - * @return \OC\Files\Node\Node[] - */ - public function getById($id) { - $mounts = $this->root->getMountsIn($this->path); - $mounts[] = $this->root->getMount($this->path); - // reverse the array so we start with the storage this view is in - // which is the most likely to contain the file we're looking for - $mounts = array_reverse($mounts); - - $nodes = array(); - foreach ($mounts as $mount) { - /** - * @var \OC\Files\Mount\MountPoint $mount - */ - if ($mount->getStorage()) { - $cache = $mount->getStorage()->getCache(); - $internalPath = $cache->getPathById($id); - if (is_string($internalPath)) { - $fullPath = $mount->getMountPoint() . $internalPath; - if (!is_null($path = $this->getRelativePath($fullPath))) { - $nodes[] = $this->get($path); - } - } - } - } - return $nodes; - } - - public function getFreeSpace() { - return $this->view->free_space($this->path); - } - - public function delete() { - if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) { - $this->sendHooks(array('preDelete')); - $fileInfo = $this->getFileInfo(); - $this->view->rmdir($this->path); - $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo); - $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); - $this->exists = false; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $targetPath - * @throws \OCP\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 \OCP\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(); - } - } - - /** - * Add a suffix to the name in case the file exists - * - * @param string $name - * @return string - * @throws NotPermittedException - */ - public function getNonExistingName($name) { - $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view); - return trim($this->getRelativePath($uniqueName), '/'); - } -} diff --git a/lib/private/files/node/hookconnector.php b/lib/private/files/node/hookconnector.php deleted file mode 100644 index 5c36ca3848e..00000000000 --- a/lib/private/files/node/hookconnector.php +++ /dev/null @@ -1,164 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Node; - -use OCP\Files\FileInfo; -use OC\Files\Filesystem; -use OC\Files\View; -use OCP\Util; - -class HookConnector { - /** - * @var Root - */ - private $root; - - /** - * @var View - */ - private $view; - - /** - * @var FileInfo[] - */ - private $deleteMetaCache = []; - - /** - * HookConnector constructor. - * - * @param Root $root - * @param View $view - */ - public function __construct(Root $root, View $view) { - $this->root = $root; - $this->view = $view; - } - - public function viewToNode() { - Util::connectHook('OC_Filesystem', 'write', $this, 'write'); - Util::connectHook('OC_Filesystem', 'post_write', $this, 'postWrite'); - - Util::connectHook('OC_Filesystem', 'create', $this, 'create'); - Util::connectHook('OC_Filesystem', 'post_create', $this, 'postCreate'); - - Util::connectHook('OC_Filesystem', 'delete', $this, 'delete'); - Util::connectHook('OC_Filesystem', 'post_delete', $this, 'postDelete'); - - Util::connectHook('OC_Filesystem', 'rename', $this, 'rename'); - Util::connectHook('OC_Filesystem', 'post_rename', $this, 'postRename'); - - Util::connectHook('OC_Filesystem', 'copy', $this, 'copy'); - Util::connectHook('OC_Filesystem', 'post_copy', $this, 'postCopy'); - - Util::connectHook('OC_Filesystem', 'touch', $this, 'touch'); - Util::connectHook('OC_Filesystem', 'post_touch', $this, 'postTouch'); - } - - public function write($arguments) { - $node = $this->getNodeForPath($arguments['path']); - $this->root->emit('\OC\Files', 'preWrite', [$node]); - } - - public function postWrite($arguments) { - $node = $this->getNodeForPath($arguments['path']); - $this->root->emit('\OC\Files', 'postWrite', [$node]); - } - - public function create($arguments) { - $node = $this->getNodeForPath($arguments['path']); - $this->root->emit('\OC\Files', 'preCreate', [$node]); - } - - public function postCreate($arguments) { - $node = $this->getNodeForPath($arguments['path']); - $this->root->emit('\OC\Files', 'postCreate', [$node]); - } - - public function delete($arguments) { - $node = $this->getNodeForPath($arguments['path']); - $this->deleteMetaCache[$node->getPath()] = $node->getFileInfo(); - $this->root->emit('\OC\Files', 'preDelete', [$node]); - } - - public function postDelete($arguments) { - $node = $this->getNodeForPath($arguments['path']); - unset($this->deleteMetaCache[$node->getPath()]); - $this->root->emit('\OC\Files', 'postDelete', [$node]); - } - - public function touch($arguments) { - $node = $this->getNodeForPath($arguments['path']); - $this->root->emit('\OC\Files', 'preTouch', [$node]); - } - - public function postTouch($arguments) { - $node = $this->getNodeForPath($arguments['path']); - $this->root->emit('\OC\Files', 'postTouch', [$node]); - } - - public function rename($arguments) { - $source = $this->getNodeForPath($arguments['oldpath']); - $target = $this->getNodeForPath($arguments['newpath']); - $this->root->emit('\OC\Files', 'preRename', [$source, $target]); - } - - public function postRename($arguments) { - $source = $this->getNodeForPath($arguments['oldpath']); - $target = $this->getNodeForPath($arguments['newpath']); - $this->root->emit('\OC\Files', 'postRename', [$source, $target]); - } - - public function copy($arguments) { - $source = $this->getNodeForPath($arguments['oldpath']); - $target = $this->getNodeForPath($arguments['newpath']); - $this->root->emit('\OC\Files', 'preCopy', [$source, $target]); - } - - public function postCopy($arguments) { - $source = $this->getNodeForPath($arguments['oldpath']); - $target = $this->getNodeForPath($arguments['newpath']); - $this->root->emit('\OC\Files', 'postCopy', [$source, $target]); - } - - private function getNodeForPath($path) { - $info = Filesystem::getView()->getFileInfo($path); - if (!$info) { - - $fullPath = Filesystem::getView()->getAbsolutePath($path); - if (isset($this->deleteMetaCache[$fullPath])) { - $info = $this->deleteMetaCache[$fullPath]; - } else { - $info = null; - } - if (Filesystem::is_dir($path)) { - return new NonExistingFolder($this->root, $this->view, $fullPath, $info); - } else { - return new NonExistingFile($this->root, $this->view, $fullPath, $info); - } - } - if ($info->getType() === FileInfo::TYPE_FILE) { - return new File($this->root, $this->view, $info->getPath(), $info); - } else { - return new Folder($this->root, $this->view, $info->getPath(), $info); - } - } -} diff --git a/lib/private/files/node/lazyroot.php b/lib/private/files/node/lazyroot.php deleted file mode 100644 index 9661f036579..00000000000 --- a/lib/private/files/node/lazyroot.php +++ /dev/null @@ -1,474 +0,0 @@ -<?php -/** - * @author Roeland Jago Douma <rullzer@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OC\Files\Node; - -use OC\Files\Mount\MountPoint; -use OCP\Files\IRootFolder; -use OCP\Files\NotPermittedException; - -/** - * Class LazyRoot - * - * This is a lazy wrapper around the root. So only - * once it is needed this will get initialized. - * - * @package OC\Files\Node - */ -class LazyRoot implements IRootFolder { - /** @var \Closure */ - private $rootFolderClosure; - - /** @var IRootFolder */ - private $rootFolder; - - /** - * LazyRoot constructor. - * - * @param \Closure $rootFolderClosure - */ - public function __construct(\Closure $rootFolderClosure) { - $this->rootFolderClosure = $rootFolderClosure; - } - - /** - * Magic method to first get the real rootFolder and then - * call $method with $args on it - * - * @param $method - * @param $args - * @return mixed - */ - public function __call($method, $args) { - if ($this->rootFolder === null) { - $this->rootFolder = call_user_func($this->rootFolderClosure); - } - - return call_user_func_array([$this->rootFolder, $method], $args); - } - - /** - * @inheritDoc - */ - public function getUser() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function listen($scope, $method, callable $callback) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function removeListener($scope = null, $method = null, callable $callback = null) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function emit($scope, $method, $arguments = array()) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function mount($storage, $mountPoint, $arguments = array()) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMount($mountPoint) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMountsIn($mountPoint) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMountByStorageId($storageId) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMountByNumericStorageId($numericId) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function unMount($mount) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function get($path) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function rename($targetPath) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function delete() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function copy($targetPath) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function touch($mtime = null) { - $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getStorage() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getPath() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getInternalPath() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getId() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function stat() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMTime() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getSize() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getEtag() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getPermissions() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isReadable() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isUpdateable() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isDeletable() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isShareable() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getParent() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getName() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getUserFolder($userId) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMimetype() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMimePart() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isEncrypted() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getType() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isShared() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isMounted() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getMountPoint() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getOwner() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getChecksum() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getFullPath($path) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getRelativePath($path) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isSubNode($node) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getDirectoryListing() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function nodeExists($path) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function newFolder($path) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function newFile($path) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function search($query) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function searchByMime($mimetype) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function searchByTag($tag, $userId) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getById($id) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getFreeSpace() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function isCreatable() { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function getNonExistingName($name) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function move($targetPath) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function lock($type) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function changeLock($targetType) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - /** - * @inheritDoc - */ - public function unlock($type) { - return $this->__call(__FUNCTION__, func_get_args()); - } - - -} diff --git a/lib/private/files/node/node.php b/lib/private/files/node/node.php deleted file mode 100644 index c4fabfc2e2e..00000000000 --- a/lib/private/files/node/node.php +++ /dev/null @@ -1,383 +0,0 @@ -<?php -/** - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Node; - -use OC\Files\Filesystem; -use OCP\Files\FileInfo; -use OCP\Files\InvalidPathException; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; - -class Node implements \OCP\Files\Node { - /** - * @var \OC\Files\View $view - */ - protected $view; - - /** - * @var \OC\Files\Node\Root $root - */ - protected $root; - - /** - * @var string $path - */ - protected $path; - - /** - * @var \OCP\Files\FileInfo - */ - protected $fileInfo; - - /** - * @param \OC\Files\View $view - * @param \OC\Files\Node\Root $root - * @param string $path - * @param FileInfo $fileInfo - */ - public function __construct($root, $view, $path, $fileInfo = null) { - $this->view = $view; - $this->root = $root; - $this->path = $path; - $this->fileInfo = $fileInfo; - } - - /** - * Returns the matching file info - * - * @return FileInfo - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getFileInfo() { - if (!Filesystem::isValidPath($this->path)) { - throw new InvalidPathException(); - } - if (!$this->fileInfo) { - $fileInfo = $this->view->getFileInfo($this->path); - if ($fileInfo instanceof FileInfo) { - $this->fileInfo = $fileInfo; - } else { - throw new NotFoundException(); - } - } - return $this->fileInfo; - } - - /** - * @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 \OCP\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 \OCP\Files\NotPermittedException - */ - public function touch($mtime = null) { - if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) { - $this->sendHooks(array('preTouch')); - $this->view->touch($this->path, $mtime); - $this->sendHooks(array('postTouch')); - if ($this->fileInfo) { - if (is_null($mtime)) { - $mtime = time(); - } - $this->fileInfo['mtime'] = $mtime; - } - } else { - throw new NotPermittedException(); - } - } - - /** - * @return \OC\Files\Storage\Storage - * @throws \OCP\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 - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getId() { - return $this->getFileInfo()->getId(); - } - - /** - * @return array - */ - public function stat() { - return $this->view->stat($this->path); - } - - /** - * @return int - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getMTime() { - return $this->getFileInfo()->getMTime(); - } - - /** - * @return int - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getSize() { - return $this->getFileInfo()->getSize(); - } - - /** - * @return string - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getEtag() { - return $this->getFileInfo()->getEtag(); - } - - /** - * @return int - * @throws InvalidPathException - * @throws NotFoundException - */ - public function getPermissions() { - return $this->getFileInfo()->getPermissions(); - } - - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isReadable() { - return $this->getFileInfo()->isReadable(); - } - - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isUpdateable() { - return $this->getFileInfo()->isUpdateable(); - } - - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isDeletable() { - return $this->getFileInfo()->isDeletable(); - } - - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isShareable() { - return $this->getFileInfo()->isShareable(); - } - - /** - * @return bool - * @throws InvalidPathException - * @throws NotFoundException - */ - public function isCreatable() { - return $this->getFileInfo()->isCreatable(); - } - - /** - * @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; - } - - public function isMounted() { - return $this->getFileInfo()->isMounted(); - } - - public function isShared() { - return $this->getFileInfo()->isShared(); - } - - public function getMimeType() { - return $this->getFileInfo()->getMimetype(); - } - - public function getMimePart() { - return $this->getFileInfo()->getMimePart(); - } - - public function getType() { - return $this->getFileInfo()->getType(); - } - - public function isEncrypted() { - return $this->getFileInfo()->isEncrypted(); - } - - public function getMountPoint() { - return $this->getFileInfo()->getMountPoint(); - } - - public function getOwner() { - return $this->getFileInfo()->getOwner(); - } - - public function getChecksum() { - return; - } - - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @throws \OCP\Lock\LockedException - */ - public function lock($type) { - $this->view->lockFile($this->path, $type); - } - - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @throws \OCP\Lock\LockedException - */ - public function changeLock($type) { - $this->view->changeLock($this->path, $type); - } - - /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @throws \OCP\Lock\LockedException - */ - public function unlock($type) { - $this->view->unlockFile($this->path, $type); - } -} diff --git a/lib/private/files/node/nonexistingfile.php b/lib/private/files/node/nonexistingfile.php deleted file mode 100644 index c1d09bcc491..00000000000 --- a/lib/private/files/node/nonexistingfile.php +++ /dev/null @@ -1,143 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Node; - -use OCP\Files\NotFoundException; - -class NonExistingFile extends File { - /** - * @param string $newPath - * @throws \OCP\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() { - if ($this->fileInfo) { - return parent::getId(); - } else { - throw new NotFoundException(); - } - } - - public function stat() { - throw new NotFoundException(); - } - - public function getMTime() { - if ($this->fileInfo) { - return parent::getMTime(); - } else { - throw new NotFoundException(); - } - } - - public function getSize() { - if ($this->fileInfo) { - return parent::getSize(); - } else { - throw new NotFoundException(); - } - } - - public function getEtag() { - if ($this->fileInfo) { - return parent::getEtag(); - } else { - throw new NotFoundException(); - } - } - - public function getPermissions() { - if ($this->fileInfo) { - return parent::getPermissions(); - } else { - throw new NotFoundException(); - } - } - - public function isReadable() { - if ($this->fileInfo) { - return parent::isReadable(); - } else { - throw new NotFoundException(); - } - } - - public function isUpdateable() { - if ($this->fileInfo) { - return parent::isUpdateable(); - } else { - throw new NotFoundException(); - } - } - - public function isDeletable() { - if ($this->fileInfo) { - return parent::isDeletable(); - } else { - throw new NotFoundException(); - } - } - - public function isShareable() { - if ($this->fileInfo) { - return parent::isShareable(); - } else { - throw new NotFoundException(); - } - } - - public function getContent() { - throw new NotFoundException(); - } - - public function putContent($data) { - throw new NotFoundException(); - } - - public function getMimeType() { - if ($this->fileInfo) { - return parent::getMimeType(); - } else { - throw new NotFoundException(); - } - } - - public function fopen($mode) { - throw new NotFoundException(); - } -} diff --git a/lib/private/files/node/nonexistingfolder.php b/lib/private/files/node/nonexistingfolder.php deleted file mode 100644 index 7d6576f1bd6..00000000000 --- a/lib/private/files/node/nonexistingfolder.php +++ /dev/null @@ -1,172 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Node; - -use OCP\Files\NotFoundException; - -class NonExistingFolder extends Folder { - /** - * @param string $newPath - * @throws \OCP\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() { - if ($this->fileInfo) { - return parent::getId(); - } else { - throw new NotFoundException(); - } - } - - public function stat() { - throw new NotFoundException(); - } - - public function getMTime() { - if ($this->fileInfo) { - return parent::getMTime(); - } else { - throw new NotFoundException(); - } - } - - public function getSize() { - if ($this->fileInfo) { - return parent::getSize(); - } else { - throw new NotFoundException(); - } - } - - public function getEtag() { - if ($this->fileInfo) { - return parent::getEtag(); - } else { - throw new NotFoundException(); - } - } - - public function getPermissions() { - if ($this->fileInfo) { - return parent::getPermissions(); - } else { - throw new NotFoundException(); - } - } - - public function isReadable() { - if ($this->fileInfo) { - return parent::isReadable(); - } else { - throw new NotFoundException(); - } - } - - public function isUpdateable() { - if ($this->fileInfo) { - return parent::isUpdateable(); - } else { - throw new NotFoundException(); - } - } - - public function isDeletable() { - if ($this->fileInfo) { - return parent::isDeletable(); - } else { - throw new NotFoundException(); - } - } - - public function isShareable() { - if ($this->fileInfo) { - return parent::isShareable(); - } else { - 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 searchByTag($tag, $userId) { - throw new NotFoundException(); - } - - public function getById($id) { - throw new NotFoundException(); - } - - public function getFreeSpace() { - throw new NotFoundException(); - } - - public function isCreatable() { - if ($this->fileInfo) { - return parent::isCreatable(); - } else { - throw new NotFoundException(); - } - } -} diff --git a/lib/private/files/node/root.php b/lib/private/files/node/root.php deleted file mode 100644 index 04866e60b87..00000000000 --- a/lib/private/files/node/root.php +++ /dev/null @@ -1,357 +0,0 @@ -<?php -/** - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Node; - -use OC\Files\Mount\Manager; -use OC\Files\Mount\MountPoint; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; -use OC\Hooks\PublicEmitter; -use OCP\Files\IRootFolder; - -/** - * Class Root - * - * Hooks available in scope \OC\Files - * - 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 - */ -class Root extends Folder implements IRootFolder { - - /** - * @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|null $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, callable $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, callable $callback = null) { - $this->emitter->removeListener($scope, $method, $callback); - } - - /** - * @param string $scope - * @param string $method - * @param Node[] $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 MountPoint($storage, $mountPoint, $arguments); - $this->mountManager->addMount($mount); - } - - /** - * @param string $mountPoint - * @return \OC\Files\Mount\MountPoint - */ - public function getMount($mountPoint) { - return $this->mountManager->find($mountPoint); - } - - /** - * @param string $mountPoint - * @return \OC\Files\Mount\MountPoint[] - */ - public function getMountsIn($mountPoint) { - return $this->mountManager->findIn($mountPoint); - } - - /** - * @param string $storageId - * @return \OC\Files\Mount\MountPoint[] - */ - public function getMountByStorageId($storageId) { - return $this->mountManager->findByStorageId($storageId); - } - - /** - * @param int $numericId - * @return MountPoint[] - */ - public function getMountByNumericStorageId($numericId) { - return $this->mountManager->findByNumericId($numericId); - } - - /** - * @param \OC\Files\Mount\MountPoint $mount - */ - public function unMount($mount) { - $this->mountManager->remove($mount); - } - - /** - * @param string $path - * @throws \OCP\Files\NotFoundException - * @throws \OCP\Files\NotPermittedException - * @return string - */ - public function get($path) { - $path = $this->normalizePath($path); - if ($this->isValidPath($path)) { - $fullPath = $this->getFullPath($path); - $fileInfo = $this->view->getFileInfo($fullPath); - if ($fileInfo) { - return $this->createNode($fullPath, $fileInfo); - } else { - throw new NotFoundException($path); - } - } else { - throw new NotPermittedException(); - } - } - - //most operations can't be done on the root - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function rename($targetPath) { - throw new NotPermittedException(); - } - - public function delete() { - throw new NotPermittedException(); - } - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function copy($targetPath) { - throw new NotPermittedException(); - } - - /** - * @param int $mtime - * @throws \OCP\Files\NotPermittedException - */ - public function touch($mtime = null) { - throw new NotPermittedException(); - } - - /** - * @return \OC\Files\Storage\Storage - * @throws \OCP\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\Constants::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 \OCP\Files\NotFoundException - */ - public function getParent() { - throw new NotFoundException(); - } - - /** - * @return string - */ - public function getName() { - return ''; - } - - /** - * Returns a view to user's files folder - * - * @param String $userId user ID - * @return \OCP\Files\Folder - */ - public function getUserFolder($userId) { - \OC\Files\Filesystem::initMountPoints($userId); - $dir = '/' . $userId; - $folder = null; - - try { - $folder = $this->get($dir); - } catch (NotFoundException $e) { - $folder = $this->newFolder($dir); - } - - $dir = '/files'; - try { - $folder = $folder->get($dir); - } catch (NotFoundException $e) { - $folder = $folder->newFolder($dir); - \OC_Util::copySkeleton($userId, $folder); - } - - return $folder; - - } -} diff --git a/lib/private/files/objectstore/homeobjectstorestorage.php b/lib/private/files/objectstore/homeobjectstorestorage.php deleted file mode 100644 index 6a330e2dab3..00000000000 --- a/lib/private/files/objectstore/homeobjectstorestorage.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\ObjectStore; - -use OC\User\User; - -class HomeObjectStoreStorage extends ObjectStoreStorage implements \OCP\Files\IHomeStorage { - - /** - * The home user storage requires a user object to create a unique storage id - * @param array $params - */ - public function __construct($params) { - if ( ! isset($params['user']) || ! $params['user'] instanceof User) { - throw new \Exception('missing user object in parameters'); - } - $this->user = $params['user']; - parent::__construct($params); - } - - public function getId () { - return 'object::user:' . $this->user->getUID(); - } - - /** - * get the owner of a path - * - * @param string $path The path to get the owner - * @return false|string uid - */ - public function getOwner($path) { - if (is_object($this->user)) { - return $this->user->getUID(); - } - return false; - } - - /** - * @param string $path, optional - * @return \OC\User\User - */ - public function getUser($path = null) { - return $this->user; - } - - -}
\ No newline at end of file diff --git a/lib/private/files/objectstore/noopscanner.php b/lib/private/files/objectstore/noopscanner.php deleted file mode 100644 index f5316175ecf..00000000000 --- a/lib/private/files/objectstore/noopscanner.php +++ /dev/null @@ -1,79 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\ObjectStore; -use \OC\Files\Cache\Scanner; -use \OC\Files\Storage\Storage; - -class NoopScanner extends Scanner { - - public function __construct(Storage $storage) { - //we don't need the storage, so do nothing here - } - - /** - * scan a single file and store it in the cache - * - * @param string $file - * @param int $reuseExisting - * @param int $parentId - * @param array|null $cacheData existing data in the cache for the file to be scanned - * @return array an array of metadata of the scanned file - */ - public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) { - return array(); - } - - /** - * scan a folder and all it's children - * - * @param string $path - * @param bool $recursive - * @param int $reuse - * @return array with the meta data of the scanned file or folder - */ - public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) { - return array(); - } - - /** - * scan all the files and folders in a folder - * - * @param string $path - * @param bool $recursive - * @param int $reuse - * @param array $folderData existing cache data for the folder to be scanned - * @return int the size of the scanned folder or -1 if the size is unknown at this stage - */ - protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderData = null, $lock = true) { - return 0; - } - - /** - * walk over any folders that are not fully scanned yet and scan them - */ - public function backgroundScan() { - //noop - } -} diff --git a/lib/private/files/objectstore/objectstorestorage.php b/lib/private/files/objectstore/objectstorestorage.php deleted file mode 100644 index 8c643dbdcc7..00000000000 --- a/lib/private/files/objectstore/objectstorestorage.php +++ /dev/null @@ -1,407 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\ObjectStore; - -use Icewind\Streams\IteratorDirectory; -use OC\Files\Cache\CacheEntry; -use OCP\Files\ObjectStore\IObjectStore; - -class ObjectStoreStorage extends \OC\Files\Storage\Common { - - /** - * @var array - */ - private static $tmpFiles = array(); - /** - * @var \OCP\Files\ObjectStore\IObjectStore $objectStore - */ - protected $objectStore; - /** - * @var string $id - */ - protected $id; - /** - * @var \OC\User\User $user - */ - protected $user; - - public function __construct($params) { - if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) { - $this->objectStore = $params['objectstore']; - } else { - throw new \Exception('missing IObjectStore instance'); - } - if (isset($params['storageid'])) { - $this->id = 'object::store:' . $params['storageid']; - } else { - $this->id = 'object::store:' . $this->objectStore->getStorageId(); - } - //initialize cache with root directory in cache - if (!$this->is_dir('/')) { - $this->mkdir('/'); - } - } - - public function mkdir($path) { - $path = $this->normalizePath($path); - - if ($this->file_exists($path)) { - return false; - } - - $mTime = time(); - $data = [ - 'mimetype' => 'httpd/unix-directory', - 'size' => 0, - 'mtime' => $mTime, - 'storage_mtime' => $mTime, - 'permissions' => \OCP\Constants::PERMISSION_ALL, - ]; - if ($path === '') { - //create root on the fly - $data['etag'] = $this->getETag(''); - $this->getCache()->put('', $data); - return true; - } else { - // if parent does not exist, create it - $parent = $this->normalizePath(dirname($path)); - $parentType = $this->filetype($parent); - if ($parentType === false) { - if (!$this->mkdir($parent)) { - // something went wrong - return false; - } - } else if ($parentType === 'file') { - // parent is a file - return false; - } - // finally create the new dir - $mTime = time(); // update mtime - $data['mtime'] = $mTime; - $data['storage_mtime'] = $mTime; - $data['etag'] = $this->getETag($path); - $this->getCache()->put($path, $data); - return true; - } - } - - /** - * @param string $path - * @return string - */ - private function normalizePath($path) { - $path = trim($path, '/'); - //FIXME why do we sometimes get a path like 'files//username'? - $path = str_replace('//', '/', $path); - - // dirname('/folder') returns '.' but internally (in the cache) we store the root as '' - if (!$path || $path === '.') { - $path = ''; - } - - return $path; - } - - /** - * Object Stores use a NoopScanner because metadata is directly stored in - * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere. - * - * @param string $path - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner - * @return \OC\Files\ObjectStore\NoopScanner - */ - public function getScanner($path = '', $storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($this->scanner)) { - $this->scanner = new NoopScanner($storage); - } - return $this->scanner; - } - - public function getId() { - return $this->id; - } - - public function rmdir($path) { - $path = $this->normalizePath($path); - - if (!$this->is_dir($path)) { - return false; - } - - $this->rmObjects($path); - - $this->getCache()->remove($path); - - return true; - } - - private function rmObjects($path) { - $children = $this->getCache()->getFolderContents($path); - foreach ($children as $child) { - if ($child['mimetype'] === 'httpd/unix-directory') { - $this->rmObjects($child['path']); - } else { - $this->unlink($child['path']); - } - } - } - - public function unlink($path) { - $path = $this->normalizePath($path); - $stat = $this->stat($path); - - if ($stat && isset($stat['fileid'])) { - if ($stat['mimetype'] === 'httpd/unix-directory') { - return $this->rmdir($path); - } - try { - $this->objectStore->deleteObject($this->getURN($stat['fileid'])); - } catch (\Exception $ex) { - if ($ex->getCode() !== 404) { - \OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR); - return false; - } else { - //removing from cache is ok as it does not exist in the objectstore anyway - } - } - $this->getCache()->remove($path); - return true; - } - return false; - } - - public function stat($path) { - $path = $this->normalizePath($path); - $cacheEntry = $this->getCache()->get($path); - if ($cacheEntry instanceof CacheEntry) { - return $cacheEntry->getData(); - } else { - return false; - } - } - - /** - * Override this method if you need a different unique resource identifier for your object storage implementation. - * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users. - * You may need a mapping table to store your URN if it cannot be generated from the fileid. - * - * @param int $fileId the fileid - * @return null|string the unified resource name used to identify the object - */ - protected function getURN($fileId) { - if (is_numeric($fileId)) { - return 'urn:oid:' . $fileId; - } - return null; - } - - public function opendir($path) { - $path = $this->normalizePath($path); - - try { - $files = array(); - $folderContents = $this->getCache()->getFolderContents($path); - foreach ($folderContents as $file) { - $files[] = $file['name']; - } - - return IteratorDirectory::wrap($files); - } catch (\Exception $e) { - \OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR); - return false; - } - } - - public function filetype($path) { - $path = $this->normalizePath($path); - $stat = $this->stat($path); - if ($stat) { - if ($stat['mimetype'] === 'httpd/unix-directory') { - return 'dir'; - } - return 'file'; - } else { - return false; - } - } - - public function fopen($path, $mode) { - $path = $this->normalizePath($path); - - switch ($mode) { - case 'r': - case 'rb': - $stat = $this->stat($path); - if (is_array($stat)) { - try { - return $this->objectStore->readObject($this->getURN($stat['fileid'])); - } catch (\Exception $ex) { - \OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR); - return false; - } - } else { - return false; - } - case 'w': - case 'wb': - case 'a': - case 'ab': - case 'r+': - case 'w+': - case 'wb+': - case 'a+': - case 'x': - case 'x+': - case 'c': - case 'c+': - if (strrpos($path, '.') !== false) { - $ext = substr($path, strrpos($path, '.')); - } else { - $ext = ''; - } - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - if ($this->file_exists($path)) { - $source = $this->fopen($path, 'r'); - file_put_contents($tmpFile, $source); - } - self::$tmpFiles[$tmpFile] = $path; - - return fopen('close://' . $tmpFile, $mode); - } - return false; - } - - public function file_exists($path) { - $path = $this->normalizePath($path); - return (bool)$this->stat($path); - } - - public function rename($source, $target) { - $source = $this->normalizePath($source); - $target = $this->normalizePath($target); - $this->remove($target); - $this->getCache()->move($source, $target); - $this->touch(dirname($target)); - return true; - } - - public function getMimeType($path) { - $path = $this->normalizePath($path); - $stat = $this->stat($path); - if (is_array($stat)) { - return $stat['mimetype']; - } else { - return false; - } - } - - public function touch($path, $mtime = null) { - if (is_null($mtime)) { - $mtime = time(); - } - - $path = $this->normalizePath($path); - $dirName = dirname($path); - $parentExists = $this->is_dir($dirName); - if (!$parentExists) { - return false; - } - - $stat = $this->stat($path); - if (is_array($stat)) { - // update existing mtime in db - $stat['mtime'] = $mtime; - $this->getCache()->update($stat['fileid'], $stat); - } else { - $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path); - // create new file - $stat = array( - 'etag' => $this->getETag($path), - 'mimetype' => $mimeType, - 'size' => 0, - 'mtime' => $mtime, - 'storage_mtime' => $mtime, - 'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE, - ); - $fileId = $this->getCache()->put($path, $stat); - try { - //read an empty file from memory - $this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r')); - } catch (\Exception $ex) { - $this->getCache()->remove($path); - \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR); - return false; - } - } - return true; - } - - public function writeBack($tmpFile) { - if (!isset(self::$tmpFiles[$tmpFile])) { - return; - } - - $path = self::$tmpFiles[$tmpFile]; - $stat = $this->stat($path); - if (empty($stat)) { - // create new file - $stat = array( - 'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE, - ); - } - // update stat with new data - $mTime = time(); - $stat['size'] = filesize($tmpFile); - $stat['mtime'] = $mTime; - $stat['storage_mtime'] = $mTime; - $stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile); - $stat['etag'] = $this->getETag($path); - - $fileId = $this->getCache()->put($path, $stat); - try { - //upload to object storage - $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r')); - } catch (\Exception $ex) { - $this->getCache()->remove($path); - \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR); - throw $ex; // make this bubble up - } - } - - /** - * external changes are not supported, exclusive access to the object storage is assumed - * - * @param string $path - * @param int $time - * @return false - */ - public function hasUpdated($path, $time) { - return false; - } -} diff --git a/lib/private/files/objectstore/swift.php b/lib/private/files/objectstore/swift.php deleted file mode 100644 index 4af09dca254..00000000000 --- a/lib/private/files/objectstore/swift.php +++ /dev/null @@ -1,154 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\ObjectStore; - -use Guzzle\Http\Exception\ClientErrorResponseException; -use OCP\Files\ObjectStore\IObjectStore; -use OpenCloud\OpenStack; -use OpenCloud\Rackspace; - -class Swift implements IObjectStore { - /** - * @var \OpenCloud\OpenStack - */ - private $client; - - /** - * @var array - */ - private $params; - - /** - * @var \OpenCloud\ObjectStore\Service - */ - private $objectStoreService; - - /** - * @var \OpenCloud\ObjectStore\Resource\Container - */ - private $container; - - public function __construct($params) { - if (!isset($params['container'])) { - $params['container'] = 'owncloud'; - } - if (!isset($params['autocreate'])) { - // should only be true for tests - $params['autocreate'] = false; - } - - if (isset($params['apiKey'])) { - $this->client = new Rackspace($params['url'], $params); - } else { - $this->client = new OpenStack($params['url'], $params); - } - $this->params = $params; - } - - protected function init() { - if ($this->container) { - return; - } - - // the OpenCloud client library will default to 'cloudFiles' if $serviceName is null - $serviceName = null; - if (isset($this->params['serviceName'])) { - $serviceName = $this->params['serviceName']; - } - - // the OpenCloud client library will default to 'publicURL' if $urlType is null - $urlType = null; - if (isset($this->params['urlType'])) { - $urlType = $this->params['urlType']; - } - $this->objectStoreService = $this->client->objectStoreService($serviceName, $this->params['region'], $urlType); - - try { - $this->container = $this->objectStoreService->getContainer($this->params['container']); - } catch (ClientErrorResponseException $ex) { - // if the container does not exist and autocreate is true try to create the container on the fly - if (isset($this->params['autocreate']) && $this->params['autocreate'] === true) { - $this->container = $this->objectStoreService->createContainer($this->params['container']); - } else { - throw $ex; - } - } - } - - /** - * @return string the container name where objects are stored - */ - public function getStorageId() { - return $this->params['container']; - } - - /** - * @param string $urn the unified resource name used to identify the object - * @param resource $stream stream with the data to write - * @throws Exception from openstack lib when something goes wrong - */ - public function writeObject($urn, $stream) { - $this->init(); - $this->container->uploadObject($urn, $stream); - } - - /** - * @param string $urn the unified resource name used to identify the object - * @return resource stream with the read data - * @throws Exception from openstack lib when something goes wrong - */ - public function readObject($urn) { - $this->init(); - $object = $this->container->getObject($urn); - - // we need to keep a reference to objectContent or - // the stream will be closed before we can do anything with it - /** @var $objectContent \Guzzle\Http\EntityBody * */ - $objectContent = $object->getContent(); - $objectContent->rewind(); - - $stream = $objectContent->getStream(); - // save the object content in the context of the stream to prevent it being gc'd until the stream is closed - stream_context_set_option($stream, 'swift','content', $objectContent); - - return $stream; - } - - /** - * @param string $urn Unified Resource Name - * @return void - * @throws Exception from openstack lib when something goes wrong - */ - public function deleteObject($urn) { - $this->init(); - // see https://github.com/rackspace/php-opencloud/issues/243#issuecomment-30032242 - $this->container->dataObject()->setName($urn)->delete(); - } - - public function deleteContainer($recursive = false) { - $this->init(); - $this->container->delete($recursive); - } - -} diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php deleted file mode 100644 index 3a811b312c6..00000000000 --- a/lib/private/files/storage/common.php +++ /dev/null @@ -1,697 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Bart Visscher <bartv@thisnet.nl> - * @author Björn Schießle <schiessle@owncloud.com> - * @author hkjolhede <hkjolhede@gmail.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Martin Mattel <martin.mattel@diemattels.at> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Sam Tuke <mail@samtuke.com> - * @author scambra <sergio@entrecables.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; - -use OC\Files\Cache\Cache; -use OC\Files\Cache\Propagator; -use OC\Files\Cache\Scanner; -use OC\Files\Cache\Updater; -use OC\Files\Filesystem; -use OC\Files\Cache\Watcher; -use OCP\Files\FileNameTooLongException; -use OCP\Files\InvalidCharacterInPathException; -use OCP\Files\InvalidPathException; -use OCP\Files\ReservedWordException; -use OCP\Files\Storage\ILockingStorage; -use OCP\Lock\ILockingProvider; - -/** - * Storage backend class for providing common filesystem operation methods - * which are not storage-backend specific. - * - * \OC\Files\Storage\Common is never used directly; it is extended by all other - * storage backends, where its methods may be overridden, and additional - * (backend-specific) methods are defined. - * - * Some \OC\Files\Storage\Common methods call functions which are first defined - * in classes which extend it, e.g. $this->stat() . - */ -abstract class Common implements Storage, ILockingStorage { - - use LocalTempFileTrait; - - protected $cache; - protected $scanner; - protected $watcher; - protected $propagator; - protected $storageCache; - protected $updater; - - protected $mountOptions = []; - protected $owner = null; - - public function __construct($parameters) { - } - - /** - * Remove a file or folder - * - * @param string $path - * @return bool - */ - protected function remove($path) { - if ($this->is_dir($path)) { - return $this->rmdir($path); - } else if ($this->is_file($path)) { - return $this->unlink($path); - } else { - return false; - } - } - - public function is_dir($path) { - return $this->filetype($path) === 'dir'; - } - - public function is_file($path) { - return $this->filetype($path) === 'file'; - } - - public function filesize($path) { - if ($this->is_dir($path)) { - return 0; //by definition - } else { - $stat = $this->stat($path); - if (isset($stat['size'])) { - return $stat['size']; - } else { - return 0; - } - } - } - - public function isReadable($path) { - // at least check whether it exists - // subclasses might want to implement this more thoroughly - return $this->file_exists($path); - } - - public function isUpdatable($path) { - // at least check whether it exists - // subclasses might want to implement this more thoroughly - // a non-existing file/folder isn't updatable - return $this->file_exists($path); - } - - public function isCreatable($path) { - if ($this->is_dir($path) && $this->isUpdatable($path)) { - return true; - } - return false; - } - - public function isDeletable($path) { - if ($path === '' || $path === '/') { - return false; - } - $parent = dirname($path); - return $this->isUpdatable($parent) && $this->isUpdatable($path); - } - - public function isSharable($path) { - return $this->isReadable($path); - } - - public function getPermissions($path) { - $permissions = 0; - if ($this->isCreatable($path)) { - $permissions |= \OCP\Constants::PERMISSION_CREATE; - } - if ($this->isReadable($path)) { - $permissions |= \OCP\Constants::PERMISSION_READ; - } - if ($this->isUpdatable($path)) { - $permissions |= \OCP\Constants::PERMISSION_UPDATE; - } - if ($this->isDeletable($path)) { - $permissions |= \OCP\Constants::PERMISSION_DELETE; - } - if ($this->isSharable($path)) { - $permissions |= \OCP\Constants::PERMISSION_SHARE; - } - return $permissions; - } - - public function filemtime($path) { - $stat = $this->stat($path); - if (isset($stat['mtime']) && $stat['mtime'] > 0) { - return $stat['mtime']; - } else { - return 0; - } - } - - public function file_get_contents($path) { - $handle = $this->fopen($path, "r"); - if (!$handle) { - return false; - } - $data = stream_get_contents($handle); - fclose($handle); - return $data; - } - - public function file_put_contents($path, $data) { - $handle = $this->fopen($path, "w"); - $this->removeCachedFile($path); - $count = fwrite($handle, $data); - fclose($handle); - return $count; - } - - public function rename($path1, $path2) { - $this->remove($path2); - - $this->removeCachedFile($path1); - return $this->copy($path1, $path2) and $this->remove($path1); - } - - public function copy($path1, $path2) { - if ($this->is_dir($path1)) { - $this->remove($path2); - $dir = $this->opendir($path1); - $this->mkdir($path2); - while ($file = readdir($dir)) { - if (!Filesystem::isIgnoredDir($file)) { - if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) { - return false; - } - } - } - closedir($dir); - return true; - } else { - $source = $this->fopen($path1, 'r'); - $target = $this->fopen($path2, 'w'); - list(, $result) = \OC_Helper::streamCopy($source, $target); - $this->removeCachedFile($path2); - return $result; - } - } - - public function getMimeType($path) { - if ($this->is_dir($path)) { - return 'httpd/unix-directory'; - } elseif ($this->file_exists($path)) { - return \OC::$server->getMimeTypeDetector()->detectPath($path); - } else { - return false; - } - } - - public function hash($type, $path, $raw = false) { - $fh = $this->fopen($path, 'rb'); - $ctx = hash_init($type); - hash_update_stream($ctx, $fh); - fclose($fh); - return hash_final($ctx, $raw); - } - - public function search($query) { - return $this->searchInDir($query); - } - - public function getLocalFile($path) { - return $this->getCachedFile($path); - } - - /** - * @param string $path - * @param string $target - */ - private function addLocalFolder($path, $target) { - $dh = $this->opendir($path); - if (is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if (!\OC\Files\Filesystem::isIgnoredDir($file)) { - if ($this->is_dir($path . '/' . $file)) { - mkdir($target . '/' . $file); - $this->addLocalFolder($path . '/' . $file, $target . '/' . $file); - } else { - $tmp = $this->toTmpFile($path . '/' . $file); - rename($tmp, $target . '/' . $file); - } - } - } - } - } - - /** - * @param string $query - * @param string $dir - * @return array - */ - protected function searchInDir($query, $dir = '') { - $files = array(); - $dh = $this->opendir($dir); - if (is_resource($dh)) { - while (($item = readdir($dh)) !== false) { - if (\OC\Files\Filesystem::isIgnoredDir($item)) continue; - if (strstr(strtolower($item), strtolower($query)) !== false) { - $files[] = $dir . '/' . $item; - } - if ($this->is_dir($dir . '/' . $item)) { - $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); - } - } - } - closedir($dh); - return $files; - } - - /** - * check if a file or folder has been updated since $time - * - * The method is only used to check if the cache needs to be updated. Storage backends that don't support checking - * the mtime should always return false here. As a result storage implementations that always return false expect - * exclusive access to the backend and will not pick up files that have been added in a way that circumvents - * ownClouds filesystem. - * - * @param string $path - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - return $this->filemtime($path) > $time; - } - - public function getCache($path = '', $storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($storage->cache)) { - $storage->cache = new Cache($storage); - } - return $storage->cache; - } - - public function getScanner($path = '', $storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($storage->scanner)) { - $storage->scanner = new Scanner($storage); - } - return $storage->scanner; - } - - public function getWatcher($path = '', $storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($this->watcher)) { - $this->watcher = new Watcher($storage); - $globalPolicy = \OC::$server->getConfig()->getSystemValue('filesystem_check_changes', Watcher::CHECK_NEVER); - $this->watcher->setPolicy((int)$this->getMountOption('filesystem_check_changes', $globalPolicy)); - } - return $this->watcher; - } - - /** - * get a propagator instance for the cache - * - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher - * @return \OC\Files\Cache\Propagator - */ - public function getPropagator($storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($storage->propagator)) { - $storage->propagator = new Propagator($storage); - } - return $storage->propagator; - } - - public function getUpdater($storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($storage->updater)) { - $storage->updater = new Updater($storage); - } - return $storage->updater; - } - - public function getStorageCache($storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($this->storageCache)) { - $this->storageCache = new \OC\Files\Cache\Storage($storage); - } - return $this->storageCache; - } - - /** - * get the owner of a path - * - * @param string $path The path to get the owner - * @return string|false uid or false - */ - public function getOwner($path) { - if ($this->owner === null) { - $this->owner = \OC_User::getUser(); - } - - return $this->owner; - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path) { - return uniqid(); - } - - /** - * clean a path, i.e. remove all redundant '.' and '..' - * making sure that it can't point to higher than '/' - * - * @param string $path The path to clean - * @return string cleaned path - */ - public function cleanPath($path) { - if (strlen($path) == 0 or $path[0] != '/') { - $path = '/' . $path; - } - - $output = array(); - foreach (explode('/', $path) as $chunk) { - if ($chunk == '..') { - array_pop($output); - } else if ($chunk == '.') { - } else { - $output[] = $chunk; - } - } - return implode('/', $output); - } - - /** - * Test a storage for availability - * - * @return bool - */ - public function test() { - if ($this->stat('')) { - return true; - } - return false; - } - - /** - * get the free space in the storage - * - * @param string $path - * @return int|false - */ - public function free_space($path) { - return \OCP\Files\FileInfo::SPACE_UNKNOWN; - } - - /** - * {@inheritdoc} - */ - public function isLocal() { - // the common implementation returns a temporary file by - // default, which is not local - return false; - } - - /** - * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class - * - * @param string $class - * @return bool - */ - public function instanceOfStorage($class) { - return is_a($this, $class); - } - - /** - * A custom storage implementation can return an url for direct download of a give file. - * - * For now the returned array can hold the parameter url - in future more attributes might follow. - * - * @param string $path - * @return array|false - */ - public function getDirectDownload($path) { - return []; - } - - /** - * @inheritdoc - */ - public function verifyPath($path, $fileName) { - if (isset($fileName[255])) { - throw new FileNameTooLongException(); - } - - // NOTE: $path will remain unverified for now - if (\OC_Util::runningOnWindows()) { - $this->verifyWindowsPath($fileName); - } else { - $this->verifyPosixPath($fileName); - } - } - - /** - * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx - * @param string $fileName - * @throws InvalidPathException - */ - protected function verifyWindowsPath($fileName) { - $fileName = trim($fileName); - $this->scanForInvalidCharacters($fileName, "\\/<>:\"|?*"); - $reservedNames = ['CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9']; - if (in_array(strtoupper($fileName), $reservedNames)) { - throw new ReservedWordException(); - } - } - - /** - * @param string $fileName - * @throws InvalidPathException - */ - protected function verifyPosixPath($fileName) { - $fileName = trim($fileName); - $this->scanForInvalidCharacters($fileName, "\\/"); - $reservedNames = ['*']; - if (in_array($fileName, $reservedNames)) { - throw new ReservedWordException(); - } - } - - /** - * @param string $fileName - * @param string $invalidChars - * @throws InvalidPathException - */ - private function scanForInvalidCharacters($fileName, $invalidChars) { - foreach (str_split($invalidChars) as $char) { - if (strpos($fileName, $char) !== false) { - throw new InvalidCharacterInPathException(); - } - } - - $sanitizedFileName = filter_var($fileName, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW); - if ($sanitizedFileName !== $fileName) { - throw new InvalidCharacterInPathException(); - } - } - - /** - * @param array $options - */ - public function setMountOptions(array $options) { - $this->mountOptions = $options; - } - - /** - * @param string $name - * @param mixed $default - * @return mixed - */ - public function getMountOption($name, $default = null) { - return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @param bool $preserveMtime - * @return bool - */ - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { - if ($sourceStorage === $this) { - return $this->copy($sourceInternalPath, $targetInternalPath); - } - - if ($sourceStorage->is_dir($sourceInternalPath)) { - $dh = $sourceStorage->opendir($sourceInternalPath); - $result = $this->mkdir($targetInternalPath); - if (is_resource($dh)) { - while ($result and ($file = readdir($dh)) !== false) { - if (!Filesystem::isIgnoredDir($file)) { - $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file); - } - } - } - } else { - $source = $sourceStorage->fopen($sourceInternalPath, 'r'); - // TODO: call fopen in a way that we execute again all storage wrappers - // to avoid that we bypass storage wrappers which perform important actions - // for this operation. Same is true for all other operations which - // are not the same as the original one.Once this is fixed we also - // need to adjust the encryption wrapper. - $target = $this->fopen($targetInternalPath, 'w'); - list(, $result) = \OC_Helper::streamCopy($source, $target); - if ($result and $preserveMtime) { - $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath)); - } - fclose($source); - fclose($target); - - if (!$result) { - // delete partially written target file - $this->unlink($targetInternalPath); - // delete cache entry that was created by fopen - $this->getCache()->remove($targetInternalPath); - } - } - return (bool)$result; - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - if ($sourceStorage === $this) { - return $this->rename($sourceInternalPath, $targetInternalPath); - } - - if (!$sourceStorage->isDeletable($sourceInternalPath)) { - return false; - } - - $result = $this->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true); - if ($result) { - if ($sourceStorage->is_dir($sourceInternalPath)) { - $result &= $sourceStorage->rmdir($sourceInternalPath); - } else { - $result &= $sourceStorage->unlink($sourceInternalPath); - } - } - return $result; - } - - /** - * @inheritdoc - */ - public function getMetaData($path) { - $permissions = $this->getPermissions($path); - if (!$permissions & \OCP\Constants::PERMISSION_READ) { - //can't read, nothing we can do - return null; - } - - $data = []; - $data['mimetype'] = $this->getMimeType($path); - $data['mtime'] = $this->filemtime($path); - if ($data['mimetype'] == 'httpd/unix-directory') { - $data['size'] = -1; //unknown - } else { - $data['size'] = $this->filesize($path); - } - $data['etag'] = $this->getETag($path); - $data['storage_mtime'] = $data['mtime']; - $data['permissions'] = $permissions; - - return $data; - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @throws \OCP\Lock\LockedException - */ - public function acquireLock($path, $type, ILockingProvider $provider) { - $provider->acquireLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type); - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - */ - public function releaseLock($path, $type, ILockingProvider $provider) { - $provider->releaseLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type); - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - */ - public function changeLock($path, $type, ILockingProvider $provider) { - $provider->changeLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type); - } - - /** - * @return array [ available, last_checked ] - */ - public function getAvailability() { - return $this->getStorageCache()->getAvailability(); - } - - /** - * @param bool $isAvailable - */ - public function setAvailability($isAvailable) { - $this->getStorageCache()->setAvailability($isAvailable); - } -} diff --git a/lib/private/files/storage/commontest.php b/lib/private/files/storage/commontest.php deleted file mode 100644 index 0047a51169c..00000000000 --- a/lib/private/files/storage/commontest.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Christopher Schäpers <kondou@ts.unde.re> - * @author Felix Moeller <mail@felixmoeller.de> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -/** - * test implementation for \OC\Files\Storage\Common with \OC\Files\Storage\Local - */ - -namespace OC\Files\Storage; - -class CommonTest extends \OC\Files\Storage\Common{ - /** - * underlying local storage used for missing functions - * @var \OC\Files\Storage\Local - */ - private $storage; - - public function __construct($params) { - $this->storage=new \OC\Files\Storage\Local($params); - } - - public function getId(){ - return 'test::'.$this->storage->getId(); - } - public function mkdir($path) { - return $this->storage->mkdir($path); - } - public function rmdir($path) { - return $this->storage->rmdir($path); - } - public function opendir($path) { - return $this->storage->opendir($path); - } - public function stat($path) { - return $this->storage->stat($path); - } - public function filetype($path) { - return @$this->storage->filetype($path); - } - public function isReadable($path) { - return $this->storage->isReadable($path); - } - public function isUpdatable($path) { - return $this->storage->isUpdatable($path); - } - public function file_exists($path) { - return $this->storage->file_exists($path); - } - public function unlink($path) { - return $this->storage->unlink($path); - } - public function fopen($path, $mode) { - return $this->storage->fopen($path, $mode); - } - public function free_space($path) { - return $this->storage->free_space($path); - } - public function touch($path, $mtime=null) { - return $this->storage->touch($path, $mtime); - } -} diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php deleted file mode 100644 index 8eebea1f3ba..00000000000 --- a/lib/private/files/storage/dav.php +++ /dev/null @@ -1,817 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Carlos Cerrillo <ccerrillo@gmail.com> - * @author Felix Moeller <mail@felixmoeller.de> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Philipp Kapfer <philipp.kapfer@gmx.at> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; - -use Exception; -use GuzzleHttp\Exception\RequestException; -use GuzzleHttp\Message\ResponseInterface; -use OC\Files\Filesystem; -use OC\Files\Stream\Close; -use Icewind\Streams\IteratorDirectory; -use OC\MemCache\ArrayCache; -use OCP\AppFramework\Http; -use OCP\Constants; -use OCP\Files; -use OCP\Files\FileInfo; -use OCP\Files\StorageInvalidException; -use OCP\Files\StorageNotAvailableException; -use OCP\Util; -use Sabre\DAV\Client; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Xml\Property\ResourceType; -use Sabre\HTTP\ClientException; -use Sabre\HTTP\ClientHttpException; - -/** - * Class DAV - * - * @package OC\Files\Storage - */ -class DAV extends Common { - /** @var string */ - protected $password; - /** @var string */ - protected $user; - /** @var string */ - protected $host; - /** @var bool */ - protected $secure; - /** @var string */ - protected $root; - /** @var string */ - protected $certPath; - /** @var bool */ - protected $ready; - /** @var Client */ - private $client; - /** @var ArrayCache */ - private $statCache; - /** @var array */ - private static $tempFiles = []; - /** @var \OCP\Http\Client\IClientService */ - private $httpClientService; - - /** - * @param array $params - * @throws \Exception - */ - public function __construct($params) { - $this->statCache = new ArrayCache(); - $this->httpClientService = \OC::$server->getHTTPClientService(); - if (isset($params['host']) && isset($params['user']) && isset($params['password'])) { - $host = $params['host']; - //remove leading http[s], will be generated in createBaseUri() - if (substr($host, 0, 8) == "https://") $host = substr($host, 8); - else if (substr($host, 0, 7) == "http://") $host = substr($host, 7); - $this->host = $host; - $this->user = $params['user']; - $this->password = $params['password']; - if (isset($params['secure'])) { - if (is_string($params['secure'])) { - $this->secure = ($params['secure'] === 'true'); - } else { - $this->secure = (bool)$params['secure']; - } - } else { - $this->secure = false; - } - if ($this->secure === true) { - // inject mock for testing - $certPath = \OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt'; - if (file_exists($certPath)) { - $this->certPath = $certPath; - } - } - $this->root = isset($params['root']) ? $params['root'] : '/'; - if (!$this->root || $this->root[0] != '/') { - $this->root = '/' . $this->root; - } - if (substr($this->root, -1, 1) != '/') { - $this->root .= '/'; - } - } else { - throw new \Exception('Invalid webdav storage configuration'); - } - } - - private function init() { - if ($this->ready) { - return; - } - $this->ready = true; - - $settings = array( - 'baseUri' => $this->createBaseUri(), - 'userName' => $this->user, - 'password' => $this->password, - ); - - $proxy = \OC::$server->getConfig()->getSystemValue('proxy', ''); - if($proxy !== '') { - $settings['proxy'] = $proxy; - } - - $this->client = new Client($settings); - $this->client->setThrowExceptions(true); - if ($this->secure === true && $this->certPath) { - $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath); - } - } - - /** - * Clear the stat cache - */ - public function clearStatCache() { - $this->statCache->clear(); - } - - /** {@inheritdoc} */ - public function getId() { - return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root; - } - - /** {@inheritdoc} */ - public function createBaseUri() { - $baseUri = 'http'; - if ($this->secure) { - $baseUri .= 's'; - } - $baseUri .= '://' . $this->host . $this->root; - return $baseUri; - } - - /** {@inheritdoc} */ - public function mkdir($path) { - $this->init(); - $path = $this->cleanPath($path); - $result = $this->simpleResponse('MKCOL', $path, null, 201); - if ($result) { - $this->statCache->set($path, true); - } - return $result; - } - - /** {@inheritdoc} */ - public function rmdir($path) { - $this->init(); - $path = $this->cleanPath($path); - // FIXME: some WebDAV impl return 403 when trying to DELETE - // a non-empty folder - $result = $this->simpleResponse('DELETE', $path . '/', null, 204); - $this->statCache->clear($path . '/'); - $this->statCache->remove($path); - return $result; - } - - /** {@inheritdoc} */ - public function opendir($path) { - $this->init(); - $path = $this->cleanPath($path); - try { - $response = $this->client->propfind( - $this->encodePath($path), - array(), - 1 - ); - $id = md5('webdav' . $this->root . $path); - $content = array(); - $files = array_keys($response); - array_shift($files); //the first entry is the current directory - - if (!$this->statCache->hasKey($path)) { - $this->statCache->set($path, true); - } - foreach ($files as $file) { - $file = urldecode($file); - // do not store the real entry, we might not have all properties - if (!$this->statCache->hasKey($path)) { - $this->statCache->set($file, true); - } - $file = basename($file); - $content[] = $file; - } - return IteratorDirectory::wrap($content); - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 404) { - $this->statCache->clear($path . '/'); - $this->statCache->set($path, false); - return false; - } - $this->convertException($e, $path); - } catch (\Exception $e) { - $this->convertException($e, $path); - } - return false; - } - - /** - * Propfind call with cache handling. - * - * First checks if information is cached. - * If not, request it from the server then store to cache. - * - * @param string $path path to propfind - * - * @return array propfind response - * - * @throws NotFound - */ - protected function propfind($path) { - $path = $this->cleanPath($path); - $cachedResponse = $this->statCache->get($path); - if ($cachedResponse === false) { - // we know it didn't exist - throw new NotFound(); - } - // we either don't know it, or we know it exists but need more details - if (is_null($cachedResponse) || $cachedResponse === true) { - $this->init(); - try { - $response = $this->client->propfind( - $this->encodePath($path), - array( - '{DAV:}getlastmodified', - '{DAV:}getcontentlength', - '{DAV:}getcontenttype', - '{http://owncloud.org/ns}permissions', - '{http://open-collaboration-services.org/ns}share-permissions', - '{DAV:}resourcetype', - '{DAV:}getetag', - ) - ); - $this->statCache->set($path, $response); - } catch (NotFound $e) { - // remember that this path did not exist - $this->statCache->clear($path . '/'); - $this->statCache->set($path, false); - throw $e; - } - } else { - $response = $cachedResponse; - } - return $response; - } - - /** {@inheritdoc} */ - public function filetype($path) { - try { - $response = $this->propfind($path); - $responseType = array(); - if (isset($response["{DAV:}resourcetype"])) { - /** @var ResourceType[] $response */ - $responseType = $response["{DAV:}resourcetype"]->getValue(); - } - return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file'; - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 404) { - return false; - } - $this->convertException($e, $path); - } catch (\Exception $e) { - $this->convertException($e, $path); - } - return false; - } - - /** {@inheritdoc} */ - public function file_exists($path) { - try { - $path = $this->cleanPath($path); - $cachedState = $this->statCache->get($path); - if ($cachedState === false) { - // we know the file doesn't exist - return false; - } else if (!is_null($cachedState)) { - return true; - } - // need to get from server - $this->propfind($path); - return true; //no 404 exception - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 404) { - return false; - } - $this->convertException($e, $path); - } catch (\Exception $e) { - $this->convertException($e, $path); - } - return false; - } - - /** {@inheritdoc} */ - public function unlink($path) { - $this->init(); - $path = $this->cleanPath($path); - $result = $this->simpleResponse('DELETE', $path, null, 204); - $this->statCache->clear($path . '/'); - $this->statCache->remove($path); - return $result; - } - - /** {@inheritdoc} */ - public function fopen($path, $mode) { - $this->init(); - $path = $this->cleanPath($path); - switch ($mode) { - case 'r': - case 'rb': - try { - $response = $this->httpClientService - ->newClient() - ->get($this->createBaseUri() . $this->encodePath($path), [ - 'auth' => [$this->user, $this->password], - 'stream' => true - ]); - } catch (RequestException $e) { - if ($e->getResponse() instanceof ResponseInterface - && $e->getResponse()->getStatusCode() === 404) { - return false; - } else { - throw $e; - } - } - - if ($response->getStatusCode() !== Http::STATUS_OK) { - if ($response->getStatusCode() === Http::STATUS_LOCKED) { - throw new \OCP\Lock\LockedException($path); - } else { - Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR); - } - } - - return $response->getBody(); - case 'w': - case 'wb': - case 'a': - case 'ab': - case 'r+': - case 'w+': - case 'wb+': - case 'a+': - case 'x': - case 'x+': - case 'c': - case 'c+': - //emulate these - $tempManager = \OC::$server->getTempManager(); - if (strrpos($path, '.') !== false) { - $ext = substr($path, strrpos($path, '.')); - } else { - $ext = ''; - } - if ($this->file_exists($path)) { - if (!$this->isUpdatable($path)) { - return false; - } - if ($mode === 'w' or $mode === 'w+') { - $tmpFile = $tempManager->getTemporaryFile($ext); - } else { - $tmpFile = $this->getCachedFile($path); - } - } else { - if (!$this->isCreatable(dirname($path))) { - return false; - } - $tmpFile = $tempManager->getTemporaryFile($ext); - } - Close::registerCallback($tmpFile, array($this, 'writeBack')); - self::$tempFiles[$tmpFile] = $path; - return fopen('close://' . $tmpFile, $mode); - } - } - - /** - * @param string $tmpFile - */ - public function writeBack($tmpFile) { - if (isset(self::$tempFiles[$tmpFile])) { - $this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]); - unlink($tmpFile); - } - } - - /** {@inheritdoc} */ - public function free_space($path) { - $this->init(); - $path = $this->cleanPath($path); - try { - // TODO: cacheable ? - $response = $this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes')); - if (isset($response['{DAV:}quota-available-bytes'])) { - return (int)$response['{DAV:}quota-available-bytes']; - } else { - return FileInfo::SPACE_UNKNOWN; - } - } catch (\Exception $e) { - return FileInfo::SPACE_UNKNOWN; - } - } - - /** {@inheritdoc} */ - public function touch($path, $mtime = null) { - $this->init(); - if (is_null($mtime)) { - $mtime = time(); - } - $path = $this->cleanPath($path); - - // if file exists, update the mtime, else create a new empty file - if ($this->file_exists($path)) { - try { - $this->statCache->remove($path); - $this->client->proppatch($this->encodePath($path), array('{DAV:}lastmodified' => $mtime)); - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 501) { - return false; - } - $this->convertException($e, $path); - return false; - } catch (\Exception $e) { - $this->convertException($e, $path); - return false; - } - } else { - $this->file_put_contents($path, ''); - } - return true; - } - - /** - * @param string $path - * @param string $data - * @return int - */ - public function file_put_contents($path, $data) { - $path = $this->cleanPath($path); - $result = parent::file_put_contents($path, $data); - $this->statCache->remove($path); - return $result; - } - - /** - * @param string $path - * @param string $target - */ - protected function uploadFile($path, $target) { - $this->init(); - - // invalidate - $target = $this->cleanPath($target); - $this->statCache->remove($target); - $source = fopen($path, 'r'); - - $this->httpClientService - ->newClient() - ->put($this->createBaseUri() . $this->encodePath($target), [ - 'body' => $source, - 'auth' => [$this->user, $this->password] - ]); - - $this->removeCachedFile($target); - } - - /** {@inheritdoc} */ - public function rename($path1, $path2) { - $this->init(); - $path1 = $this->cleanPath($path1); - $path2 = $this->cleanPath($path2); - try { - $this->client->request( - 'MOVE', - $this->encodePath($path1), - null, - array( - 'Destination' => $this->createBaseUri() . $this->encodePath($path2) - ) - ); - $this->statCache->clear($path1 . '/'); - $this->statCache->clear($path2 . '/'); - $this->statCache->set($path1, false); - $this->statCache->set($path2, true); - $this->removeCachedFile($path1); - $this->removeCachedFile($path2); - return true; - } catch (\Exception $e) { - $this->convertException($e); - } - return false; - } - - /** {@inheritdoc} */ - public function copy($path1, $path2) { - $this->init(); - $path1 = $this->encodePath($this->cleanPath($path1)); - $path2 = $this->createBaseUri() . $this->encodePath($this->cleanPath($path2)); - try { - $this->client->request('COPY', $path1, null, array('Destination' => $path2)); - $this->statCache->clear($path2 . '/'); - $this->statCache->set($path2, true); - $this->removeCachedFile($path2); - return true; - } catch (\Exception $e) { - $this->convertException($e); - } - return false; - } - - /** {@inheritdoc} */ - public function stat($path) { - try { - $response = $this->propfind($path); - return array( - 'mtime' => strtotime($response['{DAV:}getlastmodified']), - 'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0, - ); - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 404) { - return array(); - } - $this->convertException($e, $path); - } catch (\Exception $e) { - $this->convertException($e, $path); - } - return array(); - } - - /** {@inheritdoc} */ - public function getMimeType($path) { - try { - $response = $this->propfind($path); - $responseType = array(); - if (isset($response["{DAV:}resourcetype"])) { - /** @var ResourceType[] $response */ - $responseType = $response["{DAV:}resourcetype"]->getValue(); - } - $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file'; - if ($type == 'dir') { - return 'httpd/unix-directory'; - } elseif (isset($response['{DAV:}getcontenttype'])) { - return $response['{DAV:}getcontenttype']; - } else { - return false; - } - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 404) { - return false; - } - $this->convertException($e, $path); - } catch (\Exception $e) { - $this->convertException($e, $path); - } - return false; - } - - /** - * @param string $path - * @return string - */ - public function cleanPath($path) { - if ($path === '') { - return $path; - } - $path = Filesystem::normalizePath($path); - // remove leading slash - return substr($path, 1); - } - - /** - * URL encodes the given path but keeps the slashes - * - * @param string $path to encode - * @return string encoded path - */ - private function encodePath($path) { - // slashes need to stay - return str_replace('%2F', '/', rawurlencode($path)); - } - - /** - * @param string $method - * @param string $path - * @param string|resource|null $body - * @param int $expected - * @return bool - * @throws StorageInvalidException - * @throws StorageNotAvailableException - */ - private function simpleResponse($method, $path, $body, $expected) { - $path = $this->cleanPath($path); - try { - $response = $this->client->request($method, $this->encodePath($path), $body); - return $response['statusCode'] == $expected; - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 404 && $method === 'DELETE') { - $this->statCache->clear($path . '/'); - $this->statCache->set($path, false); - return false; - } - - $this->convertException($e, $path); - } catch (\Exception $e) { - $this->convertException($e, $path); - } - return false; - } - - /** - * check if curl is installed - */ - public static function checkDependencies() { - return true; - } - - /** {@inheritdoc} */ - public function isUpdatable($path) { - return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE); - } - - /** {@inheritdoc} */ - public function isCreatable($path) { - return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE); - } - - /** {@inheritdoc} */ - public function isSharable($path) { - return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE); - } - - /** {@inheritdoc} */ - public function isDeletable($path) { - return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE); - } - - /** {@inheritdoc} */ - public function getPermissions($path) { - $this->init(); - $path = $this->cleanPath($path); - $response = $this->propfind($path); - if (isset($response['{http://owncloud.org/ns}permissions'])) { - return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); - } else if ($this->is_dir($path)) { - return Constants::PERMISSION_ALL; - } else if ($this->file_exists($path)) { - return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE; - } else { - return 0; - } - } - - /** {@inheritdoc} */ - public function getETag($path) { - $this->init(); - $path = $this->cleanPath($path); - $response = $this->propfind($path); - if (isset($response['{DAV:}getetag'])) { - return trim($response['{DAV:}getetag'], '"'); - } - return parent::getEtag($path); - } - - /** - * @param string $permissionsString - * @return int - */ - protected function parsePermissions($permissionsString) { - $permissions = Constants::PERMISSION_READ; - if (strpos($permissionsString, 'R') !== false) { - $permissions |= Constants::PERMISSION_SHARE; - } - if (strpos($permissionsString, 'D') !== false) { - $permissions |= Constants::PERMISSION_DELETE; - } - if (strpos($permissionsString, 'W') !== false) { - $permissions |= Constants::PERMISSION_UPDATE; - } - if (strpos($permissionsString, 'CK') !== false) { - $permissions |= Constants::PERMISSION_CREATE; - $permissions |= Constants::PERMISSION_UPDATE; - } - return $permissions; - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @throws \OCP\Files\StorageNotAvailableException - * @return bool - */ - public function hasUpdated($path, $time) { - $this->init(); - $path = $this->cleanPath($path); - try { - // force refresh for $path - $this->statCache->remove($path); - $response = $this->propfind($path); - if (isset($response['{DAV:}getetag'])) { - $cachedData = $this->getCache()->get($path); - $etag = null; - if (isset($response['{DAV:}getetag'])) { - $etag = trim($response['{DAV:}getetag'], '"'); - } - if (!empty($etag) && $cachedData['etag'] !== $etag) { - return true; - } else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) { - $sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions']; - return $sharePermissions !== $cachedData['permissions']; - } else if (isset($response['{http://owncloud.org/ns}permissions'])) { - $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); - return $permissions !== $cachedData['permissions']; - } else { - return false; - } - } else { - $remoteMtime = strtotime($response['{DAV:}getlastmodified']); - return $remoteMtime > $time; - } - } catch (ClientHttpException $e) { - if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) { - if ($path === '') { - // if root is gone it means the storage is not available - throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage()); - } - return false; - } - $this->convertException($e, $path); - return false; - } catch (\Exception $e) { - $this->convertException($e, $path); - return false; - } - } - - /** - * Interpret the given exception and decide whether it is due to an - * unavailable storage, invalid storage or other. - * This will either throw StorageInvalidException, StorageNotAvailableException - * or do nothing. - * - * @param Exception $e sabre exception - * @param string $path optional path from the operation - * - * @throws StorageInvalidException if the storage is invalid, for example - * when the authentication expired or is invalid - * @throws StorageNotAvailableException if the storage is not available, - * which might be temporary - */ - private function convertException(Exception $e, $path = '') { - Util::writeLog('files_external', $e->getMessage(), Util::ERROR); - if ($e instanceof ClientHttpException) { - if ($e->getHttpStatus() === 423) { - throw new \OCP\Lock\LockedException($path); - } - if ($e->getHttpStatus() === 401) { - // either password was changed or was invalid all along - throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage()); - } else if ($e->getHttpStatus() === 405) { - // ignore exception for MethodNotAllowed, false will be returned - return; - } - throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage()); - } else if ($e instanceof ClientException) { - // connection timeout or refused, server could be temporarily down - throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage()); - } else if ($e instanceof \InvalidArgumentException) { - // parse error because the server returned HTML instead of XML, - // possibly temporarily down - throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage()); - } else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) { - // rethrow - throw $e; - } - - // TODO: only log for now, but in the future need to wrap/rethrow exception - } -} - diff --git a/lib/private/files/storage/failedstorage.php b/lib/private/files/storage/failedstorage.php deleted file mode 100644 index df7f76856d5..00000000000 --- a/lib/private/files/storage/failedstorage.php +++ /dev/null @@ -1,215 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; - -use OC\Files\Cache\FailedCache; -use \OCP\Lock\ILockingProvider; -use \OCP\Files\StorageNotAvailableException; - -/** - * Storage placeholder to represent a missing precondition, storage unavailable - */ -class FailedStorage extends Common { - - /** @var \Exception */ - protected $e; - - /** - * @param array $params ['exception' => \Exception] - */ - public function __construct($params) { - $this->e = $params['exception']; - if (!$this->e) { - throw new \InvalidArgumentException('Missing "exception" argument in FailedStorage constructor'); - } - } - - public function getId() { - // we can't return anything sane here - return 'failedstorage'; - } - - public function mkdir($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function rmdir($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function opendir($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function is_dir($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function is_file($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function stat($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function filetype($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function filesize($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function isCreatable($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function isReadable($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function isUpdatable($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function isDeletable($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function isSharable($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getPermissions($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function file_exists($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function filemtime($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function file_get_contents($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function file_put_contents($path, $data) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function unlink($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function rename($path1, $path2) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function copy($path1, $path2) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function fopen($path, $mode) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getMimeType($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function hash($type, $path, $raw = false) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function free_space($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function search($query) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function touch($path, $mtime = null) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getLocalFile($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getLocalFolder($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function hasUpdated($path, $time) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getETag($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getDirectDownload($path) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function verifyPath($path, $fileName) { - return true; - } - - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function acquireLock($path, $type, ILockingProvider $provider) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function releaseLock($path, $type, ILockingProvider $provider) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function changeLock($path, $type, ILockingProvider $provider) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getAvailability() { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function setAvailability($isAvailable) { - throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e); - } - - public function getCache($path = '', $storage = null) { - return new FailedCache(); - } -} diff --git a/lib/private/files/storage/flysystem.php b/lib/private/files/storage/flysystem.php deleted file mode 100644 index 608639b71a6..00000000000 --- a/lib/private/files/storage/flysystem.php +++ /dev/null @@ -1,256 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; - -use Icewind\Streams\CallbackWrapper; -use Icewind\Streams\IteratorDirectory; -use League\Flysystem\AdapterInterface; -use League\Flysystem\FileNotFoundException; -use League\Flysystem\Filesystem; -use League\Flysystem\Plugin\GetWithMetadata; - -/** - * Generic adapter between flysystem adapters and owncloud's storage system - * - * To use: subclass and call $this->buildFlysystem with the flysystem adapter of choice - */ -abstract class Flysystem extends Common { - /** - * @var Filesystem - */ - protected $flysystem; - - /** - * @var string - */ - protected $root = ''; - - /** - * Initialize the storage backend with a flyssytem adapter - * - * @param \League\Flysystem\AdapterInterface $adapter - */ - protected function buildFlySystem(AdapterInterface $adapter) { - $this->flysystem = new Filesystem($adapter); - $this->flysystem->addPlugin(new GetWithMetadata()); - } - - protected function buildPath($path) { - $fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path); - return ltrim($fullPath, '/'); - } - - /** - * {@inheritdoc} - */ - public function file_get_contents($path) { - return $this->flysystem->read($this->buildPath($path)); - } - - /** - * {@inheritdoc} - */ - public function file_put_contents($path, $data) { - return $this->flysystem->put($this->buildPath($path), $data); - } - - /** - * {@inheritdoc} - */ - public function file_exists($path) { - return $this->flysystem->has($this->buildPath($path)); - } - - /** - * {@inheritdoc} - */ - public function unlink($path) { - if ($this->is_dir($path)) { - return $this->rmdir($path); - } - try { - return $this->flysystem->delete($this->buildPath($path)); - } catch (FileNotFoundException $e) { - return false; - } - } - - /** - * {@inheritdoc} - */ - public function rename($source, $target) { - if ($this->file_exists($target)) { - $this->unlink($target); - } - return $this->flysystem->rename($this->buildPath($source), $this->buildPath($target)); - } - - /** - * {@inheritdoc} - */ - public function copy($source, $target) { - if ($this->file_exists($target)) { - $this->unlink($target); - } - return $this->flysystem->copy($this->buildPath($source), $this->buildPath($target)); - } - - /** - * {@inheritdoc} - */ - public function filesize($path) { - if ($this->is_dir($path)) { - return 0; - } else { - return $this->flysystem->getSize($this->buildPath($path)); - } - } - - /** - * {@inheritdoc} - */ - public function mkdir($path) { - if ($this->file_exists($path)) { - return false; - } - return $this->flysystem->createDir($this->buildPath($path)); - } - - /** - * {@inheritdoc} - */ - public function filemtime($path) { - return $this->flysystem->getTimestamp($this->buildPath($path)); - } - - /** - * {@inheritdoc} - */ - public function rmdir($path) { - try { - return @$this->flysystem->deleteDir($this->buildPath($path)); - } catch (FileNotFoundException $e) { - return false; - } - } - - /** - * {@inheritdoc} - */ - public function opendir($path) { - try { - $content = $this->flysystem->listContents($this->buildPath($path)); - } catch (FileNotFoundException $e) { - return false; - } - $names = array_map(function ($object) { - return $object['basename']; - }, $content); - return IteratorDirectory::wrap($names); - } - - /** - * {@inheritdoc} - */ - public function fopen($path, $mode) { - $fullPath = $this->buildPath($path); - $useExisting = true; - switch ($mode) { - case 'r': - case 'rb': - try { - return $this->flysystem->readStream($fullPath); - } catch (FileNotFoundException $e) { - return false; - } - case 'w': - case 'w+': - case 'wb': - case 'wb+': - $useExisting = false; - case 'a': - case 'ab': - case 'r+': - case 'a+': - case 'x': - case 'x+': - case 'c': - case 'c+': - //emulate these - if ($useExisting and $this->file_exists($path)) { - if (!$this->isUpdatable($path)) { - return false; - } - $tmpFile = $this->getCachedFile($path); - } else { - if (!$this->isCreatable(dirname($path))) { - return false; - } - $tmpFile = \OCP\Files::tmpFile(); - } - $source = fopen($tmpFile, $mode); - return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) { - $this->flysystem->putStream($fullPath, fopen($tmpFile, 'r')); - unlink($tmpFile); - }); - } - return false; - } - - /** - * {@inheritdoc} - */ - public function touch($path, $mtime = null) { - if ($this->file_exists($path)) { - return false; - } else { - $this->file_put_contents($path, ''); - return true; - } - } - - /** - * {@inheritdoc} - */ - public function stat($path) { - $info = $this->flysystem->getWithMetadata($this->buildPath($path), ['timestamp', 'size']); - return [ - 'mtime' => $info['timestamp'], - 'size' => $info['size'] - ]; - } - - /** - * {@inheritdoc} - */ - public function filetype($path) { - if ($path === '' or $path === '/' or $path === '.') { - return 'dir'; - } - try { - $info = $this->flysystem->getMetadata($this->buildPath($path)); - } catch (FileNotFoundException $e) { - return false; - } - return $info['type']; - } -} diff --git a/lib/private/files/storage/home.php b/lib/private/files/storage/home.php deleted file mode 100644 index 9b98f2f7e12..00000000000 --- a/lib/private/files/storage/home.php +++ /dev/null @@ -1,114 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; -use OC\Files\Cache\HomePropagator; - -/** - * Specialized version of Local storage for home directory usage - */ -class Home extends Local implements \OCP\Files\IHomeStorage { - /** - * @var string - */ - protected $id; - - /** - * @var \OC\User\User $user - */ - protected $user; - - /** - * Construct a Home storage instance - * @param array $arguments array with "user" containing the - * storage owner and "legacy" containing "true" if the storage is - * a legacy storage with "local::" URL instead of the new "home::" one. - */ - public function __construct($arguments) { - $this->user = $arguments['user']; - $datadir = $this->user->getHome(); - if (isset($arguments['legacy']) && $arguments['legacy']) { - // legacy home id (<= 5.0.12) - $this->id = 'local::' . $datadir . '/'; - } - else { - $this->id = 'home::' . $this->user->getUID(); - } - - parent::__construct(array('datadir' => $datadir)); - } - - public function getId() { - return $this->id; - } - - /** - * @return \OC\Files\Cache\HomeCache - */ - public function getCache($path = '', $storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($this->cache)) { - $this->cache = new \OC\Files\Cache\HomeCache($storage); - } - return $this->cache; - } - - /** - * get a propagator instance for the cache - * - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher - * @return \OC\Files\Cache\Propagator - */ - public function getPropagator($storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($this->propagator)) { - $this->propagator = new HomePropagator($storage); - } - return $this->propagator; - } - - - /** - * Returns the owner of this home storage - * @return \OC\User\User owner of this home storage - */ - public function getUser() { - return $this->user; - } - - /** - * get the owner of a path - * - * @param string $path The path to get the owner - * @return string uid or false - */ - public function getOwner($path) { - return $this->user->getUID(); - } -} diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php deleted file mode 100644 index 25b202af5f8..00000000000 --- a/lib/private/files/storage/local.php +++ /dev/null @@ -1,404 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Brice Maron <brice@bmaron.net> - * @author Jakob Sack <mail@jakobsack.de> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Klaas Freitag <freitag@owncloud.com> - * @author Martin Mattel <martin.mattel@diemattels.at> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Sjors van der Pluijm <sjors@desjors.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; -/** - * for local filestore, we only have to map the paths - */ -class Local extends \OC\Files\Storage\Common { - protected $datadir; - - public function __construct($arguments) { - $this->datadir = $arguments['datadir']; - if (substr($this->datadir, -1) !== '/') { - $this->datadir .= '/'; - } - } - - public function __destruct() { - } - - public function getId() { - return 'local::' . $this->datadir; - } - - public function mkdir($path) { - return @mkdir($this->getSourcePath($path), 0777, true); - } - - public function rmdir($path) { - if (!$this->isDeletable($path)) { - return false; - } - try { - $it = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator($this->getSourcePath($path)), - \RecursiveIteratorIterator::CHILD_FIRST - ); - /** - * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach - * This bug is fixed in PHP 5.5.9 or before - * See #8376 - */ - $it->rewind(); - while ($it->valid()) { - /** - * @var \SplFileInfo $file - */ - $file = $it->current(); - if (in_array($file->getBasename(), array('.', '..'))) { - $it->next(); - continue; - } elseif ($file->isDir()) { - rmdir($file->getPathname()); - } elseif ($file->isFile() || $file->isLink()) { - unlink($file->getPathname()); - } - $it->next(); - } - return rmdir($this->getSourcePath($path)); - } catch (\UnexpectedValueException $e) { - return false; - } - } - - public function opendir($path) { - return opendir($this->getSourcePath($path)); - } - - public function is_dir($path) { - if (substr($path, -1) == '/') { - $path = substr($path, 0, -1); - } - return is_dir($this->getSourcePath($path)); - } - - public function is_file($path) { - return is_file($this->getSourcePath($path)); - } - - public function stat($path) { - clearstatcache(); - $fullPath = $this->getSourcePath($path); - $statResult = stat($fullPath); - if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) { - $filesize = $this->filesize($path); - $statResult['size'] = $filesize; - $statResult[7] = $filesize; - } - return $statResult; - } - - public function filetype($path) { - $filetype = filetype($this->getSourcePath($path)); - if ($filetype == 'link') { - $filetype = filetype(realpath($this->getSourcePath($path))); - } - return $filetype; - } - - public function filesize($path) { - if ($this->is_dir($path)) { - return 0; - } - $fullPath = $this->getSourcePath($path); - if (PHP_INT_SIZE === 4) { - $helper = new \OC\LargeFileHelper; - return $helper->getFilesize($fullPath); - } - return filesize($fullPath); - } - - public function isReadable($path) { - return is_readable($this->getSourcePath($path)); - } - - public function isUpdatable($path) { - return is_writable($this->getSourcePath($path)); - } - - public function file_exists($path) { - return file_exists($this->getSourcePath($path)); - } - - public function filemtime($path) { - clearstatcache($this->getSourcePath($path)); - return filemtime($this->getSourcePath($path)); - } - - public function touch($path, $mtime = null) { - // sets the modification time of the file to the given value. - // If mtime is nil the current time is set. - // note that the access time of the file always changes to the current time. - if ($this->file_exists($path) and !$this->isUpdatable($path)) { - return false; - } - if (!is_null($mtime)) { - $result = touch($this->getSourcePath($path), $mtime); - } else { - $result = touch($this->getSourcePath($path)); - } - if ($result) { - clearstatcache(true, $this->getSourcePath($path)); - } - - return $result; - } - - public function file_get_contents($path) { - // file_get_contents() has a memory leak: https://bugs.php.net/bug.php?id=61961 - $fileName = $this->getSourcePath($path); - - $fileSize = filesize($fileName); - if ($fileSize === 0) { - return ''; - } - - $handle = fopen($fileName,'rb'); - $content = fread($handle, $fileSize); - fclose($handle); - return $content; - } - - public function file_put_contents($path, $data) { - return file_put_contents($this->getSourcePath($path), $data); - } - - public function unlink($path) { - if ($this->is_dir($path)) { - return $this->rmdir($path); - } else if ($this->is_file($path)) { - return unlink($this->getSourcePath($path)); - } else { - return false; - } - - } - - public function rename($path1, $path2) { - $srcParent = dirname($path1); - $dstParent = dirname($path2); - - if (!$this->isUpdatable($srcParent)) { - \OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, \OCP\Util::ERROR); - return false; - } - - if (!$this->isUpdatable($dstParent)) { - \OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, \OCP\Util::ERROR); - return false; - } - - if (!$this->file_exists($path1)) { - \OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, \OCP\Util::ERROR); - return false; - } - - if ($this->is_dir($path2)) { - $this->rmdir($path2); - } else if ($this->is_file($path2)) { - $this->unlink($path2); - } - - if ($this->is_dir($path1)) { - // we can't move folders across devices, use copy instead - $stat1 = stat(dirname($this->getSourcePath($path1))); - $stat2 = stat(dirname($this->getSourcePath($path2))); - if ($stat1['dev'] !== $stat2['dev']) { - $result = $this->copy($path1, $path2); - if ($result) { - $result &= $this->rmdir($path1); - } - return $result; - } - } - - return rename($this->getSourcePath($path1), $this->getSourcePath($path2)); - } - - public function copy($path1, $path2) { - if ($this->is_dir($path1)) { - return parent::copy($path1, $path2); - } else { - return copy($this->getSourcePath($path1), $this->getSourcePath($path2)); - } - } - - public function fopen($path, $mode) { - return fopen($this->getSourcePath($path), $mode); - } - - public function hash($type, $path, $raw = false) { - return hash_file($type, $this->getSourcePath($path), $raw); - } - - public function free_space($path) { - $sourcePath = $this->getSourcePath($path); - // using !is_dir because $sourcePath might be a part file or - // non-existing file, so we'd still want to use the parent dir - // in such cases - if (!is_dir($sourcePath)) { - // disk_free_space doesn't work on files - $sourcePath = dirname($sourcePath); - } - $space = @disk_free_space($sourcePath); - if ($space === false || is_null($space)) { - return \OCP\Files\FileInfo::SPACE_UNKNOWN; - } - return $space; - } - - public function search($query) { - return $this->searchInDir($query); - } - - public function getLocalFile($path) { - return $this->getSourcePath($path); - } - - public function getLocalFolder($path) { - return $this->getSourcePath($path); - } - - /** - * @param string $query - * @param string $dir - * @return array - */ - protected function searchInDir($query, $dir = '') { - $files = array(); - $physicalDir = $this->getSourcePath($dir); - foreach (scandir($physicalDir) as $item) { - if (\OC\Files\Filesystem::isIgnoredDir($item)) - continue; - $physicalItem = $physicalDir . '/' . $item; - - if (strstr(strtolower($item), strtolower($query)) !== false) { - $files[] = $dir . '/' . $item; - } - if (is_dir($physicalItem)) { - $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); - } - } - return $files; - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - if ($this->file_exists($path)) { - return $this->filemtime($path) > $time; - } else { - return true; - } - } - - /** - * Get the source path (on disk) of a given path - * - * @param string $path - * @return string - */ - public function getSourcePath($path) { - $fullPath = $this->datadir . $path; - return $fullPath; - } - - /** - * {@inheritdoc} - */ - public function isLocal() { - return true; - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path) { - if ($this->is_file($path)) { - $stat = $this->stat($path); - return md5( - $stat['mtime'] . - $stat['ino'] . - $stat['dev'] . - $stat['size'] - ); - } else { - return parent::getETag($path); - } - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - if($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')){ - /** - * @var \OC\Files\Storage\Local $sourceStorage - */ - $rootStorage = new Local(['datadir' => '/']); - return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath)); - } else { - return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) { - /** - * @var \OC\Files\Storage\Local $sourceStorage - */ - $rootStorage = new Local(['datadir' => '/']); - return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath)); - } else { - return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } - } -} diff --git a/lib/private/files/storage/localtempfiletrait.php b/lib/private/files/storage/localtempfiletrait.php deleted file mode 100644 index 88f11e4e752..00000000000 --- a/lib/private/files/storage/localtempfiletrait.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; - -/** - * Storage backend class for providing common filesystem operation methods - * which are not storage-backend specific. - * - * \OC\Files\Storage\Common is never used directly; it is extended by all other - * storage backends, where its methods may be overridden, and additional - * (backend-specific) methods are defined. - * - * Some \OC\Files\Storage\Common methods call functions which are first defined - * in classes which extend it, e.g. $this->stat() . - */ -trait LocalTempFileTrait { - - /** @var string[] */ - protected $cachedFiles = []; - - /** - * @param string $path - * @return string - */ - protected function getCachedFile($path) { - if (!isset($this->cachedFiles[$path])) { - $this->cachedFiles[$path] = $this->toTmpFile($path); - } - return $this->cachedFiles[$path]; - } - - /** - * @param string $path - */ - protected function removeCachedFile($path) { - unset($this->cachedFiles[$path]); - } - - /** - * @param string $path - * @return string - */ - protected function toTmpFile($path) { //no longer in the storage api, still useful here - $source = $this->fopen($path, 'r'); - if (!$source) { - return false; - } - if ($pos = strrpos($path, '.')) { - $extension = substr($path, $pos); - } else { - $extension = ''; - } - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension); - $target = fopen($tmpFile, 'w'); - \OC_Helper::streamCopy($source, $target); - fclose($target); - return $tmpFile; - } -} diff --git a/lib/private/files/storage/polyfill/copydirectory.php b/lib/private/files/storage/polyfill/copydirectory.php deleted file mode 100644 index d4cac117ade..00000000000 --- a/lib/private/files/storage/polyfill/copydirectory.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php -/** - * @author Martin Mattel <martin.mattel@diemattels.at> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage\PolyFill; - -trait CopyDirectory { - /** - * Check if a path is a directory - * - * @param string $path - * @return bool - */ - abstract public function is_dir($path); - - /** - * Check if a file or folder exists - * - * @param string $path - * @return bool - */ - abstract public function file_exists($path); - - /** - * Delete a file or folder - * - * @param string $path - * @return bool - */ - abstract public function unlink($path); - - /** - * Open a directory handle for a folder - * - * @param string $path - * @return resource | bool - */ - abstract public function opendir($path); - - /** - * Create a new folder - * - * @param string $path - * @return bool - */ - abstract public function mkdir($path); - - public function copy($source, $target) { - if ($this->is_dir($source)) { - if ($this->file_exists($target)) { - $this->unlink($target); - } - $this->mkdir($target); - return $this->copyRecursive($source, $target); - } else { - return parent::copy($source, $target); - } - } - - /** - * For adapters that don't support copying folders natively - * - * @param $source - * @param $target - * @return bool - */ - protected function copyRecursive($source, $target) { - $dh = $this->opendir($source); - $result = true; - while ($file = readdir($dh)) { - if (!\OC\Files\Filesystem::isIgnoredDir($file)) { - if ($this->is_dir($source . '/' . $file)) { - $this->mkdir($target . '/' . $file); - $result = $this->copyRecursive($source . '/' . $file, $target . '/' . $file); - } else { - $result = parent::copy($source . '/' . $file, $target . '/' . $file); - } - if (!$result) { - break; - } - } - } - return $result; - } -} diff --git a/lib/private/files/storage/storage.php b/lib/private/files/storage/storage.php deleted file mode 100644 index c066336d4b8..00000000000 --- a/lib/private/files/storage/storage.php +++ /dev/null @@ -1,119 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; -use OCP\Lock\ILockingProvider; - -/** - * 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 extends \OCP\Files\Storage { - - /** - * 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); - - /** - * get a scanner instance for the storage - * - * @param string $path - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner - * @return \OC\Files\Cache\Scanner - */ - public function getScanner($path = '', $storage = null); - - - /** - * get the user id of the owner of a file or folder - * - * @param string $path - * @return string - */ - public function getOwner($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); - - /** - * get a propagator instance for the cache - * - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher - * @return \OC\Files\Cache\Propagator - */ - public function getPropagator($storage = null); - - /** - * get a updater instance for the cache - * - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher - * @return \OC\Files\Cache\Updater - */ - public function getUpdater($storage = null); - - /** - * @return \OC\Files\Cache\Storage - */ - public function getStorageCache(); - - /** - * @param string $path - * @return array - */ - public function getMetaData($path); - - /** - * @param string $path The path of the file to acquire the lock for - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @throws \OCP\Lock\LockedException - */ - public function acquireLock($path, $type, ILockingProvider $provider); - - /** - * @param string $path The path of the file to release the lock for - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - */ - public function releaseLock($path, $type, ILockingProvider $provider); - - /** - * @param string $path The path of the file to change the lock for - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @throws \OCP\Lock\LockedException - */ - public function changeLock($path, $type, ILockingProvider $provider); -} diff --git a/lib/private/files/storage/storagefactory.php b/lib/private/files/storage/storagefactory.php deleted file mode 100644 index 84362cabecc..00000000000 --- a/lib/private/files/storage/storagefactory.php +++ /dev/null @@ -1,107 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; - -use OCP\Files\Mount\IMountPoint; -use OCP\Files\Storage\IStorageFactory; - -class StorageFactory implements IStorageFactory { - /** - * @var array[] [$name=>['priority'=>$priority, 'wrapper'=>$callable] $storageWrappers - */ - private $storageWrappers = []; - - /** - * allow modifier storage behaviour by adding wrappers around storages - * - * $callback should be a function of type (string $mountPoint, Storage $storage) => Storage - * - * @param string $wrapperName name of the wrapper - * @param callable $callback callback - * @param int $priority wrappers with the lower priority are applied last (meaning they get called first) - * @param \OCP\Files\Mount\IMountPoint[] $existingMounts existing mount points to apply the wrapper to - * @return bool true if the wrapper was added, false if there was already a wrapper with this - * name registered - */ - public function addStorageWrapper($wrapperName, $callback, $priority = 50, $existingMounts = []) { - if (isset($this->storageWrappers[$wrapperName])) { - return false; - } - - // apply to existing mounts before registering it to prevent applying it double in MountPoint::createStorage - foreach ($existingMounts as $mount) { - $mount->wrapStorage($callback); - } - - $this->storageWrappers[$wrapperName] = ['wrapper' => $callback, 'priority' => $priority]; - return true; - } - - /** - * Remove a storage wrapper by name. - * Note: internal method only to be used for cleanup - * - * @param string $wrapperName name of the wrapper - * @internal - */ - public function removeStorageWrapper($wrapperName) { - unset($this->storageWrappers[$wrapperName]); - } - - /** - * Create an instance of a storage and apply the registered storage wrappers - * - * @param \OCP\Files\Mount\IMountPoint $mountPoint - * @param string $class - * @param array $arguments - * @return \OCP\Files\Storage - */ - public function getInstance(IMountPoint $mountPoint, $class, $arguments) { - return $this->wrap($mountPoint, new $class($arguments)); - } - - /** - * @param \OCP\Files\Mount\IMountPoint $mountPoint - * @param \OCP\Files\Storage $storage - * @return \OCP\Files\Storage - */ - public function wrap(IMountPoint $mountPoint, $storage) { - $wrappers = array_values($this->storageWrappers); - usort($wrappers, function ($a, $b) { - return $b['priority'] - $a['priority']; - }); - /** @var callable[] $wrappers */ - $wrappers = array_map(function ($wrapper) { - return $wrapper['wrapper']; - }, $wrappers); - foreach ($wrappers as $wrapper) { - $storage = $wrapper($mountPoint->getMountPoint(), $storage, $mountPoint); - if (!($storage instanceof \OCP\Files\Storage)) { - throw new \Exception('Invalid result from storage wrapper'); - } - } - return $storage; - } -} diff --git a/lib/private/files/storage/temporary.php b/lib/private/files/storage/temporary.php deleted file mode 100644 index 2d8e84c2d52..00000000000 --- a/lib/private/files/storage/temporary.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage; - -/** - * local storage backend in temporary folder for testing purpose - */ -class Temporary extends Local{ - public function __construct($arguments = null) { - parent::__construct(array('datadir' => \OC::$server->getTempManager()->getTemporaryFolder())); - } - - public function cleanUp() { - \OC_Helper::rmdirr($this->datadir); - } - - public function __destruct() { - parent::__destruct(); - $this->cleanUp(); - } - - public function getDataDir() { - return $this->datadir; - } -} diff --git a/lib/private/files/storage/wrapper/availability.php b/lib/private/files/storage/wrapper/availability.php deleted file mode 100644 index 0ed31ba854a..00000000000 --- a/lib/private/files/storage/wrapper/availability.php +++ /dev/null @@ -1,461 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OC\Files\Storage\Wrapper; - -/** - * Availability checker for storages - * - * Throws a StorageNotAvailableException for storages with known failures - */ -class Availability extends Wrapper { - const RECHECK_TTL_SEC = 600; // 10 minutes - - public static function shouldRecheck($availability) { - if (!$availability['available']) { - // trigger a recheck if TTL reached - if ((time() - $availability['last_checked']) > self::RECHECK_TTL_SEC) { - return true; - } - } - return false; - } - - /** - * @return bool - */ - private function updateAvailability() { - try { - $result = $this->test(); - } catch (\Exception $e) { - $result = false; - } - $this->setAvailability($result); - return $result; - } - - /** - * @return bool - */ - private function isAvailable() { - $availability = $this->getAvailability(); - if (self::shouldRecheck($availability)) { - return $this->updateAvailability(); - } - return $availability['available']; - } - - /** - * @throws \OCP\Files\StorageNotAvailableException - */ - private function checkAvailability() { - if (!$this->isAvailable()) { - throw new \OCP\Files\StorageNotAvailableException(); - } - } - - /** {@inheritdoc} */ - public function mkdir($path) { - $this->checkAvailability(); - try { - return parent::mkdir($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function rmdir($path) { - $this->checkAvailability(); - try { - return parent::rmdir($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function opendir($path) { - $this->checkAvailability(); - try { - return parent::opendir($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function is_dir($path) { - $this->checkAvailability(); - try { - return parent::is_dir($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function is_file($path) { - $this->checkAvailability(); - try { - return parent::is_file($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function stat($path) { - $this->checkAvailability(); - try { - return parent::stat($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function filetype($path) { - $this->checkAvailability(); - try { - return parent::filetype($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function filesize($path) { - $this->checkAvailability(); - try { - return parent::filesize($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function isCreatable($path) { - $this->checkAvailability(); - try { - return parent::isCreatable($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function isReadable($path) { - $this->checkAvailability(); - try { - return parent::isReadable($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function isUpdatable($path) { - $this->checkAvailability(); - try { - return parent::isUpdatable($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function isDeletable($path) { - $this->checkAvailability(); - try { - return parent::isDeletable($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function isSharable($path) { - $this->checkAvailability(); - try { - return parent::isSharable($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function getPermissions($path) { - $this->checkAvailability(); - try { - return parent::getPermissions($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function file_exists($path) { - if ($path === '') { - return true; - } - $this->checkAvailability(); - try { - return parent::file_exists($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function filemtime($path) { - $this->checkAvailability(); - try { - return parent::filemtime($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function file_get_contents($path) { - $this->checkAvailability(); - try { - return parent::file_get_contents($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function file_put_contents($path, $data) { - $this->checkAvailability(); - try { - return parent::file_put_contents($path, $data); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function unlink($path) { - $this->checkAvailability(); - try { - return parent::unlink($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function rename($path1, $path2) { - $this->checkAvailability(); - try { - return parent::rename($path1, $path2); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function copy($path1, $path2) { - $this->checkAvailability(); - try { - return parent::copy($path1, $path2); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function fopen($path, $mode) { - $this->checkAvailability(); - try { - return parent::fopen($path, $mode); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function getMimeType($path) { - $this->checkAvailability(); - try { - return parent::getMimeType($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function hash($type, $path, $raw = false) { - $this->checkAvailability(); - try { - return parent::hash($type, $path, $raw); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function free_space($path) { - $this->checkAvailability(); - try { - return parent::free_space($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function search($query) { - $this->checkAvailability(); - try { - return parent::search($query); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function touch($path, $mtime = null) { - $this->checkAvailability(); - try { - return parent::touch($path, $mtime); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function getLocalFile($path) { - $this->checkAvailability(); - try { - return parent::getLocalFile($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function hasUpdated($path, $time) { - $this->checkAvailability(); - try { - return parent::hasUpdated($path, $time); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function getOwner($path) { - try { - return parent::getOwner($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function getETag($path) { - $this->checkAvailability(); - try { - return parent::getETag($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function getDirectDownload($path) { - $this->checkAvailability(); - try { - return parent::getDirectDownload($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - $this->checkAvailability(); - try { - return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - $this->checkAvailability(); - try { - return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } - - /** {@inheritdoc} */ - public function getMetaData($path) { - $this->checkAvailability(); - try { - return parent::getMetaData($path); - } catch (\OCP\Files\StorageNotAvailableException $e) { - $this->setAvailability(false); - throw $e; - } - } -} diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php deleted file mode 100644 index 02da978a700..00000000000 --- a/lib/private/files/storage/wrapper/encryption.php +++ /dev/null @@ -1,993 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage\Wrapper; - -use OC\Encryption\Exceptions\ModuleDoesNotExistsException; -use OC\Encryption\Update; -use OC\Encryption\Util; -use OC\Files\Cache\CacheEntry; -use OC\Files\Filesystem; -use OC\Files\Mount\Manager; -use OC\Files\Storage\LocalTempFileTrait; -use OC\Memcache\ArrayCache; -use OCP\Encryption\Exceptions\GenericEncryptionException; -use OCP\Encryption\IFile; -use OCP\Encryption\IManager; -use OCP\Encryption\Keys\IStorage; -use OCP\Files\Mount\IMountPoint; -use OCP\Files\Storage; -use OCP\ILogger; -use OCP\Files\Cache\ICacheEntry; - -class Encryption extends Wrapper { - - use LocalTempFileTrait; - - /** @var string */ - private $mountPoint; - - /** @var \OC\Encryption\Util */ - private $util; - - /** @var \OCP\Encryption\IManager */ - private $encryptionManager; - - /** @var \OCP\ILogger */ - private $logger; - - /** @var string */ - private $uid; - - /** @var array */ - protected $unencryptedSize; - - /** @var \OCP\Encryption\IFile */ - private $fileHelper; - - /** @var IMountPoint */ - private $mount; - - /** @var IStorage */ - private $keyStorage; - - /** @var Update */ - private $update; - - /** @var Manager */ - private $mountManager; - - /** @var array remember for which path we execute the repair step to avoid recursions */ - private $fixUnencryptedSizeOf = array(); - - /** @var ArrayCache */ - private $arrayCache; - - /** - * @param array $parameters - * @param IManager $encryptionManager - * @param Util $util - * @param ILogger $logger - * @param IFile $fileHelper - * @param string $uid - * @param IStorage $keyStorage - * @param Update $update - * @param Manager $mountManager - * @param ArrayCache $arrayCache - */ - public function __construct( - $parameters, - IManager $encryptionManager = null, - Util $util = null, - ILogger $logger = null, - IFile $fileHelper = null, - $uid = null, - IStorage $keyStorage = null, - Update $update = null, - Manager $mountManager = null, - ArrayCache $arrayCache = null - ) { - - $this->mountPoint = $parameters['mountPoint']; - $this->mount = $parameters['mount']; - $this->encryptionManager = $encryptionManager; - $this->util = $util; - $this->logger = $logger; - $this->uid = $uid; - $this->fileHelper = $fileHelper; - $this->keyStorage = $keyStorage; - $this->unencryptedSize = array(); - $this->update = $update; - $this->mountManager = $mountManager; - $this->arrayCache = $arrayCache; - parent::__construct($parameters); - } - - /** - * 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) { - $fullPath = $this->getFullPath($path); - - /** @var CacheEntry $info */ - $info = $this->getCache()->get($path); - if (isset($this->unencryptedSize[$fullPath])) { - $size = $this->unencryptedSize[$fullPath]; - // update file cache - if ($info instanceof ICacheEntry) { - $info = $info->getData(); - $info['encrypted'] = $info['encryptedVersion']; - } else { - if (!is_array($info)) { - $info = []; - } - $info['encrypted'] = true; - } - - $info['size'] = $size; - $this->getCache()->put($path, $info); - - return $size; - } - - if (isset($info['fileid']) && $info['encrypted']) { - return $this->verifyUnencryptedSize($path, $info['size']); - } - - return $this->storage->filesize($path); - } - - /** - * @param string $path - * @return array - */ - public function getMetaData($path) { - $data = $this->storage->getMetaData($path); - if (is_null($data)) { - return null; - } - $fullPath = $this->getFullPath($path); - $info = $this->getCache()->get($path); - - if (isset($this->unencryptedSize[$fullPath])) { - $data['encrypted'] = true; - $data['size'] = $this->unencryptedSize[$fullPath]; - } else { - if (isset($info['fileid']) && $info['encrypted']) { - $data['size'] = $this->verifyUnencryptedSize($path, $info['size']); - $data['encrypted'] = true; - } - } - - if (isset($info['encryptedVersion']) && $info['encryptedVersion'] > 1) { - $data['encryptedVersion'] = $info['encryptedVersion']; - } - - return $data; - } - - /** - * see http://php.net/manual/en/function.file_get_contents.php - * - * @param string $path - * @return string - */ - public function file_get_contents($path) { - - $encryptionModule = $this->getEncryptionModule($path); - - if ($encryptionModule) { - $handle = $this->fopen($path, "r"); - if (!$handle) { - return false; - } - $data = stream_get_contents($handle); - fclose($handle); - return $data; - } - return $this->storage->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) { - // file put content will always be translated to a stream write - $handle = $this->fopen($path, 'w'); - if (is_resource($handle)) { - $written = fwrite($handle, $data); - fclose($handle); - return $written; - } - - return false; - } - - /** - * see http://php.net/manual/en/function.unlink.php - * - * @param string $path - * @return bool - */ - public function unlink($path) { - $fullPath = $this->getFullPath($path); - if ($this->util->isExcluded($fullPath)) { - return $this->storage->unlink($path); - } - - $encryptionModule = $this->getEncryptionModule($path); - if ($encryptionModule) { - $this->keyStorage->deleteAllFileKeys($this->getFullPath($path)); - } - - return $this->storage->unlink($path); - } - - /** - * see http://php.net/manual/en/function.rename.php - * - * @param string $path1 - * @param string $path2 - * @return bool - */ - public function rename($path1, $path2) { - - $result = $this->storage->rename($path1, $path2); - - if ($result && - // versions always use the keys from the original file, so we can skip - // this step for versions - $this->isVersion($path2) === false && - $this->encryptionManager->isEnabled()) { - $source = $this->getFullPath($path1); - if (!$this->util->isExcluded($source)) { - $target = $this->getFullPath($path2); - if (isset($this->unencryptedSize[$source])) { - $this->unencryptedSize[$target] = $this->unencryptedSize[$source]; - } - $this->keyStorage->renameKeys($source, $target); - $module = $this->getEncryptionModule($path2); - if ($module) { - $module->update($target, $this->uid, []); - } - } - } - - return $result; - } - - /** - * see http://php.net/manual/en/function.rmdir.php - * - * @param string $path - * @return bool - */ - public function rmdir($path) { - $result = $this->storage->rmdir($path); - $fullPath = $this->getFullPath($path); - if ($result && - $this->util->isExcluded($fullPath) === false && - $this->encryptionManager->isEnabled() - ) { - $this->keyStorage->deleteAllFileKeys($fullPath); - } - - return $result; - } - - /** - * check if a file can be read - * - * @param string $path - * @return bool - */ - public function isReadable($path) { - - $isReadable = true; - - $metaData = $this->getMetaData($path); - if ( - !$this->is_dir($path) && - isset($metaData['encrypted']) && - $metaData['encrypted'] === true - ) { - $fullPath = $this->getFullPath($path); - $module = $this->getEncryptionModule($path); - $isReadable = $module->isReadable($fullPath, $this->uid); - } - - return $this->storage->isReadable($path) && $isReadable; - } - - /** - * see http://php.net/manual/en/function.copy.php - * - * @param string $path1 - * @param string $path2 - * @return bool - */ - public function copy($path1, $path2) { - - $source = $this->getFullPath($path1); - - if ($this->util->isExcluded($source)) { - return $this->storage->copy($path1, $path2); - } - - // need to stream copy file by file in case we copy between a encrypted - // and a unencrypted storage - $this->unlink($path2); - $result = $this->copyFromStorage($this, $path1, $path2); - - return $result; - } - - /** - * see http://php.net/manual/en/function.fopen.php - * - * @param string $path - * @param string $mode - * @return resource|bool - * @throws GenericEncryptionException - * @throws ModuleDoesNotExistsException - */ - public function fopen($path, $mode) { - - // check if the file is stored in the array cache, this means that we - // copy a file over to the versions folder, in this case we don't want to - // decrypt it - if ($this->arrayCache->hasKey('encryption_copy_version_' . $path)) { - $this->arrayCache->remove('encryption_copy_version_' . $path); - return $this->storage->fopen($path, $mode); - } - - $encryptionEnabled = $this->encryptionManager->isEnabled(); - $shouldEncrypt = false; - $encryptionModule = null; - $header = $this->getHeader($path); - $signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false; - $fullPath = $this->getFullPath($path); - $encryptionModuleId = $this->util->getEncryptionModuleId($header); - - if ($this->util->isExcluded($fullPath) === false) { - - $size = $unencryptedSize = 0; - $realFile = $this->util->stripPartialFileExtension($path); - $targetExists = $this->file_exists($realFile) || $this->file_exists($path); - $targetIsEncrypted = false; - if ($targetExists) { - // in case the file exists we require the explicit module as - // specified in the file header - otherwise we need to fail hard to - // prevent data loss on client side - if (!empty($encryptionModuleId)) { - $targetIsEncrypted = true; - $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); - } - - if ($this->file_exists($path)) { - $size = $this->storage->filesize($path); - $unencryptedSize = $this->filesize($path); - } else { - $size = $unencryptedSize = 0; - } - } - - try { - - if ( - $mode === 'w' - || $mode === 'w+' - || $mode === 'wb' - || $mode === 'wb+' - ) { - // don't overwrite encrypted files if encryption is not enabled - if ($targetIsEncrypted && $encryptionEnabled === false) { - throw new GenericEncryptionException('Tried to access encrypted file but encryption is not enabled'); - } - if ($encryptionEnabled) { - // if $encryptionModuleId is empty, the default module will be used - $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); - $shouldEncrypt = $encryptionModule->shouldEncrypt($fullPath); - $signed = true; - } - } else { - $info = $this->getCache()->get($path); - // only get encryption module if we found one in the header - // or if file should be encrypted according to the file cache - if (!empty($encryptionModuleId)) { - $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); - $shouldEncrypt = true; - } else if (empty($encryptionModuleId) && $info['encrypted'] === true) { - // we come from a old installation. No header and/or no module defined - // but the file is encrypted. In this case we need to use the - // OC_DEFAULT_MODULE to read the file - $encryptionModule = $this->encryptionManager->getEncryptionModule('OC_DEFAULT_MODULE'); - $shouldEncrypt = true; - $targetIsEncrypted = true; - } - } - } catch (ModuleDoesNotExistsException $e) { - $this->logger->warning('Encryption module "' . $encryptionModuleId . - '" not found, file will be stored unencrypted (' . $e->getMessage() . ')'); - } - - // encryption disabled on write of new file and write to existing unencrypted file -> don't encrypt - if (!$encryptionEnabled || !$this->mount->getOption('encrypt', true)) { - if (!$targetExists || !$targetIsEncrypted) { - $shouldEncrypt = false; - } - } - - if ($shouldEncrypt === true && $encryptionModule !== null) { - $headerSize = $this->getHeaderSize($path); - $source = $this->storage->fopen($path, $mode); - if (!is_resource($source)) { - return false; - } - $handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header, - $this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode, - $size, $unencryptedSize, $headerSize, $signed); - return $handle; - } - - } - - return $this->storage->fopen($path, $mode); - } - - - /** - * perform some plausibility checks if the the unencrypted size is correct. - * If not, we calculate the correct unencrypted size and return it - * - * @param string $path internal path relative to the storage root - * @param int $unencryptedSize size of the unencrypted file - * - * @return int unencrypted size - */ - protected function verifyUnencryptedSize($path, $unencryptedSize) { - - $size = $this->storage->filesize($path); - $result = $unencryptedSize; - - if ($unencryptedSize < 0 || - ($size > 0 && $unencryptedSize === $size) - ) { - // check if we already calculate the unencrypted size for the - // given path to avoid recursions - if (isset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]) === false) { - $this->fixUnencryptedSizeOf[$this->getFullPath($path)] = true; - try { - $result = $this->fixUnencryptedSize($path, $size, $unencryptedSize); - } catch (\Exception $e) { - $this->logger->error('Couldn\'t re-calculate unencrypted size for '. $path); - $this->logger->logException($e); - } - unset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]); - } - } - - return $result; - } - - /** - * calculate the unencrypted size - * - * @param string $path internal path relative to the storage root - * @param int $size size of the physical file - * @param int $unencryptedSize size of the unencrypted file - * - * @return int calculated unencrypted size - */ - protected function fixUnencryptedSize($path, $size, $unencryptedSize) { - - $headerSize = $this->getHeaderSize($path); - $header = $this->getHeader($path); - $encryptionModule = $this->getEncryptionModule($path); - - $stream = $this->storage->fopen($path, 'r'); - - // if we couldn't open the file we return the old unencrypted size - if (!is_resource($stream)) { - $this->logger->error('Could not open ' . $path . '. Recalculation of unencrypted size aborted.'); - return $unencryptedSize; - } - - $newUnencryptedSize = 0; - $size -= $headerSize; - $blockSize = $this->util->getBlockSize(); - - // if a header exists we skip it - if ($headerSize > 0) { - fread($stream, $headerSize); - } - - // fast path, else the calculation for $lastChunkNr is bogus - if ($size === 0) { - return 0; - } - - $signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false; - $unencryptedBlockSize = $encryptionModule->getUnencryptedBlockSize($signed); - - // calculate last chunk nr - // next highest is end of chunks, one subtracted is last one - // we have to read the last chunk, we can't just calculate it (because of padding etc) - - $lastChunkNr = ceil($size/ $blockSize)-1; - // calculate last chunk position - $lastChunkPos = ($lastChunkNr * $blockSize); - // try to fseek to the last chunk, if it fails we have to read the whole file - if (@fseek($stream, $lastChunkPos, SEEK_CUR) === 0) { - $newUnencryptedSize += $lastChunkNr * $unencryptedBlockSize; - } - - $lastChunkContentEncrypted=''; - $count = $blockSize; - - while ($count > 0) { - $data=fread($stream, $blockSize); - $count=strlen($data); - $lastChunkContentEncrypted .= $data; - if(strlen($lastChunkContentEncrypted) > $blockSize) { - $newUnencryptedSize += $unencryptedBlockSize; - $lastChunkContentEncrypted=substr($lastChunkContentEncrypted, $blockSize); - } - } - - fclose($stream); - - // we have to decrypt the last chunk to get it actual size - $encryptionModule->begin($this->getFullPath($path), $this->uid, 'r', $header, []); - $decryptedLastChunk = $encryptionModule->decrypt($lastChunkContentEncrypted, $lastChunkNr . 'end'); - $decryptedLastChunk .= $encryptionModule->end($this->getFullPath($path), $lastChunkNr . 'end'); - - // calc the real file size with the size of the last chunk - $newUnencryptedSize += strlen($decryptedLastChunk); - - $this->updateUnencryptedSize($this->getFullPath($path), $newUnencryptedSize); - - // write to cache if applicable - $cache = $this->storage->getCache(); - if ($cache) { - $entry = $cache->get($path); - $cache->update($entry['fileid'], ['size' => $newUnencryptedSize]); - } - - return $newUnencryptedSize; - } - - /** - * @param Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @param bool $preserveMtime - * @return bool - */ - public function moveFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = true) { - if ($sourceStorage === $this) { - return $this->rename($sourceInternalPath, $targetInternalPath); - } - - // TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed: - // - call $this->storage->moveFromStorage() instead of $this->copyBetweenStorage - // - copy the file cache update from $this->copyBetweenStorage to this method - // - copy the copyKeys() call from $this->copyBetweenStorage to this method - // - remove $this->copyBetweenStorage - - if (!$sourceStorage->isDeletable($sourceInternalPath)) { - return false; - } - - $result = $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, true); - if ($result) { - if ($sourceStorage->is_dir($sourceInternalPath)) { - $result &= $sourceStorage->rmdir($sourceInternalPath); - } else { - $result &= $sourceStorage->unlink($sourceInternalPath); - } - } - return $result; - } - - - /** - * @param Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @param bool $preserveMtime - * @param bool $isRename - * @return bool - */ - public function copyFromStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false, $isRename = false) { - - // TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed: - // - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage - // - copy the file cache update from $this->copyBetweenStorage to this method - // - copy the copyKeys() call from $this->copyBetweenStorage to this method - // - remove $this->copyBetweenStorage - - return $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename); - } - - /** - * Update the encrypted cache version in the database - * - * @param Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @param bool $isRename - */ - private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename) { - $isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0; - $cacheInformation = [ - 'encrypted' => (bool)$isEncrypted, - ]; - if($isEncrypted === 1) { - $encryptedVersion = $sourceStorage->getCache()->get($sourceInternalPath)['encryptedVersion']; - - // In case of a move operation from an unencrypted to an encrypted - // storage the old encrypted version would stay with "0" while the - // correct value would be "1". Thus we manually set the value to "1" - // for those cases. - // See also https://github.com/owncloud/core/issues/23078 - if($encryptedVersion === 0) { - $encryptedVersion = 1; - } - - $cacheInformation['encryptedVersion'] = $encryptedVersion; - } - - // in case of a rename we need to manipulate the source cache because - // this information will be kept for the new target - if ($isRename) { - $sourceStorage->getCache()->put($sourceInternalPath, $cacheInformation); - } else { - $this->getCache()->put($targetInternalPath, $cacheInformation); - } - } - - /** - * copy file between two storages - * - * @param Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @param bool $preserveMtime - * @param bool $isRename - * @return bool - * @throws \Exception - */ - private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename) { - - // for versions we have nothing to do, because versions should always use the - // key from the original file. Just create a 1:1 copy and done - if ($this->isVersion($targetInternalPath) || - $this->isVersion($sourceInternalPath)) { - // remember that we try to create a version so that we can detect it during - // fopen($sourceInternalPath) and by-pass the encryption in order to - // create a 1:1 copy of the file - $this->arrayCache->set('encryption_copy_version_' . $sourceInternalPath, true); - $result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - $this->arrayCache->remove('encryption_copy_version_' . $sourceInternalPath); - if ($result) { - $info = $this->getCache('', $sourceStorage)->get($sourceInternalPath); - // make sure that we update the unencrypted size for the version - if (isset($info['encrypted']) && $info['encrypted'] === true) { - $this->updateUnencryptedSize( - $this->getFullPath($targetInternalPath), - $info['size'] - ); - } - $this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename); - } - return $result; - } - - // first copy the keys that we reuse the existing file key on the target location - // and don't create a new one which would break versions for example. - $mount = $this->mountManager->findByStorageId($sourceStorage->getId()); - if (count($mount) === 1) { - $mountPoint = $mount[0]->getMountPoint(); - $source = $mountPoint . '/' . $sourceInternalPath; - $target = $this->getFullPath($targetInternalPath); - $this->copyKeys($source, $target); - } else { - $this->logger->error('Could not find mount point, can\'t keep encryption keys'); - } - - if ($sourceStorage->is_dir($sourceInternalPath)) { - $dh = $sourceStorage->opendir($sourceInternalPath); - $result = $this->mkdir($targetInternalPath); - if (is_resource($dh)) { - while ($result and ($file = readdir($dh)) !== false) { - if (!Filesystem::isIgnoredDir($file)) { - $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file, false, $isRename); - } - } - } - } else { - try { - $source = $sourceStorage->fopen($sourceInternalPath, 'r'); - $target = $this->fopen($targetInternalPath, 'w'); - list(, $result) = \OC_Helper::streamCopy($source, $target); - fclose($source); - fclose($target); - } catch (\Exception $e) { - fclose($source); - fclose($target); - throw $e; - } - if($result) { - if ($preserveMtime) { - $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath)); - } - $this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename); - } else { - // delete partially written target file - $this->unlink($targetInternalPath); - // delete cache entry that was created by fopen - $this->getCache()->remove($targetInternalPath); - } - } - return (bool)$result; - - } - - /** - * 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) { - if ($this->encryptionManager->isEnabled()) { - $cachedFile = $this->getCachedFile($path); - if (is_string($cachedFile)) { - return $cachedFile; - } - } - return $this->storage->getLocalFile($path); - } - - /** - * Returns the wrapped storage's value for isLocal() - * - * @return bool wrapped storage's isLocal() value - */ - public function isLocal() { - if ($this->encryptionManager->isEnabled()) { - return false; - } - return $this->storage->isLocal(); - } - - /** - * 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) { - $stat = $this->storage->stat($path); - $fileSize = $this->filesize($path); - $stat['size'] = $fileSize; - $stat[7] = $fileSize; - return $stat; - } - - /** - * 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) { - $fh = $this->fopen($path, 'rb'); - $ctx = hash_init($type); - hash_update_stream($ctx, $fh); - fclose($fh); - return hash_final($ctx, $raw); - } - - /** - * return full path, including mount point - * - * @param string $path relative to mount point - * @return string full path including mount point - */ - protected function getFullPath($path) { - return Filesystem::normalizePath($this->mountPoint . '/' . $path); - } - - /** - * read first block of encrypted file, typically this will contain the - * encryption header - * - * @param string $path - * @return string - */ - protected function readFirstBlock($path) { - $firstBlock = ''; - if ($this->storage->file_exists($path)) { - $handle = $this->storage->fopen($path, 'r'); - $firstBlock = fread($handle, $this->util->getHeaderSize()); - fclose($handle); - } - return $firstBlock; - } - - /** - * return header size of given file - * - * @param string $path - * @return int - */ - protected function getHeaderSize($path) { - $headerSize = 0; - $realFile = $this->util->stripPartialFileExtension($path); - if ($this->storage->file_exists($realFile)) { - $path = $realFile; - } - $firstBlock = $this->readFirstBlock($path); - - if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) { - $headerSize = $this->util->getHeaderSize(); - } - - return $headerSize; - } - - /** - * parse raw header to array - * - * @param string $rawHeader - * @return array - */ - protected function parseRawHeader($rawHeader) { - $result = array(); - if (substr($rawHeader, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) { - $header = $rawHeader; - $endAt = strpos($header, Util::HEADER_END); - if ($endAt !== false) { - $header = substr($header, 0, $endAt + strlen(Util::HEADER_END)); - - // +1 to not start with an ':' which would result in empty element at the beginning - $exploded = explode(':', substr($header, strlen(Util::HEADER_START)+1)); - - $element = array_shift($exploded); - while ($element !== Util::HEADER_END) { - $result[$element] = array_shift($exploded); - $element = array_shift($exploded); - } - } - } - - return $result; - } - - /** - * read header from file - * - * @param string $path - * @return array - */ - protected function getHeader($path) { - $realFile = $this->util->stripPartialFileExtension($path); - if ($this->storage->file_exists($realFile)) { - $path = $realFile; - } - - $firstBlock = $this->readFirstBlock($path); - $result = $this->parseRawHeader($firstBlock); - - // if the header doesn't contain a encryption module we check if it is a - // legacy file. If true, we add the default encryption module - if (!isset($result[Util::HEADER_ENCRYPTION_MODULE_KEY])) { - if (!empty($result)) { - $result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE'; - } else { - // if the header was empty we have to check first if it is a encrypted file at all - $info = $this->getCache()->get($path); - if (isset($info['encrypted']) && $info['encrypted'] === true) { - $result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE'; - } - } - } - - return $result; - } - - /** - * read encryption module needed to read/write the file located at $path - * - * @param string $path - * @return null|\OCP\Encryption\IEncryptionModule - * @throws ModuleDoesNotExistsException - * @throws \Exception - */ - protected function getEncryptionModule($path) { - $encryptionModule = null; - $header = $this->getHeader($path); - $encryptionModuleId = $this->util->getEncryptionModuleId($header); - if (!empty($encryptionModuleId)) { - try { - $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); - } catch (ModuleDoesNotExistsException $e) { - $this->logger->critical('Encryption module defined in "' . $path . '" not loaded!'); - throw $e; - } - } - return $encryptionModule; - } - - /** - * @param string $path - * @param int $unencryptedSize - */ - public function updateUnencryptedSize($path, $unencryptedSize) { - $this->unencryptedSize[$path] = $unencryptedSize; - } - - /** - * copy keys to new location - * - * @param string $source path relative to data/ - * @param string $target path relative to data/ - * @return bool - */ - protected function copyKeys($source, $target) { - if (!$this->util->isExcluded($source)) { - return $this->keyStorage->copyKeys($source, $target); - } - - return false; - } - - /** - * check if path points to a files version - * - * @param $path - * @return bool - */ - protected function isVersion($path) { - $normalized = Filesystem::normalizePath($path); - return substr($normalized, 0, strlen('/files_versions/')) === '/files_versions/'; - } - -} diff --git a/lib/private/files/storage/wrapper/jail.php b/lib/private/files/storage/wrapper/jail.php deleted file mode 100644 index e8063f670c5..00000000000 --- a/lib/private/files/storage/wrapper/jail.php +++ /dev/null @@ -1,489 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage\Wrapper; - -use OC\Files\Cache\Wrapper\CacheJail; -use OCP\Lock\ILockingProvider; - -/** - * 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']; - } - - public 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)); - } - - /** - * 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)); - } - - /** - * @param string $path - * @return array - */ - public function getMetaData($path) { - return $this->storage->getMetaData($this->getSourcePath($path)); - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @throws \OCP\Lock\LockedException - */ - public function acquireLock($path, $type, ILockingProvider $provider) { - $this->storage->acquireLock($this->getSourcePath($path), $type, $provider); - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - */ - public function releaseLock($path, $type, ILockingProvider $provider) { - $this->storage->releaseLock($this->getSourcePath($path), $type, $provider); - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - */ - public function changeLock($path, $type, ILockingProvider $provider) { - $this->storage->changeLock($this->getSourcePath($path), $type, $provider); - } - - /** - * Resolve the path for the source of the share - * - * @param string $path - * @return array - */ - public function resolvePath($path) { - return [$this->storage, $this->getSourcePath($path)]; - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - if ($sourceStorage === $this) { - return $this->copy($sourceInternalPath, $targetInternalPath); - } - return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $this->getSourcePath($targetInternalPath)); - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - if ($sourceStorage === $this) { - return $this->rename($sourceInternalPath, $targetInternalPath); - } - return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $this->getSourcePath($targetInternalPath)); - } -} diff --git a/lib/private/files/storage/wrapper/permissionsmask.php b/lib/private/files/storage/wrapper/permissionsmask.php deleted file mode 100644 index 01dd78d418c..00000000000 --- a/lib/private/files/storage/wrapper/permissionsmask.php +++ /dev/null @@ -1,131 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -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 can't 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 isSharable($path) { - return $this->checkMask(Constants::PERMISSION_SHARE) and parent::isSharable($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); - } -} diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php deleted file mode 100644 index 500677b092e..00000000000 --- a/lib/private/files/storage/wrapper/quota.php +++ /dev/null @@ -1,200 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage\Wrapper; - -use OCP\Files\Cache\ICacheEntry; - -class Quota extends Wrapper { - - /** - * @var int $quota - */ - protected $quota; - - /** - * @var string $sizeRoot - */ - protected $sizeRoot; - - /** - * @param array $parameters - */ - public function __construct($parameters) { - $this->storage = $parameters['storage']; - $this->quota = $parameters['quota']; - $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : ''; - } - - /** - * @return int quota value - */ - public function getQuota() { - return $this->quota; - } - - /** - * @param string $path - * @param \OC\Files\Storage\Storage $storage - */ - protected function getSize($path, $storage = null) { - if (is_null($storage)) { - $cache = $this->getCache(); - } else { - $cache = $storage->getCache(); - } - $data = $cache->get($path); - if ($data instanceof ICacheEntry and isset($data['size'])) { - return $data['size']; - } else { - return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; - } - } - - /** - * Get free space as limited by the quota - * - * @param string $path - * @return int - */ - public function free_space($path) { - if ($this->quota < 0) { - return $this->storage->free_space($path); - } else { - $used = $this->getSize($this->sizeRoot); - if ($used < 0) { - return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; - } else { - $free = $this->storage->free_space($path); - $quotaFree = max($this->quota - $used, 0); - // if free space is known - if ($free >= 0) { - $free = min($free, $quotaFree); - } else { - $free = $quotaFree; - } - return $free; - } - } - } - - /** - * 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) { - $free = $this->free_space(''); - if ($free < 0 or strlen($data) < $free) { - return $this->storage->file_put_contents($path, $data); - } else { - return false; - } - } - - /** - * see http://php.net/manual/en/function.copy.php - * - * @param string $source - * @param string $target - * @return bool - */ - public function copy($source, $target) { - $free = $this->free_space(''); - if ($free < 0 or $this->getSize($source) < $free) { - return $this->storage->copy($source, $target); - } else { - return false; - } - } - - /** - * see http://php.net/manual/en/function.fopen.php - * - * @param string $path - * @param string $mode - * @return resource - */ - public function fopen($path, $mode) { - $source = $this->storage->fopen($path, $mode); - - // don't apply quota for part files - if (!$this->isPartFile($path)) { - $free = $this->free_space(''); - if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') { - // only apply quota for files, not metadata, trash or others - if (strpos(ltrim($path, '/'), 'files/') === 0) { - return \OC\Files\Stream\Quota::wrap($source, $free); - } - } - } - return $source; - } - - /** - * Checks whether the given path is a part file - * - * @param string $path Path that may identify a .part file - * @return string File path without .part extension - * @note this is needed for reusing keys - */ - private function isPartFile($path) { - $extension = pathinfo($path, PATHINFO_EXTENSION); - - return ($extension === 'part'); - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - $free = $this->free_space(''); - if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) { - return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } else { - return false; - } - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - $free = $this->free_space(''); - if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) { - return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } else { - return false; - } - } -} diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php deleted file mode 100644 index 21d7db1099b..00000000000 --- a/lib/private/files/storage/wrapper/wrapper.php +++ /dev/null @@ -1,608 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Storage\Wrapper; - -use OCP\Files\InvalidPathException; -use OCP\Files\Storage\ILockingStorage; -use OCP\Lock\ILockingProvider; - -class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage { - /** - * @var \OC\Files\Storage\Storage $storage - */ - protected $storage; - - public $cache; - public $scanner; - public $watcher; - public $propagator; - public $updater; - - /** - * @param array $parameters - */ - public function __construct($parameters) { - $this->storage = $parameters['storage']; - } - - /** - * @return \OC\Files\Storage\Storage - */ - public function getWrapperStorage() { - return $this->storage; - } - - /** - * 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() { - return $this->storage->getId(); - } - - /** - * see http://php.net/manual/en/function.mkdir.php - * - * @param string $path - * @return bool - */ - public function mkdir($path) { - return $this->storage->mkdir($path); - } - - /** - * see http://php.net/manual/en/function.rmdir.php - * - * @param string $path - * @return bool - */ - public function rmdir($path) { - return $this->storage->rmdir($path); - } - - /** - * see http://php.net/manual/en/function.opendir.php - * - * @param string $path - * @return resource - */ - public function opendir($path) { - return $this->storage->opendir($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($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($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($path); - } - - /** - * see http://php.net/manual/en/function.filetype.php - * - * @param string $path - * @return bool - */ - public function filetype($path) { - return $this->storage->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) { - return $this->storage->filesize($path); - } - - /** - * check if a file can be created in $path - * - * @param string $path - * @return bool - */ - public function isCreatable($path) { - return $this->storage->isCreatable($path); - } - - /** - * check if a file can be read - * - * @param string $path - * @return bool - */ - public function isReadable($path) { - return $this->storage->isReadable($path); - } - - /** - * check if a file can be written to - * - * @param string $path - * @return bool - */ - public function isUpdatable($path) { - return $this->storage->isUpdatable($path); - } - - /** - * check if a file can be deleted - * - * @param string $path - * @return bool - */ - public function isDeletable($path) { - return $this->storage->isDeletable($path); - } - - /** - * check if a file can be shared - * - * @param string $path - * @return bool - */ - public function isSharable($path) { - return $this->storage->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) { - return $this->storage->getPermissions($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($path); - } - - /** - * see http://php.net/manual/en/function.filemtime.php - * - * @param string $path - * @return int - */ - public function filemtime($path) { - return $this->storage->filemtime($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($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($path, $data); - } - - /** - * see http://php.net/manual/en/function.unlink.php - * - * @param string $path - * @return bool - */ - public function unlink($path) { - return $this->storage->unlink($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($path1, $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($path1, $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($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($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, $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($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($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($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($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; - } - return $this->storage->getCache($path, $storage); - } - - /** - * get a scanner instance for the storage - * - * @param string $path - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner - * @return \OC\Files\Cache\Scanner - */ - public function getScanner($path = '', $storage = null) { - if (!$storage) { - $storage = $this; - } - return $this->storage->getScanner($path, $storage); - } - - - /** - * 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($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($path, $storage); - } - - public function getPropagator($storage = null) { - if (!$storage) { - $storage = $this; - } - return $this->storage->getPropagator($storage); - } - - public function getUpdater($storage = null) { - if (!$storage) { - $storage = $this; - } - return $this->storage->getUpdater($storage); - } - - /** - * @return \OC\Files\Cache\Storage - */ - public function getStorageCache() { - return $this->storage->getStorageCache(); - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path) { - return $this->storage->getETag($path); - } - - /** - * Returns true - * - * @return true - */ - public function test() { - return $this->storage->test(); - } - - /** - * Returns the wrapped storage's value for isLocal() - * - * @return bool wrapped storage's isLocal() value - */ - public function isLocal() { - return $this->storage->isLocal(); - } - - /** - * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class - * - * @param string $class - * @return bool - */ - public function instanceOfStorage($class) { - return is_a($this, $class) or $this->storage->instanceOfStorage($class); - } - - /** - * Pass any methods custom to specific storage implementations to the wrapped storage - * - * @param string $method - * @param array $args - * @return mixed - */ - public function __call($method, $args) { - return call_user_func_array(array($this->storage, $method), $args); - } - - /** - * A custom storage implementation can return an url for direct download of a give file. - * - * For now the returned array can hold the parameter url - in future more attributes might follow. - * - * @param string $path - * @return array - */ - public function getDirectDownload($path) { - return $this->storage->getDirectDownload($path); - } - - /** - * Get availability of the storage - * - * @return array [ available, last_checked ] - */ - public function getAvailability() { - return $this->storage->getAvailability(); - } - - /** - * Set availability of the storage - * - * @param bool $isAvailable - */ - public function setAvailability($isAvailable) { - $this->storage->setAvailability($isAvailable); - } - - /** - * @param string $path the path of the target folder - * @param string $fileName the name of the file itself - * @return void - * @throws InvalidPathException - */ - public function verifyPath($path, $fileName) { - $this->storage->verifyPath($path, $fileName); - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - if ($sourceStorage === $this) { - return $this->copy($sourceInternalPath, $targetInternalPath); - } - - return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } - - /** - * @param \OCP\Files\Storage $sourceStorage - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @return bool - */ - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - if ($sourceStorage === $this) { - return $this->rename($sourceInternalPath, $targetInternalPath); - } - - return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } - - /** - * @param string $path - * @return array - */ - public function getMetaData($path) { - return $this->storage->getMetaData($path); - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @throws \OCP\Lock\LockedException - */ - public function acquireLock($path, $type, ILockingProvider $provider) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $this->storage->acquireLock($path, $type, $provider); - } - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - */ - public function releaseLock($path, $type, ILockingProvider $provider) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $this->storage->releaseLock($path, $type, $provider); - } - } - - /** - * @param string $path - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - */ - public function changeLock($path, $type, ILockingProvider $provider) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $this->storage->changeLock($path, $type, $provider); - } - } -} diff --git a/lib/private/files/stream/close.php b/lib/private/files/stream/close.php deleted file mode 100644 index 1c9b30705dd..00000000000 --- a/lib/private/files/stream/close.php +++ /dev/null @@ -1,118 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Stream; - -/** - * stream wrapper that provides a callback on stream close - */ -class Close { - private static $callBacks = array(); - private $path = ''; - private $source; - private static $open = array(); - - public function stream_open($path, $mode, $options, &$opened_path) { - $path = substr($path, strlen('close://')); - $this->path = $path; - $this->source = fopen($path, $mode); - if (is_resource($this->source)) { - $this->meta = stream_get_meta_data($this->source); - } - self::$open[] = $path; - return is_resource($this->source); - } - - public function stream_seek($offset, $whence = SEEK_SET) { - return fseek($this->source, $offset, $whence) === 0; - } - - public function stream_tell() { - return ftell($this->source); - } - - public function stream_read($count) { - return fread($this->source, $count); - } - - public function stream_write($data) { - return fwrite($this->source, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch ($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->source); - } - - public function stream_lock($mode) { - flock($this->source, $mode); - } - - public function stream_flush() { - return fflush($this->source); - } - - public function stream_eof() { - return feof($this->source); - } - - public function url_stat($path) { - $path = substr($path, strlen('close://')); - if (file_exists($path)) { - return stat($path); - } else { - return false; - } - } - - public function stream_close() { - fclose($this->source); - if (isset(self::$callBacks[$this->path])) { - call_user_func(self::$callBacks[$this->path], $this->path); - } - } - - public function unlink($path) { - $path = substr($path, strlen('close://')); - return unlink($path); - } - - /** - * @param string $path - */ - public static function registerCallback($path, $callback) { - self::$callBacks[$path] = $callback; - } -} diff --git a/lib/private/files/stream/dir.php b/lib/private/files/stream/dir.php deleted file mode 100644 index 7489ee683a2..00000000000 --- a/lib/private/files/stream/dir.php +++ /dev/null @@ -1,66 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Stream; - -class Dir { - private static $dirs = array(); - private $name; - private $index; - - public function dir_opendir($path, $options) { - $this->name = substr($path, strlen('fakedir://')); - $this->index = 0; - if (!isset(self::$dirs[$this->name])) { - self::$dirs[$this->name] = array(); - } - return true; - } - - public function dir_readdir() { - if ($this->index >= count(self::$dirs[$this->name])) { - return false; - } - $filename = self::$dirs[$this->name][$this->index]; - $this->index++; - return $filename; - } - - public function dir_closedir() { - $this->name = ''; - return true; - } - - public function dir_rewinddir() { - $this->index = 0; - return true; - } - - /** - * @param string $path - * @param string[] $content - */ - public static function register($path, $content) { - self::$dirs[$path] = $content; - } -} diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php deleted file mode 100644 index 772c9769bf7..00000000000 --- a/lib/private/files/stream/encryption.php +++ /dev/null @@ -1,500 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author jknockaert <jasper@knockaert.nl> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Stream; - -use Icewind\Streams\Wrapper; -use OC\Encryption\Exceptions\EncryptionHeaderKeyExistsException; - -class Encryption extends Wrapper { - - /** @var \OC\Encryption\Util */ - protected $util; - - /** @var \OC\Encryption\File */ - protected $file; - - /** @var \OCP\Encryption\IEncryptionModule */ - protected $encryptionModule; - - /** @var \OC\Files\Storage\Storage */ - protected $storage; - - /** @var \OC\Files\Storage\Wrapper\Encryption */ - protected $encryptionStorage; - - /** @var string */ - protected $internalPath; - - /** @var string */ - protected $cache; - - /** @var integer */ - protected $size; - - /** @var integer */ - protected $position; - - /** @var integer */ - protected $unencryptedSize; - - /** @var integer */ - protected $headerSize; - - /** @var integer */ - protected $unencryptedBlockSize; - - /** @var array */ - protected $header; - - /** @var string */ - protected $fullPath; - - /** @var bool */ - protected $signed; - - /** - * header data returned by the encryption module, will be written to the file - * in case of a write operation - * - * @var array - */ - protected $newHeader; - - /** - * user who perform the read/write operation null for public access - * - * @var string - */ - protected $uid; - - /** @var bool */ - protected $readOnly; - - /** @var bool */ - protected $writeFlag; - - /** @var array */ - protected $expectedContextProperties; - - public function __construct() { - $this->expectedContextProperties = array( - 'source', - 'storage', - 'internalPath', - 'fullPath', - 'encryptionModule', - 'header', - 'uid', - 'file', - 'util', - 'size', - 'unencryptedSize', - 'encryptionStorage', - 'headerSize', - 'signed' - ); - } - - - /** - * Wraps a stream with the provided callbacks - * - * @param resource $source - * @param string $internalPath relative to mount point - * @param string $fullPath relative to data/ - * @param array $header - * @param string $uid - * @param \OCP\Encryption\IEncryptionModule $encryptionModule - * @param \OC\Files\Storage\Storage $storage - * @param \OC\Files\Storage\Wrapper\Encryption $encStorage - * @param \OC\Encryption\Util $util - * @param \OC\Encryption\File $file - * @param string $mode - * @param int $size - * @param int $unencryptedSize - * @param int $headerSize - * @param bool $signed - * @param string $wrapper stream wrapper class - * @return resource - * - * @throws \BadMethodCallException - */ - public static function wrap($source, $internalPath, $fullPath, array $header, - $uid, - \OCP\Encryption\IEncryptionModule $encryptionModule, - \OC\Files\Storage\Storage $storage, - \OC\Files\Storage\Wrapper\Encryption $encStorage, - \OC\Encryption\Util $util, - \OC\Encryption\File $file, - $mode, - $size, - $unencryptedSize, - $headerSize, - $signed, - $wrapper = 'OC\Files\Stream\Encryption') { - - $context = stream_context_create(array( - 'ocencryption' => array( - 'source' => $source, - 'storage' => $storage, - 'internalPath' => $internalPath, - 'fullPath' => $fullPath, - 'encryptionModule' => $encryptionModule, - 'header' => $header, - 'uid' => $uid, - 'util' => $util, - 'file' => $file, - 'size' => $size, - 'unencryptedSize' => $unencryptedSize, - 'encryptionStorage' => $encStorage, - 'headerSize' => $headerSize, - 'signed' => $signed - ) - )); - - return self::wrapSource($source, $context, 'ocencryption', $wrapper, $mode); - } - - /** - * add stream wrapper - * - * @param resource $source - * @param string $mode - * @param resource $context - * @param string $protocol - * @param string $class - * @return resource - * @throws \BadMethodCallException - */ - protected static function wrapSource($source, $context, $protocol, $class, $mode = 'r+') { - try { - stream_wrapper_register($protocol, $class); - if (@rewinddir($source) === false) { - $wrapped = fopen($protocol . '://', $mode, false, $context); - } else { - $wrapped = opendir($protocol . '://', $context); - } - } catch (\BadMethodCallException $e) { - stream_wrapper_unregister($protocol); - throw $e; - } - stream_wrapper_unregister($protocol); - return $wrapped; - } - - /** - * Load the source from the stream context and return the context options - * - * @param string $name - * @return array - * @throws \BadMethodCallException - */ - protected function loadContext($name) { - $context = parent::loadContext($name); - - foreach ($this->expectedContextProperties as $property) { - if (array_key_exists($property, $context)) { - $this->{$property} = $context[$property]; - } else { - throw new \BadMethodCallException('Invalid context, "' . $property . '" options not set'); - } - } - return $context; - - } - - public function stream_open($path, $mode, $options, &$opened_path) { - $this->loadContext('ocencryption'); - - $this->position = 0; - $this->cache = ''; - $this->writeFlag = false; - $this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize($this->signed); - - if ( - $mode === 'w' - || $mode === 'w+' - || $mode === 'wb' - || $mode === 'wb+' - || $mode === 'r+' - || $mode === 'rb+' - ) { - $this->readOnly = false; - } else { - $this->readOnly = true; - } - - $sharePath = $this->fullPath; - if (!$this->storage->file_exists($this->internalPath)) { - $sharePath = dirname($sharePath); - } - - $accessList = $this->file->getAccessList($sharePath); - $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $mode, $this->header, $accessList); - - if ( - $mode === 'w' - || $mode === 'w+' - || $mode === 'wb' - || $mode === 'wb+' - ) { - // We're writing a new file so start write counter with 0 bytes - $this->unencryptedSize = 0; - $this->writeHeader(); - $this->headerSize = $this->util->getHeaderSize(); - $this->size = $this->headerSize; - } else { - $this->skipHeader(); - } - - return true; - - } - - public function stream_eof() { - return $this->position >= $this->unencryptedSize; - } - - public function stream_read($count) { - - $result = ''; - - $count = min($count, $this->unencryptedSize - $this->position); - while ($count > 0) { - $remainingLength = $count; - // update the cache of the current block - $this->readCache(); - // determine the relative position in the current block - $blockPosition = ($this->position % $this->unencryptedBlockSize); - // if entire read inside current block then only position needs to be updated - if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) { - $result .= substr($this->cache, $blockPosition, $remainingLength); - $this->position += $remainingLength; - $count = 0; - // otherwise remainder of current block is fetched, the block is flushed and the position updated - } else { - $result .= substr($this->cache, $blockPosition); - $this->flush(); - $this->position += ($this->unencryptedBlockSize - $blockPosition); - $count -= ($this->unencryptedBlockSize - $blockPosition); - } - } - return $result; - - } - - public function stream_write($data) { - - $length = 0; - // loop over $data to fit it in 6126 sized unencrypted blocks - while (isset($data[0])) { - $remainingLength = strlen($data); - - // set the cache to the current 6126 block - $this->readCache(); - - // for seekable streams the pointer is moved back to the beginning of the encrypted block - // flush will start writing there when the position moves to another block - $positionInFile = (int)floor($this->position / $this->unencryptedBlockSize) * - $this->util->getBlockSize() + $this->headerSize; - $resultFseek = $this->parentStreamSeek($positionInFile); - - // only allow writes on seekable streams, or at the end of the encrypted stream - if (!($this->readOnly) && ($resultFseek || $positionInFile === $this->size)) { - - // switch the writeFlag so flush() will write the block - $this->writeFlag = true; - - // determine the relative position in the current block - $blockPosition = ($this->position % $this->unencryptedBlockSize); - // check if $data fits in current block - // if so, overwrite existing data (if any) - // update position and liberate $data - if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) { - $this->cache = substr($this->cache, 0, $blockPosition) - . $data . substr($this->cache, $blockPosition + $remainingLength); - $this->position += $remainingLength; - $length += $remainingLength; - $data = ''; - // if $data doesn't fit the current block, the fill the current block and reiterate - // after the block is filled, it is flushed and $data is updatedxxx - } else { - $this->cache = substr($this->cache, 0, $blockPosition) . - substr($data, 0, $this->unencryptedBlockSize - $blockPosition); - $this->flush(); - $this->position += ($this->unencryptedBlockSize - $blockPosition); - $length += ($this->unencryptedBlockSize - $blockPosition); - $data = substr($data, $this->unencryptedBlockSize - $blockPosition); - } - } else { - $data = ''; - } - $this->unencryptedSize = max($this->unencryptedSize, $this->position); - } - return $length; - } - - public function stream_tell() { - return $this->position; - } - - public function stream_seek($offset, $whence = SEEK_SET) { - - $return = false; - - switch ($whence) { - case SEEK_SET: - $newPosition = $offset; - break; - case SEEK_CUR: - $newPosition = $this->position + $offset; - break; - case SEEK_END: - $newPosition = $this->unencryptedSize + $offset; - break; - default: - return $return; - } - - if ($newPosition > $this->unencryptedSize || $newPosition < 0) { - return $return; - } - - $newFilePosition = floor($newPosition / $this->unencryptedBlockSize) - * $this->util->getBlockSize() + $this->headerSize; - - $oldFilePosition = parent::stream_tell(); - if ($this->parentStreamSeek($newFilePosition)) { - $this->parentStreamSeek($oldFilePosition); - $this->flush(); - $this->parentStreamSeek($newFilePosition); - $this->position = $newPosition; - $return = true; - } - return $return; - - } - - public function stream_close() { - $this->flush('end'); - $position = (int)floor($this->position/$this->unencryptedBlockSize); - $remainingData = $this->encryptionModule->end($this->fullPath, $position . 'end'); - if ($this->readOnly === false) { - if(!empty($remainingData)) { - parent::stream_write($remainingData); - } - $this->encryptionStorage->updateUnencryptedSize($this->fullPath, $this->unencryptedSize); - } - return parent::stream_close(); - } - - /** - * write block to file - * @param string $positionPrefix - */ - protected function flush($positionPrefix = '') { - // write to disk only when writeFlag was set to 1 - if ($this->writeFlag) { - // Disable the file proxies so that encryption is not - // automatically attempted when the file is written to disk - - // we are handling that separately here and we don't want to - // get into an infinite loop - $position = (int)floor($this->position/$this->unencryptedBlockSize); - $encrypted = $this->encryptionModule->encrypt($this->cache, $position . $positionPrefix); - $bytesWritten = parent::stream_write($encrypted); - $this->writeFlag = false; - // Check whether the write concerns the last block - // If so then update the encrypted filesize - // Note that the unencrypted pointer and filesize are NOT yet updated when flush() is called - // We recalculate the encrypted filesize as we do not know the context of calling flush() - $completeBlocksInFile=(int)floor($this->unencryptedSize/$this->unencryptedBlockSize); - if ($completeBlocksInFile === (int)floor($this->position/$this->unencryptedBlockSize)) { - $this->size = $this->util->getBlockSize() * $completeBlocksInFile; - $this->size += $bytesWritten; - $this->size += $this->headerSize; - } - } - // always empty the cache (otherwise readCache() will not fill it with the new block) - $this->cache = ''; - } - - /** - * read block to file - */ - protected function readCache() { - // cache should always be empty string when this function is called - // don't try to fill the cache when trying to write at the end of the unencrypted file when it coincides with new block - if ($this->cache === '' && !($this->position === $this->unencryptedSize && ($this->position % $this->unencryptedBlockSize) === 0)) { - // Get the data from the file handle - $data = parent::stream_read($this->util->getBlockSize()); - $position = (int)floor($this->position/$this->unencryptedBlockSize); - $numberOfChunks = (int)($this->unencryptedSize / $this->unencryptedBlockSize); - if($numberOfChunks === $position) { - $position .= 'end'; - } - $this->cache = $this->encryptionModule->decrypt($data, $position); - } - } - - /** - * write header at beginning of encrypted file - * - * @return integer - * @throws EncryptionHeaderKeyExistsException if header key is already in use - */ - protected function writeHeader() { - $header = $this->util->createHeader($this->newHeader, $this->encryptionModule); - return parent::stream_write($header); - } - - /** - * read first block to skip the header - */ - protected function skipHeader() { - parent::stream_read($this->headerSize); - } - - /** - * call stream_seek() from parent class - * - * @param integer $position - * @return bool - */ - protected function parentStreamSeek($position) { - return parent::stream_seek($position); - } - - /** - * @param string $path - * @param array $options - * @return bool - */ - public function dir_opendir($path, $options) { - return false; - } - -} diff --git a/lib/private/files/stream/oc.php b/lib/private/files/stream/oc.php deleted file mode 100644 index 8439770e8fa..00000000000 --- a/lib/private/files/stream/oc.php +++ /dev/null @@ -1,153 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Stream; - -/** - * a stream wrappers for ownCloud's virtual filesystem - */ -class OC { - /** - * @var \OC\Files\View - */ - static private $rootView; - - private $path; - - /** - * @var resource - */ - private $dirSource; - - /** - * @var resource - */ - private $fileSource; - private $meta; - - private function setup(){ - if (!self::$rootView) { - self::$rootView = new \OC\Files\View(''); - } - } - - public function stream_open($path, $mode, $options, &$opened_path) { - $this->setup(); - $path = substr($path, strlen('oc://')); - $this->path = $path; - $this->fileSource = self::$rootView->fopen($path, $mode); - if (is_resource($this->fileSource)) { - $this->meta = stream_get_meta_data($this->fileSource); - } - return is_resource($this->fileSource); - } - - public function stream_seek($offset, $whence = SEEK_SET) { - return fseek($this->fileSource, $offset, $whence) === 0; - } - - public function stream_tell() { - return ftell($this->fileSource); - } - - public function stream_read($count) { - return fread($this->fileSource, $count); - } - - public function stream_write($data) { - return fwrite($this->fileSource, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch ($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->fileSource, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->fileSource, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->fileSource, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->fileSource); - } - - public function stream_lock($mode) { - flock($this->fileSource, $mode); - } - - public function stream_flush() { - return fflush($this->fileSource); - } - - public function stream_eof() { - return feof($this->fileSource); - } - - public function url_stat($path) { - $this->setup(); - $path = substr($path, strlen('oc://')); - if (self::$rootView->file_exists($path)) { - return self::$rootView->stat($path); - } else { - return false; - } - } - - public function stream_close() { - fclose($this->fileSource); - } - - public function unlink($path) { - $this->setup(); - $path = substr($path, strlen('oc://')); - return self::$rootView->unlink($path); - } - - public function dir_opendir($path, $options) { - $this->setup(); - $path = substr($path, strlen('oc://')); - $this->path = $path; - $this->dirSource = self::$rootView->opendir($path); - if (is_resource($this->dirSource)) { - $this->meta = stream_get_meta_data($this->dirSource); - } - return is_resource($this->dirSource); - } - - public function dir_readdir() { - return readdir($this->dirSource); - } - - public function dir_closedir() { - closedir($this->dirSource); - } - - public function dir_rewinddir() { - rewinddir($this->dirSource); - } -} diff --git a/lib/private/files/stream/quota.php b/lib/private/files/stream/quota.php deleted file mode 100644 index 8d27575c568..00000000000 --- a/lib/private/files/stream/quota.php +++ /dev/null @@ -1,156 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Stream; - -/** - * stream wrapper limits the amount of data that can be written to a stream - * - * usage: void \OC\Files\Stream\Quota::register($id, $stream, $limit) - * or: resource \OC\Files\Stream\Quota::wrap($stream, $limit) - */ -class Quota { - private static $streams = array(); - - /** - * @var resource $source - */ - private $source; - - /** - * @var int $limit - */ - private $limit; - - /** - * @param string $id - * @param resource $stream - * @param int $limit - */ - public static function register($id, $stream, $limit) { - self::$streams[$id] = array($stream, $limit); - } - - /** - * remove all registered streams - */ - public static function clear() { - self::$streams = array(); - } - - /** - * @param resource $stream - * @param int $limit - * @return resource - */ - static public function wrap($stream, $limit) { - $id = uniqid(); - self::register($id, $stream, $limit); - $meta = stream_get_meta_data($stream); - return fopen('quota://' . $id, $meta['mode']); - } - - public function stream_open($path, $mode, $options, &$opened_path) { - $id = substr($path, strlen('quota://')); - if (isset(self::$streams[$id])) { - list($this->source, $this->limit) = self::$streams[$id]; - return true; - } else { - return false; - } - } - - public function stream_seek($offset, $whence = SEEK_SET) { - if ($whence === SEEK_END){ - // go to the end to find out last position's offset - $oldOffset = $this->stream_tell(); - if (fseek($this->source, 0, $whence) !== 0){ - return false; - } - $whence = SEEK_SET; - $offset = $this->stream_tell() + $offset; - $this->limit += $oldOffset - $offset; - } - else if ($whence === SEEK_SET) { - $this->limit += $this->stream_tell() - $offset; - } else { - $this->limit -= $offset; - } - // this wrapper needs to return "true" for success. - // the fseek call itself returns 0 on succeess - return fseek($this->source, $offset, $whence) === 0; - } - - public function stream_tell() { - return ftell($this->source); - } - - public function stream_read($count) { - $this->limit -= $count; - return fread($this->source, $count); - } - - public function stream_write($data) { - $size = strlen($data); - if ($size > $this->limit) { - $data = substr($data, 0, $this->limit); - $size = $this->limit; - } - $this->limit -= $size; - return fwrite($this->source, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch ($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->source); - } - - public function stream_lock($mode) { - return flock($this->source, $mode); - } - - public function stream_flush() { - return fflush($this->source); - } - - public function stream_eof() { - return feof($this->source); - } - - public function stream_close() { - fclose($this->source); - } -} diff --git a/lib/private/files/stream/staticstream.php b/lib/private/files/stream/staticstream.php deleted file mode 100644 index 7aacf7a9fe4..00000000000 --- a/lib/private/files/stream/staticstream.php +++ /dev/null @@ -1,170 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Stream; - -class StaticStream { - const MODE_FILE = 0100000; - - public $context; - protected static $data = array(); - - protected $path = ''; - protected $pointer = 0; - protected $writable = false; - - public function stream_close() { - } - - public function stream_eof() { - return $this->pointer >= strlen(self::$data[$this->path]); - } - - public function stream_flush() { - } - - public static function clear() { - self::$data = array(); - } - - public function stream_open($path, $mode, $options, &$opened_path) { - switch ($mode[0]) { - case 'r': - if (!isset(self::$data[$path])) return false; - $this->path = $path; - $this->writable = isset($mode[1]) && $mode[1] == '+'; - break; - case 'w': - self::$data[$path] = ''; - $this->path = $path; - $this->writable = true; - break; - case 'a': - if (!isset(self::$data[$path])) self::$data[$path] = ''; - $this->path = $path; - $this->writable = true; - $this->pointer = strlen(self::$data[$path]); - break; - case 'x': - if (isset(self::$data[$path])) return false; - $this->path = $path; - $this->writable = true; - break; - case 'c': - if (!isset(self::$data[$path])) self::$data[$path] = ''; - $this->path = $path; - $this->writable = true; - break; - default: - return false; - } - $opened_path = $this->path; - return true; - } - - public function stream_read($count) { - $bytes = min(strlen(self::$data[$this->path]) - $this->pointer, $count); - $data = substr(self::$data[$this->path], $this->pointer, $bytes); - $this->pointer += $bytes; - return $data; - } - - public function stream_seek($offset, $whence = SEEK_SET) { - $len = strlen(self::$data[$this->path]); - switch ($whence) { - case SEEK_SET: - if ($offset <= $len) { - $this->pointer = $offset; - return true; - } - break; - case SEEK_CUR: - if ($this->pointer + $offset <= $len) { - $this->pointer += $offset; - return true; - } - break; - case SEEK_END: - if ($len + $offset <= $len) { - $this->pointer = $len + $offset; - return true; - } - break; - } - return false; - } - - public function stream_stat() { - return $this->url_stat($this->path); - } - - public function stream_tell() { - return $this->pointer; - } - - public function stream_write($data) { - if (!$this->writable) return 0; - $size = strlen($data); - if ($this->stream_eof()) { - self::$data[$this->path] .= $data; - } else { - self::$data[$this->path] = substr_replace( - self::$data[$this->path], - $data, - $this->pointer - ); - } - $this->pointer += $size; - return $size; - } - - public function unlink($path) { - if (isset(self::$data[$path])) { - unset(self::$data[$path]); - } - return true; - } - - public function url_stat($path) { - if (isset(self::$data[$path])) { - $size = strlen(self::$data[$path]); - $time = time(); - $data = array( - 'dev' => 0, - 'ino' => 0, - 'mode' => self::MODE_FILE | 0777, - 'nlink' => 1, - 'uid' => 0, - 'gid' => 0, - 'rdev' => '', - 'size' => $size, - 'atime' => $time, - 'mtime' => $time, - 'ctime' => $time, - 'blksize' => -1, - 'blocks' => -1, - ); - return array_values($data) + $data; - } - return false; - } -} diff --git a/lib/private/files/type/detection.php b/lib/private/files/type/detection.php deleted file mode 100644 index f106a98064f..00000000000 --- a/lib/private/files/type/detection.php +++ /dev/null @@ -1,318 +0,0 @@ -<?php -/** - * @author Andreas Fischer <bantu@owncloud.com> - * @author Jens-Christian Fischer <jens-christian.fischer@switch.ch> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Type; - -use OCP\Files\IMimeTypeDetector; -use OCP\IURLGenerator; - -/** - * Class Detection - * - * Mimetype detection - * - * @package OC\Files\Type - */ -class Detection implements IMimeTypeDetector { - protected $mimetypes = []; - protected $secureMimeTypes = []; - - protected $mimetypeIcons = []; - /** @var string[] */ - protected $mimeTypeAlias = []; - - /** @var IURLGenerator */ - private $urlGenerator; - - /** @var string */ - private $customConfigDir; - - /** @var string */ - private $defaultConfigDir; - - /** - * @param IURLGenerator $urlGenerator - * @param string $customConfigDir - * @param string $defaultConfigDir - */ - public function __construct(IURLGenerator $urlGenerator, - $customConfigDir, - $defaultConfigDir) { - $this->urlGenerator = $urlGenerator; - $this->customConfigDir = $customConfigDir; - $this->defaultConfigDir = $defaultConfigDir; - } - - /** - * Add an extension -> mimetype mapping - * - * $mimetype is the assumed correct mime type - * The optional $secureMimeType is an alternative to send to send - * to avoid potential XSS. - * - * @param string $extension - * @param string $mimetype - * @param string|null $secureMimeType - */ - public function registerType($extension, - $mimetype, - $secureMimeType = null) { - $this->mimetypes[$extension] = array($mimetype, $secureMimeType); - $this->secureMimeTypes[$mimetype] = $secureMimeType ?: $mimetype; - } - - /** - * Add an array of extension -> mimetype mappings - * - * The mimetype value is in itself an array where the first index is - * the assumed correct mimetype and the second is either a secure alternative - * or null if the correct is considered secure. - * - * @param array $types - */ - public function registerTypeArray($types) { - $this->mimetypes = array_merge($this->mimetypes, $types); - - // Update the alternative mimetypes to avoid having to look them up each time. - foreach ($this->mimetypes as $mimeType) { - $this->secureMimeTypes[$mimeType[0]] = isset($mimeType[1]) ? $mimeType[1]: $mimeType[0]; - } - } - - /** - * Add the mimetype aliases if they are not yet present - */ - private function loadAliases() { - if (!empty($this->mimeTypeAlias)) { - return; - } - - $this->mimeTypeAlias = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypealiases.dist.json'), true); - - if (file_exists($this->customConfigDir . '/mimetypealiases.json')) { - $custom = json_decode(file_get_contents($this->customConfigDir . '/mimetypealiases.json'), true); - $this->mimeTypeAlias = array_merge($this->mimeTypeAlias, $custom); - } - } - - /** - * @return string[] - */ - public function getAllAliases() { - $this->loadAliases(); - return $this->mimeTypeAlias; - } - - /** - * Add mimetype mappings if they are not yet present - */ - private function loadMappings() { - if (!empty($this->mimetypes)) { - return; - } - - $mimetypeMapping = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypemapping.dist.json'), true); - - //Check if need to load custom mappings - if (file_exists($this->customConfigDir . '/mimetypemapping.json')) { - $custom = json_decode(file_get_contents($this->customConfigDir . '/mimetypemapping.json'), true); - $mimetypeMapping = array_merge($mimetypeMapping, $custom); - } - - $this->registerTypeArray($mimetypeMapping); - } - - /** - * @return array - */ - public function getAllMappings() { - $this->loadMappings(); - return $this->mimetypes; - } - - /** - * detect mimetype only based on filename, content of file is not used - * - * @param string $path - * @return string - */ - public function detectPath($path) { - $this->loadMappings(); - - if (strpos($path, '.')) { - //try to guess the type by the file extension - $extension = strtolower(strrchr(basename($path), ".")); - $extension = substr($extension, 1); //remove leading . - return (isset($this->mimetypes[$extension]) && isset($this->mimetypes[$extension][0])) - ? $this->mimetypes[$extension][0] - : 'application/octet-stream'; - } else { - return 'application/octet-stream'; - } - } - - /** - * detect mimetype based on both filename and content - * - * @param string $path - * @return string - */ - public function detect($path) { - $this->loadMappings(); - - if (@is_dir($path)) { - // directories are easy - return "httpd/unix-directory"; - } - - $mimeType = $this->detectPath($path); - - if ($mimeType === 'application/octet-stream' and function_exists('finfo_open') - and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME) - ) { - $info = @strtolower(finfo_file($finfo, $path)); - finfo_close($finfo); - if ($info) { - $mimeType = substr($info, 0, strpos($info, ';')); - return empty($mimeType) ? 'application/octet-stream' : $mimeType; - } - - } - $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://'); - if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) { - // use mime magic extension if available - $mimeType = mime_content_type($path); - } - if (!$isWrapped and $mimeType === 'application/octet-stream' && \OC_Helper::canExecute("file")) { - // it looks like we have a 'file' command, - // lets see if it does have mime support - $path = escapeshellarg($path); - $fp = popen("file -b --mime-type $path 2>/dev/null", "r"); - $reply = fgets($fp); - pclose($fp); - - //trim the newline - $mimeType = trim($reply); - - if (empty($mimeType)) { - $mimeType = 'application/octet-stream'; - } - - } - return $mimeType; - } - - /** - * detect mimetype based on the content of a string - * - * @param string $data - * @return string - */ - public function detectString($data) { - if (function_exists('finfo_open') and function_exists('finfo_file')) { - $finfo = finfo_open(FILEINFO_MIME); - return finfo_buffer($finfo, $data); - } else { - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile(); - $fh = fopen($tmpFile, 'wb'); - fwrite($fh, $data, 8024); - fclose($fh); - $mime = $this->detect($tmpFile); - unset($tmpFile); - return $mime; - } - } - - /** - * Get a secure mimetype that won't expose potential XSS. - * - * @param string $mimeType - * @return string - */ - public function getSecureMimeType($mimeType) { - $this->loadMappings(); - - return isset($this->secureMimeTypes[$mimeType]) - ? $this->secureMimeTypes[$mimeType] - : 'application/octet-stream'; - } - - /** - * Get path to the icon of a file type - * @param string $mimetype the MIME type - * @return string the url - */ - public function mimeTypeIcon($mimetype) { - $this->loadAliases(); - - while (isset($this->mimeTypeAlias[$mimetype])) { - $mimetype = $this->mimeTypeAlias[$mimetype]; - } - if (isset($this->mimetypeIcons[$mimetype])) { - return $this->mimetypeIcons[$mimetype]; - } - - // Replace slash and backslash with a minus - $icon = str_replace('/', '-', $mimetype); - $icon = str_replace('\\', '-', $icon); - - // Is it a dir? - if ($mimetype === 'dir') { - $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder.png'); - return $this->mimetypeIcons[$mimetype]; - } - if ($mimetype === 'dir-shared') { - $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder-shared.png'); - return $this->mimetypeIcons[$mimetype]; - } - if ($mimetype === 'dir-external') { - $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder-external.png'); - return $this->mimetypeIcons[$mimetype]; - } - - // Icon exists? - try { - $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/' . $icon . '.png'); - return $this->mimetypeIcons[$mimetype]; - } catch (\RuntimeException $e) { - // Specified image not found - } - - // Try only the first part of the filetype - $mimePart = substr($icon, 0, strpos($icon, '-')); - try { - $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/' . $mimePart . '.png'); - return $this->mimetypeIcons[$mimetype]; - } catch (\RuntimeException $e) { - // Image for the first part of the mimetype not found - } - - $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/file.png'); - return $this->mimetypeIcons[$mimetype]; - } -} diff --git a/lib/private/files/type/loader.php b/lib/private/files/type/loader.php deleted file mode 100644 index 95ba7597257..00000000000 --- a/lib/private/files/type/loader.php +++ /dev/null @@ -1,173 +0,0 @@ -<?php -/** - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Type; - -use OCP\Files\IMimeTypeLoader; -use OCP\IDBConnection; - -use Doctrine\DBAL\Exception\UniqueConstraintViolationException; - -/** - * Mimetype database loader - * - * @package OC\Files\Type - */ -class Loader implements IMimeTypeLoader { - - /** @var IDBConnection */ - private $dbConnection; - - /** @var array [id => mimetype] */ - protected $mimetypes; - - /** @var array [mimetype => id] */ - protected $mimetypeIds; - - /** - * @param IDBConnection $dbConnection - */ - public function __construct(IDBConnection $dbConnection) { - $this->dbConnection = $dbConnection; - $this->mimetypes = []; - $this->mimetypeIds = []; - } - - /** - * Get a mimetype from its ID - * - * @param int $id - * @return string|null - */ - public function getMimetypeById($id) { - if (!$this->mimetypes) { - $this->loadMimetypes(); - } - if (isset($this->mimetypes[$id])) { - return $this->mimetypes[$id]; - } - return null; - } - - /** - * Get a mimetype ID, adding the mimetype to the DB if it does not exist - * - * @param string $mimetype - * @return int - */ - public function getId($mimetype) { - if (!$this->mimetypeIds) { - $this->loadMimetypes(); - } - if (isset($this->mimetypeIds[$mimetype])) { - return $this->mimetypeIds[$mimetype]; - } - return $this->store($mimetype); - } - - /** - * Test if a mimetype exists in the database - * - * @param string $mimetype - * @return bool - */ - public function exists($mimetype) { - if (!$this->mimetypeIds) { - $this->loadMimetypes(); - } - return isset($this->mimetypeIds[$mimetype]); - } - - /** - * Clear all loaded mimetypes, allow for re-loading - */ - public function reset() { - $this->mimetypes = []; - $this->mimetypeIds = []; - } - - /** - * Store a mimetype in the DB - * - * @param string $mimetype - * @param int inserted ID - */ - protected function store($mimetype) { - try { - $qb = $this->dbConnection->getQueryBuilder(); - $qb->insert('mimetypes') - ->values([ - 'mimetype' => $qb->createNamedParameter($mimetype) - ]); - $qb->execute(); - } catch (UniqueConstraintViolationException $e) { - // something inserted it before us - } - - $fetch = $this->dbConnection->getQueryBuilder(); - $fetch->select('id') - ->from('mimetypes') - ->where( - $fetch->expr()->eq('mimetype', $fetch->createNamedParameter($mimetype) - )); - $row = $fetch->execute()->fetch(); - - $this->mimetypes[$row['id']] = $mimetype; - $this->mimetypeIds[$mimetype] = $row['id']; - return $row['id']; - } - - /** - * Load all mimetypes from DB - */ - private function loadMimetypes() { - $qb = $this->dbConnection->getQueryBuilder(); - $qb->select('id', 'mimetype') - ->from('mimetypes'); - $results = $qb->execute()->fetchAll(); - - foreach ($results as $row) { - $this->mimetypes[$row['id']] = $row['mimetype']; - $this->mimetypeIds[$row['mimetype']] = $row['id']; - } - } - - /** - * Update filecache mimetype based on file extension - * - * @param string $ext file extension - * @param int $mimetypeId - * @return int number of changed rows - */ - public function updateFilecache($ext, $mimetypeId) { - $update = $this->dbConnection->getQueryBuilder(); - $update->update('filecache') - ->set('mimetype', $update->createNamedParameter($mimetypeId)) - ->where($update->expr()->neq( - 'mimetype', $update->createNamedParameter($mimetypeId) - )) - ->andWhere($update->expr()->like( - $update->createFunction('LOWER(`name`)'), $update->createNamedParameter($ext) - )); - return $update->execute(); - } - -} diff --git a/lib/private/files/type/templatemanager.php b/lib/private/files/type/templatemanager.php deleted file mode 100644 index 363fb7a2a6c..00000000000 --- a/lib/private/files/type/templatemanager.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Type; - -class TemplateManager { - protected $templates = array(); - - public function registerTemplate($mimetype, $path) { - $this->templates[$mimetype] = $path; - } - - /** - * get the path of the template for a mimetype - * - * @param string $mimetype - * @return string|null - */ - public function getTemplatePath($mimetype) { - if (isset($this->templates[$mimetype])) { - return $this->templates[$mimetype]; - } else { - return null; - } - } - - /** - * get the template content for a mimetype - * - * @param string $mimetype - * @return string - */ - public function getTemplate($mimetype) { - $path = $this->getTemplatePath($mimetype); - if ($path) { - return file_get_contents($path); - } else { - return ''; - } - } -} diff --git a/lib/private/files/utils/scanner.php b/lib/private/files/utils/scanner.php deleted file mode 100644 index 06526583899..00000000000 --- a/lib/private/files/utils/scanner.php +++ /dev/null @@ -1,172 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Files\Utils; - -use OC\Files\Filesystem; -use OC\ForbiddenException; -use OC\Hooks\PublicEmitter; -use OC\Lock\DBLockingProvider; -use OCP\Files\StorageNotAvailableException; -use OCP\ILogger; - -/** - * Class Scanner - * - * Hooks available in scope \OC\Utils\Scanner - * - scanFile(string $absolutePath) - * - scanFolder(string $absolutePath) - * - * @package OC\Files\Utils - */ -class Scanner extends PublicEmitter { - /** - * @var string $user - */ - private $user; - - /** - * @var \OCP\IDBConnection - */ - protected $db; - - /** - * @var ILogger - */ - protected $logger; - - /** - * @param string $user - * @param \OCP\IDBConnection $db - * @param ILogger $logger - */ - public function __construct($user, $db, ILogger $logger) { - $this->logger = $logger; - $this->user = $user; - $this->db = $db; - } - - /** - * get all storages for $dir - * - * @param string $dir - * @return \OC\Files\Mount\MountPoint[] - */ - protected function getMounts($dir) { - //TODO: move to the node based fileapi once that's done - \OC_Util::tearDownFS(); - \OC_Util::setupFS($this->user); - - $mountManager = Filesystem::getMountManager(); - $mounts = $mountManager->findIn($dir); - $mounts[] = $mountManager->find($dir); - $mounts = array_reverse($mounts); //start with the mount of $dir - - return $mounts; - } - - /** - * attach listeners to the scanner - * - * @param \OC\Files\Mount\MountPoint $mount - */ - protected function attachListener($mount) { - $scanner = $mount->getStorage()->getScanner(); - $emitter = $this; - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function ($path) use ($mount, $emitter) { - $emitter->emit('\OC\Files\Utils\Scanner', 'scanFile', array($mount->getMountPoint() . $path)); - }); - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFolder', function ($path) use ($mount, $emitter) { - $emitter->emit('\OC\Files\Utils\Scanner', 'scanFolder', array($mount->getMountPoint() . $path)); - }); - $scanner->listen('\OC\Files\Cache\Scanner', 'postScanFile', function ($path) use ($mount, $emitter) { - $emitter->emit('\OC\Files\Utils\Scanner', 'postScanFile', array($mount->getMountPoint() . $path)); - }); - $scanner->listen('\OC\Files\Cache\Scanner', 'postScanFolder', function ($path) use ($mount, $emitter) { - $emitter->emit('\OC\Files\Utils\Scanner', 'postScanFolder', array($mount->getMountPoint() . $path)); - }); - } - - /** - * @param string $dir - */ - public function backgroundScan($dir) { - $mounts = $this->getMounts($dir); - foreach ($mounts as $mount) { - if (is_null($mount->getStorage())) { - continue; - } - // don't scan the root storage - if ($mount->getStorage()->instanceOfStorage('\OC\Files\Storage\Local') && $mount->getMountPoint() === '/') { - continue; - } - $scanner = $mount->getStorage()->getScanner(); - $this->attachListener($mount); - $scanner->backgroundScan(); - } - } - - /** - * @param string $dir - * @throws \OC\ForbiddenException - */ - public function scan($dir = '') { - if (!Filesystem::isValidPath($dir)) { - throw new \InvalidArgumentException('Invalid path to scan'); - } - $mounts = $this->getMounts($dir); - foreach ($mounts as $mount) { - if (is_null($mount->getStorage())) { - continue; - } - $storage = $mount->getStorage(); - // if the home storage isn't writable then the scanner is run as the wrong user - if ($storage->instanceOfStorage('\OC\Files\Storage\Home') and - (!$storage->isCreatable('') or !$storage->isCreatable('files')) - ) { - throw new ForbiddenException(); - } - $relativePath = $mount->getInternalPath($dir); - $scanner = $storage->getScanner(); - $scanner->setUseTransactions(false); - $this->attachListener($mount); - $isDbLocking = \OC::$server->getLockingProvider() instanceof DBLockingProvider; - if (!$isDbLocking) { - $this->db->beginTransaction(); - } - try { - $scanner->scan($relativePath, \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE); - } catch (StorageNotAvailableException $e) { - $this->logger->error('Storage ' . $storage->getId() . ' not available'); - $this->logger->logException($e); - $this->emit('\OC\Files\Utils\Scanner', 'StorageNotAvailable', [$e]); - } - if (!$isDbLocking) { - $this->db->commit(); - } - } - } -} - diff --git a/lib/private/files/view.php b/lib/private/files/view.php deleted file mode 100644 index aac33a4598c..00000000000 --- a/lib/private/files/view.php +++ /dev/null @@ -1,2058 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Bart Visscher <bartv@thisnet.nl> - * @author Björn Schießle <schiessle@owncloud.com> - * @author cmeh <cmeh@users.noreply.github.com> - * @author Florin Peter <github@florin-peter.de> - * @author Jesús Macias <jmacias@solidgear.es> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Klaas Freitag <freitag@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Luke Policinski <lpolicinski@gmail.com> - * @author Martin Mattel <martin.mattel@diemattels.at> - * @author Michael Gapczynski <GapczynskiM@gmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Sam Tuke <mail@samtuke.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - - -namespace OC\Files; - -use Icewind\Streams\CallbackWrapper; -use OC\Files\Mount\MoveableMount; -use OC\Files\Storage\Storage; -use OC\User\User; -use OCP\Constants; -use OCP\Files\Cache\ICacheEntry; -use OCP\Files\FileNameTooLongException; -use OCP\Files\InvalidCharacterInPathException; -use OCP\Files\InvalidPathException; -use OCP\Files\NotFoundException; -use OCP\Files\ReservedWordException; -use OCP\Files\Storage\ILockingStorage; -use OCP\IUser; -use OCP\Lock\ILockingProvider; -use OCP\Lock\LockedException; - -/** - * Class to provide access to ownCloud filesystem via a "view", and methods for - * working with files within that view (e.g. read, write, delete, etc.). Each - * view is restricted to a set of directories via a virtual root. The default view - * uses the currently logged in user's data directory as root (parts of - * OC_Filesystem are merely a wrapper for OC\Files\View). - * - * Apps that need to access files outside of the user data folders (to modify files - * belonging to a user other than the one currently logged in, for example) should - * use this class directly rather than using OC_Filesystem, or making use of PHP's - * built-in file manipulation functions. This will ensure all hooks and proxies - * are triggered correctly. - * - * Filesystem functions are not called directly; they are passed to the correct - * \OC\Files\Storage\Storage object - */ -class View { - /** @var string */ - private $fakeRoot = ''; - - /** - * @var \OCP\Lock\ILockingProvider - */ - private $lockingProvider; - - private $lockingEnabled; - - private $updaterEnabled = true; - - private $userManager; - - /** - * @param string $root - * @throws \Exception If $root contains an invalid path - */ - public function __construct($root = '') { - if (is_null($root)) { - throw new \InvalidArgumentException('Root can\'t be null'); - } - if (!Filesystem::isValidPath($root)) { - throw new \Exception(); - } - - $this->fakeRoot = $root; - $this->lockingProvider = \OC::$server->getLockingProvider(); - $this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider); - $this->userManager = \OC::$server->getUserManager(); - } - - public function getAbsolutePath($path = '/') { - if ($path === null) { - return null; - } - $this->assertPathLength($path); - if ($path === '') { - $path = '/'; - } - if ($path[0] !== '/') { - $path = '/' . $path; - } - return $this->fakeRoot . $path; - } - - /** - * change the root to a fake root - * - * @param string $fakeRoot - * @return boolean|null - */ - public function chroot($fakeRoot) { - if (!$fakeRoot == '') { - if ($fakeRoot[0] !== '/') { - $fakeRoot = '/' . $fakeRoot; - } - } - $this->fakeRoot = $fakeRoot; - } - - /** - * get the fake root - * - * @return string - */ - public function getRoot() { - return $this->fakeRoot; - } - - /** - * get path relative to the root of the view - * - * @param string $path - * @return string - */ - public function getRelativePath($path) { - $this->assertPathLength($path); - if ($this->fakeRoot == '') { - return $path; - } - - if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) { - return '/'; - } - - // missing slashes can cause wrong matches! - $root = rtrim($this->fakeRoot, '/') . '/'; - - if (strpos($path, $root) !== 0) { - return null; - } else { - $path = substr($path, strlen($this->fakeRoot)); - if (strlen($path) === 0) { - return '/'; - } else { - return $path; - } - } - } - - /** - * get the mountpoint of the storage object for a path - * ( note: because a storage is not always mounted inside the fakeroot, the - * returned mountpoint is relative to the absolute root of the filesystem - * and does not take the chroot into account ) - * - * @param string $path - * @return string - */ - public function getMountPoint($path) { - return Filesystem::getMountPoint($this->getAbsolutePath($path)); - } - - /** - * get the mountpoint of the storage object for a path - * ( note: because a storage is not always mounted inside the fakeroot, the - * returned mountpoint is relative to the absolute root of the filesystem - * and does not take the chroot into account ) - * - * @param string $path - * @return \OCP\Files\Mount\IMountPoint - */ - public function getMount($path) { - return Filesystem::getMountManager()->find($this->getAbsolutePath($path)); - } - - /** - * resolve a path to a storage and internal path - * - * @param string $path - * @return array an array consisting of the storage and the internal path - */ - public function resolvePath($path) { - $a = $this->getAbsolutePath($path); - $p = Filesystem::normalizePath($a); - return Filesystem::resolvePath($p); - } - - /** - * return the path to a local version of the file - * we need this because we can't know if a file is stored local or not from - * outside the filestorage and for some purposes a local file is needed - * - * @param string $path - * @return string - */ - public function getLocalFile($path) { - $parent = substr($path, 0, strrpos($path, '/')); - $path = $this->getAbsolutePath($path); - list($storage, $internalPath) = Filesystem::resolvePath($path); - if (Filesystem::isValidPath($parent) and $storage) { - return $storage->getLocalFile($internalPath); - } else { - return null; - } - } - - /** - * @param string $path - * @return string - */ - public function getLocalFolder($path) { - $parent = substr($path, 0, strrpos($path, '/')); - $path = $this->getAbsolutePath($path); - list($storage, $internalPath) = Filesystem::resolvePath($path); - if (Filesystem::isValidPath($parent) and $storage) { - return $storage->getLocalFolder($internalPath); - } else { - return null; - } - } - - /** - * the following functions operate with arguments and return values identical - * to those of their PHP built-in equivalents. Mostly they are merely wrappers - * for \OC\Files\Storage\Storage via basicOperation(). - */ - public function mkdir($path) { - return $this->basicOperation('mkdir', $path, array('create', 'write')); - } - - /** - * remove mount point - * - * @param \OC\Files\Mount\MoveableMount $mount - * @param string $path relative to data/ - * @return boolean - */ - protected function removeMount($mount, $path) { - if ($mount instanceof MoveableMount) { - // cut of /user/files to get the relative path to data/user/files - $pathParts = explode('/', $path, 4); - $relPath = '/' . $pathParts[3]; - $this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true); - \OC_Hook::emit( - Filesystem::CLASSNAME, "umount", - array(Filesystem::signal_param_path => $relPath) - ); - $this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true); - $result = $mount->removeMount(); - $this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true); - if ($result) { - \OC_Hook::emit( - Filesystem::CLASSNAME, "post_umount", - array(Filesystem::signal_param_path => $relPath) - ); - } - $this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true); - return $result; - } else { - // do not allow deleting the storage's root / the mount point - // because for some storages it might delete the whole contents - // but isn't supposed to work that way - return false; - } - } - - public function disableCacheUpdate() { - $this->updaterEnabled = false; - } - - public function enableCacheUpdate() { - $this->updaterEnabled = true; - } - - protected function writeUpdate(Storage $storage, $internalPath, $time = null) { - if ($this->updaterEnabled) { - if (is_null($time)) { - $time = time(); - } - $storage->getUpdater()->update($internalPath, $time); - } - } - - protected function removeUpdate(Storage $storage, $internalPath) { - if ($this->updaterEnabled) { - $storage->getUpdater()->remove($internalPath); - } - } - - protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) { - if ($this->updaterEnabled) { - $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } - } - - /** - * @param string $path - * @return bool|mixed - */ - public function rmdir($path) { - $absolutePath = $this->getAbsolutePath($path); - $mount = Filesystem::getMountManager()->find($absolutePath); - if ($mount->getInternalPath($absolutePath) === '') { - return $this->removeMount($mount, $absolutePath); - } - if ($this->is_dir($path)) { - return $this->basicOperation('rmdir', $path, array('delete')); - } else { - return false; - } - } - - /** - * @param string $path - * @return resource - */ - public function opendir($path) { - return $this->basicOperation('opendir', $path, array('read')); - } - - /** - * @param $handle - * @return mixed - */ - public function readdir($handle) { - $fsLocal = new Storage\Local(array('datadir' => '/')); - return $fsLocal->readdir($handle); - } - - /** - * @param string $path - * @return bool|mixed - */ - public function is_dir($path) { - if ($path == '/') { - return true; - } - return $this->basicOperation('is_dir', $path); - } - - /** - * @param string $path - * @return bool|mixed - */ - public function is_file($path) { - if ($path == '/') { - return false; - } - return $this->basicOperation('is_file', $path); - } - - /** - * @param string $path - * @return mixed - */ - public function stat($path) { - return $this->basicOperation('stat', $path); - } - - /** - * @param string $path - * @return mixed - */ - public function filetype($path) { - return $this->basicOperation('filetype', $path); - } - - /** - * @param string $path - * @return mixed - */ - public function filesize($path) { - return $this->basicOperation('filesize', $path); - } - - /** - * @param string $path - * @return bool|mixed - * @throws \OCP\Files\InvalidPathException - */ - public function readfile($path) { - $this->assertPathLength($path); - @ob_end_clean(); - $handle = $this->fopen($path, 'rb'); - if ($handle) { - $chunkSize = 8192; // 8 kB chunks - while (!feof($handle)) { - echo fread($handle, $chunkSize); - flush(); - } - $size = $this->filesize($path); - return $size; - } - return false; - } - - /** - * @param string $path - * @return mixed - */ - public function isCreatable($path) { - return $this->basicOperation('isCreatable', $path); - } - - /** - * @param string $path - * @return mixed - */ - public function isReadable($path) { - return $this->basicOperation('isReadable', $path); - } - - /** - * @param string $path - * @return mixed - */ - public function isUpdatable($path) { - return $this->basicOperation('isUpdatable', $path); - } - - /** - * @param string $path - * @return bool|mixed - */ - public function isDeletable($path) { - $absolutePath = $this->getAbsolutePath($path); - $mount = Filesystem::getMountManager()->find($absolutePath); - if ($mount->getInternalPath($absolutePath) === '') { - return $mount instanceof MoveableMount; - } - return $this->basicOperation('isDeletable', $path); - } - - /** - * @param string $path - * @return mixed - */ - public function isSharable($path) { - return $this->basicOperation('isSharable', $path); - } - - /** - * @param string $path - * @return bool|mixed - */ - public function file_exists($path) { - if ($path == '/') { - return true; - } - return $this->basicOperation('file_exists', $path); - } - - /** - * @param string $path - * @return mixed - */ - public function filemtime($path) { - return $this->basicOperation('filemtime', $path); - } - - /** - * @param string $path - * @param int|string $mtime - * @return bool - */ - public function touch($path, $mtime = null) { - if (!is_null($mtime) and !is_numeric($mtime)) { - $mtime = strtotime($mtime); - } - - $hooks = array('touch'); - - if (!$this->file_exists($path)) { - $hooks[] = 'create'; - $hooks[] = 'write'; - } - $result = $this->basicOperation('touch', $path, $hooks, $mtime); - if (!$result) { - // If create file fails because of permissions on external storage like SMB folders, - // check file exists and return false if not. - if (!$this->file_exists($path)) { - return false; - } - if (is_null($mtime)) { - $mtime = time(); - } - //if native touch fails, we emulate it by changing the mtime in the cache - $this->putFileInfo($path, array('mtime' => $mtime)); - } - return true; - } - - /** - * @param string $path - * @return mixed - */ - public function file_get_contents($path) { - return $this->basicOperation('file_get_contents', $path, array('read')); - } - - /** - * @param bool $exists - * @param string $path - * @param bool $run - */ - protected function emit_file_hooks_pre($exists, $path, &$run) { - if (!$exists) { - \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, array( - Filesystem::signal_param_path => $this->getHookPath($path), - Filesystem::signal_param_run => &$run, - )); - } else { - \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, array( - Filesystem::signal_param_path => $this->getHookPath($path), - Filesystem::signal_param_run => &$run, - )); - } - \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, array( - Filesystem::signal_param_path => $this->getHookPath($path), - Filesystem::signal_param_run => &$run, - )); - } - - /** - * @param bool $exists - * @param string $path - */ - protected function emit_file_hooks_post($exists, $path) { - if (!$exists) { - \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, array( - Filesystem::signal_param_path => $this->getHookPath($path), - )); - } else { - \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, array( - Filesystem::signal_param_path => $this->getHookPath($path), - )); - } - \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, array( - Filesystem::signal_param_path => $this->getHookPath($path), - )); - } - - /** - * @param string $path - * @param mixed $data - * @return bool|mixed - * @throws \Exception - */ - public function file_put_contents($path, $data) { - if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier - $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (Filesystem::isValidPath($path) - and !Filesystem::isFileBlacklisted($path) - ) { - $path = $this->getRelativePath($absolutePath); - - $this->lockFile($path, ILockingProvider::LOCK_SHARED); - - $exists = $this->file_exists($path); - $run = true; - if ($this->shouldEmitHooks($path)) { - $this->emit_file_hooks_pre($exists, $path, $run); - } - if (!$run) { - $this->unlockFile($path, ILockingProvider::LOCK_SHARED); - return false; - } - - $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE); - - /** @var \OC\Files\Storage\Storage $storage */ - list($storage, $internalPath) = $this->resolvePath($path); - $target = $storage->fopen($internalPath, 'w'); - if ($target) { - list (, $result) = \OC_Helper::streamCopy($data, $target); - fclose($target); - fclose($data); - - $this->writeUpdate($storage, $internalPath); - - $this->changeLock($path, ILockingProvider::LOCK_SHARED); - - if ($this->shouldEmitHooks($path) && $result !== false) { - $this->emit_file_hooks_post($exists, $path); - } - $this->unlockFile($path, ILockingProvider::LOCK_SHARED); - return $result; - } else { - $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); - return false; - } - } else { - return false; - } - } else { - $hooks = ($this->file_exists($path)) ? array('update', 'write') : array('create', 'write'); - return $this->basicOperation('file_put_contents', $path, $hooks, $data); - } - } - - /** - * @param string $path - * @return bool|mixed - */ - public function unlink($path) { - if ($path === '' || $path === '/') { - // do not allow deleting the root - return false; - } - $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; - $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - $mount = Filesystem::getMountManager()->find($absolutePath . $postFix); - if ($mount and $mount->getInternalPath($absolutePath) === '') { - return $this->removeMount($mount, $absolutePath); - } - return $this->basicOperation('unlink', $path, array('delete')); - } - - /** - * @param string $directory - * @return bool|mixed - */ - public function deleteAll($directory) { - return $this->rmdir($directory); - } - - /** - * Rename/move a file or folder from the source path to target path. - * - * @param string $path1 source path - * @param string $path2 target path - * - * @return bool|mixed - */ - public function rename($path1, $path2) { - $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); - $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); - $result = false; - if ( - Filesystem::isValidPath($path2) - and Filesystem::isValidPath($path1) - and !Filesystem::isFileBlacklisted($path2) - ) { - $path1 = $this->getRelativePath($absolutePath1); - $path2 = $this->getRelativePath($absolutePath2); - $exists = $this->file_exists($path2); - - if ($path1 == null or $path2 == null) { - return false; - } - - $this->lockFile($path1, ILockingProvider::LOCK_SHARED, true); - try { - $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true); - } catch (LockedException $e) { - $this->unlockFile($path1, ILockingProvider::LOCK_SHARED); - throw $e; - } - - $run = true; - if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) { - // if it was a rename from a part file to a regular file it was a write and not a rename operation - $this->emit_file_hooks_pre($exists, $path2, $run); - } elseif ($this->shouldEmitHooks($path1)) { - \OC_Hook::emit( - Filesystem::CLASSNAME, Filesystem::signal_rename, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2), - Filesystem::signal_param_run => &$run - ) - ); - } - if ($run) { - $this->verifyPath(dirname($path2), basename($path2)); - - $manager = Filesystem::getMountManager(); - $mount1 = $this->getMount($path1); - $mount2 = $this->getMount($path2); - $storage1 = $mount1->getStorage(); - $storage2 = $mount2->getStorage(); - $internalPath1 = $mount1->getInternalPath($absolutePath1); - $internalPath2 = $mount2->getInternalPath($absolutePath2); - - $this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true); - $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true); - - if ($internalPath1 === '' and $mount1 instanceof MoveableMount) { - if ($this->isTargetAllowed($absolutePath2)) { - /** - * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1 - */ - $sourceMountPoint = $mount1->getMountPoint(); - $result = $mount1->moveMount($absolutePath2); - $manager->moveMount($sourceMountPoint, $mount1->getMountPoint()); - } else { - $result = false; - } - // moving a file/folder within the same mount point - } elseif ($storage1 == $storage2) { - if ($storage1) { - $result = $storage1->rename($internalPath1, $internalPath2); - } else { - $result = false; - } - // moving a file/folder between storages (from $storage1 to $storage2) - } else { - $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2); - } - - if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { - // if it was a rename from a part file to a regular file it was a write and not a rename operation - - $this->writeUpdate($storage2, $internalPath2); - } else if ($result) { - if ($internalPath1 !== '') { // don't do a cache update for moved mounts - $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2); - } - } - - $this->changeLock($path1, ILockingProvider::LOCK_SHARED, true); - $this->changeLock($path2, ILockingProvider::LOCK_SHARED, true); - - if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { - if ($this->shouldEmitHooks()) { - $this->emit_file_hooks_post($exists, $path2); - } - } elseif ($result) { - if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_rename, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2) - ) - ); - } - } - } - $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true); - $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true); - } - return $result; - } - - /** - * Copy a file/folder from the source path to target path - * - * @param string $path1 source path - * @param string $path2 target path - * @param bool $preserveMtime whether to preserve mtime on the copy - * - * @return bool|mixed - */ - public function copy($path1, $path2, $preserveMtime = false) { - $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); - $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); - $result = false; - if ( - Filesystem::isValidPath($path2) - and Filesystem::isValidPath($path1) - and !Filesystem::isFileBlacklisted($path2) - ) { - $path1 = $this->getRelativePath($absolutePath1); - $path2 = $this->getRelativePath($absolutePath2); - - if ($path1 == null or $path2 == null) { - return false; - } - $run = true; - - $this->lockFile($path2, ILockingProvider::LOCK_SHARED); - $this->lockFile($path1, ILockingProvider::LOCK_SHARED); - $lockTypePath1 = ILockingProvider::LOCK_SHARED; - $lockTypePath2 = ILockingProvider::LOCK_SHARED; - - try { - - $exists = $this->file_exists($path2); - if ($this->shouldEmitHooks()) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_copy, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2), - Filesystem::signal_param_run => &$run - ) - ); - $this->emit_file_hooks_pre($exists, $path2, $run); - } - if ($run) { - $mount1 = $this->getMount($path1); - $mount2 = $this->getMount($path2); - $storage1 = $mount1->getStorage(); - $internalPath1 = $mount1->getInternalPath($absolutePath1); - $storage2 = $mount2->getStorage(); - $internalPath2 = $mount2->getInternalPath($absolutePath2); - - $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE); - $lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE; - - if ($mount1->getMountPoint() == $mount2->getMountPoint()) { - if ($storage1) { - $result = $storage1->copy($internalPath1, $internalPath2); - } else { - $result = false; - } - } else { - $result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2); - } - - $this->writeUpdate($storage2, $internalPath2); - - $this->changeLock($path2, ILockingProvider::LOCK_SHARED); - $lockTypePath2 = ILockingProvider::LOCK_SHARED; - - if ($this->shouldEmitHooks() && $result !== false) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_copy, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2) - ) - ); - $this->emit_file_hooks_post($exists, $path2); - } - - } - } catch (\Exception $e) { - $this->unlockFile($path2, $lockTypePath2); - $this->unlockFile($path1, $lockTypePath1); - throw $e; - } - - $this->unlockFile($path2, $lockTypePath2); - $this->unlockFile($path1, $lockTypePath1); - - } - return $result; - } - - /** - * @param string $path - * @param string $mode - * @return resource - */ - public function fopen($path, $mode) { - $hooks = array(); - switch ($mode) { - case 'r': - case 'rb': - $hooks[] = 'read'; - break; - case 'r+': - case 'rb+': - case 'w+': - case 'wb+': - case 'x+': - case 'xb+': - case 'a+': - case 'ab+': - $hooks[] = 'read'; - $hooks[] = 'write'; - break; - case 'w': - case 'wb': - case 'x': - case 'xb': - case 'a': - case 'ab': - $hooks[] = 'write'; - break; - default: - \OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR); - } - - return $this->basicOperation('fopen', $path, $hooks, $mode); - } - - /** - * @param string $path - * @return bool|string - * @throws \OCP\Files\InvalidPathException - */ - public function toTmpFile($path) { - $this->assertPathLength($path); - if (Filesystem::isValidPath($path)) { - $source = $this->fopen($path, 'r'); - if ($source) { - $extension = pathinfo($path, PATHINFO_EXTENSION); - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension); - file_put_contents($tmpFile, $source); - return $tmpFile; - } else { - return false; - } - } else { - return false; - } - } - - /** - * @param string $tmpFile - * @param string $path - * @return bool|mixed - * @throws \OCP\Files\InvalidPathException - */ - public function fromTmpFile($tmpFile, $path) { - $this->assertPathLength($path); - if (Filesystem::isValidPath($path)) { - - // Get directory that the file is going into - $filePath = dirname($path); - - // Create the directories if any - if (!$this->file_exists($filePath)) { - $this->mkdir($filePath); - } - - $source = fopen($tmpFile, 'r'); - if ($source) { - $result = $this->file_put_contents($path, $source); - // $this->file_put_contents() might have already closed - // the resource, so we check it, before trying to close it - // to avoid messages in the error log. - if (is_resource($source)) { - fclose($source); - } - unlink($tmpFile); - return $result; - } else { - return false; - } - } else { - return false; - } - } - - - /** - * @param string $path - * @return mixed - * @throws \OCP\Files\InvalidPathException - */ - public function getMimeType($path) { - $this->assertPathLength($path); - return $this->basicOperation('getMimeType', $path); - } - - /** - * @param string $type - * @param string $path - * @param bool $raw - * @return bool|null|string - */ - public function hash($type, $path, $raw = false) { - $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; - $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (Filesystem::isValidPath($path)) { - $path = $this->getRelativePath($absolutePath); - if ($path == null) { - return false; - } - if ($this->shouldEmitHooks($path)) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_read, - array(Filesystem::signal_param_path => $this->getHookPath($path)) - ); - } - list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); - if ($storage) { - $result = $storage->hash($type, $internalPath, $raw); - return $result; - } - } - return null; - } - - /** - * @param string $path - * @return mixed - * @throws \OCP\Files\InvalidPathException - */ - public function free_space($path = '/') { - $this->assertPathLength($path); - return $this->basicOperation('free_space', $path); - } - - /** - * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage - * - * @param string $operation - * @param string $path - * @param array $hooks (optional) - * @param mixed $extraParam (optional) - * @return mixed - * @throws \Exception - * - * This method takes requests for basic filesystem functions (e.g. reading & writing - * files), processes hooks and proxies, sanitises paths, and finally passes them on to - * \OC\Files\Storage\Storage for delegation to a storage backend for execution - */ - private function basicOperation($operation, $path, $hooks = [], $extraParam = null) { - $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; - $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (Filesystem::isValidPath($path) - and !Filesystem::isFileBlacklisted($path) - ) { - $path = $this->getRelativePath($absolutePath); - if ($path == null) { - return false; - } - - if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) { - // always a shared lock during pre-hooks so the hook can read the file - $this->lockFile($path, ILockingProvider::LOCK_SHARED); - } - - $run = $this->runHooks($hooks, $path); - /** @var \OC\Files\Storage\Storage $storage */ - list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); - if ($run and $storage) { - if (in_array('write', $hooks) || in_array('delete', $hooks)) { - $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE); - } - try { - if (!is_null($extraParam)) { - $result = $storage->$operation($internalPath, $extraParam); - } else { - $result = $storage->$operation($internalPath); - } - } catch (\Exception $e) { - if (in_array('write', $hooks) || in_array('delete', $hooks)) { - $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); - } else if (in_array('read', $hooks)) { - $this->unlockFile($path, ILockingProvider::LOCK_SHARED); - } - throw $e; - } - - if (in_array('delete', $hooks) and $result) { - $this->removeUpdate($storage, $internalPath); - } - if (in_array('write', $hooks) and $operation !== 'fopen') { - $this->writeUpdate($storage, $internalPath); - } - if (in_array('touch', $hooks)) { - $this->writeUpdate($storage, $internalPath, $extraParam); - } - - if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) { - $this->changeLock($path, ILockingProvider::LOCK_SHARED); - } - - $unlockLater = false; - if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) { - $unlockLater = true; - $result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) { - if (in_array('write', $hooks)) { - $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); - } else if (in_array('read', $hooks)) { - $this->unlockFile($path, ILockingProvider::LOCK_SHARED); - } - }); - } - - if ($this->shouldEmitHooks($path) && $result !== false) { - if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open - $this->runHooks($hooks, $path, true); - } - } - - if (!$unlockLater - && (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) - ) { - $this->unlockFile($path, ILockingProvider::LOCK_SHARED); - } - return $result; - } else { - $this->unlockFile($path, ILockingProvider::LOCK_SHARED); - } - } - return null; - } - - /** - * get the path relative to the default root for hook usage - * - * @param string $path - * @return string - */ - private function getHookPath($path) { - if (!Filesystem::getView()) { - return $path; - } - return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path)); - } - - private function shouldEmitHooks($path = '') { - if ($path && Cache\Scanner::isPartialFile($path)) { - return false; - } - if (!Filesystem::$loaded) { - return false; - } - $defaultRoot = Filesystem::getRoot(); - if ($defaultRoot === null) { - return false; - } - if ($this->fakeRoot === $defaultRoot) { - return true; - } - $fullPath = $this->getAbsolutePath($path); - - if ($fullPath === $defaultRoot) { - return true; - } - - return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/'); - } - - /** - * @param string[] $hooks - * @param string $path - * @param bool $post - * @return bool - */ - private function runHooks($hooks, $path, $post = false) { - $relativePath = $path; - $path = $this->getHookPath($path); - $prefix = ($post) ? 'post_' : ''; - $run = true; - if ($this->shouldEmitHooks($relativePath)) { - foreach ($hooks as $hook) { - if ($hook != 'read') { - \OC_Hook::emit( - Filesystem::CLASSNAME, - $prefix . $hook, - array( - Filesystem::signal_param_run => &$run, - Filesystem::signal_param_path => $path - ) - ); - } elseif (!$post) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - $prefix . $hook, - array( - Filesystem::signal_param_path => $path - ) - ); - } - } - } - return $run; - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - return $this->basicOperation('hasUpdated', $path, array(), $time); - } - - /** - * @param string $ownerId - * @return \OC\User\User - */ - private function getUserObjectForOwner($ownerId) { - $owner = $this->userManager->get($ownerId); - if ($owner instanceof IUser) { - return $owner; - } else { - return new User($ownerId, null); - } - } - - /** - * Get file info from cache - * - * If the file is not in cached it will be scanned - * If the file has changed on storage the cache will be updated - * - * @param \OC\Files\Storage\Storage $storage - * @param string $internalPath - * @param string $relativePath - * @return array|bool - */ - private function getCacheEntry($storage, $internalPath, $relativePath) { - $cache = $storage->getCache($internalPath); - $data = $cache->get($internalPath); - $watcher = $storage->getWatcher($internalPath); - - try { - // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data - if (!$data || $data['size'] === -1) { - $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); - if (!$storage->file_exists($internalPath)) { - $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); - return false; - } - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); - $data = $cache->get($internalPath); - $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); - } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) { - $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); - $watcher->update($internalPath, $data); - $storage->getPropagator()->propagateChange($internalPath, time()); - $data = $cache->get($internalPath); - $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); - } - } catch (LockedException $e) { - // if the file is locked we just use the old cache info - } - - return $data; - } - - /** - * get the filesystem info - * - * @param string $path - * @param boolean|string $includeMountPoints true to add mountpoint sizes, - * 'ext' to add only ext storage mount point sizes. Defaults to true. - * defaults to true - * @return \OC\Files\FileInfo|false False if file does not exist - */ - public function getFileInfo($path, $includeMountPoints = true) { - $this->assertPathLength($path); - if (!Filesystem::isValidPath($path)) { - return false; - } - if (Cache\Scanner::isPartialFile($path)) { - return $this->getPartFileInfo($path); - } - $relativePath = $path; - $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); - - $mount = Filesystem::getMountManager()->find($path); - $storage = $mount->getStorage(); - $internalPath = $mount->getInternalPath($path); - if ($storage) { - $data = $this->getCacheEntry($storage, $internalPath, $relativePath); - - if (!$data instanceof ICacheEntry) { - return false; - } - - if ($mount instanceof MoveableMount && $internalPath === '') { - $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE; - } - - $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath)); - $info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner); - - if ($data and isset($data['fileid'])) { - if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') { - //add the sizes of other mount points to the folder - $extOnly = ($includeMountPoints === 'ext'); - $mounts = Filesystem::getMountManager()->findIn($path); - foreach ($mounts as $mount) { - $subStorage = $mount->getStorage(); - if ($subStorage) { - // exclude shared storage ? - if ($extOnly && $subStorage instanceof \OC\Files\Storage\Shared) { - continue; - } - $subCache = $subStorage->getCache(''); - $rootEntry = $subCache->get(''); - $info->addSubEntry($rootEntry, $mount->getMountPoint()); - } - } - } - } - - return $info; - } - - return false; - } - - /** - * get the content of a directory - * - * @param string $directory path under datadirectory - * @param string $mimetype_filter limit returned content to this mimetype or mimepart - * @return FileInfo[] - */ - public function getDirectoryContent($directory, $mimetype_filter = '') { - $this->assertPathLength($directory); - if (!Filesystem::isValidPath($directory)) { - return []; - } - $path = $this->getAbsolutePath($directory); - $path = Filesystem::normalizePath($path); - $mount = $this->getMount($directory); - $storage = $mount->getStorage(); - $internalPath = $mount->getInternalPath($path); - if ($storage) { - $cache = $storage->getCache($internalPath); - $user = \OC_User::getUser(); - - $data = $this->getCacheEntry($storage, $internalPath, $directory); - - if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) { - return []; - } - - $folderId = $data['fileid']; - $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter - - $sharingDisabled = \OCP\Util::isSharingDisabledForUser(); - /** - * @var \OC\Files\FileInfo[] $files - */ - $files = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) { - if ($sharingDisabled) { - $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; - } - $owner = $this->getUserObjectForOwner($storage->getOwner($content['path'])); - return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner); - }, $contents); - - //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders - $mounts = Filesystem::getMountManager()->findIn($path); - $dirLength = strlen($path); - foreach ($mounts as $mount) { - $mountPoint = $mount->getMountPoint(); - $subStorage = $mount->getStorage(); - if ($subStorage) { - $subCache = $subStorage->getCache(''); - - $rootEntry = $subCache->get(''); - if (!$rootEntry) { - $subScanner = $subStorage->getScanner(''); - try { - $subScanner->scanFile(''); - } catch (\OCP\Files\StorageNotAvailableException $e) { - continue; - } catch (\OCP\Files\StorageInvalidException $e) { - continue; - } catch (\Exception $e) { - // sometimes when the storage is not available it can be any exception - \OCP\Util::writeLog( - 'core', - 'Exception while scanning storage "' . $subStorage->getId() . '": ' . - get_class($e) . ': ' . $e->getMessage(), - \OCP\Util::ERROR - ); - continue; - } - $rootEntry = $subCache->get(''); - } - - if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) { - $relativePath = trim(substr($mountPoint, $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->getName() === $entryName) { - $entry->addSubEntry($rootEntry, $mountPoint); - } - } - } else { //mountpoint in this folder, add an entry for it - $rootEntry['name'] = $relativePath; - $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; - $permissions = $rootEntry['permissions']; - // do not allow renaming/deleting the mount point if they are not shared files/folders - // for shared files/folders we use the permissions given by the owner - if ($mount instanceof MoveableMount) { - $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE; - } else { - $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)); - } - - //remove any existing entry with the same name - foreach ($files as $i => $file) { - if ($file['name'] === $rootEntry['name']) { - unset($files[$i]); - break; - } - } - $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/ - - // if sharing was disabled for the user we remove the share permissions - if (\OCP\Util::isSharingDisabledForUser()) { - $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; - } - - $owner = $this->getUserObjectForOwner($subStorage->getOwner('')); - $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner); - } - } - } - } - - if ($mimetype_filter) { - $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) { - if (strpos($mimetype_filter, '/')) { - return $file->getMimetype() === $mimetype_filter; - } else { - return $file->getMimePart() === $mimetype_filter; - } - }); - } - - return $files; - } else { - return []; - } - } - - /** - * change file metadata - * - * @param string $path - * @param array|\OCP\Files\FileInfo $data - * @return int - * - * returns the fileid of the updated file - */ - public function putFileInfo($path, $data) { - $this->assertPathLength($path); - if ($data instanceof FileInfo) { - $data = $data->getData(); - } - $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = Filesystem::resolvePath($path); - if ($storage) { - $cache = $storage->getCache($path); - - if (!$cache->inCache($internalPath)) { - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); - } - - return $cache->put($internalPath, $data); - } else { - return -1; - } - } - - /** - * search for files with the name matching $query - * - * @param string $query - * @return FileInfo[] - */ - public function search($query) { - return $this->searchCommon('search', array('%' . $query . '%')); - } - - /** - * search for files with the name matching $query - * - * @param string $query - * @return FileInfo[] - */ - public function searchRaw($query) { - return $this->searchCommon('search', array($query)); - } - - /** - * search for files by mimetype - * - * @param string $mimetype - * @return FileInfo[] - */ - public function searchByMime($mimetype) { - return $this->searchCommon('searchByMime', array($mimetype)); - } - - /** - * search for files by tag - * - * @param string|int $tag name or tag id - * @param string $userId owner of the tags - * @return FileInfo[] - */ - public function searchByTag($tag, $userId) { - return $this->searchCommon('searchByTag', array($tag, $userId)); - } - - /** - * @param string $method cache method - * @param array $args - * @return FileInfo[] - */ - private function searchCommon($method, $args) { - $files = array(); - $rootLength = strlen($this->fakeRoot); - - $mount = $this->getMount(''); - $mountPoint = $mount->getMountPoint(); - $storage = $mount->getStorage(); - if ($storage) { - $cache = $storage->getCache(''); - - $results = call_user_func_array(array($cache, $method), $args); - foreach ($results as $result) { - if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') { - $internalPath = $result['path']; - $path = $mountPoint . $result['path']; - $result['path'] = substr($mountPoint . $result['path'], $rootLength); - $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath)); - $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner); - } - } - - $mounts = Filesystem::getMountManager()->findIn($this->fakeRoot); - foreach ($mounts as $mount) { - $mountPoint = $mount->getMountPoint(); - $storage = $mount->getStorage(); - if ($storage) { - $cache = $storage->getCache(''); - - $relativeMountPoint = substr($mountPoint, $rootLength); - $results = call_user_func_array(array($cache, $method), $args); - if ($results) { - foreach ($results as $result) { - $internalPath = $result['path']; - $result['path'] = rtrim($relativeMountPoint . $result['path'], '/'); - $path = rtrim($mountPoint . $internalPath, '/'); - $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath)); - $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner); - } - } - } - } - } - return $files; - } - - /** - * Get the owner for a file or folder - * - * @param string $path - * @return string the user id of the owner - * @throws NotFoundException - */ - public function getOwner($path) { - $info = $this->getFileInfo($path); - if (!$info) { - throw new NotFoundException($path . ' not found while trying to get owner'); - } - return $info->getOwner()->getUID(); - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path) { - /** - * @var Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = $this->resolvePath($path); - if ($storage) { - return $storage->getETag($internalPath); - } else { - return null; - } - } - - /** - * Get the path of a file by id, relative to the view - * - * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file - * - * @param int $id - * @throws NotFoundException - * @return string - */ - public function getPath($id) { - $id = (int)$id; - $manager = Filesystem::getMountManager(); - $mounts = $manager->findIn($this->fakeRoot); - $mounts[] = $manager->find($this->fakeRoot); - // reverse the array so we start with the storage this view is in - // which is the most likely to contain the file we're looking for - $mounts = array_reverse($mounts); - foreach ($mounts as $mount) { - /** - * @var \OC\Files\Mount\MountPoint $mount - */ - if ($mount->getStorage()) { - $cache = $mount->getStorage()->getCache(); - $internalPath = $cache->getPathById($id); - if (is_string($internalPath)) { - $fullPath = $mount->getMountPoint() . $internalPath; - if (!is_null($path = $this->getRelativePath($fullPath))) { - return $path; - } - } - } - } - throw new NotFoundException(sprintf('File with id "%s" has not been found.', $id)); - } - - /** - * @param string $path - * @throws InvalidPathException - */ - private function assertPathLength($path) { - $maxLen = min(PHP_MAXPATHLEN, 4000); - // Check for the string length - performed using isset() instead of strlen() - // because isset() is about 5x-40x faster. - if (isset($path[$maxLen])) { - $pathLen = strlen($path); - throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path"); - } - } - - /** - * check if it is allowed to move a mount point to a given target. - * It is not allowed to move a mount point into a different mount point or - * into an already shared folder - * - * @param string $target path - * @return boolean - */ - private function isTargetAllowed($target) { - - list($targetStorage, $targetInternalPath) = \OC\Files\Filesystem::resolvePath($target); - if (!$targetStorage->instanceOfStorage('\OCP\Files\IHomeStorage')) { - \OCP\Util::writeLog('files', - 'It is not allowed to move one mount point into another one', - \OCP\Util::DEBUG); - return false; - } - - // note: cannot use the view because the target is already locked - $fileId = (int)$targetStorage->getCache()->getId($targetInternalPath); - if ($fileId === -1) { - // target might not exist, need to check parent instead - $fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath)); - } - - // check if any of the parents were shared by the current owner (include collections) - $shares = \OCP\Share::getItemShared( - 'folder', - $fileId, - \OCP\Share::FORMAT_NONE, - null, - true - ); - - if (count($shares) > 0) { - \OCP\Util::writeLog('files', - 'It is not allowed to move one mount point into a shared folder', - \OCP\Util::DEBUG); - return false; - } - - return true; - } - - /** - * Get a fileinfo object for files that are ignored in the cache (part files) - * - * @param string $path - * @return \OCP\Files\FileInfo - */ - private function getPartFileInfo($path) { - $mount = $this->getMount($path); - $storage = $mount->getStorage(); - $internalPath = $mount->getInternalPath($this->getAbsolutePath($path)); - $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath)); - return new FileInfo( - $this->getAbsolutePath($path), - $storage, - $internalPath, - [ - 'fileid' => null, - 'mimetype' => $storage->getMimeType($internalPath), - 'name' => basename($path), - 'etag' => null, - 'size' => $storage->filesize($internalPath), - 'mtime' => $storage->filemtime($internalPath), - 'encrypted' => false, - 'permissions' => \OCP\Constants::PERMISSION_ALL - ], - $mount, - $owner - ); - } - - /** - * @param string $path - * @param string $fileName - * @throws InvalidPathException - */ - public function verifyPath($path, $fileName) { - - $l10n = \OC::$server->getL10N('lib'); - - // verify empty and dot files - $trimmed = trim($fileName); - if ($trimmed === '') { - throw new InvalidPathException($l10n->t('Empty filename is not allowed')); - } - if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) { - throw new InvalidPathException($l10n->t('Dot files are not allowed')); - } - - // verify database - e.g. mysql only 3-byte chars - if (preg_match('%(?: - \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 - | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 - | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 -)%xs', $fileName)) { - throw new InvalidPathException($l10n->t('4-byte characters are not supported in file names')); - } - - try { - /** @type \OCP\Files\Storage $storage */ - list($storage, $internalPath) = $this->resolvePath($path); - $storage->verifyPath($internalPath, $fileName); - } catch (ReservedWordException $ex) { - throw new InvalidPathException($l10n->t('File name is a reserved word')); - } catch (InvalidCharacterInPathException $ex) { - throw new InvalidPathException($l10n->t('File name contains at least one invalid character')); - } catch (FileNameTooLongException $ex) { - throw new InvalidPathException($l10n->t('File name is too long')); - } - } - - /** - * get all parent folders of $path - * - * @param string $path - * @return string[] - */ - private function getParents($path) { - $path = trim($path, '/'); - if (!$path) { - return []; - } - - $parts = explode('/', $path); - - // remove the single file - array_pop($parts); - $result = array('/'); - $resultPath = ''; - foreach ($parts as $part) { - if ($part) { - $resultPath .= '/' . $part; - $result[] = $resultPath; - } - } - return $result; - } - - /** - * Returns the mount point for which to lock - * - * @param string $absolutePath absolute path - * @param bool $useParentMount true to return parent mount instead of whatever - * is mounted directly on the given path, false otherwise - * @return \OC\Files\Mount\MountPoint mount point for which to apply locks - */ - private function getMountForLock($absolutePath, $useParentMount = false) { - $results = []; - $mount = Filesystem::getMountManager()->find($absolutePath); - if (!$mount) { - return $results; - } - - if ($useParentMount) { - // find out if something is mounted directly on the path - $internalPath = $mount->getInternalPath($absolutePath); - if ($internalPath === '') { - // resolve the parent mount instead - $mount = Filesystem::getMountManager()->find(dirname($absolutePath)); - } - } - - return $mount; - } - - /** - * Lock the given path - * - * @param string $path the path of the file to lock, relative to the view - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage - * - * @return bool False if the path is excluded from locking, true otherwise - * @throws \OCP\Lock\LockedException if the path is already locked - */ - private function lockPath($path, $type, $lockMountPoint = false) { - $absolutePath = $this->getAbsolutePath($path); - $absolutePath = Filesystem::normalizePath($absolutePath); - if (!$this->shouldLockFile($absolutePath)) { - return false; - } - - $mount = $this->getMountForLock($absolutePath, $lockMountPoint); - if ($mount) { - try { - $storage = $mount->getStorage(); - if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $storage->acquireLock( - $mount->getInternalPath($absolutePath), - $type, - $this->lockingProvider - ); - } - } catch (\OCP\Lock\LockedException $e) { - // rethrow with the a human-readable path - throw new \OCP\Lock\LockedException( - $this->getPathRelativeToFiles($absolutePath), - $e - ); - } - } - - return true; - } - - /** - * Change the lock type - * - * @param string $path the path of the file to lock, relative to the view - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage - * - * @return bool False if the path is excluded from locking, true otherwise - * @throws \OCP\Lock\LockedException if the path is already locked - */ - public function changeLock($path, $type, $lockMountPoint = false) { - $path = Filesystem::normalizePath($path); - $absolutePath = $this->getAbsolutePath($path); - $absolutePath = Filesystem::normalizePath($absolutePath); - if (!$this->shouldLockFile($absolutePath)) { - return false; - } - - $mount = $this->getMountForLock($absolutePath, $lockMountPoint); - if ($mount) { - try { - $storage = $mount->getStorage(); - if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $storage->changeLock( - $mount->getInternalPath($absolutePath), - $type, - $this->lockingProvider - ); - } - } catch (\OCP\Lock\LockedException $e) { - // rethrow with the a human-readable path - throw new \OCP\Lock\LockedException( - $this->getPathRelativeToFiles($absolutePath), - $e - ); - } - } - - return true; - } - - /** - * Unlock the given path - * - * @param string $path the path of the file to unlock, relative to the view - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage - * - * @return bool False if the path is excluded from locking, true otherwise - */ - private function unlockPath($path, $type, $lockMountPoint = false) { - $absolutePath = $this->getAbsolutePath($path); - $absolutePath = Filesystem::normalizePath($absolutePath); - if (!$this->shouldLockFile($absolutePath)) { - return false; - } - - $mount = $this->getMountForLock($absolutePath, $lockMountPoint); - if ($mount) { - $storage = $mount->getStorage(); - if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { - $storage->releaseLock( - $mount->getInternalPath($absolutePath), - $type, - $this->lockingProvider - ); - } - } - - return true; - } - - /** - * Lock a path and all its parents up to the root of the view - * - * @param string $path the path of the file to lock relative to the view - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage - * - * @return bool False if the path is excluded from locking, true otherwise - */ - public function lockFile($path, $type, $lockMountPoint = false) { - $absolutePath = $this->getAbsolutePath($path); - $absolutePath = Filesystem::normalizePath($absolutePath); - if (!$this->shouldLockFile($absolutePath)) { - return false; - } - - $this->lockPath($path, $type, $lockMountPoint); - - $parents = $this->getParents($path); - foreach ($parents as $parent) { - $this->lockPath($parent, ILockingProvider::LOCK_SHARED); - } - - return true; - } - - /** - * Unlock a path and all its parents up to the root of the view - * - * @param string $path the path of the file to lock relative to the view - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage - * - * @return bool False if the path is excluded from locking, true otherwise - */ - public function unlockFile($path, $type, $lockMountPoint = false) { - $absolutePath = $this->getAbsolutePath($path); - $absolutePath = Filesystem::normalizePath($absolutePath); - if (!$this->shouldLockFile($absolutePath)) { - return false; - } - - $this->unlockPath($path, $type, $lockMountPoint); - - $parents = $this->getParents($path); - foreach ($parents as $parent) { - $this->unlockPath($parent, ILockingProvider::LOCK_SHARED); - } - - return true; - } - - /** - * Only lock files in data/user/files/ - * - * @param string $path Absolute path to the file/folder we try to (un)lock - * @return bool - */ - protected function shouldLockFile($path) { - $path = Filesystem::normalizePath($path); - - $pathSegments = explode('/', $path); - if (isset($pathSegments[2])) { - // E.g.: /username/files/path-to-file - return ($pathSegments[2] === 'files') && (count($pathSegments) > 3); - } - - return true; - } - - /** - * Shortens the given absolute path to be relative to - * "$user/files". - * - * @param string $absolutePath absolute path which is under "files" - * - * @return string path relative to "files" with trimmed slashes or null - * if the path was NOT relative to files - * - * @throws \InvalidArgumentException if the given path was not under "files" - * @since 8.1.0 - */ - public function getPathRelativeToFiles($absolutePath) { - $path = Filesystem::normalizePath($absolutePath); - $parts = explode('/', trim($path, '/'), 3); - // "$user", "files", "path/to/dir" - if (!isset($parts[1]) || $parts[1] !== 'files') { - throw new \InvalidArgumentException('$absolutePath must be relative to "files"'); - } - if (isset($parts[2])) { - return $parts[2]; - } - return ''; - } - - /** - * @param string $filename - * @return array - * @throws \OC\User\NoUserException - * @throws NotFoundException - */ - public function getUidAndFilename($filename) { - $info = $this->getFileInfo($filename); - if (!$info instanceof \OCP\Files\FileInfo) { - throw new NotFoundException($this->getAbsolutePath($filename) . ' not found'); - } - $uid = $info->getOwner()->getUID(); - if ($uid != \OCP\User::getUser()) { - Filesystem::initMountPoints($uid); - $ownerView = new View('/' . $uid . '/files'); - try { - $filename = $ownerView->getPath($info['fileid']); - } catch (NotFoundException $e) { - throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid); - } - } - return [$uid, $filename]; - } -} |