Merge pull request #20898 from owncloud/cache-interfaces

Public Cache interfaces
This commit is contained in:
Thomas Müller 2016-01-15 12:02:31 +01:00
commit 52040a3f23
37 changed files with 1495 additions and 142 deletions

View File

@ -135,9 +135,8 @@ class ObjectTree extends \Sabre\DAV\Tree {
/**
* @var \OC\Files\Storage\Storage $storage
*/
$scanner = $storage->getScanner($internalPath);
// get data directly
$data = $scanner->getData($internalPath);
$data = $storage->getMetaData($internalPath);
$info = new FileInfo($absPath, $storage, $internalPath, $data, $mount);
} else {
$info = null;

View File

@ -33,6 +33,7 @@
namespace OC\Files\Cache;
use OC\User\NoUserException;
use OCP\Files\Cache\ICacheEntry;
use OCP\Share_Backend_Collection;
/**
@ -98,8 +99,8 @@ class Shared_Cache extends Cache {
/**
* get the stored metadata of a file or folder
*
* @param string $file
* @return array|false
* @param string|int $file
* @return ICacheEntry|false
*/
public function get($file) {
$mimetypeLoader = \OC::$server->getMimeTypeLoader();
@ -161,7 +162,7 @@ class Shared_Cache extends Cache {
* get the metadata of all files stored in $folder
*
* @param string $folderId
* @return array|false
* @return ICacheEntry[]|false
*/
public function getFolderContentsById($folderId) {
$cache = $this->getSourceCache('');
@ -281,7 +282,7 @@ class Shared_Cache extends Cache {
* search for files matching $pattern
*
* @param string $pattern
* @return array of file data
* @return ICacheEntry[] of file data
*/
public function search($pattern) {
@ -320,7 +321,7 @@ class Shared_Cache extends Cache {
* search for files by mimetype
*
* @param string $mimetype
* @return array
* @return ICacheEntry[]
*/
public function searchByMime($mimetype) {
$mimepart = null;
@ -373,7 +374,7 @@ class Shared_Cache extends Cache {
*
* @param string|int $tag tag to search for
* @param string $userId owner of the tags
* @return array file data
* @return ICacheEntry[] file data
*/
public function searchByTag($tag, $userId) {
// TODO: inject this

View File

@ -35,7 +35,7 @@ class SharedScanner extends Scanner {
*
* @return array an array of metadata of the file
*/
public function getData($path){
protected function getData($path){
$data = parent::getData($path);
$sourcePath = $this->storage->getSourcePath($path);
list($sourceStorage, $internalPath) = \OC\Files\Filesystem::resolvePath($sourcePath);

View File

@ -24,6 +24,7 @@
*/
namespace OC\Files\Cache;
use OCP\Files\Cache\ICacheEntry;
/**
* check the storage backends for updates and change the cache accordingly
@ -38,7 +39,7 @@ class Shared_Watcher extends Watcher {
* Update the cache for changes to $path
*
* @param string $path
* @param array $cachedData
* @param ICacheEntry $cachedData
*/
public function update($path, $cachedData) {
parent::update($path, $cachedData);

View File

@ -58,8 +58,10 @@ class Test_Files_Sharing_Backend extends TestCase {
}
protected function tearDown() {
$this->view->unlink($this->filename);
$this->view->deleteAll($this->folder);
if ($this->view) {
$this->view->unlink($this->filename);
$this->view->deleteAll($this->folder);
}
parent::tearDown();
}

View File

@ -75,7 +75,9 @@ class Cache extends TestCase {
}
protected function tearDown() {
$this->cache->clear();
if ($this->cache) {
$this->cache->clear();
}
parent::tearDown();
}

View File

@ -48,8 +48,10 @@ class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase {
}
protected function tearDown() {
$this->view->unlink($this->folder);
$this->view->unlink($this->filename);
if ($this->view) {
$this->view->unlink($this->folder);
$this->view->unlink($this->filename);
}
parent::tearDown();
}

View File

@ -52,8 +52,10 @@ class Test_Files_Sharing_Updater extends OCA\Files_Sharing\Tests\TestCase {
}
protected function tearDown() {
$this->view->unlink($this->filename);
$this->view->deleteAll($this->folder);
if ($this->view) {
$this->view->unlink($this->filename);
$this->view->deleteAll($this->folder);
}
parent::tearDown();
}

View File

@ -88,13 +88,15 @@ class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileinfo = $this->view->getFileInfo('container/shareddir');
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2);
if ($this->view) {
$fileinfo = $this->view->getFileInfo('container/shareddir');
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2);
$this->view->deleteAll('container');
$this->view->deleteAll('container');
$this->ownerCache->clear();
$this->ownerCache->clear();
}
parent::tearDown();
}

View File

@ -86,10 +86,12 @@ class Test_Files_Versioning extends \Test\TestCase {
}
protected function tearDown() {
$this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/');
$this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/');
$this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/');
$this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/');
if ($this->rootView) {
$this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/');
$this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/');
$this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/');
$this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/');
}
\OC_Hook::clear();

View File

@ -33,6 +33,8 @@
namespace OC\Files\Cache;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\ICacheEntry;
use \OCP\Files\IMimeTypeLoader;
use OCP\IDBConnection;
@ -46,12 +48,7 @@ use OCP\IDBConnection;
* - 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 {
const NOT_FOUND = 0;
const PARTIAL = 1; //only partial data available, file not cached in the database
const SHALLOW = 2; //folder in cache, but not all child files are completely scanned
const COMPLETE = 3;
class Cache implements ICache {
/**
* @var array partial data for the cache
*/
@ -105,28 +102,8 @@ class Cache {
/**
* get the stored metadata of a file or folder
*
* the returned cache entry contains at least the following values:
* [
* 'fileid' => int, the numeric id of a file (see getId)
* 'storage' => int, the numeric id of the storage the file is stored on
* 'path' => string, the path of the file within the storage ('foo/bar.txt')
* 'name' => string, the basename of a file ('bar.txt)
* 'mimetype' => string, the full mimetype of the file ('text/plain')
* 'mimepart' => string, the first half of the mimetype ('text')
* 'size' => int, the size of the file or folder in bytes
* 'mtime' => int, the last modified date of the file as unix timestamp as shown in the ui
* 'storage_mtime' => int, the last modified date of the file as unix timestamp as stored on the storage
* Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently
* This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed
* 'etag' => string, the etag for the file
* An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes
* Etag for folders change whenever a file in the folder has changed
* 'permissions' int, the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE
* \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE
* ]
*
* @param string | int $file either the path of a file or folder or the file id for a file or folder
* @return array|false the cache entry as array of false if the file is not found in the cache
* @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 == '') {
@ -156,6 +133,7 @@ class Cache {
if (isset($this->partial[$file])) {
$data = $this->partial[$file];
}
return $data;
} else {
//fix types
$data['fileid'] = (int)$data['fileid'];
@ -171,16 +149,15 @@ class Cache {
$data['storage_mtime'] = $data['mtime'];
}
$data['permissions'] = (int)$data['permissions'];
return new CacheEntry($data);
}
return $data;
}
/**
* get the metadata of all files stored in $folder
*
* @param string $folder
* @return array
* @return ICacheEntry[]
*/
public function getFolderContents($folder) {
$fileId = $this->getId($folder);
@ -191,7 +168,7 @@ class Cache {
* get the metadata of all files stored in $folder
*
* @param int $fileId the file id of the folder
* @return array
* @return ICacheEntry[]
*/
public function getFolderContentsById($fileId) {
if ($fileId > -1) {
@ -211,7 +188,9 @@ class Cache {
$file['storage_mtime'] = (int)$file['storage_mtime'];
$file['size'] = 0 + $file['size'];
}
return $files;
return array_map(function (array $data) {
return new CacheEntry($data);
}, $files);
} else {
return array();
}
@ -392,7 +371,7 @@ class Cache {
return -1;
} else {
$parent = $this->getParentPath($file);
return (int) $this->getId($parent);
return (int)$this->getId($parent);
}
}
@ -481,12 +460,12 @@ class Cache {
/**
* Move a file or folder in the cache
*
* @param \OC\Files\Cache\Cache $sourceCache
* @param \OCP\Files\Cache\ICache $sourceCache
* @param string $sourcePath
* @param string $targetPath
* @throws \OC\DatabaseException
*/
public function moveFromCache(Cache $sourceCache, $sourcePath, $targetPath) {
public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
// normalize source and target
$sourcePath = $this->normalize($sourcePath);
$targetPath = $this->normalize($targetPath);
@ -571,7 +550,7 @@ class Cache {
* search for files matching $pattern
*
* @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%')
* @return array an array of cache entries where the name matches the search pattern
* @return ICacheEntry[] an array of cache entries where the name matches the search pattern
*/
public function search($pattern) {
// normalize pattern
@ -594,7 +573,9 @@ class Cache {
$row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
$files[] = $row;
}
return $files;
return array_map(function(array $data) {
return new CacheEntry($data);
}, $files);
}
/**
@ -602,7 +583,7 @@ class Cache {
*
* @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 array an array of cache entries where the mimetype matches the search
* @return ICacheEntry[] an array of cache entries where the mimetype matches the search
*/
public function searchByMime($mimetype) {
if (strpos($mimetype, '/')) {
@ -620,7 +601,9 @@ class Cache {
$row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
$files[] = $row;
}
return $files;
return array_map(function (array $data) {
return new CacheEntry($data);
}, $files);
}
/**
@ -630,7 +613,7 @@ class Cache {
*
* @param string|int $tag name or tag id
* @param string $userId owner of the tags
* @return array file data
* @return ICacheEntry[] file data
*/
public function searchByTag($tag, $userId) {
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
@ -665,7 +648,9 @@ class Cache {
while ($row = $result->fetch()) {
$files[] = $row;
}
return $files;
return array_map(function (array $data) {
return new CacheEntry($data);
}, $files);
}
/**

114
lib/private/files/cache/cacheentry.php vendored Normal file
View File

@ -0,0 +1,114 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>>
*
* @copyright Copyright (c) 2015, 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;
}
}

View File

@ -26,6 +26,8 @@
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
@ -67,7 +69,7 @@ class HomeCache extends Cache {
/**
* @param string $path
* @return array
* @return ICacheEntry
*/
public function get($path) {
$data = parent::get($path);

View File

@ -21,10 +21,12 @@
namespace OC\Files\Cache;
use OCP\Files\Cache\IPropagator;
/**
* Propagate etags and mtimes within the storage
*/
class Propagator {
class Propagator implements IPropagator {
/**
* @var \OC\Files\Storage\Storage
*/
@ -41,7 +43,7 @@ class Propagator {
/**
* @param string $internalPath
* @param int $time
* @return array[] all propagated entries
* @return array[] all propagated cache entries
*/
public function propagateChange($internalPath, $time) {
$cache = $this->storage->getCache($internalPath);

View File

@ -37,6 +37,8 @@ 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;
/**
@ -50,7 +52,7 @@ use OCP\Lock\ILockingProvider;
*
* @package OC\Files\Cache
*/
class Scanner extends BasicEmitter {
class Scanner extends BasicEmitter implements IScanner {
/**
* @var \OC\Files\Storage\Storage $storage
*/
@ -81,12 +83,6 @@ class Scanner extends BasicEmitter {
*/
protected $lockingProvider;
const SCAN_RECURSIVE = true;
const SCAN_SHALLOW = false;
const REUSE_ETAG = 1;
const REUSE_SIZE = 2;
public function __construct(\OC\Files\Storage\Storage $storage) {
$this->storage = $storage;
$this->storageId = $this->storage->getId();
@ -112,7 +108,7 @@ class Scanner extends BasicEmitter {
* @param string $path
* @return array an array of metadata of the file
*/
public function getData($path) {
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);
@ -137,7 +133,9 @@ class Scanner extends BasicEmitter {
and !Filesystem::isFileBlacklisted($file)
) {
if ($lock) {
$this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
}
}
$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));
@ -160,6 +158,7 @@ class Scanner extends BasicEmitter {
$data['parent'] = $parentId;
}
if (is_null($cacheData)) {
/** @var CacheEntry $cacheData */
$cacheData = $this->cache->get($file);
}
if ($cacheData and $reuseExisting and isset($cacheData['fileid'])) {
@ -182,7 +181,7 @@ class Scanner extends BasicEmitter {
}
}
// Only update metadata that has changed
$newData = array_diff_assoc($data, $cacheData);
$newData = array_diff_assoc($data, $cacheData->getData());
} else {
$newData = $data;
$fileId = -1;
@ -196,7 +195,9 @@ class Scanner extends BasicEmitter {
$this->removeFromCache($file);
}
if ($lock) {
$this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
}
}
return $data;
}
@ -263,7 +264,9 @@ class Scanner extends BasicEmitter {
$reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
}
if ($lock) {
$this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
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') {
@ -271,7 +274,9 @@ class Scanner extends BasicEmitter {
$data['size'] = $size;
}
if ($lock) {
$this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
}
}
return $data;
}

View File

@ -24,12 +24,14 @@
*/
namespace OC\Files\Cache;
use OCP\Files\Cache\IUpdater;
use OCP\Files\Storage\IStorage;
/**
* Update the cache and propagate changes
*
*/
class Updater {
class Updater implements IUpdater {
/**
* @var bool
*/
@ -145,18 +147,18 @@ class Updater {
/**
* Rename a file or folder in the cache and update the size, etag and mtime of the parent folders
*
* @param \OC\Files\Storage\Storage $sourceStorage
* @param IStorage $sourceStorage
* @param string $source
* @param string $target
*/
public function renameFromStorage(\OC\Files\Storage\Storage $sourceStorage, $source, $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($source);
$sourceCache = $sourceStorage->getCache();
$sourceUpdater = $sourceStorage->getUpdater();
$sourcePropagator = $sourceStorage->getPropagator();
@ -181,7 +183,9 @@ class Updater {
$sourceCache->correctFolderSize($source);
$this->cache->correctFolderSize($target);
$sourceUpdater->correctParentStorageMtime($source);
if ($sourceUpdater instanceof Updater) {
$sourceUpdater->correctParentStorageMtime($source);
}
$this->correctParentStorageMtime($target);
$this->updateStorageMTimeOnly($target);
$sourcePropagator->propagateChange($source, $time);
@ -205,7 +209,7 @@ class Updater {
*
* @param string $internalPath
*/
public function correctParentStorageMtime($internalPath) {
private function correctParentStorageMtime($internalPath) {
$parentId = $this->cache->getParentId($internalPath);
$parent = dirname($internalPath);
if ($parentId != -1) {

View File

@ -22,14 +22,13 @@
*/
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 {
const CHECK_NEVER = 0; // never check the underlying filesystem for updates
const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file
const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates
class Watcher implements IWatcher {
protected $watchPolicy = self::CHECK_ONCE;
@ -77,7 +76,7 @@ class Watcher {
* check $path for updates and update if needed
*
* @param string $path
* @param array $cachedEntry
* @param ICacheEntry|null $cachedEntry
* @return boolean true if path was updated
*/
public function checkUpdate($path, $cachedEntry = null) {
@ -96,7 +95,7 @@ class Watcher {
* Update the cache for changes to $path
*
* @param string $path
* @param array $cachedData
* @param ICacheEntry $cachedData
*/
public function update($path, $cachedData) {
if ($this->storage->is_dir($path)) {
@ -114,7 +113,7 @@ class Watcher {
* Check if the cache for $path needs to be updated
*
* @param string $path
* @param array $cachedData
* @param ICacheEntry $cachedData
* @return bool
*/
public function needsUpdate($path, $cachedData) {

View File

@ -25,6 +25,7 @@
namespace OC\Files\Cache\Wrapper;
use OC\Files\Cache\Cache;
use OCP\Files\Cache\ICacheEntry;
class CacheWrapper extends Cache {
/**
@ -42,8 +43,8 @@ class CacheWrapper extends Cache {
/**
* Make it easy for wrappers to modify every returned cache entry
*
* @param array $entry
* @return array
* @param ICacheEntry $entry
* @return ICacheEntry
*/
protected function formatCacheEntry($entry) {
return $entry;
@ -53,7 +54,7 @@ class CacheWrapper extends Cache {
* get the stored metadata of a file or folder
*
* @param string /int $file
* @return array|false
* @return ICacheEntry|false
*/
public function get($file) {
$result = $this->cache->get($file);
@ -67,7 +68,7 @@ class CacheWrapper extends Cache {
* get the metadata of all files stored in $folder
*
* @param string $folder
* @return array
* @return ICacheEntry[]
*/
public function getFolderContents($folder) {
// cant do a simple $this->cache->.... call here since getFolderContentsById needs to be called on this
@ -178,7 +179,7 @@ class CacheWrapper extends Cache {
* search for files matching $pattern
*
* @param string $pattern
* @return array an array of file data
* @return ICacheEntry[] an array of file data
*/
public function search($pattern) {
$results = $this->cache->search($pattern);
@ -189,7 +190,7 @@ class CacheWrapper extends Cache {
* search for files by mimetype
*
* @param string $mimetype
* @return array
* @return ICacheEntry[]
*/
public function searchByMime($mimetype) {
$results = $this->cache->searchByMime($mimetype);
@ -201,7 +202,7 @@ class CacheWrapper extends Cache {
*
* @param string|int $tag name or tag id
* @param string $userId owner of the tags
* @return array file data
* @return ICacheEntry[] file data
*/
public function searchByTag($tag, $userId) {
$results = $this->cache->searchByTag($tag, $userId);

View File

@ -29,6 +29,7 @@
namespace OC\Files;
use OCP\Files\Cache\ICacheEntry;
use OCP\IUser;
class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
@ -71,7 +72,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @param string|boolean $path
* @param Storage\Storage $storage
* @param string $internalPath
* @param array $data
* @param array|ICacheEntry $data
* @param \OCP\Files\Mount\IMountPoint $mount
* @param \OCP\IUser|null $owner
*/

View File

@ -25,6 +25,7 @@
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 {
@ -192,7 +193,12 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
public function stat($path) {
$path = $this->normalizePath($path);
return $this->getCache()->get($path);
$cacheEntry = $this->getCache()->get($path);
if ($cacheEntry instanceof CacheEntry) {
return $cacheEntry->getData();
} else {
return false;
}
}
/**

View File

@ -46,6 +46,7 @@ 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;
/**
@ -59,7 +60,7 @@ use OCP\Lock\ILockingProvider;
* 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 {
abstract class Common implements Storage, ILockingStorage {
use LocalTempFileTrait;

View File

@ -28,6 +28,7 @@ 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;
@ -123,13 +124,14 @@ class Encryption extends Wrapper {
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
$info['encrypted'] = true;
$info['size'] = $size;
$this->getCache()->put($path, $info);
$this->getCache()->put($path, $info->getData());
return $size;
}

View File

@ -25,6 +25,8 @@
namespace OC\Files\Storage\Wrapper;
use OCP\Files\Cache\ICacheEntry;
class Quota extends Wrapper {
/**
@ -64,7 +66,7 @@ class Quota extends Wrapper {
$cache = $storage->getCache();
}
$data = $cache->get($path);
if (is_array($data) and isset($data['size'])) {
if ($data instanceof ICacheEntry and isset($data['size'])) {
return $data['size'];
} else {
return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;

View File

@ -26,9 +26,10 @@
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 {
class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage {
/**
* @var \OC\Files\Storage\Storage $storage
*/
@ -583,7 +584,9 @@ class Wrapper implements \OC\Files\Storage\Storage {
* @throws \OCP\Lock\LockedException
*/
public function acquireLock($path, $type, ILockingProvider $provider) {
$this->storage->acquireLock($path, $type, $provider);
if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->storage->acquireLock($path, $type, $provider);
}
}
/**
@ -592,7 +595,9 @@ class Wrapper implements \OC\Files\Storage\Storage {
* @param \OCP\Lock\ILockingProvider $provider
*/
public function releaseLock($path, $type, ILockingProvider $provider) {
$this->storage->releaseLock($path, $type, $provider);
if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->storage->releaseLock($path, $type, $provider);
}
}
/**
@ -601,6 +606,8 @@ class Wrapper implements \OC\Files\Storage\Storage {
* @param \OCP\Lock\ILockingProvider $provider
*/
public function changeLock($path, $type, ILockingProvider $provider) {
$this->storage->changeLock($path, $type, $provider);
if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$this->storage->changeLock($path, $type, $provider);
}
}
}

View File

@ -43,15 +43,16 @@
namespace OC\Files;
use Icewind\Streams\CallbackWrapper;
use OC\Files\Cache\Updater;
use OC\Files\Mount\MoveableMount;
use OC\Files\Storage\Storage;
use OC\User\User;
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;
@ -1274,7 +1275,7 @@ class View {
if ($storage) {
$data = $this->getCacheEntry($storage, $internalPath, $relativePath);
if (!is_array($data)) {
if (!$data instanceof ICacheEntry) {
return false;
}
@ -1334,7 +1335,7 @@ class View {
$data = $this->getCacheEntry($storage, $internalPath, $directory);
if (!is_array($data) || !isset($data['fileid'])) {
if (!$data instanceof ICacheEntry || !isset($data['fileid'])) {
return [];
}
@ -1345,7 +1346,7 @@ class View {
/**
* @var \OC\Files\FileInfo[] $files
*/
$files = array_map(function (array $content) use ($path, $storage, $mount, $sharingDisabled) {
$files = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
if ($sharingDisabled) {
$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
}
@ -1834,11 +1835,14 @@ class View {
$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
if ($mount) {
try {
$mount->getStorage()->acquireLock(
$mount->getInternalPath($absolutePath),
$type,
$this->lockingProvider
);
$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(
@ -1872,11 +1876,14 @@ class View {
$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
if ($mount) {
try {
$mount->getStorage()->changeLock(
$mount->getInternalPath($absolutePath),
$type,
$this->lockingProvider
);
$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(
@ -1907,11 +1914,14 @@ class View {
$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
if ($mount) {
$mount->getStorage()->releaseLock(
$mount->getInternalPath($absolutePath),
$type,
$this->lockingProvider
);
$storage = $mount->getStorage();
if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
$storage->releaseLock(
$mount->getInternalPath($absolutePath),
$type,
$this->lockingProvider
);
}
}
return true;

249
lib/public/files/cache/icache.php vendored Normal file
View File

@ -0,0 +1,249 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>>
*
* @copyright Copyright (c) 2015, 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 OCP\Files\Cache;
/**
* 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
*
* @since 9.0.0
*/
interface ICache {
const NOT_FOUND = 0;
const PARTIAL = 1; //only partial data available, file not cached in the database
const SHALLOW = 2; //folder in cache, but not all child files are completely scanned
const COMPLETE = 3;
/**
* Get the numeric storage id for this cache's storage
*
* @return int
* @since 9.0.0
*/
public function getNumericStorageId();
/**
* 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 or false if the file is not found in the cache
* @since 9.0.0
*/
public function get($file);
/**
* get the metadata of all files stored in $folder
*
* @param string $folder
* @return ICacheEntry[]
* @since 9.0.0
*/
public function getFolderContents($folder);
/**
* get the metadata of all files stored in $folder
*
* @param int $fileId the file id of the folder
* @return ICacheEntry[]
* @since 9.0.0
*/
public function getFolderContentsById($fileId);
/**
* store meta data for a file or folder
*
* @param string $file
* @param array $data
*
* @return int file id
* @throws \RuntimeException
* @since 9.0.0
*/
public function put($file, array $data);
/**
* 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
* @since 9.0.0
*/
public function update($id, array $data);
/**
* 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
* @since 9.0.0
*/
public function getId($file);
/**
* get the id of the parent folder of a file
*
* @param string $file
* @return int
* @since 9.0.0
*/
public function getParentId($file);
/**
* check if a file is available in the cache
*
* @param string $file
* @return bool
* @since 9.0.0
*/
public function inCache($file);
/**
* 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
* @since 9.0.0
*/
public function remove($file);
/**
* Move a file or folder in the cache
*
* @param string $source
* @param string $target
* @since 9.0.0
*/
public function move($source, $target);
/**
* Move a file or folder in the cache
*
* @param \OCP\Files\Cache\ICache $sourceCache
* @param string $sourcePath
* @param string $targetPath
* @throws \OC\DatabaseException
* @since 9.0.0
*/
public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath);
/**
* remove all entries for files that are stored on the storage from the cache
*
* @since 9.0.0
*/
public function clear();
/**
* Get the scan status of a file
*
* - ICache::NOT_FOUND: File is not in the cache
* - ICache::PARTIAL: File is not stored in the cache but some incomplete data is known
* - ICache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned
* - ICache::COMPLETE: The file or folder, with all it's children) are fully scanned
*
* @param string $file
*
* @return int ICache::NOT_FOUND, ICache::PARTIAL, ICache::SHALLOW or ICache::COMPLETE
* @since 9.0.0
*/
public function getStatus($file);
/**
* 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
* @since 9.0.0
*/
public function search($pattern);
/**
* 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
* @since 9.0.0
*/
public function searchByMime($mimetype);
/**
* 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
* @since 9.0.0
*/
public function searchByTag($tag, $userId);
/**
* get all file ids on the files on the storage
*
* @return int[]
* @since 9.0.0
*/
public function 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
* @since 9.0.0
*/
public function getIncomplete();
/**
* 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
* @since 9.0.0
*/
public function getPathById($id);
/**
* normalize the given path for usage in the cache
*
* @param string $path
* @return string
* @since 9.0.0
*/
public function normalize($path);
}

132
lib/public/files/cache/icacheentry.php vendored Normal file
View File

@ -0,0 +1,132 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>>
*
* @copyright Copyright (c) 2015, 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 OCP\Files\Cache;
/**
* meta data for a file or folder
*
* @since 9.0.0
*/
interface ICacheEntry {
/**
* Get the numeric id of a file
*
* @return int
* @since 9.0.0
*/
public function getId();
/**
* Get the numeric id for the storage
*
* @return int
* @since 9.0.0
*/
public function getStorageId();
/**
* Get the path of the file relative to the storage root
*
* @return string
* @since 9.0.0
*/
public function getPath();
/**
* Get the file name
*
* @return string
* @since 9.0.0
*/
public function getName();
/**
* Get the full mimetype
*
* @return string
* @since 9.0.0
*/
public function getMimeType();
/**
* Get the first part of the mimetype
*
* @return string
* @since 9.0.0
*/
public function getMimePart();
/**
* Get the file size in bytes
*
* @return int
* @since 9.0.0
*/
public function getSize();
/**
* Get the last modified date as unix timestamp
*
* @return int
* @since 9.0.0
*/
public function getMTime();
/**
* Get the last modified date on the storage as unix timestamp
*
* Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently
* This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed
*
* @return int
* @since 9.0.0
*/
public function getStorageMTime();
/**
* Get the etag for the file
*
* An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes
* Etag for folders change whenever a file in the folder has changed
*
* @return string
* @since 9.0.0
*/
public function getEtag();
/**
* Get the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE
* \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE
*
* @return int
* @since 9.0.0
*/
public function getPermissions();
/**
* Check if the file is encrypted
*
* @return bool
* @since 9.0.0
*/
public function isEncrypted();
}

37
lib/public/files/cache/ipropagator.php vendored Normal file
View File

@ -0,0 +1,37 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>>
*
* @copyright Copyright (c) 2015, 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 OCP\Files\Cache;
/**
* Propagate etags and mtimes within the storage
*
* @since 9.0.0
*/
interface IPropagator {
/**
* @param string $internalPath
* @param int $time
* @return array[] all propagated cache entries
* @since 9.0.0
*/
public function propagateChange($internalPath, $time);
}

81
lib/public/files/cache/iscanner.php vendored Normal file
View File

@ -0,0 +1,81 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>>
*
* @copyright Copyright (c) 2015, 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 OCP\Files\Cache;
/**
* Scan files from the storage and save to the cache
*
* @since 9.0.0
*/
interface IScanner {
const SCAN_RECURSIVE = true;
const SCAN_SHALLOW = false;
const REUSE_ETAG = 1;
const REUSE_SIZE = 2;
/**
* 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
* @since 9.0.0
*/
public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true);
/**
* scan a folder and all its 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
* @since 9.0.0
*/
public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true);
/**
* 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
* @since 9.0.0
*/
public static function isPartialFile($file);
/**
* walk over any folders that are not fully scanned yet and scan them
*
* @since 9.0.0
*/
public function backgroundScan();
}

75
lib/public/files/cache/iupdater.php vendored Normal file
View File

@ -0,0 +1,75 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>>
*
* @copyright Copyright (c) 2015, 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 OCP\Files\Cache;
use OCP\Files\Storage\IStorage;
/**
* Update the cache and propagate changes
*
* @since 9.0.0
*/
interface IUpdater {
/**
* Get the propagator for etags and mtime for the view the updater works on
*
* @return IPropagator
* @since 9.0.0
*/
public function getPropagator();
/**
* 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
* @since 9.0.0
*/
public function propagate($path, $time = null);
/**
* Update the cache for $path and update the size, etag and mtime of the parent folders
*
* @param string $path
* @param int $time
* @since 9.0.0
*/
public function update($path, $time = null);
/**
* Remove $path from the cache and update the size, etag and mtime of the parent folders
*
* @param string $path
* @since 9.0.0
*/
public function remove($path);
/**
* 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
* @since 9.0.0
*/
public function renameFromStorage(IStorage $sourceStorage, $source, $target);
}

82
lib/public/files/cache/iwatcher.php vendored Normal file
View File

@ -0,0 +1,82 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>>
*
* @copyright Copyright (c) 2015, 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 OCP\Files\Cache;
/**
* check the storage backends for updates and change the cache accordingly
*
* @since 9.0.0
*/
interface IWatcher {
const CHECK_NEVER = 0; // never check the underlying filesystem for updates
const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file
const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates
/**
* @param int $policy either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS
* @since 9.0.0
*/
public function setPolicy($policy);
/**
* @return int either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS
* @since 9.0.0
*/
public function getPolicy();
/**
* check $path for updates and update if needed
*
* @param string $path
* @param ICacheEntry|null $cachedEntry
* @return boolean true if path was updated
* @since 9.0.0
*/
public function checkUpdate($path, $cachedEntry = null);
/**
* Update the cache for changes to $path
*
* @param string $path
* @param ICacheEntry $cachedData
* @since 9.0.0
*/
public function update($path, $cachedData);
/**
* Check if the cache for $path needs to be updated
*
* @param string $path
* @param ICacheEntry $cachedData
* @return bool
* @since 9.0.0
*/
public function needsUpdate($path, $cachedData);
/**
* remove deleted files in $path from the cache
*
* @param string $path
* @since 9.0.0
*/
public function cleanFolder($path);
}

View File

@ -33,16 +33,19 @@
// use OCP namespace for all classes that are considered public.
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP\Files;
use OCP\Files\InvalidPathException;
use OCP\Files\Storage\IStorage;
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.
*
* @since 6.0.0
* @deprecated 9.0.0 use \OCP\Files\Storage\IStorage instead
*/
interface Storage {
interface Storage extends IStorage {
/**
* $parameters is a free form array with the configuration options needed to construct the storage
*
@ -462,10 +465,4 @@ interface Storage {
* @param bool $isAvailable
*/
public function setAvailability($isAvailable);
/**
* @param $path path for which to retrieve the owner
* @since 9.0.0
*/
public function getOwner($path);
}

View File

@ -0,0 +1,60 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>
*
* @copyright Copyright (c) 2015, 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 OCP\Files\Storage;
use OCP\Lock\ILockingProvider;
/**
* Storage backends that require explicit locking
*
* Storage backends implementing this interface do not need to implement their own locking implementation but should use the provided lockingprovider instead
* The implementation of the locking methods only need to map internal storage paths to "lock keys"
*
* @since 9.0.0
*/
interface ILockingStorage {
/**
* @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
* @since 9.0.0
*/
public function acquireLock($path, $type, ILockingProvider $provider);
/**
* @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
* @since 9.0.0
*/
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
* @since 9.0.0
*/
public function changeLock($path, $type, ILockingProvider $provider);
}

View File

@ -0,0 +1,482 @@
<?php
/**
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Michael Roth <michael.roth@rz.uni-augsburg.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
* @copyright Copyright (c) 2015, 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/>
*
*/
/**
* Public interface of ownCloud for apps to use.
* Files/Storage interface
*/
// use OCP namespace for all classes that are considered public.
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP\Files\Storage;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\IPropagator;
use OCP\Files\Cache\IScanner;
use OCP\Files\Cache\IUpdater;
use OCP\Files\Cache\IWatcher;
use OCP\Files\InvalidPathException;
/**
* 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.
*
* @since 9.0.0
*/
interface IStorage {
/**
* $parameters is a free form array with the configuration options needed to construct the storage
*
* @param array $parameters
* @since 9.0.0
*/
public function __construct($parameters);
/**
* Get the identifier for the storage,
* the returned id should be the same for every storage object that is created with the same parameters
* and two storage objects with the same id should refer to two storages that display the same files.
*
* @return string
* @since 9.0.0
*/
public function getId();
/**
* see http://php.net/manual/en/function.mkdir.php
* implementations need to implement a recursive mkdir
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function mkdir($path);
/**
* see http://php.net/manual/en/function.rmdir.php
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function rmdir($path);
/**
* see http://php.net/manual/en/function.opendir.php
*
* @param string $path
* @return resource|false
* @since 9.0.0
*/
public function opendir($path);
/**
* see http://php.net/manual/en/function.is-dir.php
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function is_dir($path);
/**
* see http://php.net/manual/en/function.is-file.php
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function is_file($path);
/**
* see http://php.net/manual/en/function.stat.php
* only the following keys are required in the result: size and mtime
*
* @param string $path
* @return array|false
* @since 9.0.0
*/
public function stat($path);
/**
* see http://php.net/manual/en/function.filetype.php
*
* @param string $path
* @return string|false
* @since 9.0.0
*/
public function filetype($path);
/**
* see http://php.net/manual/en/function.filesize.php
* The result for filesize when called on a folder is required to be 0
*
* @param string $path
* @return int|false
* @since 9.0.0
*/
public function filesize($path);
/**
* check if a file can be created in $path
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function isCreatable($path);
/**
* check if a file can be read
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function isReadable($path);
/**
* check if a file can be written to
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function isUpdatable($path);
/**
* check if a file can be deleted
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function isDeletable($path);
/**
* check if a file can be shared
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function isSharable($path);
/**
* get the full permissions of a path.
* Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
*
* @param string $path
* @return int
* @since 9.0.0
*/
public function getPermissions($path);
/**
* see http://php.net/manual/en/function.file_exists.php
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function file_exists($path);
/**
* see http://php.net/manual/en/function.filemtime.php
*
* @param string $path
* @return int|false
* @since 9.0.0
*/
public function filemtime($path);
/**
* see http://php.net/manual/en/function.file_get_contents.php
*
* @param string $path
* @return string|false
* @since 9.0.0
*/
public function file_get_contents($path);
/**
* see http://php.net/manual/en/function.file_put_contents.php
*
* @param string $path
* @param string $data
* @return bool
* @since 9.0.0
*/
public function file_put_contents($path, $data);
/**
* see http://php.net/manual/en/function.unlink.php
*
* @param string $path
* @return bool
* @since 9.0.0
*/
public function unlink($path);
/**
* see http://php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @return bool
* @since 9.0.0
*/
public function rename($path1, $path2);
/**
* see http://php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @return bool
* @since 9.0.0
*/
public function copy($path1, $path2);
/**
* see http://php.net/manual/en/function.fopen.php
*
* @param string $path
* @param string $mode
* @return resource|false
* @since 9.0.0
*/
public function fopen($path, $mode);
/**
* get the mimetype for a file or folder
* The mimetype for a folder is required to be "httpd/unix-directory"
*
* @param string $path
* @return string|false
* @since 9.0.0
*/
public function getMimeType($path);
/**
* see http://php.net/manual/en/function.hash-file.php
*
* @param string $type
* @param string $path
* @param bool $raw
* @return string|false
* @since 9.0.0
*/
public function hash($type, $path, $raw = false);
/**
* see http://php.net/manual/en/function.free_space.php
*
* @param string $path
* @return int|false
* @since 9.0.0
*/
public function free_space($path);
/**
* search for occurrences of $query in file names
*
* @param string $query
* @return array|false
* @since 9.0.0
*/
public function search($query);
/**
* see http://php.net/manual/en/function.touch.php
* If the backend does not support the operation, false should be returned
*
* @param string $path
* @param int $mtime
* @return bool
* @since 9.0.0
*/
public function touch($path, $mtime = null);
/**
* get the path to a local version of the file.
* The local version of the file can be temporary and doesn't have to be persistent across requests
*
* @param string $path
* @return string|false
* @since 9.0.0
*/
public function getLocalFile($path);
/**
* get the path to a local version of the folder.
* The local version of the folder can be temporary and doesn't have to be persistent across requests
*
* @param string $path
* @return string|false
* @since 9.0.0
*/
public function getLocalFolder($path);
/**
* check if a file or folder has been updated since $time
*
* @param string $path
* @param int $time
* @return bool
* @since 9.0.0
*
* hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
* returning true for other changes in the folder is optional
*/
public function hasUpdated($path, $time);
/**
* get the ETag for a file or folder
*
* @param string $path
* @return string|false
* @since 9.0.0
*/
public function getETag($path);
/**
* Returns whether the storage is local, which means that files
* are stored on the local filesystem instead of remotely.
* Calling getLocalFile() for local storages should always
* return the local files, whereas for non-local storages
* it might return a temporary file.
*
* @return bool true if the files are stored locally, false otherwise
* @since 9.0.0
*/
public function 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
* @since 9.0.0
*/
public function instanceOfStorage($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
* @since 9.0.0
*/
public function getDirectDownload($path);
/**
* @param string $path the path of the target folder
* @param string $fileName the name of the file itself
* @return void
* @throws InvalidPathException
* @since 9.0.0
*/
public function verifyPath($path, $fileName);
/**
* @param \OCP\Files\Storage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
* @since 9.0.0
*/
public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath);
/**
* @param \OCP\Files\Storage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @return bool
* @since 9.0.0
*/
public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath);
/**
* Test a storage for availability
*
* @since 9.0.0
* @return bool
*/
public function test();
/**
* @since 9.0.0
* @return array [ available, last_checked ]
*/
public function getAvailability();
/**
* @since 9.0.0
* @param bool $isAvailable
*/
public function setAvailability($isAvailable);
/**
* @param string $path path for which to retrieve the owner
* @since 9.0.0
*/
public function getOwner($path);
/**
* @return ICache
* @since 9.0.0
*/
public function getCache();
/**
* @return IPropagator
* @since 9.0.0
*/
public function getPropagator();
/**
* @return IScanner
* @since 9.0.0
*/
public function getScanner();
/**
* @return IUpdater
* @since 9.0.0
*/
public function getUpdater();
/**
* @return IWatcher
* @since 9.0.0
*/
public function getWatcher();
}

View File

@ -556,7 +556,7 @@ class Cache extends \Test\TestCase {
$this->assertEquals($folderWith00F6, $unNormalizedFolderName['name']);
// put normalized folder
$this->assertTrue(is_array($this->cache->get('folder/' . $folderWith00F6)));
$this->assertInstanceOf('\OCP\Files\Cache\ICacheEntry', $this->cache->get('folder/' . $folderWith00F6));
$this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith00F6, $data));
// at this point we should have only one folder named "Schön"

View File

@ -7,6 +7,7 @@
*/
namespace Test\Files\Cache;
use OC\Files\Cache\CacheEntry;
/**
* Class Scanner
@ -226,6 +227,7 @@ class Scanner extends \Test\TestCase {
// manipulate etag to simulate an empty etag
$this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG);
/** @var CacheEntry $data0 */
$data0 = $this->cache->get('folder/bar.txt');
$this->assertInternalType('string', $data0['etag']);
$data1 = $this->cache->get('folder');
@ -233,7 +235,7 @@ class Scanner extends \Test\TestCase {
$data2 = $this->cache->get('');
$this->assertInternalType('string', $data2['etag']);
$data0['etag'] = '';
$this->cache->put('folder/bar.txt', $data0);
$this->cache->put('folder/bar.txt', $data0->getData());
// rescan
$this->scanner->scan('folder/bar.txt', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG);

View File

@ -9,6 +9,8 @@
namespace Test\Files\Storage\Wrapper;
//ensure the constants are loaded
use OC\Files\Cache\CacheEntry;
\OC::$loader->load('\OC\Files\Filesystem');
/**
@ -194,7 +196,7 @@ class Quota extends \Test\Files\Storage\Storage {
$cache->expects($this->once())
->method('get')
->with('files')
->will($this->returnValue(array('size' => 50)));
->will($this->returnValue(new CacheEntry(['size' => 50])));
$instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 1024, 'root' => 'files'));