2023-03-31 18:58:59 +02:00
< ? php
declare ( strict_types = 1 );
2024-05-09 20:20:32 +02:00
/**
* SPDX - FileCopyrightText : 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX - License - Identifier : AGPL - 3.0 - or - later
*/
2023-03-31 18:58:59 +02:00
namespace OC\Core\Command\Info ;
use OC\Files\ObjectStore\ObjectStoreStorage ;
2024-01-17 17:47:01 +01:00
use OC\Files\View ;
2023-03-31 18:58:59 +02:00
use OCA\Files_External\Config\ExternalMountPoint ;
use OCA\GroupFolders\Mount\GroupMountPoint ;
2024-08-26 19:28:44 +02:00
use OCP\Files\File as OCPFile ;
2023-03-31 18:58:59 +02:00
use OCP\Files\Folder ;
use OCP\Files\IHomeStorage ;
use OCP\Files\Mount\IMountPoint ;
use OCP\Files\Node ;
use OCP\Files\NotFoundException ;
use OCP\IL10N ;
use OCP\L10N\IFactory ;
use OCP\Util ;
use Symfony\Component\Console\Command\Command ;
use Symfony\Component\Console\Input\InputArgument ;
use Symfony\Component\Console\Input\InputInterface ;
use Symfony\Component\Console\Input\InputOption ;
use Symfony\Component\Console\Output\OutputInterface ;
class File extends Command {
private IL10N $l10n ;
2024-01-17 17:47:01 +01:00
private View $rootView ;
2023-03-31 18:58:59 +02:00
2023-06-12 18:40:19 +03:30
public function __construct (
IFactory $l10nFactory ,
private FileUtils $fileUtils ,
2024-01-17 17:47:01 +01:00
private \OC\Encryption\Util $encryptionUtil ,
2023-06-12 18:40:19 +03:30
) {
2023-03-31 18:58:59 +02:00
$this -> l10n = $l10nFactory -> get ( 'core' );
parent :: __construct ();
2024-01-17 17:47:01 +01:00
$this -> rootView = new View ();
2023-03-31 18:58:59 +02:00
}
2023-04-14 16:39:50 +02:00
protected function configure () : void {
2023-03-31 18:58:59 +02:00
$this
-> setName ( 'info:file' )
-> setDescription ( 'get information for a file' )
-> addArgument ( 'file' , InputArgument :: REQUIRED , 'File id or path' )
2024-04-15 11:35:51 +02:00
-> addOption ( 'children' , 'c' , InputOption :: VALUE_NONE , 'List children of folders' )
-> addOption ( 'storage-tree' , null , InputOption :: VALUE_NONE , 'Show storage and cache wrapping tree' );
2023-03-31 18:58:59 +02:00
}
public function execute ( InputInterface $input , OutputInterface $output ) : int {
$fileInput = $input -> getArgument ( 'file' );
$showChildren = $input -> getOption ( 'children' );
2023-04-14 19:16:29 +02:00
$node = $this -> fileUtils -> getNode ( $fileInput );
2023-03-31 18:58:59 +02:00
if ( ! $node ) {
$output -> writeln ( " <error>file $fileInput not found</error> " );
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 ()));
2024-08-26 19:28:44 +02:00
if ( $node instanceof OCPFile && $node -> isEncrypted ()) {
$output -> writeln ( ' ' . 'server-side encrypted: yes' );
2024-01-17 17:47:01 +01:00
$keyPath = $this -> encryptionUtil -> getFileKeyDir ( '' , $node -> getPath ());
if ( $this -> rootView -> file_exists ( $keyPath )) {
$output -> writeln ( ' encryption key at: ' . $keyPath );
} else {
$output -> writeln ( ' <error>encryption key not found</error> should be located at: ' . $keyPath );
}
}
2024-08-26 19:28:44 +02:00
if ( $node instanceof Folder && $node -> isEncrypted () || $node instanceof OCPFile && $node -> getParent () -> isEncrypted ()) {
$output -> writeln ( ' ' . 'end-to-end encrypted: yes' );
}
2023-04-14 16:39:50 +02:00
$output -> writeln ( ' size: ' . Util :: humanFileSize ( $node -> getSize ()));
2023-05-09 14:56:37 +02:00
$output -> writeln ( ' etag: ' . $node -> getEtag ());
2025-03-27 19:51:50 +01:00
$output -> writeln ( ' permissions: ' . $this -> fileUtils -> formatPermissions ( $node -> getType (), $node -> getPermissions ()));
2023-03-31 18:58:59 +02:00
if ( $node instanceof Folder ) {
$children = $node -> getDirectoryListing ();
2023-04-14 16:39:50 +02:00
$childSize = array_sum ( array_map ( function ( Node $node ) {
return $node -> getSize ();
}, $children ));
if ( $childSize != $node -> getSize ()) {
$output -> writeln ( ' <error>warning: folder has a size of ' . Util :: humanFileSize ( $node -> getSize ()) . " but it's children sum up to " . Util :: humanFileSize ( $childSize ) . '</error>.' );
$output -> writeln ( ' Run <info>occ files:scan --path ' . $node -> getPath () . '</info> to attempt to resolve this.' );
}
2023-03-31 18:58:59 +02:00
if ( $showChildren ) {
$output -> writeln ( ' children: ' . count ( $children ) . ':' );
foreach ( $children as $child ) {
$output -> writeln ( ' - ' . $child -> getName ());
}
} else {
2023-04-14 16:39:50 +02:00
$output -> writeln ( ' children: ' . count ( $children ) . ' (use <info>--children</info> option to list)' );
2023-03-31 18:58:59 +02:00
}
}
2024-04-15 11:35:51 +02:00
$this -> outputStorageDetails ( $node -> getMountPoint (), $node , $input , $output );
2023-03-31 18:58:59 +02:00
2023-04-14 19:16:29 +02:00
$filesPerUser = $this -> fileUtils -> getFilesByUser ( $node );
2023-03-31 18:58:59 +02:00
$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 ) {
2023-04-14 19:16:29 +02:00
$output -> writeln ( ' ' . $userFile -> getPath () . ': ' . $this -> fileUtils -> formatPermissions ( $userFile -> getType (), $userFile -> getPermissions ()));
2023-03-31 18:58:59 +02:00
$mount = $userFile -> getMountPoint ();
2023-04-14 19:16:29 +02:00
$output -> writeln ( ' ' . $this -> fileUtils -> formatMountType ( $mount ));
2023-03-31 18:58:59 +02:00
}
}
return 0 ;
}
2023-04-14 16:39:50 +02:00
/**
* @ psalm - suppress UndefinedClass
* @ psalm - suppress UndefinedInterfaceMethod
*/
2024-04-15 11:35:51 +02:00
private function outputStorageDetails ( IMountPoint $mountPoint , Node $node , InputInterface $input , OutputInterface $output ) : void {
2023-03-31 18:58:59 +02:00
$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 );
2023-04-14 16:39:50 +02:00
/** @var string $bucket */
2023-03-31 18:58:59 +02:00
$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 ( ' <error>warning: object had a size of ' . $stat [ 'size' ] . ' but cache entry has a size of ' . $node -> getSize () . '</error>. This should have been automatically repaired' );
}
} catch ( \Exception $e ) {
$output -> writeln ( ' <error>warning: object not found in bucket</error>' );
}
}
} else {
if ( ! $storage -> file_exists ( $node -> getInternalPath ())) {
$output -> writeln ( ' <error>warning: file not found in storage</error>' );
}
}
if ( $mountPoint instanceof ExternalMountPoint ) {
$storageConfig = $mountPoint -> getStorageConfig ();
$output -> writeln ( ' external storage id: ' . $storageConfig -> getId ());
$output -> writeln ( ' external type: ' . $storageConfig -> getBackend () -> getText ());
2023-04-14 16:39:50 +02:00
} elseif ( $mountPoint instanceof GroupMountPoint ) {
2023-03-31 18:58:59 +02:00
$output -> writeln ( ' groupfolder id: ' . $mountPoint -> getFolderId ());
}
2024-04-15 11:35:51 +02:00
if ( $input -> getOption ( 'storage-tree' )) {
$storageTmp = $storage ;
$storageClass = get_class ( $storageTmp ) . ' (cache:' . get_class ( $storageTmp -> getCache ()) . ')' ;
while ( $storageTmp instanceof \OC\Files\Storage\Wrapper\Wrapper ) {
$storageTmp = $storageTmp -> getWrapperStorage ();
$storageClass .= " \n \t " . '> ' . get_class ( $storageTmp ) . ' (cache:' . get_class ( $storageTmp -> getCache ()) . ')' ;
}
$output -> writeln ( ' storage wrapping: ' . $storageClass );
}
2023-03-31 18:58:59 +02:00
}
}