$paths[] = \OC::$SERVERROOT . '/core/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
} else if ($split[1] === 'settings') {
$paths[] = \OC::$SERVERROOT . '/settings/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
- } else if ($split[1] === 'repair') {
- $paths[] = \OC::$SERVERROOT . '/lib/repair/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
-
} else {
$paths[] = \OC::$SERVERROOT . '/lib/private/' . $split[1] . '/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
}
--- /dev/null
+<?php
+/**
+ * @author Adam Williamson <awilliam@redhat.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @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\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class AssetCache extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Clear asset cache after upgrade';
+ }
+
+ public function run() {
+ if (!\OC_Template::isAssetPipelineEnabled()) {
+ $this->emit('\OC\Repair', 'info', array('Asset pipeline disabled -> nothing to do'));
+ return;
+ }
+ $assetDir = \OC::$server->getConfig()->getSystemValue('assetdirectory', \OC::$SERVERROOT) . '/assets';
+ \OC_Helper::rmdirr($assetDir, false);
+ $this->emit('\OC\Repair', 'info', array('Asset cache cleared.'));
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IDBConnection;
+
+/**
+ * Class RepairConfig
+ *
+ * @package OC\Repair
+ */
+class CleanTags extends BasicEmitter implements RepairStep {
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /**
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return 'Clean tags and favorites';
+ }
+
+ /**
+ * Updates the configuration after running an update
+ */
+ public function run() {
+ $this->deleteOrphanFileEntries();
+ $this->deleteOrphanTagEntries();
+ $this->deleteOrphanCategoryEntries();
+ }
+
+ /**
+ * Delete tag entries for deleted files
+ */
+ protected function deleteOrphanFileEntries() {
+ $this->deleteOrphanEntries(
+ '%d tags for delete files have been removed.',
+ 'vcategory_to_object', 'objid',
+ 'filecache', 'fileid', 'path_hash'
+ );
+ }
+
+ /**
+ * Delete tag entries for deleted tags
+ */
+ protected function deleteOrphanTagEntries() {
+ $this->deleteOrphanEntries(
+ '%d tag entries for deleted tags have been removed.',
+ 'vcategory_to_object', 'categoryid',
+ 'vcategory', 'id', 'uid'
+ );
+ }
+
+ /**
+ * Delete tags that have no entries
+ */
+ protected function deleteOrphanCategoryEntries() {
+ $this->deleteOrphanEntries(
+ '%d tags with no entries have been removed.',
+ 'vcategory', 'id',
+ 'vcategory_to_object', 'categoryid', 'type'
+ );
+ }
+
+ /**
+ * Deletes all entries from $deleteTable that do not have a matching entry in $sourceTable
+ *
+ * A query joins $deleteTable.$deleteId = $sourceTable.$sourceId and checks
+ * whether $sourceNullColumn is null. If it is null, the entry in $deleteTable
+ * is being deleted.
+ *
+ * @param string $repairInfo
+ * @param string $deleteTable
+ * @param string $deleteId
+ * @param string $sourceTable
+ * @param string $sourceId
+ * @param string $sourceNullColumn If this column is null in the source table,
+ * the entry is deleted in the $deleteTable
+ */
+ protected function deleteOrphanEntries($repairInfo, $deleteTable, $deleteId, $sourceTable, $sourceId, $sourceNullColumn) {
+ $qb = $this->connection->getQueryBuilder();
+
+ $qb->select('d.' . $deleteId)
+ ->from($deleteTable, 'd')
+ ->leftJoin('d', $sourceTable, 's', $qb->expr()->eq('d.' . $deleteId, ' s.' . $sourceId))
+ ->where(
+ $qb->expr()->eq('d.type', $qb->expr()->literal('files'))
+ )
+ ->andWhere(
+ $qb->expr()->isNull('s.' . $sourceNullColumn)
+ );
+ $result = $qb->execute();
+
+ $orphanItems = array();
+ while ($row = $result->fetch()) {
+ $orphanItems[] = (int) $row[$deleteId];
+ }
+
+ if (!empty($orphanItems)) {
+ $orphanItemsBatch = array_chunk($orphanItems, 200);
+ foreach ($orphanItemsBatch as $items) {
+ $qb->delete($deleteTable)
+ ->where(
+ $qb->expr()->eq('type', $qb->expr()->literal('files'))
+ )
+ ->andWhere($qb->expr()->in($deleteId, $qb->createParameter('ids')));
+ $qb->setParameter('ids', $items, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
+ $qb->execute();
+ }
+ }
+
+ if ($repairInfo) {
+ $this->emit('\OC\Repair', 'info', array(sprintf($repairInfo, sizeof($orphanItems))));
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @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\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class Collation extends BasicEmitter implements \OC\RepairStep {
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var \OC\DB\Connection
+ */
+ protected $connection;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OC\DB\Connection $connection
+ */
+ public function __construct($config, $connection) {
+ $this->connection = $connection;
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Repair MySQL collation';
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+ if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
+ $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to no'));
+ return;
+ }
+
+ $tables = $this->getAllNonUTF8BinTables($this->connection);
+ foreach ($tables as $table) {
+ $this->emit('\OC\Repair', 'info', array("Change collation for $table ..."));
+ $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
+ $query->execute();
+ }
+ }
+
+ /**
+ * @param \Doctrine\DBAL\Connection $connection
+ * @return string[]
+ */
+ protected function getAllNonUTF8BinTables($connection) {
+ $dbName = $this->config->getSystemValue("dbname");
+ $rows = $connection->fetchAll(
+ "SELECT DISTINCT(TABLE_NAME) AS `table`" .
+ " FROM INFORMATION_SCHEMA . COLUMNS" .
+ " WHERE TABLE_SCHEMA = ?" .
+ " AND (COLLATION_NAME <> 'utf8_bin' OR CHARACTER_SET_NAME <> 'utf8')" .
+ " AND TABLE_NAME LIKE \"*PREFIX*%\"",
+ array($dbName)
+ );
+ $result = array();
+ foreach ($rows as $row) {
+ $result[] = $row['table'];
+ }
+ return $result;
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\BackgroundJob\IJobList;
+
+class DropOldJobs extends BasicEmitter implements RepairStep {
+
+ /** @var IJobList */
+ protected $jobList;
+
+ /**
+ * @param IJobList $jobList
+ */
+ public function __construct(IJobList $jobList) {
+ $this->jobList = $jobList;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ */
+ public function getName() {
+ return 'Drop old background jobs';
+ }
+
+ /**
+ * Run repair step.
+ * Must throw exception on error.
+ *
+ * @throws \Exception in case of failure
+ */
+ public function run() {
+ $oldJobs = $this->oldJobs();
+ foreach($oldJobs as $job) {
+ if($this->jobList->has($job['class'], $job['arguments'])) {
+ $this->jobList->remove($job['class'], $job['arguments']);
+ }
+ }
+ }
+
+ /**
+ * returns a list of old jobs as an associative array with keys 'class' and
+ * 'arguments'.
+ *
+ * @return array
+ */
+ public function oldJobs() {
+ return [
+ ['class' => 'OC_Cache_FileGlobalGC', 'arguments' => null],
+ ['class' => 'OC\Cache\FileGlobalGC', 'arguments' => null],
+ ];
+ }
+
+
+}
--- /dev/null
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@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\Repair;
+
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IDBConnection;
+
+class DropOldTables extends BasicEmitter implements RepairStep {
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /**
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ */
+ public function getName() {
+ return 'Drop old database tables';
+ }
+
+ /**
+ * Run repair step.
+ * Must throw exception on error.
+ *
+ * @throws \Exception in case of failure
+ */
+ public function run() {
+ foreach ($this->oldDatabaseTables() as $tableName) {
+ if ($this->connection->tableExists($tableName)){
+ $this->emit('\OC\Repair', 'info', [
+ sprintf('Table %s has been deleted', $tableName)
+ ]);
+ $this->connection->dropTable($tableName);
+ }
+ }
+ }
+
+ /**
+ * Returns a list of outdated tables which are not used anymore
+ * @return array
+ */
+ protected function oldDatabaseTables() {
+ return [
+ 'calendar_calendars',
+ 'calendar_objects',
+ 'calendar_share_calendar',
+ 'calendar_share_event',
+ 'file_map',
+ 'foldersize',
+ 'fscache',
+ 'gallery_sharing',
+ 'locks',
+ 'log',
+ 'media_albums',
+ 'media_artists',
+ 'media_sessions',
+ 'media_songs',
+ 'media_users',
+ 'permissions',
+ 'pictures_images_cache',
+ 'principalgroups',
+ 'principals',
+ 'queuedtasks',
+ 'sharing',
+ ];
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+class FillETags extends BasicEmitter implements \OC\RepairStep {
+
+ /** @var \OCP\IDBConnection */
+ protected $connection;
+
+ /**
+ * @param \OCP\IDBConnection $connection
+ */
+ public function __construct($connection) {
+ $this->connection = $connection;
+ }
+
+ public function getName() {
+ return 'Generate ETags for file where no ETag is present.';
+ }
+
+ public function run() {
+ $qb = $this->connection->getQueryBuilder();
+ $qb->update('filecache')
+ ->set('etag', $qb->expr()->literal('xxx'))
+ ->where($qb->expr()->eq('etag', $qb->expr()->literal('')))
+ ->orWhere($qb->expr()->isNull('etag'));
+
+ $result = $qb->execute();
+ $this->emit('\OC\Repair', 'info', array("ETags have been fixed for $result files/folders."));
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @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\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class InnoDB extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Repair MySQL database engine';
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+ $connection = \OC_DB::getConnection();
+ if (!$connection->getDatabasePlatform() instanceof MySqlPlatform) {
+ $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to do'));
+ return;
+ }
+
+ $tables = $this->getAllMyIsamTables($connection);
+ if (is_array($tables)) {
+ foreach ($tables as $table) {
+ $connection->exec("ALTER TABLE $table ENGINE=InnoDB;");
+ $this->emit('\OC\Repair', 'info', array("Fixed $table"));
+ }
+ }
+ }
+
+ /**
+ * @param \Doctrine\DBAL\Connection $connection
+ * @return string[]
+ */
+ private function getAllMyIsamTables($connection) {
+ $dbName = \OC::$server->getConfig()->getSystemValue("dbname");
+ $result = $connection->fetchArray(
+ "SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND engine = 'MyISAM' AND TABLE_NAME LIKE \"*PREFIX*%\"",
+ array($dbName)
+ );
+
+ return $result;
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@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\Repair;
+
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IDBConnection;
+use OCP\IGroupManager;
+use OCP\Share;
+
+class OldGroupMembershipShares extends BasicEmitter implements RepairStep {
+
+ /** @var \OCP\IDBConnection */
+ protected $connection;
+
+ /** @var \OCP\IGroupManager */
+ protected $groupManager;
+
+ /**
+ * @var array [gid => [uid => (bool)]]
+ */
+ protected $memberships;
+
+ /**
+ * @param IDBConnection $connection
+ * @param IGroupManager $groupManager
+ */
+ public function __construct(IDBConnection $connection, IGroupManager $groupManager) {
+ $this->connection = $connection;
+ $this->groupManager = $groupManager;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ */
+ public function getName() {
+ return 'Remove shares of old group memberships';
+ }
+
+ /**
+ * Run repair step.
+ * Must throw exception on error.
+ *
+ * @throws \Exception in case of failure
+ */
+ public function run() {
+ $deletedEntries = 0;
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['s1.id', $query->createFunction('s1.`share_with` AS `user`'), $query->createFunction('s2.`share_with` AS `group`')])
+ ->from('share', 's1')
+ ->where($query->expr()->isNotNull('s1.parent'))
+ // \OC\Share\Constant::$shareTypeGroupUserUnique === 2
+ ->andWhere($query->expr()->eq('s1.share_type', $query->expr()->literal(2)))
+ ->andWhere($query->expr()->isNotNull('s2.id'))
+ ->andWhere($query->expr()->eq('s2.share_type', $query->expr()->literal(Share::SHARE_TYPE_GROUP)))
+ ->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'));
+
+ $deleteQuery = $this->connection->getQueryBuilder();
+ $deleteQuery->delete('share')
+ ->where($query->expr()->eq('id', $deleteQuery->createParameter('share')));
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ if (!$this->isMember($row['group'], $row['user'])) {
+ $deletedEntries += $deleteQuery->setParameter('share', (int) $row['id'])
+ ->execute();
+ }
+ }
+ $result->closeCursor();
+
+ if ($deletedEntries) {
+ $this->emit('\OC\Repair', 'info', array('Removed ' . $deletedEntries . ' shares where user is not a member of the group anymore'));
+ }
+ }
+
+ /**
+ * @param string $gid
+ * @param string $uid
+ * @return bool
+ */
+ protected function isMember($gid, $uid) {
+ if (isset($this->memberships[$gid][$uid])) {
+ return $this->memberships[$gid][$uid];
+ }
+
+ $isMember = $this->groupManager->isInGroup($uid, $gid);
+ if (!isset($this->memberships[$gid])) {
+ $this->memberships[$gid] = [];
+ }
+ $this->memberships[$gid][$uid] = $isMember;
+
+ return $isMember;
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Georg Ehrke <georg@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\Repair;
+
+use OC\Files\View;
+use OC\Hooks\BasicEmitter;
+
+class Preview extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Cleaning-up broken previews';
+ }
+
+ public function run() {
+ $view = new View('/');
+ $children = $view->getDirectoryContent('/');
+
+ foreach ($children as $child) {
+ if ($view->is_dir($child->getPath())) {
+ $thumbnailsFolder = $child->getPath() . '/thumbnails';
+ if ($view->is_dir($thumbnailsFolder)) {
+ $view->rmdir($thumbnailsFolder);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OCP\IDBConnection;
+
+class RemoveGetETagEntries extends BasicEmitter {
+
+ /**
+ * @var IDBConnection
+ */
+ protected $connection;
+
+ /**
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ public function getName() {
+ return 'Remove getetag entries in properties table';
+ }
+
+ /**
+ * Removes all entries with the key "{DAV:}getetag" from the table properties
+ */
+ public function run() {
+ $sql = 'DELETE FROM `*PREFIX*properties`'
+ . ' WHERE `propertyname` = ?';
+ $deletedRows = $this->connection->executeUpdate($sql, ['{DAV:}getetag']);
+
+ $this->emit(
+ '\OC\Repair',
+ 'info',
+ ['Removed ' . $deletedRows . ' unneeded "{DAV:}getetag" entries from properties table.']
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Vincent Petry <pvince81@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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+/**
+ * Repairs shares with invalid data
+ */
+class RepairInvalidShares extends BasicEmitter implements \OC\RepairStep {
+
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var \OCP\IDBConnection
+ */
+ protected $connection;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OCP\IDBConnection $connection
+ */
+ public function __construct($config, $connection) {
+ $this->connection = $connection;
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Repair invalid shares';
+ }
+
+ /**
+ * Past bugs would make it possible to set an expiration date on user shares even
+ * though it is not supported. This functions removes the expiration date from such entries.
+ */
+ private function removeExpirationDateFromNonLinkShares() {
+ $builder = $this->connection->getQueryBuilder();
+ $builder
+ ->update('share')
+ ->set('expiration', 'null')
+ ->where($builder->expr()->isNotNull('expiration'))
+ ->andWhere($builder->expr()->neq('share_type', $builder->expr()->literal(\OC\Share\Constants::SHARE_TYPE_LINK)));
+
+ $updatedEntries = $builder->execute();
+ if ($updatedEntries > 0) {
+ $this->emit('\OC\Repair', 'info', array('Removed invalid expiration date from ' . $updatedEntries . ' shares'));
+ }
+ }
+
+ /**
+ * Remove shares where the parent share does not exist anymore
+ */
+ private function removeSharesNonExistingParent() {
+ $deletedEntries = 0;
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('s1.parent')
+ ->from('share', 's1')
+ ->where($query->expr()->isNotNull('s1.parent'))
+ ->andWhere($query->expr()->isNull('s2.id'))
+ ->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'))
+ ->groupBy('s1.parent');
+
+ $deleteQuery = $this->connection->getQueryBuilder();
+ $deleteQuery->delete('share')
+ ->where($query->expr()->eq('parent', $deleteQuery->createParameter('parent')));
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $deletedEntries += $deleteQuery->setParameter('parent', (int) $row['parent'])
+ ->execute();
+ }
+ $result->closeCursor();
+
+ if ($deletedEntries) {
+ $this->emit('\OC\Repair', 'info', array('Removed ' . $deletedEntries . ' shares where the parent did not exist'));
+ }
+ }
+
+ public function run() {
+ $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
+ if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.7', '<')) {
+ // this situation was only possible before 8.2
+ $this->removeExpirationDateFromNonLinkShares();
+ }
+
+ $this->removeSharesNonExistingParent();
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Vincent Petry <pvince81@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\Repair;
+
+use OC\Files\Cache\Storage;
+use OC\Hooks\BasicEmitter;
+use OC\RepairException;
+
+class RepairLegacyStorages extends BasicEmitter {
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var \OCP\IDBConnection
+ */
+ protected $connection;
+
+ protected $findStorageInCacheStatement;
+ protected $renameStorageStatement;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OCP\IDBConnection $connection
+ */
+ public function __construct($config, $connection) {
+ $this->connection = $connection;
+ $this->config = $config;
+
+ $this->findStorageInCacheStatement = $this->connection->prepare(
+ 'SELECT DISTINCT `storage` FROM `*PREFIX*filecache`'
+ . ' WHERE `storage` in (?, ?)'
+ );
+ $this->renameStorageStatement = $this->connection->prepare(
+ 'UPDATE `*PREFIX*storages`'
+ . ' SET `id` = ?'
+ . ' WHERE `id` = ?'
+ );
+ }
+
+ public function getName() {
+ return 'Repair legacy storages';
+ }
+
+ /**
+ * Extracts the user id from a legacy storage id
+ *
+ * @param string $storageId legacy storage id in the
+ * format "local::/path/to/datadir/userid"
+ * @return string user id extracted from the storage id
+ */
+ private function extractUserId($storageId) {
+ $storageId = rtrim($storageId, '/');
+ $pos = strrpos($storageId, '/');
+ return substr($storageId, $pos + 1);
+ }
+
+ /**
+ * Fix the given legacy storage by renaming the old id
+ * to the new id. If the new id already exists, whichever
+ * storage that has data in the file cache will be used.
+ * If both have data, nothing will be done and false is
+ * returned.
+ *
+ * @param string $oldId old storage id
+ * @param int $oldNumericId old storage numeric id
+ * @param string $userId
+ * @return bool true if fixed, false otherwise
+ * @throws RepairException
+ */
+ private function fixLegacyStorage($oldId, $oldNumericId, $userId = null) {
+ // check whether the new storage already exists
+ if (is_null($userId)) {
+ $userId = $this->extractUserId($oldId);
+ }
+ $newId = 'home::' . $userId;
+
+ // check if target id already exists
+ $newNumericId = Storage::getNumericStorageId($newId);
+ if (!is_null($newNumericId)) {
+ $newNumericId = (int)$newNumericId;
+ // try and resolve the conflict
+ // check which one of "local::" or "home::" needs to be kept
+ $this->findStorageInCacheStatement->execute(array($oldNumericId, $newNumericId));
+ $row1 = $this->findStorageInCacheStatement->fetch();
+ $row2 = $this->findStorageInCacheStatement->fetch();
+ $this->findStorageInCacheStatement->closeCursor();
+ if ($row2 !== false) {
+ // two results means both storages have data, not auto-fixable
+ throw new RepairException(
+ 'Could not automatically fix legacy storage '
+ . '"' . $oldId . '" => "' . $newId . '"'
+ . ' because they both have data.'
+ );
+ }
+ if ($row1 === false || (int)$row1['storage'] === $oldNumericId) {
+ // old storage has data, then delete the empty new id
+ $toDelete = $newId;
+ } else if ((int)$row1['storage'] === $newNumericId) {
+ // new storage has data, then delete the empty old id
+ $toDelete = $oldId;
+ } else {
+ // unknown case, do not continue
+ return false;
+ }
+
+ // delete storage including file cache
+ Storage::remove($toDelete);
+
+ // if we deleted the old id, the new id will be used
+ // automatically
+ if ($toDelete === $oldId) {
+ // nothing more to do
+ return true;
+ }
+ }
+
+ // rename old id to new id
+ $newId = Storage::adjustStorageId($newId);
+ $oldId = Storage::adjustStorageId($oldId);
+ $rowCount = $this->renameStorageStatement->execute(array($newId, $oldId));
+ $this->renameStorageStatement->closeCursor();
+ return ($rowCount === 1);
+ }
+
+ /**
+ * Converts legacy home storage ids in the format
+ * "local::/data/dir/path/userid/" to the new format "home::userid"
+ */
+ public function run() {
+ // 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;
+ $this->emit(
+ '\OC\Repair',
+ 'warning',
+ array('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;
+ $this->emit(
+ '\OC\Repair',
+ 'warning',
+ array('Could not repair legacy storage ' . $storageId . ' automatically.')
+ );
+ }
+ }
+ }
+ $offset += $limit;
+ } while (count($results) >= $limit);
+ }
+
+ $this->emit('\OC\Repair', 'info', array('Updated ' . $count . ' legacy home storage ids'));
+
+ $this->connection->commit();
+
+ if ($hasWarnings) {
+ $this->emit(
+ '\OC\Repair',
+ 'warning',
+ array('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');
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Normal Ra <normalraw@gmail.com>
+ * @author Olivier Paroz <github@oparoz.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Victor Dubiniuk <dubiniuk@owncloud.com>
+ * @author Vincent Petry <pvince81@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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+class RepairMimeTypes extends BasicEmitter implements \OC\RepairStep {
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var int
+ */
+ protected $folderMimeTypeId;
+
+ /**
+ * @param \OCP\IConfig $config
+ */
+ public function __construct($config) {
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Repair mime types';
+ }
+
+ private static function existsStmt() {
+ return \OC_DB::prepare('
+ SELECT count(`mimetype`)
+ FROM `*PREFIX*mimetypes`
+ WHERE `mimetype` = ?
+ ');
+ }
+
+ private static function getIdStmt() {
+ return \OC_DB::prepare('
+ SELECT `id`
+ FROM `*PREFIX*mimetypes`
+ WHERE `mimetype` = ?
+ ');
+ }
+
+ private static function insertStmt() {
+ return \OC_DB::prepare('
+ INSERT INTO `*PREFIX*mimetypes` ( `mimetype` )
+ VALUES ( ? )
+ ');
+ }
+
+ private static function updateWrongStmt() {
+ return \OC_DB::prepare('
+ UPDATE `*PREFIX*filecache`
+ SET `mimetype` = (
+ SELECT `id`
+ FROM `*PREFIX*mimetypes`
+ WHERE `mimetype` = ?
+ ) WHERE `mimetype` = ?
+ ');
+ }
+
+ private static function deleteStmt() {
+ return \OC_DB::prepare('
+ DELETE FROM `*PREFIX*mimetypes`
+ WHERE `id` = ?
+ ');
+ }
+
+ private static function updateByNameStmt() {
+ return \OC_DB::prepare('
+ UPDATE `*PREFIX*filecache`
+ SET `mimetype` = ?
+ WHERE `mimetype` <> ? AND `mimetype` <> ? AND `name` ILIKE ?
+ ');
+ }
+
+ private function repairMimetypes($wrongMimetypes) {
+ foreach ($wrongMimetypes as $wrong => $correct) {
+ // do we need to remove a wrong mimetype?
+ $result = \OC_DB::executeAudited(self::getIdStmt(), array($wrong));
+ $wrongId = $result->fetchOne();
+
+ if ($wrongId !== false) {
+ // do we need to insert the correct mimetype?
+ $result = \OC_DB::executeAudited(self::existsStmt(), array($correct));
+ $exists = $result->fetchOne();
+
+ if (!is_null($correct)) {
+ if (!$exists) {
+ // insert mimetype
+ \OC_DB::executeAudited(self::insertStmt(), array($correct));
+ }
+
+ // change wrong mimetype to correct mimetype in filecache
+ \OC_DB::executeAudited(self::updateWrongStmt(), array($correct, $wrongId));
+ }
+
+ // delete wrong mimetype
+ \OC_DB::executeAudited(self::deleteStmt(), array($wrongId));
+
+ }
+ }
+ }
+
+ private function updateMimetypes($updatedMimetypes) {
+ if (empty($this->folderMimeTypeId)) {
+ $result = \OC_DB::executeAudited(self::getIdStmt(), array('httpd/unix-directory'));
+ $this->folderMimeTypeId = (int)$result->fetchOne();
+ }
+
+ foreach ($updatedMimetypes as $extension => $mimetype) {
+ $result = \OC_DB::executeAudited(self::existsStmt(), array($mimetype));
+ $exists = $result->fetchOne();
+
+ if (!$exists) {
+ // insert mimetype
+ \OC_DB::executeAudited(self::insertStmt(), array($mimetype));
+ }
+
+ // get target mimetype id
+ $result = \OC_DB::executeAudited(self::getIdStmt(), array($mimetype));
+ $mimetypeId = $result->fetchOne();
+
+ // change mimetype for files with x extension
+ \OC_DB::executeAudited(self::updateByNameStmt(), array($mimetypeId, $this->folderMimeTypeId, $mimetypeId, '%.' . $extension));
+ }
+ }
+
+ private function fixOfficeMimeTypes() {
+ // update wrong mimetypes
+ $wrongMimetypes = array(
+ 'application/mspowerpoint' => 'application/vnd.ms-powerpoint',
+ 'application/msexcel' => 'application/vnd.ms-excel',
+ );
+
+ self::repairMimetypes($wrongMimetypes);
+
+ $updatedMimetypes = array(
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ );
+
+
+ // separate doc from docx etc
+ self::updateMimetypes($updatedMimetypes);
+
+ }
+
+ private function fixApkMimeType() {
+ $updatedMimetypes = array(
+ 'apk' => 'application/vnd.android.package-archive',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function fixFontsMimeTypes() {
+ // update wrong mimetypes
+ $wrongMimetypes = array(
+ 'font' => null,
+ 'font/opentype' => 'application/font-sfnt',
+ 'application/x-font-ttf' => 'application/font-sfnt',
+ );
+
+ self::repairMimetypes($wrongMimetypes);
+
+ $updatedMimetypes = array(
+ 'ttf' => 'application/font-sfnt',
+ 'otf' => 'application/font-sfnt',
+ 'pfb' => 'application/x-font',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function fixPostscriptMimeType() {
+ $updatedMimetypes = array(
+ 'eps' => 'application/postscript',
+ 'ps' => 'application/postscript',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceRawMimeType() {
+ $updatedMimetypes = array(
+ 'arw' => 'image/x-dcraw',
+ 'cr2' => 'image/x-dcraw',
+ 'dcr' => 'image/x-dcraw',
+ 'dng' => 'image/x-dcraw',
+ 'erf' => 'image/x-dcraw',
+ 'iiq' => 'image/x-dcraw',
+ 'k25' => 'image/x-dcraw',
+ 'kdc' => 'image/x-dcraw',
+ 'mef' => 'image/x-dcraw',
+ 'nef' => 'image/x-dcraw',
+ 'orf' => 'image/x-dcraw',
+ 'pef' => 'image/x-dcraw',
+ 'raf' => 'image/x-dcraw',
+ 'rw2' => 'image/x-dcraw',
+ 'srf' => 'image/x-dcraw',
+ 'sr2' => 'image/x-dcraw',
+ 'xrf' => 'image/x-dcraw',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduce3dImagesMimeType() {
+ $updatedMimetypes = array(
+ 'jps' => 'image/jpeg',
+ 'mpo' => 'image/jpeg',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceConfMimeType() {
+ $updatedMimetypes = array(
+ 'conf' => 'text/plain',
+ 'cnf' => 'text/plain',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceYamlMimeType() {
+ $updatedMimetypes = array(
+ 'yaml' => 'application/yaml',
+ 'yml' => 'application/yaml',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceJavaMimeType() {
+ $updatedMimetypes = array(
+ 'class' => 'application/java',
+ 'java' => 'text/x-java-source',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceHppMimeType() {
+ $updatedMimetypes = array(
+ 'hpp' => 'text/x-h',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceRssMimeType() {
+ $updatedMimetypes = array(
+ 'rss' => 'application/rss+xml',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceRtfMimeType() {
+ $updatedMimetypes = array(
+ 'rtf' => 'text/rtf',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+
+ $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
+
+ // NOTE TO DEVELOPERS: when adding new mime types, please make sure to
+ // add a version comparison to avoid doing it every time
+
+ // only update mime types if necessary as it can be expensive
+ if (version_compare($ocVersionFromBeforeUpdate, '8.2.0', '<')) {
+ if ($this->fixOfficeMimeTypes()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed office mime types'));
+ }
+
+ if ($this->fixApkMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed APK mime type'));
+ }
+
+ if ($this->fixFontsMimeTypes()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed fonts mime types'));
+ }
+
+ if ($this->fixPostscriptMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Postscript mime types'));
+ }
+
+ if ($this->introduceRawMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Raw mime types'));
+ }
+
+ if ($this->introduce3dImagesMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed 3D images mime types'));
+ }
+
+ if ($this->introduceConfMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Conf/cnf mime types'));
+ }
+
+ if ($this->introduceYamlMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Yaml/Yml mime types'));
+ }
+ }
+
+ // Mimetype updates from #19272
+ if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.8', '<')) {
+ if ($this->introduceJavaMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed java/class mime types'));
+ }
+
+ if ($this->introduceHppMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed hpp mime type'));
+ }
+
+ if ($this->introduceRssMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed rss mime type'));
+ }
+
+ if ($this->introduceRtfMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed rtf mime type'));
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+class SearchLuceneTables extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Repair duplicate entries in oc_lucene_status';
+ }
+
+ /**
+ * Fix duplicate entries in oc_lucene_status
+ *
+ * search_lucene prior to v0.5.0 did not have a primary key on the lucene_status table. Newer versions do, which
+ * causes the migration check to fail because it tries to insert duplicate rows into the new schema.
+ *
+ * FIXME Currently, apps don't have a way of repairing anything before the migration check:
+ * @link https://github.com/owncloud/core/issues/10980
+ *
+ * As a result this repair step needs to live in the core repo, although it belongs into search_lucene:
+ * @link https://github.com/owncloud/core/issues/10205#issuecomment-54957557
+ *
+ * It will completely remove any rows that make a file id have more than one status:
+ * fileid | status fileid | status
+ * --------+-------- will become --------+--------
+ * 2 | E 3 | E
+ * 2 | I
+ * 3 | E
+ *
+ * search_lucene will then reindex the fileids without a status when the next indexing job is executed
+ */
+ public function run() {
+ if (\OC_DB::tableExists('lucene_status')) {
+ $this->emit('\OC\Repair', 'info', array('removing duplicate entries from lucene_status'));
+
+ $connection = \OC_DB::getConnection();
+ $query = $connection->prepare('
+ DELETE FROM `*PREFIX*lucene_status`
+ WHERE `fileid` IN (
+ SELECT `fileid`
+ FROM (
+ SELECT `fileid`
+ FROM `*PREFIX*lucene_status`
+ GROUP BY `fileid`
+ HAVING count(`fileid`) > 1
+ ) AS `mysqlerr1093hack`
+ )');
+ $query->execute();
+ } else {
+ $this->emit('\OC\Repair', 'info', array('lucene_status table does not exist -> nothing to do'));
+ }
+ }
+
+}
+
--- /dev/null
+<?php
+/**
+ * @author Vincent Petry <pvince81@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\Repair;
+
+use Doctrine\DBAL\Platforms\SqlitePlatform;
+use Doctrine\DBAL\Schema\SchemaException;
+use Doctrine\DBAL\Schema\SchemaDiff;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Schema\ColumnDiff;
+use OC\Hooks\BasicEmitter;
+
+/**
+ * Fixes Sqlite autoincrement by forcing the SQLite table schemas to be
+ * altered in order to retrigger SQL schema generation through OCSqlitePlatform.
+ */
+class SqliteAutoincrement extends BasicEmitter implements \OC\RepairStep {
+ /**
+ * @var \OC\DB\Connection
+ */
+ protected $connection;
+
+ /**
+ * @param \OC\DB\Connection $connection
+ */
+ public function __construct($connection) {
+ $this->connection = $connection;
+ }
+
+ public function getName() {
+ return 'Repair SQLite autoincrement';
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+ if (!$this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
+ return;
+ }
+
+ $sourceSchema = $this->connection->getSchemaManager()->createSchema();
+
+ $schemaDiff = new SchemaDiff();
+
+ foreach ($sourceSchema->getTables() as $tableSchema) {
+ $primaryKey = $tableSchema->getPrimaryKey();
+ if (!$primaryKey) {
+ continue;
+ }
+
+ $columnNames = $primaryKey->getColumns();
+
+ // add a column diff for every primary key column,
+ // but do not actually change anything, this will
+ // force the generation of SQL statements to alter
+ // those tables, which will then trigger the
+ // specific SQL code from OCSqlitePlatform
+ try {
+ $tableDiff = new TableDiff($tableSchema->getName());
+ $tableDiff->fromTable = $tableSchema;
+ foreach ($columnNames as $columnName) {
+ $columnSchema = $tableSchema->getColumn($columnName);
+ $columnDiff = new ColumnDiff($columnSchema->getName(), $columnSchema);
+ $tableDiff->changedColumns[] = $columnDiff;
+ $schemaDiff->changedTables[] = $tableDiff;
+ }
+ } catch (SchemaException $e) {
+ // ignore
+ }
+ }
+
+ $this->connection->beginTransaction();
+ foreach ($schemaDiff->toSql($this->connection->getDatabasePlatform()) as $sql) {
+ $this->connection->query($sql);
+ }
+ $this->connection->commit();
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * @author Lukas Reschke <lukas@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\Repair;
+
+use OC\Files\View;
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OC\Server;
+use OCP\IConfig;
+
+/**
+ * Class UpdateCertificateStore rewrites the user specific certificate store after
+ * an update has been performed. This is done because a new root certificate file
+ * might have been added.
+ *
+ * @package OC\Repair
+ */
+class UpdateCertificateStore extends BasicEmitter implements RepairStep {
+ /**
+ * FIXME: The certificate manager does only allow specifying the user
+ * within the constructor. This makes DI impossible.
+ * @var Server
+ */
+ protected $server;
+ /** @var IConfig */
+ protected $config;
+
+ /**
+ * @param Server $server
+ * @param IConfig $config
+ */
+ public function __construct(Server $server,
+ IConfig $config) {
+ $this->server = $server;
+ $this->config = $config;
+ }
+
+ /** {@inheritDoc} */
+ public function getName() {
+ return 'Update user certificate stores with new root certificates';
+ }
+
+ /** {@inheritDoc} */
+ public function run() {
+ $rootView = new View();
+ $dataDirectory = $this->config->getSystemValue('datadirectory', null);
+ if(is_null($dataDirectory)) {
+ throw new \Exception('No data directory specified');
+ }
+
+ $pathToRootCerts = '/files_external/rootcerts.crt';
+
+ foreach($rootView->getDirectoryContent('', 'httpd/unix-directory') as $fileInfo) {
+ $uid = trim($fileInfo->getPath(), '/');
+ if($rootView->file_exists($uid . $pathToRootCerts)) {
+ // Delete the existing root certificate
+ $rootView->unlink($uid . $pathToRootCerts);
+
+ /**
+ * FIXME: The certificate manager does only allow specifying the user
+ * within the constructor. This makes DI impossible.
+ */
+ // Regenerate the certificates
+ $certificateManager = $this->server->getCertificateManager($uid);
+ $certificateManager->createCertificateBundle();
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Lukas Reschke <lukas@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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IConfig;
+
+/**
+ * Class UpdateOutdatedOcsIds is used to update invalid outdated OCS IDs, this is
+ * for example the case when an application has had another OCS ID in the past such
+ * as for contacts and calendar when apps.owncloud.com migrated to a unified identifier
+ * for multiple versions.
+ *
+ * @package OC\Repair
+ */
+class UpdateOutdatedOcsIds extends BasicEmitter implements RepairStep {
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * @param IConfig $config
+ */
+ public function __construct(IConfig $config) {
+ $this->config = $config;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName() {
+ return 'Repair outdated OCS IDs';
+ }
+
+ /**
+ * @param string $appName
+ * @param string $oldId
+ * @param string $newId
+ * @return bool True if updated, false otherwise
+ */
+ public function fixOcsId($appName, $oldId, $newId) {
+ $existingId = $this->config->getAppValue($appName, 'ocsid');
+
+ if($existingId === $oldId) {
+ $this->config->setAppValue($appName, 'ocsid', $newId);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run() {
+ $appsToUpdate = [
+ 'contacts' => [
+ 'old' => '166044',
+ 'new' => '168708',
+ ],
+ 'calendar' => [
+ 'old' => '166043',
+ 'new' => '168707',
+ ],
+ 'bookmarks' => [
+ 'old' => '166042',
+ 'new' => '168710',
+ ],
+ 'search_lucene' => [
+ 'old' => '166057',
+ 'new' => '168709',
+ ],
+ 'documents' => [
+ 'old' => '166045',
+ 'new' => '168711',
+ ]
+ ];
+
+ foreach($appsToUpdate as $appName => $ids) {
+ if ($this->fixOcsId($appName, $ids['old'], $ids['new'])) {
+ $this->emit(
+ '\OC\Repair',
+ 'info',
+ [sprintf('Fixed invalid %s OCS id', $appName)]
+ );
+ }
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * @author Adam Williamson <awilliam@redhat.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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\Repair;
-
-use Doctrine\DBAL\Platforms\MySqlPlatform;
-use OC\Hooks\BasicEmitter;
-
-class AssetCache extends BasicEmitter implements \OC\RepairStep {
-
- public function getName() {
- return 'Clear asset cache after upgrade';
- }
-
- public function run() {
- if (!\OC_Template::isAssetPipelineEnabled()) {
- $this->emit('\OC\Repair', 'info', array('Asset pipeline disabled -> nothing to do'));
- return;
- }
- $assetDir = \OC::$server->getConfig()->getSystemValue('assetdirectory', \OC::$SERVERROOT) . '/assets';
- \OC_Helper::rmdirr($assetDir, false);
- $this->emit('\OC\Repair', 'info', array('Asset cache cleared.'));
- }
-}
-
+++ /dev/null
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @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\Repair;
-
-use OC\Hooks\BasicEmitter;
-use OC\RepairStep;
-use OCP\IDBConnection;
-
-/**
- * Class RepairConfig
- *
- * @package OC\Repair
- */
-class CleanTags extends BasicEmitter implements RepairStep {
-
- /** @var IDBConnection */
- protected $connection;
-
- /**
- * @param IDBConnection $connection
- */
- public function __construct(IDBConnection $connection) {
- $this->connection = $connection;
- }
-
- /**
- * @return string
- */
- public function getName() {
- return 'Clean tags and favorites';
- }
-
- /**
- * Updates the configuration after running an update
- */
- public function run() {
- $this->deleteOrphanFileEntries();
- $this->deleteOrphanTagEntries();
- $this->deleteOrphanCategoryEntries();
- }
-
- /**
- * Delete tag entries for deleted files
- */
- protected function deleteOrphanFileEntries() {
- $this->deleteOrphanEntries(
- '%d tags for delete files have been removed.',
- 'vcategory_to_object', 'objid',
- 'filecache', 'fileid', 'path_hash'
- );
- }
-
- /**
- * Delete tag entries for deleted tags
- */
- protected function deleteOrphanTagEntries() {
- $this->deleteOrphanEntries(
- '%d tag entries for deleted tags have been removed.',
- 'vcategory_to_object', 'categoryid',
- 'vcategory', 'id', 'uid'
- );
- }
-
- /**
- * Delete tags that have no entries
- */
- protected function deleteOrphanCategoryEntries() {
- $this->deleteOrphanEntries(
- '%d tags with no entries have been removed.',
- 'vcategory', 'id',
- 'vcategory_to_object', 'categoryid', 'type'
- );
- }
-
- /**
- * Deletes all entries from $deleteTable that do not have a matching entry in $sourceTable
- *
- * A query joins $deleteTable.$deleteId = $sourceTable.$sourceId and checks
- * whether $sourceNullColumn is null. If it is null, the entry in $deleteTable
- * is being deleted.
- *
- * @param string $repairInfo
- * @param string $deleteTable
- * @param string $deleteId
- * @param string $sourceTable
- * @param string $sourceId
- * @param string $sourceNullColumn If this column is null in the source table,
- * the entry is deleted in the $deleteTable
- */
- protected function deleteOrphanEntries($repairInfo, $deleteTable, $deleteId, $sourceTable, $sourceId, $sourceNullColumn) {
- $qb = $this->connection->getQueryBuilder();
-
- $qb->select('d.' . $deleteId)
- ->from($deleteTable, 'd')
- ->leftJoin('d', $sourceTable, 's', $qb->expr()->eq('d.' . $deleteId, ' s.' . $sourceId))
- ->where(
- $qb->expr()->eq('d.type', $qb->expr()->literal('files'))
- )
- ->andWhere(
- $qb->expr()->isNull('s.' . $sourceNullColumn)
- );
- $result = $qb->execute();
-
- $orphanItems = array();
- while ($row = $result->fetch()) {
- $orphanItems[] = (int) $row[$deleteId];
- }
-
- if (!empty($orphanItems)) {
- $orphanItemsBatch = array_chunk($orphanItems, 200);
- foreach ($orphanItemsBatch as $items) {
- $qb->delete($deleteTable)
- ->where(
- $qb->expr()->eq('type', $qb->expr()->literal('files'))
- )
- ->andWhere($qb->expr()->in($deleteId, $qb->createParameter('ids')));
- $qb->setParameter('ids', $items, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
- $qb->execute();
- }
- }
-
- if ($repairInfo) {
- $this->emit('\OC\Repair', 'info', array(sprintf($repairInfo, sizeof($orphanItems))));
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Morris Jobke <hey@morrisjobke.de>
- * @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\Repair;
-
-use Doctrine\DBAL\Platforms\MySqlPlatform;
-use OC\Hooks\BasicEmitter;
-
-class Collation extends BasicEmitter implements \OC\RepairStep {
- /**
- * @var \OCP\IConfig
- */
- protected $config;
-
- /**
- * @var \OC\DB\Connection
- */
- protected $connection;
-
- /**
- * @param \OCP\IConfig $config
- * @param \OC\DB\Connection $connection
- */
- public function __construct($config, $connection) {
- $this->connection = $connection;
- $this->config = $config;
- }
-
- public function getName() {
- return 'Repair MySQL collation';
- }
-
- /**
- * Fix mime types
- */
- public function run() {
- if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
- $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to no'));
- return;
- }
-
- $tables = $this->getAllNonUTF8BinTables($this->connection);
- foreach ($tables as $table) {
- $this->emit('\OC\Repair', 'info', array("Change collation for $table ..."));
- $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
- $query->execute();
- }
- }
-
- /**
- * @param \Doctrine\DBAL\Connection $connection
- * @return string[]
- */
- protected function getAllNonUTF8BinTables($connection) {
- $dbName = $this->config->getSystemValue("dbname");
- $rows = $connection->fetchAll(
- "SELECT DISTINCT(TABLE_NAME) AS `table`" .
- " FROM INFORMATION_SCHEMA . COLUMNS" .
- " WHERE TABLE_SCHEMA = ?" .
- " AND (COLLATION_NAME <> 'utf8_bin' OR CHARACTER_SET_NAME <> 'utf8')" .
- " AND TABLE_NAME LIKE \"*PREFIX*%\"",
- array($dbName)
- );
- $result = array();
- foreach ($rows as $row) {
- $result[] = $row['table'];
- }
- return $result;
- }
-}
-
+++ /dev/null
-<?php
-/**
- * @author Arthur Schiwon <blizzz@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\Repair;
-
-use OC\Hooks\BasicEmitter;
-use OC\RepairStep;
-use OCP\BackgroundJob\IJobList;
-
-class DropOldJobs extends BasicEmitter implements RepairStep {
-
- /** @var IJobList */
- protected $jobList;
-
- /**
- * @param IJobList $jobList
- */
- public function __construct(IJobList $jobList) {
- $this->jobList = $jobList;
- }
-
- /**
- * Returns the step's name
- *
- * @return string
- */
- public function getName() {
- return 'Drop old background jobs';
- }
-
- /**
- * Run repair step.
- * Must throw exception on error.
- *
- * @throws \Exception in case of failure
- */
- public function run() {
- $oldJobs = $this->oldJobs();
- foreach($oldJobs as $job) {
- if($this->jobList->has($job['class'], $job['arguments'])) {
- $this->jobList->remove($job['class'], $job['arguments']);
- }
- }
- }
-
- /**
- * returns a list of old jobs as an associative array with keys 'class' and
- * 'arguments'.
- *
- * @return array
- */
- public function oldJobs() {
- return [
- ['class' => 'OC_Cache_FileGlobalGC', 'arguments' => null],
- ['class' => 'OC\Cache\FileGlobalGC', 'arguments' => null],
- ];
- }
-
-
-}
+++ /dev/null
-<?php
-/**
- * @author Joas Schilling <nickvergessen@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\Repair;
-
-
-use OC\Hooks\BasicEmitter;
-use OC\RepairStep;
-use OCP\IDBConnection;
-
-class DropOldTables extends BasicEmitter implements RepairStep {
-
- /** @var IDBConnection */
- protected $connection;
-
- /**
- * @param IDBConnection $connection
- */
- public function __construct(IDBConnection $connection) {
- $this->connection = $connection;
- }
-
- /**
- * Returns the step's name
- *
- * @return string
- */
- public function getName() {
- return 'Drop old database tables';
- }
-
- /**
- * Run repair step.
- * Must throw exception on error.
- *
- * @throws \Exception in case of failure
- */
- public function run() {
- foreach ($this->oldDatabaseTables() as $tableName) {
- if ($this->connection->tableExists($tableName)){
- $this->emit('\OC\Repair', 'info', [
- sprintf('Table %s has been deleted', $tableName)
- ]);
- $this->connection->dropTable($tableName);
- }
- }
- }
-
- /**
- * Returns a list of outdated tables which are not used anymore
- * @return array
- */
- protected function oldDatabaseTables() {
- return [
- 'calendar_calendars',
- 'calendar_objects',
- 'calendar_share_calendar',
- 'calendar_share_event',
- 'file_map',
- 'foldersize',
- 'fscache',
- 'gallery_sharing',
- 'locks',
- 'log',
- 'media_albums',
- 'media_artists',
- 'media_sessions',
- 'media_songs',
- 'media_users',
- 'permissions',
- 'pictures_images_cache',
- 'principalgroups',
- 'principals',
- 'queuedtasks',
- 'sharing',
- ];
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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\Repair;
-
-use OC\Hooks\BasicEmitter;
-
-class FillETags extends BasicEmitter implements \OC\RepairStep {
-
- /** @var \OCP\IDBConnection */
- protected $connection;
-
- /**
- * @param \OCP\IDBConnection $connection
- */
- public function __construct($connection) {
- $this->connection = $connection;
- }
-
- public function getName() {
- return 'Generate ETags for file where no ETag is present.';
- }
-
- public function run() {
- $qb = $this->connection->getQueryBuilder();
- $qb->update('filecache')
- ->set('etag', $qb->expr()->literal('xxx'))
- ->where($qb->expr()->eq('etag', $qb->expr()->literal('')))
- ->orWhere($qb->expr()->isNull('etag'));
-
- $result = $qb->execute();
- $this->emit('\OC\Repair', 'info', array("ETags have been fixed for $result files/folders."));
- }
-}
-
+++ /dev/null
-<?php
-/**
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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\Repair;
-
-use Doctrine\DBAL\Platforms\MySqlPlatform;
-use OC\Hooks\BasicEmitter;
-
-class InnoDB extends BasicEmitter implements \OC\RepairStep {
-
- public function getName() {
- return 'Repair MySQL database engine';
- }
-
- /**
- * Fix mime types
- */
- public function run() {
- $connection = \OC_DB::getConnection();
- if (!$connection->getDatabasePlatform() instanceof MySqlPlatform) {
- $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to do'));
- return;
- }
-
- $tables = $this->getAllMyIsamTables($connection);
- if (is_array($tables)) {
- foreach ($tables as $table) {
- $connection->exec("ALTER TABLE $table ENGINE=InnoDB;");
- $this->emit('\OC\Repair', 'info', array("Fixed $table"));
- }
- }
- }
-
- /**
- * @param \Doctrine\DBAL\Connection $connection
- * @return string[]
- */
- private function getAllMyIsamTables($connection) {
- $dbName = \OC::$server->getConfig()->getSystemValue("dbname");
- $result = $connection->fetchArray(
- "SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND engine = 'MyISAM' AND TABLE_NAME LIKE \"*PREFIX*%\"",
- array($dbName)
- );
-
- return $result;
- }
-}
-
+++ /dev/null
-<?php
-/**
- * @author Joas Schilling <nickvergessen@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\Repair;
-
-
-use OC\Hooks\BasicEmitter;
-use OC\RepairStep;
-use OCP\IDBConnection;
-use OCP\IGroupManager;
-use OCP\Share;
-
-class OldGroupMembershipShares extends BasicEmitter implements RepairStep {
-
- /** @var \OCP\IDBConnection */
- protected $connection;
-
- /** @var \OCP\IGroupManager */
- protected $groupManager;
-
- /**
- * @var array [gid => [uid => (bool)]]
- */
- protected $memberships;
-
- /**
- * @param IDBConnection $connection
- * @param IGroupManager $groupManager
- */
- public function __construct(IDBConnection $connection, IGroupManager $groupManager) {
- $this->connection = $connection;
- $this->groupManager = $groupManager;
- }
-
- /**
- * Returns the step's name
- *
- * @return string
- */
- public function getName() {
- return 'Remove shares of old group memberships';
- }
-
- /**
- * Run repair step.
- * Must throw exception on error.
- *
- * @throws \Exception in case of failure
- */
- public function run() {
- $deletedEntries = 0;
-
- $query = $this->connection->getQueryBuilder();
- $query->select(['s1.id', $query->createFunction('s1.`share_with` AS `user`'), $query->createFunction('s2.`share_with` AS `group`')])
- ->from('share', 's1')
- ->where($query->expr()->isNotNull('s1.parent'))
- // \OC\Share\Constant::$shareTypeGroupUserUnique === 2
- ->andWhere($query->expr()->eq('s1.share_type', $query->expr()->literal(2)))
- ->andWhere($query->expr()->isNotNull('s2.id'))
- ->andWhere($query->expr()->eq('s2.share_type', $query->expr()->literal(Share::SHARE_TYPE_GROUP)))
- ->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'));
-
- $deleteQuery = $this->connection->getQueryBuilder();
- $deleteQuery->delete('share')
- ->where($query->expr()->eq('id', $deleteQuery->createParameter('share')));
-
- $result = $query->execute();
- while ($row = $result->fetch()) {
- if (!$this->isMember($row['group'], $row['user'])) {
- $deletedEntries += $deleteQuery->setParameter('share', (int) $row['id'])
- ->execute();
- }
- }
- $result->closeCursor();
-
- if ($deletedEntries) {
- $this->emit('\OC\Repair', 'info', array('Removed ' . $deletedEntries . ' shares where user is not a member of the group anymore'));
- }
- }
-
- /**
- * @param string $gid
- * @param string $uid
- * @return bool
- */
- protected function isMember($gid, $uid) {
- if (isset($this->memberships[$gid][$uid])) {
- return $this->memberships[$gid][$uid];
- }
-
- $isMember = $this->groupManager->isInGroup($uid, $gid);
- if (!isset($this->memberships[$gid])) {
- $this->memberships[$gid] = [];
- }
- $this->memberships[$gid][$uid] = $isMember;
-
- return $isMember;
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Georg Ehrke <georg@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\Repair;
-
-use OC\Files\View;
-use OC\Hooks\BasicEmitter;
-
-class Preview extends BasicEmitter implements \OC\RepairStep {
-
- public function getName() {
- return 'Cleaning-up broken previews';
- }
-
- public function run() {
- $view = new View('/');
- $children = $view->getDirectoryContent('/');
-
- foreach ($children as $child) {
- if ($view->is_dir($child->getPath())) {
- $thumbnailsFolder = $child->getPath() . '/thumbnails';
- if ($view->is_dir($thumbnailsFolder)) {
- $view->rmdir($thumbnailsFolder);
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-<?php
-/**
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @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\Repair;
-
-use OC\Hooks\BasicEmitter;
-use OCP\IDBConnection;
-
-class RemoveGetETagEntries extends BasicEmitter {
-
- /**
- * @var IDBConnection
- */
- protected $connection;
-
- /**
- * @param IDBConnection $connection
- */
- public function __construct(IDBConnection $connection) {
- $this->connection = $connection;
- }
-
- public function getName() {
- return 'Remove getetag entries in properties table';
- }
-
- /**
- * Removes all entries with the key "{DAV:}getetag" from the table properties
- */
- public function run() {
- $sql = 'DELETE FROM `*PREFIX*properties`'
- . ' WHERE `propertyname` = ?';
- $deletedRows = $this->connection->executeUpdate($sql, ['{DAV:}getetag']);
-
- $this->emit(
- '\OC\Repair',
- 'info',
- ['Removed ' . $deletedRows . ' unneeded "{DAV:}getetag" entries from properties table.']
- );
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Vincent Petry <pvince81@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\Repair;
-
-use OC\Hooks\BasicEmitter;
-
-/**
- * Repairs shares with invalid data
- */
-class RepairInvalidShares extends BasicEmitter implements \OC\RepairStep {
-
- /**
- * @var \OCP\IConfig
- */
- protected $config;
-
- /**
- * @var \OCP\IDBConnection
- */
- protected $connection;
-
- /**
- * @param \OCP\IConfig $config
- * @param \OCP\IDBConnection $connection
- */
- public function __construct($config, $connection) {
- $this->connection = $connection;
- $this->config = $config;
- }
-
- public function getName() {
- return 'Repair invalid shares';
- }
-
- /**
- * Past bugs would make it possible to set an expiration date on user shares even
- * though it is not supported. This functions removes the expiration date from such entries.
- */
- private function removeExpirationDateFromNonLinkShares() {
- $builder = $this->connection->getQueryBuilder();
- $builder
- ->update('share')
- ->set('expiration', 'null')
- ->where($builder->expr()->isNotNull('expiration'))
- ->andWhere($builder->expr()->neq('share_type', $builder->expr()->literal(\OC\Share\Constants::SHARE_TYPE_LINK)));
-
- $updatedEntries = $builder->execute();
- if ($updatedEntries > 0) {
- $this->emit('\OC\Repair', 'info', array('Removed invalid expiration date from ' . $updatedEntries . ' shares'));
- }
- }
-
- /**
- * Remove shares where the parent share does not exist anymore
- */
- private function removeSharesNonExistingParent() {
- $deletedEntries = 0;
-
- $query = $this->connection->getQueryBuilder();
- $query->select('s1.parent')
- ->from('share', 's1')
- ->where($query->expr()->isNotNull('s1.parent'))
- ->andWhere($query->expr()->isNull('s2.id'))
- ->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'))
- ->groupBy('s1.parent');
-
- $deleteQuery = $this->connection->getQueryBuilder();
- $deleteQuery->delete('share')
- ->where($query->expr()->eq('parent', $deleteQuery->createParameter('parent')));
-
- $result = $query->execute();
- while ($row = $result->fetch()) {
- $deletedEntries += $deleteQuery->setParameter('parent', (int) $row['parent'])
- ->execute();
- }
- $result->closeCursor();
-
- if ($deletedEntries) {
- $this->emit('\OC\Repair', 'info', array('Removed ' . $deletedEntries . ' shares where the parent did not exist'));
- }
- }
-
- public function run() {
- $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
- if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.7', '<')) {
- // this situation was only possible before 8.2
- $this->removeExpirationDateFromNonLinkShares();
- }
-
- $this->removeSharesNonExistingParent();
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Vincent Petry <pvince81@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\Repair;
-
-use OC\Files\Cache\Storage;
-use OC\Hooks\BasicEmitter;
-use OC\RepairException;
-
-class RepairLegacyStorages extends BasicEmitter {
- /**
- * @var \OCP\IConfig
- */
- protected $config;
-
- /**
- * @var \OCP\IDBConnection
- */
- protected $connection;
-
- protected $findStorageInCacheStatement;
- protected $renameStorageStatement;
-
- /**
- * @param \OCP\IConfig $config
- * @param \OCP\IDBConnection $connection
- */
- public function __construct($config, $connection) {
- $this->connection = $connection;
- $this->config = $config;
-
- $this->findStorageInCacheStatement = $this->connection->prepare(
- 'SELECT DISTINCT `storage` FROM `*PREFIX*filecache`'
- . ' WHERE `storage` in (?, ?)'
- );
- $this->renameStorageStatement = $this->connection->prepare(
- 'UPDATE `*PREFIX*storages`'
- . ' SET `id` = ?'
- . ' WHERE `id` = ?'
- );
- }
-
- public function getName() {
- return 'Repair legacy storages';
- }
-
- /**
- * Extracts the user id from a legacy storage id
- *
- * @param string $storageId legacy storage id in the
- * format "local::/path/to/datadir/userid"
- * @return string user id extracted from the storage id
- */
- private function extractUserId($storageId) {
- $storageId = rtrim($storageId, '/');
- $pos = strrpos($storageId, '/');
- return substr($storageId, $pos + 1);
- }
-
- /**
- * Fix the given legacy storage by renaming the old id
- * to the new id. If the new id already exists, whichever
- * storage that has data in the file cache will be used.
- * If both have data, nothing will be done and false is
- * returned.
- *
- * @param string $oldId old storage id
- * @param int $oldNumericId old storage numeric id
- * @param string $userId
- * @return bool true if fixed, false otherwise
- * @throws RepairException
- */
- private function fixLegacyStorage($oldId, $oldNumericId, $userId = null) {
- // check whether the new storage already exists
- if (is_null($userId)) {
- $userId = $this->extractUserId($oldId);
- }
- $newId = 'home::' . $userId;
-
- // check if target id already exists
- $newNumericId = Storage::getNumericStorageId($newId);
- if (!is_null($newNumericId)) {
- $newNumericId = (int)$newNumericId;
- // try and resolve the conflict
- // check which one of "local::" or "home::" needs to be kept
- $this->findStorageInCacheStatement->execute(array($oldNumericId, $newNumericId));
- $row1 = $this->findStorageInCacheStatement->fetch();
- $row2 = $this->findStorageInCacheStatement->fetch();
- $this->findStorageInCacheStatement->closeCursor();
- if ($row2 !== false) {
- // two results means both storages have data, not auto-fixable
- throw new RepairException(
- 'Could not automatically fix legacy storage '
- . '"' . $oldId . '" => "' . $newId . '"'
- . ' because they both have data.'
- );
- }
- if ($row1 === false || (int)$row1['storage'] === $oldNumericId) {
- // old storage has data, then delete the empty new id
- $toDelete = $newId;
- } else if ((int)$row1['storage'] === $newNumericId) {
- // new storage has data, then delete the empty old id
- $toDelete = $oldId;
- } else {
- // unknown case, do not continue
- return false;
- }
-
- // delete storage including file cache
- Storage::remove($toDelete);
-
- // if we deleted the old id, the new id will be used
- // automatically
- if ($toDelete === $oldId) {
- // nothing more to do
- return true;
- }
- }
-
- // rename old id to new id
- $newId = Storage::adjustStorageId($newId);
- $oldId = Storage::adjustStorageId($oldId);
- $rowCount = $this->renameStorageStatement->execute(array($newId, $oldId));
- $this->renameStorageStatement->closeCursor();
- return ($rowCount === 1);
- }
-
- /**
- * Converts legacy home storage ids in the format
- * "local::/data/dir/path/userid/" to the new format "home::userid"
- */
- public function run() {
- // 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;
- $this->emit(
- '\OC\Repair',
- 'warning',
- array('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;
- $this->emit(
- '\OC\Repair',
- 'warning',
- array('Could not repair legacy storage ' . $storageId . ' automatically.')
- );
- }
- }
- }
- $offset += $limit;
- } while (count($results) >= $limit);
- }
-
- $this->emit('\OC\Repair', 'info', array('Updated ' . $count . ' legacy home storage ids'));
-
- $this->connection->commit();
-
- if ($hasWarnings) {
- $this->emit(
- '\OC\Repair',
- 'warning',
- array('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');
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Normal Ra <normalraw@gmail.com>
- * @author Olivier Paroz <github@oparoz.com>
- * @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@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\Repair;
-
-use OC\Hooks\BasicEmitter;
-
-class RepairMimeTypes extends BasicEmitter implements \OC\RepairStep {
- /**
- * @var \OCP\IConfig
- */
- protected $config;
-
- /**
- * @var int
- */
- protected $folderMimeTypeId;
-
- /**
- * @param \OCP\IConfig $config
- */
- public function __construct($config) {
- $this->config = $config;
- }
-
- public function getName() {
- return 'Repair mime types';
- }
-
- private static function existsStmt() {
- return \OC_DB::prepare('
- SELECT count(`mimetype`)
- FROM `*PREFIX*mimetypes`
- WHERE `mimetype` = ?
- ');
- }
-
- private static function getIdStmt() {
- return \OC_DB::prepare('
- SELECT `id`
- FROM `*PREFIX*mimetypes`
- WHERE `mimetype` = ?
- ');
- }
-
- private static function insertStmt() {
- return \OC_DB::prepare('
- INSERT INTO `*PREFIX*mimetypes` ( `mimetype` )
- VALUES ( ? )
- ');
- }
-
- private static function updateWrongStmt() {
- return \OC_DB::prepare('
- UPDATE `*PREFIX*filecache`
- SET `mimetype` = (
- SELECT `id`
- FROM `*PREFIX*mimetypes`
- WHERE `mimetype` = ?
- ) WHERE `mimetype` = ?
- ');
- }
-
- private static function deleteStmt() {
- return \OC_DB::prepare('
- DELETE FROM `*PREFIX*mimetypes`
- WHERE `id` = ?
- ');
- }
-
- private static function updateByNameStmt() {
- return \OC_DB::prepare('
- UPDATE `*PREFIX*filecache`
- SET `mimetype` = ?
- WHERE `mimetype` <> ? AND `mimetype` <> ? AND `name` ILIKE ?
- ');
- }
-
- private function repairMimetypes($wrongMimetypes) {
- foreach ($wrongMimetypes as $wrong => $correct) {
- // do we need to remove a wrong mimetype?
- $result = \OC_DB::executeAudited(self::getIdStmt(), array($wrong));
- $wrongId = $result->fetchOne();
-
- if ($wrongId !== false) {
- // do we need to insert the correct mimetype?
- $result = \OC_DB::executeAudited(self::existsStmt(), array($correct));
- $exists = $result->fetchOne();
-
- if (!is_null($correct)) {
- if (!$exists) {
- // insert mimetype
- \OC_DB::executeAudited(self::insertStmt(), array($correct));
- }
-
- // change wrong mimetype to correct mimetype in filecache
- \OC_DB::executeAudited(self::updateWrongStmt(), array($correct, $wrongId));
- }
-
- // delete wrong mimetype
- \OC_DB::executeAudited(self::deleteStmt(), array($wrongId));
-
- }
- }
- }
-
- private function updateMimetypes($updatedMimetypes) {
- if (empty($this->folderMimeTypeId)) {
- $result = \OC_DB::executeAudited(self::getIdStmt(), array('httpd/unix-directory'));
- $this->folderMimeTypeId = (int)$result->fetchOne();
- }
-
- foreach ($updatedMimetypes as $extension => $mimetype) {
- $result = \OC_DB::executeAudited(self::existsStmt(), array($mimetype));
- $exists = $result->fetchOne();
-
- if (!$exists) {
- // insert mimetype
- \OC_DB::executeAudited(self::insertStmt(), array($mimetype));
- }
-
- // get target mimetype id
- $result = \OC_DB::executeAudited(self::getIdStmt(), array($mimetype));
- $mimetypeId = $result->fetchOne();
-
- // change mimetype for files with x extension
- \OC_DB::executeAudited(self::updateByNameStmt(), array($mimetypeId, $this->folderMimeTypeId, $mimetypeId, '%.' . $extension));
- }
- }
-
- private function fixOfficeMimeTypes() {
- // update wrong mimetypes
- $wrongMimetypes = array(
- 'application/mspowerpoint' => 'application/vnd.ms-powerpoint',
- 'application/msexcel' => 'application/vnd.ms-excel',
- );
-
- self::repairMimetypes($wrongMimetypes);
-
- $updatedMimetypes = array(
- 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
- 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
- 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
- );
-
-
- // separate doc from docx etc
- self::updateMimetypes($updatedMimetypes);
-
- }
-
- private function fixApkMimeType() {
- $updatedMimetypes = array(
- 'apk' => 'application/vnd.android.package-archive',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function fixFontsMimeTypes() {
- // update wrong mimetypes
- $wrongMimetypes = array(
- 'font' => null,
- 'font/opentype' => 'application/font-sfnt',
- 'application/x-font-ttf' => 'application/font-sfnt',
- );
-
- self::repairMimetypes($wrongMimetypes);
-
- $updatedMimetypes = array(
- 'ttf' => 'application/font-sfnt',
- 'otf' => 'application/font-sfnt',
- 'pfb' => 'application/x-font',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function fixPostscriptMimeType() {
- $updatedMimetypes = array(
- 'eps' => 'application/postscript',
- 'ps' => 'application/postscript',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduceRawMimeType() {
- $updatedMimetypes = array(
- 'arw' => 'image/x-dcraw',
- 'cr2' => 'image/x-dcraw',
- 'dcr' => 'image/x-dcraw',
- 'dng' => 'image/x-dcraw',
- 'erf' => 'image/x-dcraw',
- 'iiq' => 'image/x-dcraw',
- 'k25' => 'image/x-dcraw',
- 'kdc' => 'image/x-dcraw',
- 'mef' => 'image/x-dcraw',
- 'nef' => 'image/x-dcraw',
- 'orf' => 'image/x-dcraw',
- 'pef' => 'image/x-dcraw',
- 'raf' => 'image/x-dcraw',
- 'rw2' => 'image/x-dcraw',
- 'srf' => 'image/x-dcraw',
- 'sr2' => 'image/x-dcraw',
- 'xrf' => 'image/x-dcraw',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduce3dImagesMimeType() {
- $updatedMimetypes = array(
- 'jps' => 'image/jpeg',
- 'mpo' => 'image/jpeg',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduceConfMimeType() {
- $updatedMimetypes = array(
- 'conf' => 'text/plain',
- 'cnf' => 'text/plain',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduceYamlMimeType() {
- $updatedMimetypes = array(
- 'yaml' => 'application/yaml',
- 'yml' => 'application/yaml',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduceJavaMimeType() {
- $updatedMimetypes = array(
- 'class' => 'application/java',
- 'java' => 'text/x-java-source',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduceHppMimeType() {
- $updatedMimetypes = array(
- 'hpp' => 'text/x-h',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduceRssMimeType() {
- $updatedMimetypes = array(
- 'rss' => 'application/rss+xml',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- private function introduceRtfMimeType() {
- $updatedMimetypes = array(
- 'rtf' => 'text/rtf',
- );
-
- self::updateMimetypes($updatedMimetypes);
- }
-
- /**
- * Fix mime types
- */
- public function run() {
-
- $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
-
- // NOTE TO DEVELOPERS: when adding new mime types, please make sure to
- // add a version comparison to avoid doing it every time
-
- // only update mime types if necessary as it can be expensive
- if (version_compare($ocVersionFromBeforeUpdate, '8.2.0', '<')) {
- if ($this->fixOfficeMimeTypes()) {
- $this->emit('\OC\Repair', 'info', array('Fixed office mime types'));
- }
-
- if ($this->fixApkMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed APK mime type'));
- }
-
- if ($this->fixFontsMimeTypes()) {
- $this->emit('\OC\Repair', 'info', array('Fixed fonts mime types'));
- }
-
- if ($this->fixPostscriptMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed Postscript mime types'));
- }
-
- if ($this->introduceRawMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed Raw mime types'));
- }
-
- if ($this->introduce3dImagesMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed 3D images mime types'));
- }
-
- if ($this->introduceConfMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed Conf/cnf mime types'));
- }
-
- if ($this->introduceYamlMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed Yaml/Yml mime types'));
- }
- }
-
- // Mimetype updates from #19272
- if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.8', '<')) {
- if ($this->introduceJavaMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed java/class mime types'));
- }
-
- if ($this->introduceHppMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed hpp mime type'));
- }
-
- if ($this->introduceRssMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed rss mime type'));
- }
-
- if ($this->introduceRtfMimeType()) {
- $this->emit('\OC\Repair', 'info', array('Fixed rtf mime type'));
- }
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @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\Repair;
-
-use OC\Hooks\BasicEmitter;
-
-class SearchLuceneTables extends BasicEmitter implements \OC\RepairStep {
-
- public function getName() {
- return 'Repair duplicate entries in oc_lucene_status';
- }
-
- /**
- * Fix duplicate entries in oc_lucene_status
- *
- * search_lucene prior to v0.5.0 did not have a primary key on the lucene_status table. Newer versions do, which
- * causes the migration check to fail because it tries to insert duplicate rows into the new schema.
- *
- * FIXME Currently, apps don't have a way of repairing anything before the migration check:
- * @link https://github.com/owncloud/core/issues/10980
- *
- * As a result this repair step needs to live in the core repo, although it belongs into search_lucene:
- * @link https://github.com/owncloud/core/issues/10205#issuecomment-54957557
- *
- * It will completely remove any rows that make a file id have more than one status:
- * fileid | status fileid | status
- * --------+-------- will become --------+--------
- * 2 | E 3 | E
- * 2 | I
- * 3 | E
- *
- * search_lucene will then reindex the fileids without a status when the next indexing job is executed
- */
- public function run() {
- if (\OC_DB::tableExists('lucene_status')) {
- $this->emit('\OC\Repair', 'info', array('removing duplicate entries from lucene_status'));
-
- $connection = \OC_DB::getConnection();
- $query = $connection->prepare('
- DELETE FROM `*PREFIX*lucene_status`
- WHERE `fileid` IN (
- SELECT `fileid`
- FROM (
- SELECT `fileid`
- FROM `*PREFIX*lucene_status`
- GROUP BY `fileid`
- HAVING count(`fileid`) > 1
- ) AS `mysqlerr1093hack`
- )');
- $query->execute();
- } else {
- $this->emit('\OC\Repair', 'info', array('lucene_status table does not exist -> nothing to do'));
- }
- }
-
-}
-
+++ /dev/null
-<?php
-/**
- * @author Vincent Petry <pvince81@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\Repair;
-
-use Doctrine\DBAL\Platforms\SqlitePlatform;
-use Doctrine\DBAL\Schema\SchemaException;
-use Doctrine\DBAL\Schema\SchemaDiff;
-use Doctrine\DBAL\Schema\TableDiff;
-use Doctrine\DBAL\Schema\ColumnDiff;
-use OC\Hooks\BasicEmitter;
-
-/**
- * Fixes Sqlite autoincrement by forcing the SQLite table schemas to be
- * altered in order to retrigger SQL schema generation through OCSqlitePlatform.
- */
-class SqliteAutoincrement extends BasicEmitter implements \OC\RepairStep {
- /**
- * @var \OC\DB\Connection
- */
- protected $connection;
-
- /**
- * @param \OC\DB\Connection $connection
- */
- public function __construct($connection) {
- $this->connection = $connection;
- }
-
- public function getName() {
- return 'Repair SQLite autoincrement';
- }
-
- /**
- * Fix mime types
- */
- public function run() {
- if (!$this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
- return;
- }
-
- $sourceSchema = $this->connection->getSchemaManager()->createSchema();
-
- $schemaDiff = new SchemaDiff();
-
- foreach ($sourceSchema->getTables() as $tableSchema) {
- $primaryKey = $tableSchema->getPrimaryKey();
- if (!$primaryKey) {
- continue;
- }
-
- $columnNames = $primaryKey->getColumns();
-
- // add a column diff for every primary key column,
- // but do not actually change anything, this will
- // force the generation of SQL statements to alter
- // those tables, which will then trigger the
- // specific SQL code from OCSqlitePlatform
- try {
- $tableDiff = new TableDiff($tableSchema->getName());
- $tableDiff->fromTable = $tableSchema;
- foreach ($columnNames as $columnName) {
- $columnSchema = $tableSchema->getColumn($columnName);
- $columnDiff = new ColumnDiff($columnSchema->getName(), $columnSchema);
- $tableDiff->changedColumns[] = $columnDiff;
- $schemaDiff->changedTables[] = $tableDiff;
- }
- } catch (SchemaException $e) {
- // ignore
- }
- }
-
- $this->connection->beginTransaction();
- foreach ($schemaDiff->toSql($this->connection->getDatabasePlatform()) as $sql) {
- $this->connection->query($sql);
- }
- $this->connection->commit();
- }
-}
-
+++ /dev/null
-<?php
-/**
- * @author Lukas Reschke <lukas@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\Repair;
-
-use OC\Files\View;
-use OC\Hooks\BasicEmitter;
-use OC\RepairStep;
-use OC\Server;
-use OCP\IConfig;
-
-/**
- * Class UpdateCertificateStore rewrites the user specific certificate store after
- * an update has been performed. This is done because a new root certificate file
- * might have been added.
- *
- * @package OC\Repair
- */
-class UpdateCertificateStore extends BasicEmitter implements RepairStep {
- /**
- * FIXME: The certificate manager does only allow specifying the user
- * within the constructor. This makes DI impossible.
- * @var Server
- */
- protected $server;
- /** @var IConfig */
- protected $config;
-
- /**
- * @param Server $server
- * @param IConfig $config
- */
- public function __construct(Server $server,
- IConfig $config) {
- $this->server = $server;
- $this->config = $config;
- }
-
- /** {@inheritDoc} */
- public function getName() {
- return 'Update user certificate stores with new root certificates';
- }
-
- /** {@inheritDoc} */
- public function run() {
- $rootView = new View();
- $dataDirectory = $this->config->getSystemValue('datadirectory', null);
- if(is_null($dataDirectory)) {
- throw new \Exception('No data directory specified');
- }
-
- $pathToRootCerts = '/files_external/rootcerts.crt';
-
- foreach($rootView->getDirectoryContent('', 'httpd/unix-directory') as $fileInfo) {
- $uid = trim($fileInfo->getPath(), '/');
- if($rootView->file_exists($uid . $pathToRootCerts)) {
- // Delete the existing root certificate
- $rootView->unlink($uid . $pathToRootCerts);
-
- /**
- * FIXME: The certificate manager does only allow specifying the user
- * within the constructor. This makes DI impossible.
- */
- // Regenerate the certificates
- $certificateManager = $this->server->getCertificateManager($uid);
- $certificateManager->createCertificateBundle();
- }
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * @author Lukas Reschke <lukas@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\Repair;
-
-use OC\Hooks\BasicEmitter;
-use OC\RepairStep;
-use OCP\IConfig;
-
-/**
- * Class UpdateOutdatedOcsIds is used to update invalid outdated OCS IDs, this is
- * for example the case when an application has had another OCS ID in the past such
- * as for contacts and calendar when apps.owncloud.com migrated to a unified identifier
- * for multiple versions.
- *
- * @package OC\Repair
- */
-class UpdateOutdatedOcsIds extends BasicEmitter implements RepairStep {
- /** @var IConfig */
- private $config;
-
- /**
- * @param IConfig $config
- */
- public function __construct(IConfig $config) {
- $this->config = $config;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName() {
- return 'Repair outdated OCS IDs';
- }
-
- /**
- * @param string $appName
- * @param string $oldId
- * @param string $newId
- * @return bool True if updated, false otherwise
- */
- public function fixOcsId($appName, $oldId, $newId) {
- $existingId = $this->config->getAppValue($appName, 'ocsid');
-
- if($existingId === $oldId) {
- $this->config->setAppValue($appName, 'ocsid', $newId);
- return true;
- }
-
- return false;
- }
-
- /**
- * {@inheritdoc}
- */
- public function run() {
- $appsToUpdate = [
- 'contacts' => [
- 'old' => '166044',
- 'new' => '168708',
- ],
- 'calendar' => [
- 'old' => '166043',
- 'new' => '168707',
- ],
- 'bookmarks' => [
- 'old' => '166042',
- 'new' => '168710',
- ],
- 'search_lucene' => [
- 'old' => '166057',
- 'new' => '168709',
- ],
- 'documents' => [
- 'old' => '166045',
- 'new' => '168711',
- ]
- ];
-
- foreach($appsToUpdate as $appName => $ids) {
- if ($this->fixOcsId($appName, $ids['old'], $ids['new'])) {
- $this->emit(
- '\OC\Repair',
- 'info',
- [sprintf('Fixed invalid %s OCS id', $appName)]
- );
- }
- }
- }
-}
public function testLoadCoreNamespaceRepair() {
$this->assertEquals([
- \OC::$SERVERROOT . '/lib/repair/foo/bar.php',
+ \OC::$SERVERROOT . '/lib/private/repair/foo/bar.php',
], $this->loader->findClass('OC\Repair\Foo\Bar'));
}
}