From 850542c5d61cd68f46d028e2bbbe21ed69d37c96 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 4 Aug 2014 14:29:46 +0200 Subject: Refactor Cache\Updater to work outside of the users home --- lib/private/files/cache/changepropagator.php | 8 +- lib/private/files/cache/updater.php | 207 +++++++++------------------ 2 files changed, 69 insertions(+), 146 deletions(-) (limited to 'lib/private/files/cache') diff --git a/lib/private/files/cache/changepropagator.php b/lib/private/files/cache/changepropagator.php index 30f2e675e2e..2967c8f6259 100644 --- a/lib/private/files/cache/changepropagator.php +++ b/lib/private/files/cache/changepropagator.php @@ -57,9 +57,11 @@ class ChangePropagator { */ list($storage, $internalPath) = $this->view->resolvePath($parent); - $cache = $storage->getCache(); - $id = $cache->getId($internalPath); - $cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath))); + if ($storage) { + $cache = $storage->getCache(); + $id = $cache->getId($internalPath); + $cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath))); + } } } diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index 0e5e07c587d..a59dc7c08c6 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -9,166 +9,122 @@ namespace OC\Files\Cache; /** - * listen to filesystem hooks and change the cache accordingly + * Update the cache and propagate changes */ class Updater { + /** + * @var \OC\Files\View + */ + protected $view; /** - * resolve a path to a storage and internal path - * - * @param string $path the relative path - * @return array an array consisting of the storage and the internal path + * @var \OC\Files\Cache\ChangePropagator + */ + protected $propagator; + + /** + * @param \OC\Files\View $view */ - static public function resolvePath($path) { - $view = \OC\Files\Filesystem::getView(); - return $view->resolvePath($path); + public function __construct($view) { + $this->view = $view; + $this->propagator = new ChangePropagator($view); } /** - * perform a write update + * Update the cache for $path * - * @param string $path the relative path of the file + * @param string $path */ - static public function writeUpdate($path) { + public function update($path) { /** * @var \OC\Files\Storage\Storage $storage * @var string $internalPath */ - list($storage, $internalPath) = self::resolvePath($path); + 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); + $this->correctParentStorageMtime($storage, $internalPath); $cache->correctFolderSize($internalPath, $data); - self::correctFolder($path, $storage->filemtime($internalPath)); - self::correctParentStorageMtime($storage, $internalPath); } } /** - * perform a delete update + * Remove $path from the cache * - * @param string $path the relative path of the file + * @param string $path */ - static public function deleteUpdate($path) { + public function remove($path) { /** * @var \OC\Files\Storage\Storage $storage * @var string $internalPath */ - list($storage, $internalPath) = self::resolvePath($path); + 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); - self::correctFolder($path, time()); - self::correctParentStorageMtime($storage, $internalPath); + $this->correctParentStorageMtime($storage, $internalPath); } } /** - * preform a rename update - * - * @param string $from the relative path of the source file - * @param string $to the relative path of the target file + * @param string $source + * @param string $target */ - static public function renameUpdate($from, $to) { + public function rename($source, $target) { /** - * @var \OC\Files\Storage\Storage $storageFrom - * @var \OC\Files\Storage\Storage $storageTo - * @var string $internalFrom - * @var string $internalTo + * @var \OC\Files\Storage\Storage $sourceStorage + * @var \OC\Files\Storage\Storage $targetStorage + * @var string $sourceInternalPath + * @var string $targetInternalPath */ - list($storageFrom, $internalFrom) = self::resolvePath($from); + list($sourceStorage, $sourceInternalPath) = $this->view->resolvePath($source); // if it's a moved mountpoint we dont need to do anything - if ($internalFrom === '') { + if ($sourceInternalPath === '') { return; } - list($storageTo, $internalTo) = self::resolvePath($to); - if ($storageFrom && $storageTo) { - if ($storageFrom === $storageTo) { - $cache = $storageFrom->getCache($internalFrom); - $cache->move($internalFrom, $internalTo); - if (pathinfo($internalFrom, PATHINFO_EXTENSION) !== pathinfo($internalTo, PATHINFO_EXTENSION)) { - // redetect mime type change - $mimeType = $storageTo->getMimeType($internalTo); - $fileId = $storageTo->getCache()->getId($internalTo); - $storageTo->getCache()->update($fileId, array('mimetype' => $mimeType)); + list($targetStorage, $targetInternalPath) = $this->view->resolvePath($target); + + if ($sourceStorage && $targetStorage) { + if ($sourceStorage === $targetStorage) { + $cache = $sourceStorage->getCache($sourceInternalPath); + $cache->move($sourceInternalPath, $targetInternalPath); + + if (pathinfo($sourceInternalPath, PATHINFO_EXTENSION) !== pathinfo($targetInternalPath, PATHINFO_EXTENSION)) { + // handle mime type change + $mimeType = $sourceStorage->getMimeType($targetInternalPath); + $fileId = $cache->getId($targetInternalPath); + $cache->update($fileId, array('mimetype' => $mimeType)); } - $cache->correctFolderSize($internalFrom); - $cache->correctFolderSize($internalTo); - self::correctFolder($from, time()); - self::correctFolder($to, time()); - self::correctParentStorageMtime($storageFrom, $internalFrom); - self::correctParentStorageMtime($storageTo, $internalTo); - } else { - self::deleteUpdate($from); - self::writeUpdate($to); - } - } - } - - /** - * get file owner and path - * @param string $filename - * @return string[] with the owner's uid and the owner's path - */ - private static function getUidAndFilename($filename) { - - $uid = \OC\Files\Filesystem::getOwner($filename); - \OC\Files\Filesystem::initMountPoints($uid); - $filename = (strpos($filename, '/') !== 0) ? '/' . $filename : $filename; - if ($uid != \OCP\User::getUser()) { - $info = \OC\Files\Filesystem::getFileInfo($filename); - if (!$info) { - return array($uid, '/files' . $filename); + $cache->correctFolderSize($sourceInternalPath); + $cache->correctFolderSize($targetInternalPath); + $this->correctParentStorageMtime($sourceStorage, $sourceInternalPath); + $this->correctParentStorageMtime($targetStorage, $targetInternalPath); + $this->propagator->addChange($source); + $this->propagator->addChange($target); + } else { + $this->remove($source); + $this->update($target); } - $ownerView = new \OC\Files\View('/' . $uid . '/files'); - $filename = $ownerView->getPath($info['fileid']); } - return array($uid, '/files' . $filename); } /** - * Update the mtime and ETag of all parent folders + * propagate the updates to their parent folders * - * @param string $path - * @param string $time + * @param int $time (optional) the mtime to set for the folders, if not set the current time is used */ - static public function correctFolder($path, $time) { - if ($path !== '' && $path !== '/' && $path !== '\\') { - list($owner, $realPath) = self::getUidAndFilename(dirname($path)); - - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - $view = new \OC\Files\View('/' . $owner); - - list($storage, $internalPath) = $view->resolvePath($realPath); - $cache = $storage->getCache(); - $id = $cache->getId($internalPath); - - while ($id !== -1) { - $cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath))); - if ($realPath !== '') { - $realPath = dirname($realPath); - if ($realPath === DIRECTORY_SEPARATOR) { - $realPath = ""; - } - // check storage for parent in case we change the storage in this step - list($storage, $internalPath) = $view->resolvePath($realPath); - $cache = $storage->getCache(); - $id = $cache->getId($internalPath); - } else { - $id = -1; - } - } - } + public function propagate($time = null) { + $this->propagator->propagateChanges($time); } /** @@ -177,52 +133,17 @@ class Updater { * @param \OC\Files\Storage\Storage $storage * @param string $internalPath */ - static private function correctParentStorageMtime($storage, $internalPath) { + private function correctParentStorageMtime($storage, $internalPath) { $cache = $storage->getCache(); $parentId = $cache->getParentId($internalPath); $parent = dirname($internalPath); - - if ($parent === '.' || $parent === '/' || $parent === '\\') { - $parent = ''; - } - if ($parentId != -1) { $cache->update($parentId, array('storage_mtime' => $storage->filemtime($parent))); } } - /** - * @param array $params - */ - static public function writeHook($params) { - self::writeUpdate($params['path']); - } - - /** - * @param array $params - */ - static public function touchHook($params) { - $path = $params['path']; - list($storage, $internalPath) = self::resolvePath($path); - $cache = $storage->getCache(); - $id = $cache->getId($internalPath); - if ($id !== -1) { - $cache->update($id, array('etag' => $storage->getETag($internalPath))); - } - self::writeUpdate($path); - } - - /** - * @param array $params - */ - static public function renameHook($params) { - self::renameUpdate($params['oldpath'], $params['newpath']); - } - - /** - * @param array $params - */ - static public function deleteHook($params) { - self::deleteUpdate($params['path']); + public function __destruct() { + // propagate any leftover changes + $this->propagator->propagateChanges(); } } -- cgit v1.2.3