summaryrefslogtreecommitdiffstats
path: root/lib/private/files
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/files')
-rw-r--r--lib/private/files/cache/cache.php16
-rw-r--r--lib/private/files/cache/changepropagator.php24
-rw-r--r--lib/private/files/cache/propagator.php66
-rw-r--r--lib/private/files/cache/updater.php168
-rw-r--r--lib/private/files/fileinfo.php36
-rw-r--r--lib/private/files/storage/common.php30
-rw-r--r--lib/private/files/storage/dav.php9
-rw-r--r--lib/private/files/storage/storage.php16
-rw-r--r--lib/private/files/storage/wrapper/wrapper.php14
-rw-r--r--lib/private/files/stream/encryption.php4
-rw-r--r--lib/private/files/view.php236
11 files changed, 392 insertions, 227 deletions
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php
index 40477243324..e6110c1925d 100644
--- a/lib/private/files/cache/cache.php
+++ b/lib/private/files/cache/cache.php
@@ -160,6 +160,7 @@ class Cache {
} 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'];
@@ -391,12 +392,17 @@ class Cache {
if ($file === '') {
return -1;
} else {
- $parent = dirname($file);
- if ($parent === '.') {
- $parent = '';
- }
- return $this->getId($parent);
+ $parent = $this->getParentPath($file);
+ return (int) $this->getId($parent);
+ }
+ }
+
+ private function getParentPath($path) {
+ $parent = dirname($path);
+ if ($parent === '.') {
+ $parent = '';
}
+ return $parent;
}
/**
diff --git a/lib/private/files/cache/changepropagator.php b/lib/private/files/cache/changepropagator.php
index 9696a82257e..2a48eb13c59 100644
--- a/lib/private/files/cache/changepropagator.php
+++ b/lib/private/files/cache/changepropagator.php
@@ -22,6 +22,7 @@
namespace OC\Files\Cache;
+use OC\Files\Filesystem;
use OC\Hooks\BasicEmitter;
/**
@@ -61,23 +62,30 @@ class ChangePropagator extends BasicEmitter {
* @param int $time (optional) the mtime to set for the folders, if not set the current time is used
*/
public function propagateChanges($time = null) {
- $parents = $this->getAllParents();
- $this->changedFiles = array();
+ $changes = $this->getChanges();
+ $this->changedFiles = [];
if (!$time) {
$time = time();
}
- foreach ($parents as $parent) {
+ foreach ($changes as $change) {
/**
* @var \OC\Files\Storage\Storage $storage
* @var string $internalPath
*/
- list($storage, $internalPath) = $this->view->resolvePath($parent);
+ $absolutePath = $this->view->getAbsolutePath($change);
+ $mount = $this->view->getMount($change);
+ $storage = $mount->getStorage();
+ $internalPath = $mount->getInternalPath($absolutePath);
if ($storage) {
- $cache = $storage->getCache();
- $entry = $cache->get($internalPath);
- $cache->update($entry['fileid'], array('mtime' => max($time, $entry['mtime']), 'etag' => $storage->getETag($internalPath)));
- $this->emit('\OC\Files', 'propagate', [$parent, $entry]);
+ $propagator = $storage->getPropagator();
+ $propagatedEntries = $propagator->propagateChange($internalPath, $time);
+
+ foreach ($propagatedEntries as $entry) {
+ $absolutePath = Filesystem::normalizePath($mount->getMountPoint() . '/' . $entry['path']);
+ $relativePath = $this->view->getRelativePath($absolutePath);
+ $this->emit('\OC\Files', 'propagate', [$relativePath, $entry]);
+ }
}
}
}
diff --git a/lib/private/files/cache/propagator.php b/lib/private/files/cache/propagator.php
new file mode 100644
index 00000000000..bd11cef5990
--- /dev/null
+++ b/lib/private/files/cache/propagator.php
@@ -0,0 +1,66 @@
+<?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;
+
+/**
+ * Propagate etags and mtimes within the storage
+ */
+class Propagator {
+ /**
+ * @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
+ * @return array[] all propagated entries
+ */
+ public function propagateChange($internalPath, $time) {
+ $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']);
+
+ $cache->update($parentId, ['mtime' => $mtime, 'etag' => $this->storage->getETag($entry['path'])]);
+
+ $parentId = $entry['parent'];
+ }
+
+ return $propagatedEntries;
+ }
+}
diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php
index 85dcc8589de..4d11fa3a251 100644
--- a/lib/private/files/cache/updater.php
+++ b/lib/private/files/cache/updater.php
@@ -29,8 +29,6 @@ namespace OC\Files\Cache;
/**
* Update the cache and propagate changes
*
- * Unlike most other classes an Updater is not related to a specific storage but handles updates for all storages in a users filesystem.
- * This is needed because the propagation of mtime and etags need to cross storage boundaries
*/
class Updater {
/**
@@ -39,21 +37,33 @@ class Updater {
protected $enabled = true;
/**
- * @var \OC\Files\View
+ * @var \OC\Files\Storage\Storage
*/
- protected $view;
+ protected $storage;
/**
- * @var \OC\Files\Cache\ChangePropagator
+ * @var \OC\Files\Cache\Propagator
*/
protected $propagator;
/**
- * @param \OC\Files\View $view the view the updater works on, usually the view of the logged in user
+ * @var Scanner
*/
- public function __construct($view) {
- $this->view = $view;
- $this->propagator = new ChangePropagator($view);
+ 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();
}
/**
@@ -73,7 +83,7 @@ class Updater {
/**
* Get the propagator for etags and mtime for the view the updater works on
*
- * @return ChangePropagator
+ * @return Propagator
*/
public function getPropagator() {
return $this->propagator;
@@ -89,8 +99,7 @@ class Updater {
if (Scanner::isPartialFile($path)) {
return;
}
- $this->propagator->addChange($path);
- $this->propagator->propagateChanges($time);
+ $this->propagator->propagateChange($path, $time);
}
/**
@@ -103,20 +112,14 @@ class Updater {
if (!$this->enabled or Scanner::isPartialFile($path)) {
return;
}
- /**
- * @var \OC\Files\Storage\Storage $storage
- * @var string $internalPath
- */
- list($storage, $internalPath) = $this->view->resolvePath($path);
- if ($storage) {
- $this->propagator->addChange($path);
- $cache = $storage->getCache($internalPath);
- $scanner = $storage->getScanner($internalPath);
- $data = $scanner->scan($internalPath, Scanner::SCAN_SHALLOW, -1, false);
- $this->correctParentStorageMtime($storage, $internalPath);
- $cache->correctFolderSize($internalPath, $data);
- $this->propagator->propagateChanges($time);
+ if (is_null($time)) {
+ $time = time();
}
+
+ $data = $this->scanner->scan($path, Scanner::SCAN_SHALLOW, -1, false);
+ $this->correctParentStorageMtime($path);
+ $this->cache->correctFolderSize($path, $data);
+ $this->propagator->propagateChange($path, $time);
}
/**
@@ -128,87 +131,71 @@ class Updater {
if (!$this->enabled or Scanner::isPartialFile($path)) {
return;
}
- /**
- * @var \OC\Files\Storage\Storage $storage
- * @var string $internalPath
- */
- list($storage, $internalPath) = $this->view->resolvePath($path);
- if ($storage) {
- $parent = dirname($internalPath);
- if ($parent === '.') {
- $parent = '';
- }
- $this->propagator->addChange($path);
- $cache = $storage->getCache($internalPath);
- $cache->remove($internalPath);
- $cache->correctFolderSize($parent);
- $this->correctParentStorageMtime($storage, $internalPath);
- $this->propagator->propagateChanges();
+
+ $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 \OC\Files\Storage\Storage $sourceStorage
* @param string $source
* @param string $target
*/
- public function rename($source, $target) {
+ public function renameFromStorage(\OC\Files\Storage\Storage $sourceStorage, $source, $target) {
if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) {
return;
}
- /**
- * @var \OC\Files\Storage\Storage $sourceStorage
- * @var \OC\Files\Storage\Storage $targetStorage
- * @var string $sourceInternalPath
- * @var string $targetInternalPath
- */
- list($sourceStorage, $sourceInternalPath) = $this->view->resolvePath($source);
- // if it's a moved mountpoint we dont need to do anything
- if ($sourceInternalPath === '') {
- return;
- }
- list($targetStorage, $targetInternalPath) = $this->view->resolvePath($target);
-
- if ($sourceStorage && $targetStorage) {
- $targetCache = $targetStorage->getCache($sourceInternalPath);
- if ($sourceStorage->getCache($sourceInternalPath)->inCache($sourceInternalPath)) {
- if ($targetCache->inCache($targetInternalPath)) {
- $targetCache->remove($targetInternalPath);
- }
- if ($sourceStorage === $targetStorage) {
- $targetCache->move($sourceInternalPath, $targetInternalPath);
- } else {
- $targetCache->moveFromCache($sourceStorage->getCache(), $sourceInternalPath, $targetInternalPath);
- }
+
+ $time = time();
+
+ $sourceCache = $sourceStorage->getCache($source);
+ $sourceUpdater = $sourceStorage->getUpdater();
+ $sourcePropagator = $sourceStorage->getPropagator();
+
+ if ($sourceCache->inCache($source)) {
+ if ($this->cache->inCache($target)) {
+ $this->cache->remove($target);
}
- if (pathinfo($sourceInternalPath, PATHINFO_EXTENSION) !== pathinfo($targetInternalPath, PATHINFO_EXTENSION)) {
- // handle mime type change
- $mimeType = $targetStorage->getMimeType($targetInternalPath);
- $fileId = $targetCache->getId($targetInternalPath);
- $targetCache->update($fileId, array('mimetype' => $mimeType));
+ if ($sourceStorage === $this->storage) {
+ $this->cache->move($source, $target);
+ } else {
+ $this->cache->moveFromCache($sourceCache, $source, $target);
}
+ }
- $targetCache->correctFolderSize($sourceInternalPath);
- $targetCache->correctFolderSize($targetInternalPath);
- $this->correctParentStorageMtime($sourceStorage, $sourceInternalPath);
- $this->correctParentStorageMtime($targetStorage, $targetInternalPath);
- $this->updateStorageMTimeOnly($targetStorage, $targetInternalPath);
- $this->propagator->addChange($source);
- $this->propagator->addChange($target);
- $this->propagator->propagateChanges();
+ 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);
+ $sourceUpdater->correctParentStorageMtime($source);
+ $this->correctParentStorageMtime($target);
+ $this->updateStorageMTimeOnly($target);
+ $sourcePropagator->propagateChange($source, $time);
+ $this->propagator->propagateChange($target, $time);
}
- private function updateStorageMTimeOnly($storage, $internalPath) {
- $cache = $storage->getCache();
- $fileId = $cache->getId($internalPath);
+ private function updateStorageMTimeOnly($internalPath) {
+ $fileId = $this->cache->getId($internalPath);
if ($fileId !== -1) {
- $cache->update(
+ $this->cache->update(
$fileId, [
'mtime' => null, // this magic tells it to not overwrite mtime
- 'storage_mtime' => $storage->filemtime($internalPath)
+ 'storage_mtime' => $this->storage->filemtime($internalPath)
]
);
}
@@ -217,20 +204,13 @@ class Updater {
/**
* update the storage_mtime of the direct parent in the cache to the mtime from the storage
*
- * @param \OC\Files\Storage\Storage $storage
* @param string $internalPath
*/
- private function correctParentStorageMtime($storage, $internalPath) {
- $cache = $storage->getCache();
- $parentId = $cache->getParentId($internalPath);
+ public function correctParentStorageMtime($internalPath) {
+ $parentId = $this->cache->getParentId($internalPath);
$parent = dirname($internalPath);
if ($parentId != -1) {
- $cache->update($parentId, array('storage_mtime' => $storage->filemtime($parent)));
+ $this->cache->update($parentId, array('storage_mtime' => $this->storage->filemtime($parent)));
}
}
-
- public function __destruct() {
- // propagate any leftover changes
- $this->propagator->propagateChanges();
- }
}
diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php
index bb810dd45ed..5b5e8697004 100644
--- a/lib/private/files/fileinfo.php
+++ b/lib/private/files/fileinfo.php
@@ -62,6 +62,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
private $owner;
/**
+ * @var string[]
+ */
+ private $childEtags = [];
+
+ /**
* @param string|boolean $path
* @param Storage\Storage $storage
* @param string $internalPath
@@ -93,6 +98,8 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
public function offsetGet($offset) {
if ($offset === 'type') {
return $this->getType();
+ } else if ($offset === 'etag') {
+ return $this->getEtag();
} elseif (isset($this->data[$offset])) {
return $this->data[$offset];
} else {
@@ -153,7 +160,12 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @return string
*/
public function getEtag() {
- return $this->data['etag'];
+ if (count($this->childEtags) > 0) {
+ $combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags);
+ return md5($combinedEtag);
+ } else {
+ return $this->data['etag'];
+ }
}
/**
@@ -285,4 +297,26 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
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;
+ }
+ }
}
diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php
index 8e4958a930d..0cd67e343ff 100644
--- a/lib/private/files/storage/common.php
+++ b/lib/private/files/storage/common.php
@@ -37,7 +37,9 @@
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;
@@ -64,7 +66,9 @@ abstract class Common implements Storage {
protected $cache;
protected $scanner;
protected $watcher;
+ protected $propagator;
protected $storageCache;
+ protected $updater;
protected $mountOptions = [];
@@ -345,6 +349,32 @@ abstract class Common implements Storage {
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($this->propagator)) {
+ $this->propagator = new Propagator($storage);
+ }
+ return $this->propagator;
+ }
+
+ public function getUpdater($storage = null) {
+ if (!$storage) {
+ $storage = $this;
+ }
+ if (!isset($this->updater)) {
+ $this->updater = new Updater($storage);
+ }
+ return $this->updater;
+ }
+
public function getStorageCache($storage = null) {
if (!$storage) {
$storage = $this;
diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php
index dcde7b8029b..9147f572461 100644
--- a/lib/private/files/storage/dav.php
+++ b/lib/private/files/storage/dav.php
@@ -47,6 +47,7 @@ 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;
@@ -137,7 +138,7 @@ class DAV extends Common {
$this->client->setThrowExceptions(true);
if ($this->secure === true && $this->certPath) {
- $this->client->addTrustedCertificates($this->certPath);
+ $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
}
}
@@ -280,7 +281,8 @@ class DAV extends Common {
$response = $this->propfind($path);
$responseType = array();
if (isset($response["{DAV:}resourcetype"])) {
- $responseType = $response["{DAV:}resourcetype"]->resourceType;
+ /** @var ResourceType[] $response */
+ $responseType = $response["{DAV:}resourcetype"]->getValue();
}
return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
} catch (ClientHttpException $e) {
@@ -554,7 +556,8 @@ class DAV extends Common {
$response = $this->propfind($path);
$responseType = array();
if (isset($response["{DAV:}resourcetype"])) {
- $responseType = $response["{DAV:}resourcetype"]->resourceType;
+ /** @var ResourceType[] $response */
+ $responseType = $response["{DAV:}resourcetype"]->getValue();
}
$type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
if ($type == 'dir') {
diff --git a/lib/private/files/storage/storage.php b/lib/private/files/storage/storage.php
index f46ac544b56..fb59752ede1 100644
--- a/lib/private/files/storage/storage.php
+++ b/lib/private/files/storage/storage.php
@@ -68,6 +68,22 @@ interface Storage extends \OCP\Files\Storage {
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();
diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php
index 048738170db..81284c7aa69 100644
--- a/lib/private/files/storage/wrapper/wrapper.php
+++ b/lib/private/files/storage/wrapper/wrapper.php
@@ -430,6 +430,20 @@ class Wrapper implements \OC\Files\Storage\Storage {
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
*/
diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php
index 4c328993ef7..585a697c5d1 100644
--- a/lib/private/files/stream/encryption.php
+++ b/lib/private/files/stream/encryption.php
@@ -167,7 +167,7 @@ class Encryption extends Wrapper {
)
));
- return self::wrapSource($source, $mode, $context, 'ocencryption', $wrapper);
+ return self::wrapSource($source, $context, 'ocencryption', $wrapper, $mode);
}
/**
@@ -181,7 +181,7 @@ class Encryption extends Wrapper {
* @return resource
* @throws \BadMethodCallException
*/
- protected static function wrapSource($source, $mode, $context, $protocol, $class) {
+ protected static function wrapSource($source, $context, $protocol, $class, $mode = 'r+') {
try {
stream_wrapper_register($protocol, $class);
if (@rewinddir($source) === false) {
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index cee4b182425..7854790d0e5 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -46,6 +46,7 @@ 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\FileNameTooLongException;
use OCP\Files\InvalidCharacterInPathException;
@@ -76,9 +77,6 @@ class View {
/** @var string */
private $fakeRoot = '';
- /** @var \OC\Files\Cache\Updater */
- protected $updater;
-
/**
* @var \OCP\Lock\ILockingProvider
*/
@@ -86,6 +84,8 @@ class View {
private $lockingEnabled;
+ private $updaterEnabled = true;
+
/**
* @param string $root
* @throws \Exception If $root contains an invalid path
@@ -99,7 +99,6 @@ class View {
}
$this->fakeRoot = $root;
- $this->updater = new Updater($this);
$this->lockingProvider = \OC::$server->getLockingProvider();
$this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
}
@@ -286,6 +285,35 @@ class View {
}
}
+ 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
@@ -569,7 +597,7 @@ class View {
fclose($target);
fclose($data);
- $this->updater->update($path);
+ $this->writeUpdate($storage, $internalPath);
$this->changeLock($path, ILockingProvider::LOCK_SHARED);
@@ -703,14 +731,11 @@ class View {
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->updater->update($path2);
+
+ $this->writeUpdate($storage2, $internalPath2);
} else if ($result) {
if ($internalPath1 !== '') { // dont do a cache update for moved mounts
- $this->updater->rename($path1, $path2);
- } else { // only do etag propagation
- $this->getUpdater()->getPropagator()->addChange($path1);
- $this->getUpdater()->getPropagator()->addChange($path2);
- $this->getUpdater()->getPropagator()->propagateChanges();
+ $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
}
}
@@ -807,7 +832,7 @@ class View {
$result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
}
- $this->updater->update($path2);
+ $this->writeUpdate($storage2, $internalPath2);
$this->changeLock($path2, ILockingProvider::LOCK_SHARED);
$lockTypePath2 = ILockingProvider::LOCK_SHARED;
@@ -1017,6 +1042,7 @@ class View {
}
$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)) {
@@ -1038,13 +1064,13 @@ class View {
}
if (in_array('delete', $hooks) and $result) {
- $this->updater->remove($path);
+ $this->removeUpdate($storage, $internalPath);
}
if (in_array('write', $hooks) and $operation !== 'fopen') {
- $this->updater->update($path);
+ $this->writeUpdate($storage, $internalPath);
}
if (in_array('touch', $hooks)) {
- $this->updater->update($path, $extraParam);
+ $this->writeUpdate($storage, $internalPath, $extraParam);
}
if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
@@ -1179,6 +1205,48 @@ class View {
}
/**
+ * 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
@@ -1189,9 +1257,8 @@ class View {
*/
public function getFileInfo($path, $includeMountPoints = true) {
$this->assertPathLength($path);
- $data = array();
if (!Filesystem::isValidPath($path)) {
- return $data;
+ return false;
}
if (Cache\Scanner::isPartialFile($path)) {
return $this->getPartFileInfo($path);
@@ -1202,48 +1269,27 @@ class View {
$mount = Filesystem::getMountManager()->find($path);
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($path);
- $data = null;
if ($storage) {
- $cache = $storage->getCache($internalPath);
+ $data = $this->getCacheEntry($storage, $internalPath, $relativePath);
- $data = $cache->get($internalPath);
- $watcher = $storage->getWatcher($internalPath);
+ if (!is_array($data)) {
+ return false;
+ }
- try {
- // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
- if (!$data) {
- $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);
- $this->updater->propagate($path);
- $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
+ 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'])) {
- // upgrades from oc6 or lower might not have the permissions set in the file cache
- if ($data['permissions'] === 0) {
- $data['permissions'] = $storage->getPermissions($data['path']);
- $cache->update($data['fileid'], array('permissions' => $data['permissions']));
- }
if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
//add the sizes of other mount points to the folder
$extOnly = ($includeMountPoints === 'ext');
- $mountPoints = Filesystem::getMountPoints($path);
- foreach ($mountPoints as $mountPoint) {
- $subStorage = Filesystem::getStorage($mountPoint);
+ $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) {
@@ -1251,22 +1297,16 @@ class View {
}
$subCache = $subStorage->getCache('');
$rootEntry = $subCache->get('');
- $data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0;
+ $info->addSubEntry($rootEntry, $mount->getMountPoint());
}
}
}
}
- }
- if (!$data) {
- return false;
- }
- if ($mount instanceof MoveableMount && $internalPath === '') {
- $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
+ return $info;
}
- $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath));
- return new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
+ return false;
}
/**
@@ -1278,9 +1318,8 @@ class View {
*/
public function getDirectoryContent($directory, $mimetype_filter = '') {
$this->assertPathLength($directory);
- $result = array();
if (!Filesystem::isValidPath($directory)) {
- return $result;
+ return [];
}
$path = $this->getAbsolutePath($directory);
$path = Filesystem::normalizePath($path);
@@ -1291,50 +1330,25 @@ class View {
$cache = $storage->getCache($internalPath);
$user = \OC_User::getUser();
- /**
- * @var \OC\Files\FileInfo[] $files
- */
- $files = array();
+ $data = $this->getCacheEntry($storage, $internalPath, $directory);
- $data = $cache->get($internalPath);
- $watcher = $storage->getWatcher($internalPath);
- try {
- if (!$data or $data['size'] === -1) {
- $this->lockFile($directory, ILockingProvider::LOCK_SHARED);
- if (!$storage->file_exists($internalPath)) {
- $this->unlockFile($directory, ILockingProvider::LOCK_SHARED);
- return array();
- }
- $scanner = $storage->getScanner($internalPath);
- $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
- $data = $cache->get($internalPath);
- $this->unlockFile($directory, ILockingProvider::LOCK_SHARED);
- } else if ($watcher->needsUpdate($internalPath, $data)) {
- $this->lockFile($directory, ILockingProvider::LOCK_SHARED);
- $watcher->update($internalPath, $data);
- $this->updater->propagate($path);
- $data = $cache->get($internalPath);
- $this->unlockFile($directory, ILockingProvider::LOCK_SHARED);
- }
- } catch (LockedException $e) {
- // if the file is locked we just use the old cache info
+ if (!is_array($data) || !isset($data['fileid'])) {
+ return [];
}
$folderId = $data['fileid'];
$contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
- foreach ($contents as $content) {
- if ($content['permissions'] === 0) {
- $content['permissions'] = $storage->getPermissions($content['path']);
- $cache->update($content['fileid'], array('permissions' => $content['permissions']));
- }
- // if sharing was disabled for the user we remove the share permissions
+ /**
+ * @var \OC\Files\FileInfo[] $files
+ */
+ $files = array_map(function (array $content) use ($path, $storage, $mount) {
if (\OCP\Util::isSharingDisabledForUser()) {
$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
}
$owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
- $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
- }
+ 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);
@@ -1345,7 +1359,8 @@ class View {
if ($subStorage) {
$subCache = $subStorage->getCache('');
- if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) {
+ $rootEntry = $subCache->get('');
+ if (!$rootEntry) {
$subScanner = $subStorage->getScanner('');
try {
$subScanner->scanFile('');
@@ -1363,17 +1378,17 @@ class View {
);
continue;
}
+ $rootEntry = $subCache->get('');
}
- $rootEntry = $subCache->get('');
if ($rootEntry) {
$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['name'] === $entryName) {
- $entry['size'] += $rootEntry['size'];
+ if ($entry->getName() === $entryName) {
+ $entry->addSubEntry($rootEntry, $mountPoint);
}
}
} else { //mountpoint in this folder, add an entry for it
@@ -1410,23 +1425,23 @@ class View {
}
if ($mimetype_filter) {
- foreach ($files as $file) {
+ $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
if (strpos($mimetype_filter, '/')) {
- if ($file['mimetype'] === $mimetype_filter) {
+ if ($file->getMimetype() === $mimetype_filter) {
$result[] = $file;
}
} else {
- if ($file['mimepart'] === $mimetype_filter) {
+ if ($file->getMimePart() === $mimetype_filter) {
$result[] = $file;
}
}
- }
- } else {
- $result = $files;
+ });
}
- }
- return $result;
+ return $files;
+ } else {
+ return [];
+ }
}
/**
@@ -1707,13 +1722,6 @@ class View {
}
/**
- * @return Updater
- */
- public function getUpdater() {
- return $this->updater;
- }
-
- /**
* @param string $path
* @param string $fileName
* @throws InvalidPathException