123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- <?php
- declare(strict_types=1);
- /**
- * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
- namespace OC\Core\Command\Info;
- use OCA\Circles\MountManager\CircleMount;
- use OCA\Files_External\Config\ExternalMountPoint;
- use OCA\Files_Sharing\SharedMount;
- use OCA\GroupFolders\Mount\GroupMountPoint;
- use OCP\Constants;
- use OCP\Files\Config\IUserMountCache;
- use OCP\Files\FileInfo;
- use OCP\Files\Folder;
- use OCP\Files\IHomeStorage;
- use OCP\Files\IRootFolder;
- use OCP\Files\Mount\IMountPoint;
- use OCP\Files\Node;
- use OCP\Files\NotFoundException;
- use OCP\Share\IShare;
- use OCP\Util;
- use Symfony\Component\Console\Output\OutputInterface;
- class FileUtils {
- public function __construct(
- private IRootFolder $rootFolder,
- private IUserMountCache $userMountCache,
- ) {
- }
- /**
- * @param FileInfo $file
- * @return array<string, Node[]>
- * @throws \OCP\Files\NotPermittedException
- * @throws \OC\User\NoUserException
- */
- public function getFilesByUser(FileInfo $file): array {
- $id = $file->getId();
- if (!$id) {
- return [];
- }
- $mounts = $this->userMountCache->getMountsForFileId($id);
- $result = [];
- foreach ($mounts as $mount) {
- if (isset($result[$mount->getUser()->getUID()])) {
- continue;
- }
- $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
- $result[$mount->getUser()->getUID()] = $userFolder->getById($id);
- }
- return $result;
- }
- /**
- * Get file by either id of path
- *
- * @param string $fileInput
- * @return Node|null
- */
- public function getNode(string $fileInput): ?Node {
- if (is_numeric($fileInput)) {
- $mounts = $this->userMountCache->getMountsForFileId((int)$fileInput);
- if (!$mounts) {
- return null;
- }
- $mount = reset($mounts);
- $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
- return $userFolder->getFirstNodeById((int)$fileInput);
- } else {
- try {
- return $this->rootFolder->get($fileInput);
- } catch (NotFoundException $e) {
- return null;
- }
- }
- }
- public function formatPermissions(string $type, int $permissions): string {
- if ($permissions == Constants::PERMISSION_ALL || ($type === 'file' && $permissions == (Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE))) {
- return "full permissions";
- }
- $perms = [];
- $allPerms = [Constants::PERMISSION_READ => "read", Constants::PERMISSION_UPDATE => "update", Constants::PERMISSION_CREATE => "create", Constants::PERMISSION_DELETE => "delete", Constants::PERMISSION_SHARE => "share"];
- foreach ($allPerms as $perm => $name) {
- if (($permissions & $perm) === $perm) {
- $perms[] = $name;
- }
- }
- return implode(", ", $perms);
- }
- /**
- * @psalm-suppress UndefinedClass
- * @psalm-suppress UndefinedInterfaceMethod
- */
- public function formatMountType(IMountPoint $mountPoint): string {
- $storage = $mountPoint->getStorage();
- if ($storage && $storage->instanceOfStorage(IHomeStorage::class)) {
- return "home storage";
- } elseif ($mountPoint instanceof SharedMount) {
- $share = $mountPoint->getShare();
- $shares = $mountPoint->getGroupedShares();
- $sharedBy = array_map(function (IShare $share) {
- $shareType = $this->formatShareType($share);
- if ($shareType) {
- return $share->getSharedBy() . " (via " . $shareType . " " . $share->getSharedWith() . ")";
- } else {
- return $share->getSharedBy();
- }
- }, $shares);
- $description = "shared by " . implode(', ', $sharedBy);
- if ($share->getSharedBy() !== $share->getShareOwner()) {
- $description .= " owned by " . $share->getShareOwner();
- }
- return $description;
- } elseif ($mountPoint instanceof GroupMountPoint) {
- return "groupfolder " . $mountPoint->getFolderId();
- } elseif ($mountPoint instanceof ExternalMountPoint) {
- return "external storage " . $mountPoint->getStorageConfig()->getId();
- } elseif ($mountPoint instanceof CircleMount) {
- return "circle";
- }
- return get_class($mountPoint);
- }
- public function formatShareType(IShare $share): ?string {
- switch ($share->getShareType()) {
- case IShare::TYPE_GROUP:
- return "group";
- case IShare::TYPE_CIRCLE:
- return "circle";
- case IShare::TYPE_DECK:
- return "deck";
- case IShare::TYPE_ROOM:
- return "room";
- case IShare::TYPE_USER:
- return null;
- default:
- return "Unknown (" . $share->getShareType() . ")";
- }
- }
- /**
- * Print out the largest count($sizeLimits) files in the directory tree
- *
- * @param OutputInterface $output
- * @param Folder $node
- * @param string $prefix
- * @param array $sizeLimits largest items that are still in the queue to be printed, ordered ascending
- * @return int how many items we've printed
- */
- public function outputLargeFilesTree(
- OutputInterface $output,
- Folder $node,
- string $prefix,
- array &$sizeLimits,
- bool $all,
- ): int {
- /**
- * Algorithm to print the N largest items in a folder without requiring to query or sort the entire three
- *
- * This is done by keeping a list ($sizeLimits) of size N that contain the largest items outside of this
- * folders that are could be printed if there aren't enough items in this folder that are larger.
- *
- * We loop over the items in this folder by size descending until the size of the item falls before the smallest
- * size in $sizeLimits (at that point there are enough items outside this folder to complete the N items).
- *
- * When encountering a folder, we create an updated $sizeLimits with the largest items in the current folder still
- * remaining which we pass into the recursion. (We don't update the current $sizeLimits because that should only
- * hold items *outside* of the current folder.)
- *
- * For every item printed we remove the first item of $sizeLimits are there is no longer room in the output to print
- * items that small.
- */
- $count = 0;
- $children = $node->getDirectoryListing();
- usort($children, function (Node $a, Node $b) {
- return $b->getSize() <=> $a->getSize();
- });
- foreach ($children as $i => $child) {
- if (!$all) {
- if (count($sizeLimits) === 0 || $child->getSize() < $sizeLimits[0]) {
- return $count;
- }
- array_shift($sizeLimits);
- }
- $count += 1;
- /** @var Node $child */
- $output->writeln("$prefix- " . $child->getName() . ": <info>" . Util::humanFileSize($child->getSize()) . "</info>");
- if ($child instanceof Folder) {
- $recurseSizeLimits = $sizeLimits;
- if (!$all) {
- for ($j = 0; $j < count($recurseSizeLimits); $j++) {
- if (isset($children[$i + $j + 1])) {
- $nextChildSize = $children[$i + $j + 1]->getSize();
- if ($nextChildSize > $recurseSizeLimits[0]) {
- array_shift($recurseSizeLimits);
- $recurseSizeLimits[] = $nextChildSize;
- }
- }
- }
- sort($recurseSizeLimits);
- }
- $recurseCount = $this->outputLargeFilesTree($output, $child, $prefix . " ", $recurseSizeLimits, $all);
- $sizeLimits = array_slice($sizeLimits, $recurseCount);
- $count += $recurseCount;
- }
- }
- return $count;
- }
- }
|