diff options
Diffstat (limited to 'lib/files/cache')
-rw-r--r-- | lib/files/cache/backgroundwatcher.php | 104 | ||||
-rw-r--r-- | lib/files/cache/cache.php | 81 | ||||
-rw-r--r-- | lib/files/cache/legacy.php | 54 | ||||
-rw-r--r-- | lib/files/cache/permissions.php | 15 | ||||
-rw-r--r-- | lib/files/cache/scanner.php | 72 | ||||
-rw-r--r-- | lib/files/cache/storage.php | 59 | ||||
-rw-r--r-- | lib/files/cache/updater.php | 75 | ||||
-rw-r--r-- | lib/files/cache/upgrade.php | 116 |
8 files changed, 469 insertions, 107 deletions
diff --git a/lib/files/cache/backgroundwatcher.php b/lib/files/cache/backgroundwatcher.php new file mode 100644 index 00000000000..8933101577d --- /dev/null +++ b/lib/files/cache/backgroundwatcher.php @@ -0,0 +1,104 @@ +<?php +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +use \OC\Files\Mount; +use \OC\Files\Filesystem; + +class BackgroundWatcher { + static $folderMimetype = null; + + static private function getFolderMimetype() { + if (!is_null(self::$folderMimetype)) { + return self::$folderMimetype; + } + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'); + $result = $query->execute(array('httpd/unix-directory')); + $row = $result->fetchRow(); + return $row['id']; + } + + static private function checkUpdate($id) { + $cacheItem = Cache::getById($id); + if (is_null($cacheItem)) { + return; + } + list($storageId, $internalPath) = $cacheItem; + $mounts = Filesystem::getMountByStorageId($storageId); + + if (count($mounts) === 0) { + //if the storage we need isn't mounted on default, try to find a user that has access to the storage + $permissionsCache = new Permissions($storageId); + $users = $permissionsCache->getUsers($id); + if (count($users) === 0) { + return; + } + Filesystem::initMountPoints($users[0]); + $mounts = Filesystem::getMountByStorageId($storageId); + if (count($mounts) === 0) { + return; + } + } + $storage = $mounts[0]->getStorage(); + $watcher = new Watcher($storage); + $watcher->checkUpdate($internalPath); + } + + /** + * get the next fileid in the cache + * + * @param int $previous + * @param bool $folder + * @return int + */ + static private function getNextFileId($previous, $folder) { + if ($folder) { + $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND mimetype = ' . self::getFolderMimetype() . ' ORDER BY `fileid` ASC', 1); + } else { + $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND mimetype != ' . self::getFolderMimetype() . ' ORDER BY `fileid` ASC', 1); + } + $result = $query->execute(array($previous)); + if ($row = $result->fetchRow()) { + return $row['fileid']; + } else { + return 0; + } + } + + static public function checkNext() { + // check both 1 file and 1 folder, this way new files are detected quicker because there are less folders than files usually + $previousFile = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_file', 0); + $previousFolder = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_folder', 0); + $nextFile = self::getNextFileId($previousFile, false); + $nextFolder = self::getNextFileId($previousFolder, true); + \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_file', $nextFile); + \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_folder', $nextFolder); + if ($nextFile > 0) { + self::checkUpdate($nextFile); + } + if ($nextFolder > 0) { + self::checkUpdate($nextFolder); + } + } + + static public function checkAll() { + $previous = 0; + $next = 1; + while ($next != 0) { + $next = self::getNextFileId($previous, true); + self::checkUpdate($next); + } + $previous = 0; + $next = 1; + while ($next != 0) { + $next = self::getNextFileId($previous, false); + self::checkUpdate($next); + } + } +} diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php index 2413c05b8cd..0617471079b 100644 --- a/lib/files/cache/cache.php +++ b/lib/files/cache/cache.php @@ -30,11 +30,9 @@ class Cache { private $storageId; /** - * numeric storage id - * - * @var int $numericId + * @var Storage $storageCache */ - private $numericId; + private $storageCache; private $mimetypeIds = array(); private $mimetypes = array(); @@ -52,19 +50,11 @@ class Cache { $this->storageId = md5($this->storageId); } - $query = \OC_DB::prepare('SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'); - $result = $query->execute(array($this->storageId)); - if ($row = $result->fetchRow()) { - $this->numericId = $row['numeric_id']; - } else { - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*storages`(`id`) VALUES(?)'); - $query->execute(array($this->storageId)); - $this->numericId = \OC_DB::insertid('*PREFIX*storages'); - } + $this->storageCache = new Storage($storage); } public function getNumericStorageId() { - return $this->numericId; + return $this->storageCache->getNumericId(); } /** @@ -111,7 +101,7 @@ class Cache { public function get($file) { if (is_string($file) or $file == '') { $where = 'WHERE `storage` = ? AND `path_hash` = ?'; - $params = array($this->numericId, md5($file)); + $params = array($this->getNumericStorageId(), md5($file)); } else { //file id $where = 'WHERE `fileid` = ?'; $params = array($file); @@ -204,12 +194,15 @@ class Cache { list($queryParts, $params) = $this->buildParts($data); $queryParts[] = '`storage`'; - $params[] = $this->numericId; + $params[] = $this->getNumericStorageId(); $valuesPlaceholder = array_fill(0, count($queryParts), '?'); $query = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`(' . implode(', ', $queryParts) . ')' . ' VALUES(' . implode(', ', $valuesPlaceholder) . ')'); - $query->execute($params); + $result = $query->execute($params); + if (\OC_DB::isError($result)) { + \OCP\Util::writeLog('cache', 'Insert to cache failed: ' . $result, \OCP\Util::ERROR); + } return (int)\OC_DB::insertid('*PREFIX*filecache'); } @@ -272,7 +265,7 @@ class Cache { $pathHash = md5($file); $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'); - $result = $query->execute(array($this->numericId, $pathHash)); + $result = $query->execute(array($this->getNumericStorageId(), $pathHash)); if ($row = $result->fetchRow()) { return $row['fileid']; @@ -336,24 +329,27 @@ class Cache { * @param string $target */ public function move($source, $target) { - $sourceId = $this->getId($source); + $sourceData = $this->get($source); + $sourceId = $sourceData['fileid']; $newParentId = $this->getParentId($target); - //find all child entries - $query = \OC_DB::prepare('SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `path` LIKE ?'); - $result = $query->execute(array($source . '/%')); - $childEntries = $result->fetchAll(); - $sourceLength = strlen($source); - $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); - - foreach ($childEntries as $child) { - $targetPath = $target . substr($child['path'], $sourceLength); - $query->execute(array($targetPath, md5($targetPath), $child['fileid'])); + if ($sourceData['mimetype'] === 'httpd/unix-directory') { + //find all child entries + $query = \OC_DB::prepare('SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `path` LIKE ?'); + $result = $query->execute(array($source . '/%')); + $childEntries = $result->fetchAll(); + $sourceLength = strlen($source); + $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); + + foreach ($childEntries as $child) { + $targetPath = $target . substr($child['path'], $sourceLength); + $query->execute(array($targetPath, md5($targetPath), $child['fileid'])); + } } - $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `parent` =?' + $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `name` = ?, `parent` =?' . ' WHERE `fileid` = ?'); - $query->execute(array($target, md5($target), $newParentId, $sourceId)); + $query->execute(array($target, md5($target), basename($target), $newParentId, $sourceId)); } /** @@ -361,7 +357,7 @@ class Cache { */ public function clear() { $query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE storage = ?'); - $query->execute(array($this->numericId)); + $query->execute(array($this->getNumericStorageId())); $query = \OC_DB::prepare('DELETE FROM `*PREFIX*storages` WHERE id = ?'); $query->execute(array($this->storageId)); @@ -375,7 +371,7 @@ class Cache { public function getStatus($file) { $pathHash = md5($file); $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'); - $result = $query->execute(array($this->numericId, $pathHash)); + $result = $query->execute(array($this->getNumericStorageId(), $pathHash)); if ($row = $result->fetchRow()) { if ((int)$row['size'] === -1) { return self::SHALLOW; @@ -402,7 +398,7 @@ class Cache { SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?' ); - $result = $query->execute(array($pattern, $this->numericId)); + $result = $query->execute(array($pattern, $this->getNumericStorageId())); $files = array(); while ($row = $result->fetchRow()) { $row['mimetype'] = $this->getMimetype($row['mimetype']); @@ -429,7 +425,7 @@ class Cache { FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?' ); $mimetype = $this->getMimetypeId($mimetype); - $result = $query->execute(array($mimetype, $this->numericId)); + $result = $query->execute(array($mimetype, $this->getNumericStorageId())); $files = array(); while ($row = $result->fetchRow()) { $row['mimetype'] = $this->getMimetype($row['mimetype']); @@ -448,7 +444,7 @@ class Cache { $this->calculateFolderSize($path); if ($path !== '') { $parent = dirname($path); - if ($parent === '.') { + if ($parent === '.' or $parent === '/') { $parent = ''; } $this->correctFolderSize($parent); @@ -467,7 +463,7 @@ class Cache { return 0; } $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*filecache` WHERE `parent` = ? AND `storage` = ?'); - $result = $query->execute(array($id, $this->numericId)); + $result = $query->execute(array($id, $this->getNumericStorageId())); $totalSize = 0; $hasChilds = 0; while ($row = $result->fetchRow()) { @@ -494,7 +490,7 @@ class Cache { */ public function getAll() { $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?'); - $result = $query->execute(array($this->numericId)); + $result = $query->execute(array($this->getNumericStorageId())); $ids = array(); while ($row = $result->fetchRow()) { $ids[] = $row['fileid']; @@ -514,7 +510,7 @@ class Cache { public function getIncomplete() { $query = \OC_DB::prepare('SELECT `path` FROM `*PREFIX*filecache`' . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC LIMIT 1'); - $result = $query->execute(array($this->numericId)); + $result = $query->execute(array($this->getNumericStorageId())); if ($row = $result->fetchRow()) { return $row['path']; } else { @@ -525,6 +521,7 @@ class Cache { /** * get the storage id of the storage for a file and the internal path of the file * + * @param int $id * @return array, first element holding the storage id, second the path */ static public function getById($id) { @@ -537,10 +534,8 @@ class Cache { return null; } - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?'); - $result = $query->execute(array($numericId)); - if ($row = $result->fetchRow()) { - return array($row['id'], $path); + if ($id = Storage::getStorageId($numericId)) { + return array($id, $path); } else { return null; } diff --git a/lib/files/cache/legacy.php b/lib/files/cache/legacy.php index 2b8689fcbda..b8e2548639b 100644 --- a/lib/files/cache/legacy.php +++ b/lib/files/cache/legacy.php @@ -20,6 +20,11 @@ class Legacy { $this->user = $user; } + /** + * get the numbers of items in the legacy cache + * + * @return int + */ function getCount() { $query = \OC_DB::prepare('SELECT COUNT(`id`) AS `count` FROM `*PREFIX*fscache` WHERE `user` = ?'); $result = $query->execute(array($this->user)); @@ -62,6 +67,8 @@ class Legacy { } /** + * get an item from the legacy cache + * * @param string|int $path * @return array */ @@ -72,16 +79,59 @@ class Legacy { $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?'); } $result = $query->execute(array($path)); - return $result->fetchRow(); + $data = $result->fetchRow(); + $data['etag'] = $this->getEtag($data['path'], $data['user']); + return $data; } /** + * Get the ETag for the given path + * + * @param type $path + * @return string + */ + function getEtag($path, $user = null) { + static $query = null; + + $pathDetails = explode('/', $path, 4); + if((!$user) && !isset($pathDetails[1])) { + //no user!? Too odd, return empty string. + return ''; + } else if(!$user) { + //guess user from path, if no user passed. + $user = $pathDetails[1]; + } + + if(!isset($pathDetails[3]) || is_null($pathDetails[3])) { + $relativePath = ''; + } else { + $relativePath = $pathDetails[3]; + } + + if(is_null($query)){ + $query = \OC_DB::prepare('SELECT `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = \'{DAV:}getetag\''); + } + $result = $query->execute(array($user, '/' . $relativePath)); + if ($row = $result->fetchRow()) { + return trim($row['propertyvalue'], '"'); + } else { + return ''; + } + } + + /** + * get all child items of an item from the legacy cache + * * @param int $id * @return array */ function getChildren($id) { $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?'); $result = $query->execute(array($id)); - return $result->fetchAll(); + $data = $result->fetchAll(); + foreach ($data as $i => $item) { + $data[$i]['etag'] = $this->getEtag($item['path'], $item['user']); + } + return $data; } } diff --git a/lib/files/cache/permissions.php b/lib/files/cache/permissions.php index a5c9c144054..faa5ff5eacc 100644 --- a/lib/files/cache/permissions.php +++ b/lib/files/cache/permissions.php @@ -107,4 +107,19 @@ class Permissions { $query->execute(array($fileId, $user)); } } + + /** + * get the list of users which have permissions stored for a file + * + * @param int $fileId + */ + public function getUsers($fileId) { + $query = \OC_DB::prepare('SELECT `user` FROM `*PREFIX*permissions` WHERE `fileid` = ?'); + $result = $query->execute(array($fileId)); + $users = array(); + while ($row = $result->fetchRow()) { + $users[] = $row['user']; + } + return $users; + } } diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index 9c5ce9df7fc..a98953b42aa 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -63,36 +63,44 @@ class Scanner { * @return array with metadata of the scanned file */ public function scanFile($file, $checkExisting = false) { - \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId)); - $data = $this->getData($file); - if ($data) { - if ($file) { - $parent = dirname($file); - if ($parent === '.') { - $parent = ''; - } - if (!$this->cache->inCache($parent)) { - $this->scanFile($parent); + if ( ! self::isPartialFile($file) + and ! \OC\Files\Filesystem::isFileBlacklisted($file) + ) { + \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId)); + $data = $this->getData($file); + if ($data) { + if ($file) { + $parent = dirname($file); + if ($parent === '.' or $parent === '/') { + $parent = ''; + } + if (!$this->cache->inCache($parent)) { + $this->scanFile($parent); + } } - } - if ($checkExisting and $cacheData = $this->cache->get($file)) { - if ($data['size'] === -1) { - $data['size'] = $cacheData['size']; + if($cacheData = $this->cache->get($file)) { + if ($data['mtime'] === $cacheData['mtime'] && + $data['size'] === $cacheData['size']) { + $data['etag'] = $cacheData['etag']; + } } - if ($data['mtime'] === $cacheData['mtime']) { - $data['etag'] = $cacheData['etag']; + if ($checkExisting and $cacheData) { + if ($data['size'] === -1) { + $data['size'] = $cacheData['size']; + } } + $this->cache->put($file, $data); } - $this->cache->put($file, $data); + return $data; } - return $data; + return null; } /** * scan all the files in a folder and store them in the cache * * @param string $path - * @param SCAN_RECURSIVE/SCAN_SHALLOW $recursive + * @param bool $recursive * @param bool $onlyChilds * @return int the size of the scanned folder or -1 if the size is unknown at this stage */ @@ -107,8 +115,8 @@ class Scanner { if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) { \OC_DB::beginTransaction(); while ($file = readdir($dh)) { - if (!$this->isIgnoredFile($file)) { - $child = ($path) ? $path . '/' . $file : $file; + $child = ($path) ? $path . '/' . $file : $file; + if (!$this->isIgnoredDir($file)) { $data = $this->scanFile($child, $recursive === self::SCAN_SHALLOW); if ($data) { if ($data['size'] === -1) { @@ -143,16 +151,26 @@ class Scanner { } /** + * @brief check if the directory should be ignored when scanning + * NOTE: the special directories . and .. would cause never ending recursion + * @param String $dir + * @return boolean + */ + private function isIgnoredDir($dir) { + if ($dir === '.' || $dir === '..') { + return true; + } + return false; + } + /** * @brief 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 */ - private function isIgnoredFile($file) { - if ($file === '.' || $file === '..' - || pathinfo($file, PATHINFO_EXTENSION) === 'part' - ) { + public static function isPartialFile($file) { + if (pathinfo($file, PATHINFO_EXTENSION) === 'part') { return true; } return false; @@ -162,9 +180,11 @@ class Scanner { * walk over any folders that are not fully scanned yet and scan them */ public function backgroundScan() { - while (($path = $this->cache->getIncomplete()) !== false) { + $lastPath = null; + while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) { $this->scan($path); $this->cache->correctFolderSize($path); + $lastPath = $path; } } } diff --git a/lib/files/cache/storage.php b/lib/files/cache/storage.php new file mode 100644 index 00000000000..72de376798c --- /dev/null +++ b/lib/files/cache/storage.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * Class Storage + * + * cache storage specific data + * + * @package OC\Files\Cache + */ +class Storage { + private $storageId; + private $numericId; + + /** + * @param \OC\Files\Storage\Storage|string $storage + */ + public function __construct($storage) { + if ($storage instanceof \OC\Files\Storage\Storage) { + $this->storageId = $storage->getId(); + } else { + $this->storageId = $storage; + } + if (strlen($this->storageId) > 64) { + $this->storageId = md5($this->storageId); + } + + $query = \OC_DB::prepare('SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'); + $result = $query->execute(array($this->storageId)); + if ($row = $result->fetchRow()) { + $this->numericId = $row['numeric_id']; + } else { + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*storages`(`id`) VALUES(?)'); + $query->execute(array($this->storageId)); + $this->numericId = \OC_DB::insertid('*PREFIX*storages'); + } + } + + public function getNumericId() { + return $this->numericId; + } + + public static function getStorageId($numericId) { + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?'); + $result = $query->execute(array($numericId)); + if ($row = $result->fetchRow()) { + return $row['id']; + } else { + return null; + } + } +} diff --git a/lib/files/cache/updater.php b/lib/files/cache/updater.php index d04541c219f..417a47f3830 100644 --- a/lib/files/cache/updater.php +++ b/lib/files/cache/updater.php @@ -16,7 +16,7 @@ class Updater { /** * resolve a path to a storage and internal path * - * @param string $path + * @param string $path the relative path * @return array consisting of the storage and the internal path */ static public function resolvePath($path) { @@ -24,6 +24,11 @@ class Updater { return $view->resolvePath($path); } + /** + * preform a write update + * + * @param string $path the relative path of the file + */ static public function writeUpdate($path) { /** * @var \OC\Files\Storage\Storage $storage @@ -39,6 +44,11 @@ class Updater { } } + /** + * preform a delete update + * + * @param string $path the relative path of the file + */ static public function deleteUpdate($path) { /** * @var \OC\Files\Storage\Storage $storage @@ -54,11 +64,41 @@ class Updater { } /** - * Update the mtime and ETag of all parent folders - * - * @param string $path - * @param string $time - */ + * preform a rename update + * + * @param string $from the relative path of the source file + * @param string $to the relative path of the target file + */ + static public function renameUpdate($from, $to) { + /** + * @var \OC\Files\Storage\Storage $storageFrom + * @var \OC\Files\Storage\Storage $storageTo + * @var string $internalFrom + * @var string $internalTo + */ + list($storageFrom, $internalFrom) = self::resolvePath($from); + list($storageTo, $internalTo) = self::resolvePath($to); + if ($storageFrom && $storageTo) { + if ($storageFrom === $storageTo) { + $cache = $storageFrom->getCache($internalFrom); + $cache->move($internalFrom, $internalTo); + $cache->correctFolderSize($internalFrom); + $cache->correctFolderSize($internalTo); + self::correctFolder($from, time()); + self::correctFolder($to, time()); + } else { + self::deleteUpdate($from); + self::writeUpdate($to); + } + } + } + + /** + * Update the mtime and ETag of all parent folders + * + * @param string $path + * @param string $time + */ static public function correctFolder($path, $time) { if ($path !== '' && $path !== '/') { $parent = dirname($path); @@ -66,9 +106,9 @@ class Updater { $parent = ''; } /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ list($storage, $internalPath) = self::resolvePath($parent); if ($storage) { $cache = $storage->getCache(); @@ -91,9 +131,22 @@ class Updater { /** * @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::deleteUpdate($params['oldpath']); - self::writeUpdate($params['newpath']); + self::renameUpdate($params['oldpath'], $params['newpath']); } /** diff --git a/lib/files/cache/upgrade.php b/lib/files/cache/upgrade.php index 811d82d7437..ca044ba81de 100644 --- a/lib/files/cache/upgrade.php +++ b/lib/files/cache/upgrade.php @@ -26,63 +26,77 @@ class Upgrade { } /** - * Preform a shallow upgrade + * Preform a upgrade a path and it's childs * * @param string $path - * @param int $mode + * @param bool $mode */ function upgradePath($path, $mode = Scanner::SCAN_RECURSIVE) { if (!$this->legacy->hasItems()) { return; } \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $path); - if ($row = $this->legacy->get($path)) { $data = $this->getNewData($row); - $this->insert($data); - - $this->upgradeChilds($data['id'], $mode); + if ($data) { + $this->insert($data); + $this->upgradeChilds($data['id'], $mode); + } } } /** + * upgrade all child elements of an item + * * @param int $id + * @param bool $mode */ function upgradeChilds($id, $mode = Scanner::SCAN_RECURSIVE) { $children = $this->legacy->getChildren($id); foreach ($children as $child) { $childData = $this->getNewData($child); \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $child['path']); - $this->insert($childData); - if ($mode == Scanner::SCAN_RECURSIVE) { - $this->upgradeChilds($child['id']); + if ($childData) { + $this->insert($childData); + if ($mode == Scanner::SCAN_RECURSIVE) { + $this->upgradeChilds($child['id']); + } } } } /** + * insert data into the new cache + * * @param array $data the data for the new cache */ function insert($data) { - if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) { + static $insertQuery = null; + if(is_null($insertQuery)) { $insertQuery = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` - ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted` ) - VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); - + ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` ) + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); + } + if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) { $insertQuery->execute(array($data['id'], $data['storage'], $data['path'], $data['path_hash'], $data['parent'], $data['name'], - $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'])); + $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'], $data['etag'])); } } /** + * check if an item is already in the new cache + * * @param string $storage * @param string $pathHash * @param string $id * @return bool */ function inCache($storage, $pathHash, $id) { - $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?'); + static $query = null; + if(is_null($query)) { + $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?'); + } $result = $query->execute(array($storage, $pathHash, $id)); return (bool)$result->fetchRow(); } @@ -91,24 +105,53 @@ class Upgrade { * get the new data array from the old one * * @param array $data the data from the old cache + * Example data array + * Array + * ( + * [id] => 418 + * [path] => /tina/files/picture.jpg //relative to datadir + * [path_hash] => 66d4547e372888deed80b24fec9b192b + * [parent] => 234 + * [name] => picture.jpg + * [user] => tina + * [size] => 1265283 + * [ctime] => 1363909709 + * [mtime] => 1363909709 + * [mimetype] => image/jpeg + * [mimepart] => image + * [encrypted] => 0 + * [versioned] => 0 + * [writable] => 1 + * ) + * * @return array */ function getNewData($data) { + //Make sure there is a path, otherwise we can do nothing. + if(!isset($data['path'])) { + return false; + } $newData = $data; - list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']); /** * @var \OC\Files\Storage\Storage $storage * @var string $internalPath; */ - $newData['path_hash'] = md5($internalPath); - $newData['path'] = $internalPath; - $newData['storage'] = $this->getNumericId($storage); - $newData['parent'] = ($internalPath === '') ? -1 : $data['parent']; - $newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ; - $newData['storage_object'] = $storage; - $newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage); - $newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage); - return $newData; + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']); + if ($storage) { + $newData['etag'] = $data['etag']; + $newData['path_hash'] = md5($internalPath); + $newData['path'] = $internalPath; + $newData['storage'] = $this->getNumericId($storage); + $newData['parent'] = ($internalPath === '') ? -1 : $data['parent']; + $newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ; + $newData['storage_object'] = $storage; + $newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage); + $newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage); + return $newData; + } else { + \OC_Log::write('core', 'Unable to migrate data from old cache for '.$data['path'].' because the storage was not found', \OC_Log::ERROR); + return false; + } } /** @@ -127,6 +170,8 @@ class Upgrade { } /** + * get the numeric id for a mimetype + * * @param string $mimetype * @param \OC\Files\Storage\Storage $storage * @return int @@ -158,4 +203,25 @@ class Upgrade { static function upgradeDone($user) { \OCP\Config::setUserValue($user, 'files', 'cache_version', 5); } + + /** + * Does a "silent" upgrade, i.e. without an Event-Source as triggered + * on User-Login via Ajax. This method is called within the regular + * ownCloud upgrade. + * + * @param string $user a User ID + */ + public static function doSilentUpgrade($user) { + if(!self::needUpgrade($user)) { + return; + } + $legacy = new \OC\Files\Cache\Legacy($user); + if ($legacy->hasItems()) { + \OC_DB::beginTransaction(); + $upgrade = new \OC\Files\Cache\Upgrade($legacy); + $upgrade->upgradePath('/' . $user . '/files'); + \OC_DB::commit(); + } + \OC\Files\Cache\Upgrade::upgradeDone($user); + } } |