summaryrefslogtreecommitdiffstats
path: root/core/l10n/pt_PT.js
diff options
context:
space:
mode:
authorPytal <24800714+Pytal@users.noreply.github.com>2023-02-24 12:28:57 -0800
committerGitHub <noreply@github.com>2023-02-24 12:28:57 -0800
commit16d7973f7d32af4cd8d64ac4d16a0e909e9d640d (patch)
treebee6bb361721cb1688397bf6f80d5a59f31aad79 /core/l10n/pt_PT.js
parent9650685351878f50934be8b6942f441864480951 (diff)
parent0a9ce1ff346466b7de0a8ad521decb7d9558b3c0 (diff)
downloadnextcloud-server-16d7973f7d32af4cd8d64ac4d16a0e909e9d640d.tar.gz
nextcloud-server-16d7973f7d32af4cd8d64ac4d16a0e909e9d640d.zip
Merge pull request #36741 from nextcloud/enh/a11y-filepicker-home-crumb
Diffstat (limited to 'core/l10n/pt_PT.js')
0 files changed, 0 insertions, 0 deletions
145'>145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
<?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');
		}
	}
}