rootFolder = $rootFolder; $this->userMountCache = $userMountCache; $this->l10n = $l10nFactory->get("core"); parent::__construct(); } protected function configure(): void { $this ->setName('info:file') ->setDescription('get information for a file') ->addArgument('file', InputArgument::REQUIRED, "File id or path") ->addOption('children', 'c', InputOption::VALUE_NONE, "List children of folders"); } public function execute(InputInterface $input, OutputInterface $output): int { $fileInput = $input->getArgument('file'); $showChildren = $input->getOption('children'); $node = $this->getNode($fileInput); if (!$node) { $output->writeln("file $fileInput not found"); return 1; } $output->writeln($node->getName()); $output->writeln(" fileid: " . $node->getId()); $output->writeln(" mimetype: " . $node->getMimetype()); $output->writeln(" modified: " . (string)$this->l10n->l("datetime", $node->getMTime())); $output->writeln(" " . ($node->isEncrypted() ? "encrypted" : "not encrypted")); $output->writeln(" size: " . Util::humanFileSize($node->getSize())); if ($node instanceof Folder) { $children = $node->getDirectoryListing(); $childSize = array_sum(array_map(function (Node $node) { return $node->getSize(); }, $children)); if ($childSize != $node->getSize()) { $output->writeln(" warning: folder has a size of " . Util::humanFileSize($node->getSize()) ." but it's children sum up to " . Util::humanFileSize($childSize) . "."); $output->writeln(" Run occ files:scan --path " . $node->getPath() . " to attempt to resolve this."); } if ($showChildren) { $output->writeln(" children: " . count($children) . ":"); foreach ($children as $child) { $output->writeln(" - " . $child->getName()); } } else { $output->writeln(" children: " . count($children) . " (use --children option to list)"); } } $this->outputStorageDetails($node->getMountPoint(), $node, $output); $filesPerUser = $this->getFilesByUser($node); $output->writeln(""); $output->writeln("The following users have access to the file"); $output->writeln(""); foreach ($filesPerUser as $user => $files) { $output->writeln("$user:"); foreach ($files as $userFile) { $output->writeln(" " . $userFile->getPath() . ": " . $this->formatPermissions($userFile->getType(), $userFile->getPermissions())); $mount = $userFile->getMountPoint(); $output->writeln(" " . $this->formatMountType($mount)); } } return 0; } private function getNode(string $fileInput): ?Node { if (is_numeric($fileInput)) { $mounts = $this->userMountCache->getMountsForFileId((int)$fileInput); if (!$mounts) { return null; } $mount = $mounts[0]; $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID()); $nodes = $userFolder->getById((int)$fileInput); if (!$nodes) { return null; } return $nodes[0]; } else { try { return $this->rootFolder->get($fileInput); } catch (NotFoundException $e) { return null; } } } /** * @param FileInfo $file * @return array * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ private 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; } private 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 */ private 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); } private 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().")"; } } /** * @psalm-suppress UndefinedClass * @psalm-suppress UndefinedInterfaceMethod */ private function outputStorageDetails(IMountPoint $mountPoint, Node $node, OutputInterface $output): void { $storage = $mountPoint->getStorage(); if (!$storage) { return; } if (!$storage->instanceOfStorage(IHomeStorage::class)) { $output->writeln(" mounted at: " . $mountPoint->getMountPoint()); } if ($storage->instanceOfStorage(ObjectStoreStorage::class)) { /** @var ObjectStoreStorage $storage */ $objectStoreId = $storage->getObjectStore()->getStorageId(); $parts = explode(':', $objectStoreId); /** @var string $bucket */ $bucket = array_pop($parts); $output->writeln(" bucket: " . $bucket); if ($node instanceof \OC\Files\Node\File) { $output->writeln(" object id: " . $storage->getURN($node->getId())); try { $fh = $node->fopen('r'); if (!$fh) { throw new NotFoundException(); } $stat = fstat($fh); fclose($fh); if ($stat['size'] !== $node->getSize()) { $output->writeln(" warning: object had a size of " . $stat['size'] . " but cache entry has a size of " . $node->getSize() . ". This should have been automatically repaired"); } } catch (\Exception $e) { $output->writeln(" warning: object not found in bucket"); } } } else { if (!$storage->file_exists($node->getInternalPath())) { $output->writeln(" warning: file not found in storage"); } } if ($mountPoint instanceof ExternalMountPoint) { $storageConfig = $mountPoint->getStorageConfig(); $output->writeln(" external storage id: " . $storageConfig->getId()); $output->writeln(" external type: " . $storageConfig->getBackend()->getText()); } elseif ($mountPoint instanceof GroupMountPoint) { $output->writeln(" groupfolder id: " . $mountPoint->getFolderId()); } } }