* This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. */ namespace OC\Files\Cache; class Upgrade { /** * @var Legacy $legacy */ private $legacy; private $numericIds = array(); private $mimeTypeIds = array(); /** * @param Legacy $legacy */ public function __construct($legacy) { $this->legacy = $legacy; } /** * Preform a upgrade a path and it's childs * * @param string $path * @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); 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']); 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) { 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`, `etag` ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); } if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) { \OC_DB::executeAudited($insertQuery, 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['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) { static $query = null; if(is_null($query)) { $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?'); } $result = \OC_DB::executeAudited($query, array($storage, $pathHash, $id)); return (bool)$result->fetchRow(); } /** * 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; /** * @var \OC\Files\Storage\Storage $storage * @var string $internalPath; */ 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; } } /** * get the numeric storage id * * @param \OC\Files\Storage\Storage $storage * @return int */ function getNumericId($storage) { $storageId = $storage->getId(); if (!isset($this->numericIds[$storageId])) { $cache = $storage->getCache(); $this->numericIds[$storageId] = $cache->getNumericStorageId(); } return $this->numericIds[$storageId]; } /** * get the numeric id for a mimetype * * @param string $mimetype * @param \OC\Files\Storage\Storage $storage * @return int */ function getMimetypeId($mimetype, $storage) { if (!isset($this->mimeTypeIds[$mimetype])) { $cache = new Cache($storage); $this->mimeTypeIds[$mimetype] = $cache->getMimetypeId($mimetype); } return $this->mimeTypeIds[$mimetype]; } /** * check if a cache upgrade is required for $user * * @param string $user * @return bool */ static function needUpgrade($user) { $cacheVersion = (int)\OCP\Config::getUserValue($user, 'files', 'cache_version', 4); return $cacheVersion < 5; } /** * mark the filecache as upgrade * * @param string $user */ 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); } }