/** * new add data set to database * * @param array $data */ public function add($data) { $source = $data['id']; $timestamp = time(); $this->connection->beginTransaction(); $query = $this->connection->getQueryBuilder(); $query->insert($this->table)->values(['source' => $query->createNamedParameter($source), 'timestamp' => $query->createNamedParameter($timestamp), 'category' => $query->createParameter('category'), 'key' => $query->createParameter('key'), 'value' => $query->createParameter('value')]); $this->removeOldStatistics($source); foreach ($data['items'] as $item) { $query->setParameter('category', $item[0])->setParameter('key', $item[1])->setParameter('value', $item[2]); $query->execute(); } $this->connection->commit(); }
/** * @param string $dir * @throws \OC\ForbiddenException */ public function scan($dir = '') { if (!Filesystem::isValidPath($dir)) { throw new \InvalidArgumentException('Invalid path to scan'); } $mounts = $this->getMounts($dir); foreach ($mounts as $mount) { if (is_null($mount->getStorage())) { continue; } $storage = $mount->getStorage(); // if the home storage isn't writable then the scanner is run as the wrong user if ($storage->instanceOfStorage('\\OC\\Files\\Storage\\Home') and (!$storage->isCreatable('') or !$storage->isCreatable('files'))) { throw new ForbiddenException(); } $relativePath = $mount->getInternalPath($dir); $scanner = $storage->getScanner(); $scanner->setUseTransactions(false); $this->attachListener($mount); $isDbLocking = \OC::$server->getLockingProvider() instanceof DBLockingProvider; if (!$isDbLocking) { $this->db->beginTransaction(); } try { $scanner->scan($relativePath, \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE); } catch (StorageNotAvailableException $e) { $this->logger->error('Storage ' . $storage->getId() . ' not available'); $this->logger->logException($e); $this->emit('\\OC\\Files\\Utils\\Scanner', 'StorageNotAvailable', [$e]); } if (!$isDbLocking) { $this->db->commit(); } } }
/** * Update properties * * @param Node $node node for which to update properties * @param array $properties array of properties to update * * @return bool */ private function updateProperties($node, $properties) { $path = $node->getPath(); $deleteStatement = 'DELETE FROM `*PREFIX*properties`' . ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; $insertStatement = 'INSERT INTO `*PREFIX*properties`' . ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)'; $updateStatement = 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' . ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; // TODO: use "insert or update" strategy ? $existing = $this->getProperties($node, array()); $this->connection->beginTransaction(); foreach ($properties as $propertyName => $propertyValue) { // If it was null, we need to delete the property if (is_null($propertyValue)) { if (array_key_exists($propertyName, $existing)) { $this->connection->executeUpdate($deleteStatement, array($this->user, $path, $propertyName)); } } else { if (!array_key_exists($propertyName, $existing)) { $this->connection->executeUpdate($insertStatement, array($this->user, $path, $propertyName, $propertyValue)); } else { $this->connection->executeUpdate($updateStatement, array($propertyValue, $this->user, $path, $propertyName)); } } } $this->connection->commit(); unset($this->cache[$path]); return true; }
/** * Move a file or folder in the cache * * @param \OC\Files\Cache\Cache $sourceCache * @param string $sourcePath * @param string $targetPath * @throws \OC\DatabaseException */ public function moveFromCache(Cache $sourceCache, $sourcePath, $targetPath) { // normalize source and target $sourcePath = $this->normalize($sourcePath); $targetPath = $this->normalize($targetPath); $sourceData = $sourceCache->get($sourcePath); $sourceId = $sourceData['fileid']; $newParentId = $this->getParentId($targetPath); list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath); list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath); // sql for final update $moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?'; if ($sourceData['mimetype'] === 'httpd/unix-directory') { //find all child entries $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?'; $result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']); $childEntries = $result->fetchAll(); $sourceLength = strlen($sourcePath); $this->connection->beginTransaction(); $query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); foreach ($childEntries as $child) { $newTargetPath = $targetPath . substr($child['path'], $sourceLength); $query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]); } $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]); $this->connection->commit(); } else { $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]); } }
/** * Commit the active propagation batch */ public function commitBatch() { if (!$this->inBatch) { throw new \BadMethodCallException('Not in batch'); } $this->inBatch = false; $this->connection->beginTransaction(); $query = $this->connection->getQueryBuilder(); $storageId = (int) $this->storage->getStorageCache()->getNumericId(); $query->update('filecache')->set('mtime', $query->createFunction('GREATEST(`mtime`, ' . $query->createParameter('time') . ')'))->set('etag', $query->expr()->literal(uniqid()))->where($query->expr()->eq('storage', $query->expr()->literal($storageId, IQueryBuilder::PARAM_INT)))->andWhere($query->expr()->eq('path_hash', $query->createParameter('hash'))); $sizeQuery = $this->connection->getQueryBuilder(); $sizeQuery->update('filecache')->set('size', $sizeQuery->createFunction('`size` + ' . $sizeQuery->createParameter('size')))->where($query->expr()->eq('storage', $query->expr()->literal($storageId, IQueryBuilder::PARAM_INT)))->andWhere($query->expr()->eq('path_hash', $query->createParameter('hash')))->andWhere($sizeQuery->expr()->gt('size', $sizeQuery->expr()->literal(-1, IQueryBuilder::PARAM_INT))); foreach ($this->batch as $item) { $query->setParameter('time', $item['time'], IQueryBuilder::PARAM_INT); $query->setParameter('hash', $item['hash']); $query->execute(); if ($item['size']) { $sizeQuery->setParameter('size', $item['size'], IQueryBuilder::PARAM_INT); $sizeQuery->setParameter('hash', $item['hash']); $sizeQuery->execute(); } } $this->batch = []; $this->connection->commit(); }
/** * @param string $dir * @throws \OC\ForbiddenException */ public function scan($dir = '') { if (!Filesystem::isValidPath($dir)) { throw new \InvalidArgumentException('Invalid path to scan'); } $mounts = $this->getMounts($dir); foreach ($mounts as $mount) { if (is_null($mount->getStorage())) { continue; } $storage = $mount->getStorage(); // if the home storage isn't writable then the scanner is run as the wrong user if ($storage->instanceOfStorage('\\OC\\Files\\Storage\\Home') and (!$storage->isCreatable('') or !$storage->isCreatable('files'))) { throw new ForbiddenException(); } $relativePath = $mount->getInternalPath($dir); $scanner = $storage->getScanner(); $scanner->setUseTransactions(false); $this->attachListener($mount); $this->db->beginTransaction(); $scanner->scan($relativePath, \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE); $this->db->commit(); } $this->propagator->propagateChanges(time()); }
/** * @param string $dir * @throws \OC\ForbiddenException */ public function scan($dir = '') { if (!Filesystem::isValidPath($dir)) { throw new \InvalidArgumentException('Invalid path to scan'); } $mounts = $this->getMounts($dir); foreach ($mounts as $mount) { if (is_null($mount->getStorage())) { continue; } $storage = $mount->getStorage(); // if the home storage isn't writable then the scanner is run as the wrong user if ($storage->instanceOfStorage('\\OC\\Files\\Storage\\Home') and (!$storage->isCreatable('') or !$storage->isCreatable('files'))) { if ($storage->file_exists('') or $storage->getCache()->inCache('')) { throw new ForbiddenException(); } else { // if the root exists in neither the cache nor the storage the user isn't setup yet break; } } $relativePath = $mount->getInternalPath($dir); $scanner = $storage->getScanner(); $scanner->setUseTransactions(false); $this->attachListener($mount); $isDbLocking = \OC::$server->getLockingProvider() instanceof DBLockingProvider; $scanner->listen('\\OC\\Files\\Cache\\Scanner', 'removeFromCache', function ($path) use($storage) { $this->triggerPropagator($storage, $path); }); $scanner->listen('\\OC\\Files\\Cache\\Scanner', 'updateCache', function ($path) use($storage) { $this->triggerPropagator($storage, $path); }); $scanner->listen('\\OC\\Files\\Cache\\Scanner', 'addToCache', function ($path) use($storage) { $this->triggerPropagator($storage, $path); }); if (!$isDbLocking) { $this->db->beginTransaction(); } try { $storage->getPropagator()->beginBatch(); $scanner->scan($relativePath, \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE); $cache = $storage->getCache(); if ($cache instanceof Cache) { // only re-calculate for the root folder we scanned, anything below that is taken care of by the scanner $cache->correctFolderSize($relativePath); } $storage->getPropagator()->commitBatch(); } catch (StorageNotAvailableException $e) { $this->logger->error('Storage ' . $storage->getId() . ' not available'); $this->logger->logException($e); $this->emit('\\OC\\Files\\Utils\\Scanner', 'StorageNotAvailable', [$e]); } if (!$isDbLocking) { $this->db->commit(); } } }
/** * update database with the new owners * * @param array $owners * @throws \Exception */ private function updateOwners($owners) { $this->connection->beginTransaction(); try { foreach ($owners as $id => $owner) { $query = $this->connection->getQueryBuilder(); $query->update($this->table)->set('parent', $query->createNamedParameter(null))->set('uid_owner', $query->createNamedParameter($owner['owner']))->set('uid_initiator', $query->createNamedParameter($owner['initiator']))->where($query->expr()->eq('id', $query->createNamedParameter($id)))->execute(); } $this->connection->commit(); } catch (\Exception $e) { $this->connection->rollBack(); throw $e; } }
private function migrate(LegacyStoragesService $legacyService, StoragesService $storageService) { $existingStorage = $legacyService->getAllStorages(); $this->connection->beginTransaction(); try { foreach ($existingStorage as $storage) { $storageService->addStorage($storage); } $this->connection->commit(); } catch (\Exception $e) { $this->logger->logException($e); $this->connection->rollBack(); } }
/** * @param string $path * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE * @throws \OCP\Lock\LockedException */ public function acquireLock($path, $type) { if ($this->connection->inTransaction()) { $this->logger->warning("Trying to acquire a lock for '{$path}' while inside a transition"); } $this->connection->beginTransaction(); $this->initLockField($path); if ($type === self::LOCK_SHARED) { $result = $this->connection->executeUpdate('UPDATE `*PREFIX*file_locks` SET `lock` = `lock` + 1 WHERE `key` = ? AND `lock` >= 0', [$path]); } else { $result = $this->connection->executeUpdate('UPDATE `*PREFIX*file_locks` SET `lock` = -1 WHERE `key` = ? AND `lock` = 0', [$path]); } $this->connection->commit(); if ($result !== 1) { throw new LockedException($path); } $this->markAcquire($path, $type); }
private function migrate(LegacyStoragesService $legacyService, StoragesService $storageService) { $existingStorage = $legacyService->getAllStorages(); $this->connection->beginTransaction(); try { foreach ($existingStorage as $storage) { $mountOptions = $storage->getMountOptions(); if (!empty($mountOptions) && !isset($mountOptions['enable_sharing'])) { // existing mounts must have sharing enabled by default to avoid surprises $mountOptions['enable_sharing'] = true; $storage->setMountOptions($mountOptions); } $storageService->addStorage($storage); } $this->connection->commit(); } catch (\Exception $e) { $this->logger->logException($e); $this->connection->rollBack(); } }
/** * {@inheritdoc} */ public function setTagGroups(ISystemTag $tag, $groupIds) { // delete relationships first $this->connection->beginTransaction(); try { $query = $this->connection->getQueryBuilder(); $query->delete(self::TAG_GROUP_TABLE)->where($query->expr()->eq('systemtagid', $query->createNamedParameter($tag->getId())))->execute(); // add each group id $query = $this->connection->getQueryBuilder(); $query->insert(self::TAG_GROUP_TABLE)->values(['systemtagid' => $query->createNamedParameter($tag->getId()), 'gid' => $query->createParameter('gid')]); foreach ($groupIds as $groupId) { $query->setParameter('gid', $groupId); $query->execute(); } $this->connection->commit(); } catch (\Exception $e) { $this->connection->rollback(); throw $e; } }
/** * Share a path * * @param \OCP\Share\IShare $share * @return \OCP\Share\IShare The share object * @throws ShareNotFound * @throws \Exception */ public function create(\OCP\Share\IShare $share) { $qb = $this->dbConn->getQueryBuilder(); $qb->insert('share'); $qb->setValue('share_type', $qb->createNamedParameter($share->getShareType())); if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { //Set the UID of the user we share with $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith())); } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { //Set the GID of the group we share with $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith())); } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { //Set the token of the share $qb->setValue('token', $qb->createNamedParameter($share->getToken())); //If a password is set store it if ($share->getPassword() !== null) { $qb->setValue('share_with', $qb->createNamedParameter($share->getPassword())); } //If an expiration date is set store it if ($share->getExpirationDate() !== null) { $qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime')); } if (method_exists($share, 'getParent')) { $qb->setValue('parent', $qb->createNamedParameter($share->getParent())); } } else { throw new \Exception('invalid share type!'); } } } // Set what is shares $qb->setValue('item_type', $qb->createParameter('itemType')); if ($share->getNode() instanceof \OCP\Files\File) { $qb->setParameter('itemType', 'file'); } else { $qb->setParameter('itemType', 'folder'); } // Set the file id $qb->setValue('item_source', $qb->createNamedParameter($share->getNode()->getId())); $qb->setValue('file_source', $qb->createNamedParameter($share->getNode()->getId())); // set the permissions $qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions())); // Set who created this share $qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy())); // Set who is the owner of this file/folder (and this the owner of the share) $qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner())); // Set the file target $qb->setValue('file_target', $qb->createNamedParameter($share->getTarget())); // Set the time this share was created $qb->setValue('stime', $qb->createNamedParameter(time())); // insert the data and fetch the id of the share $this->dbConn->beginTransaction(); $qb->execute(); $id = $this->dbConn->lastInsertId('*PREFIX*share'); $this->dbConn->commit(); // Now fetch the inserted share and create a complete share object $qb = $this->dbConn->getQueryBuilder(); $qb->select('*')->from('share')->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); $cursor = $qb->execute(); $data = $cursor->fetch(); $cursor->closeCursor(); if ($data === false) { throw new ShareNotFound(); } $share = $this->createShare($data); return $share; }
/** * Converts legacy home storage ids in the format * "local::/data/dir/path/userid/" to the new format "home::userid" */ public function run(IOutput $out) { // only run once if ($this->config->getAppValue('core', 'repairlegacystoragesdone') === 'yes') { return; } $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); $dataDir = rtrim($dataDir, '/') . '/'; $dataDirId = 'local::' . $dataDir; $count = 0; $hasWarnings = false; $this->connection->beginTransaction(); // note: not doing a direct UPDATE with the REPLACE function // because regexp search/extract is needed and it is not guaranteed // to work on all database types $sql = 'SELECT `id`, `numeric_id` FROM `*PREFIX*storages`' . ' WHERE `id` LIKE ?' . ' ORDER BY `id`'; $result = $this->connection->executeQuery($sql, array($dataDirId . '%')); while ($row = $result->fetch()) { $currentId = $row['id']; // one entry is the datadir itself if ($currentId === $dataDirId) { continue; } try { if ($this->fixLegacyStorage($currentId, (int) $row['numeric_id'])) { $count++; } } catch (RepairException $e) { $hasWarnings = true; $out->warning('Could not repair legacy storage ' . $currentId . ' automatically.'); } } // check for md5 ids, not in the format "prefix::" $sql = 'SELECT COUNT(*) AS "c" FROM `*PREFIX*storages`' . ' WHERE `id` NOT LIKE \'%::%\''; $result = $this->connection->executeQuery($sql); $row = $result->fetch(); // find at least one to make sure it's worth // querying the user list if ((int) $row['c'] > 0) { $userManager = \OC::$server->getUserManager(); // use chunks to avoid caching too many users in memory $limit = 30; $offset = 0; do { // query the next page of users $results = $userManager->search('', $limit, $offset); $storageIds = array(); foreach ($results as $uid => $userObject) { $storageId = $dataDirId . $uid . '/'; if (strlen($storageId) <= 64) { // skip short storage ids as they were handled in the previous section continue; } $storageIds[$uid] = $storageId; } if (count($storageIds) > 0) { // update the storages of these users foreach ($storageIds as $uid => $storageId) { $numericId = Storage::getNumericStorageId($storageId); try { if (!is_null($numericId) && $this->fixLegacyStorage($storageId, (int) $numericId)) { $count++; } } catch (RepairException $e) { $hasWarnings = true; $out->warning('Could not repair legacy storage ' . $storageId . ' automatically.'); } } } $offset += $limit; } while (count($results) >= $limit); } $out->info('Updated ' . $count . ' legacy home storage ids'); $this->connection->commit(); if ($hasWarnings) { $out->warning('Some legacy storages could not be repaired. Please manually fix them then re-run ./occ maintenance:repair'); } else { // if all were done, no need to redo the repair during next upgrade $this->config->setAppValue('core', 'repairlegacystoragesdone', 'yes'); } }
/** * Commit the database changes done during a transaction that is in progress */ public function commit() { $this->connection->commit(); }