2012-09-16 18:52:32 +04:00
< ? php
/**
2016-07-21 18:07:57 +03:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
*
2015-03-26 13:44:34 +03:00
* @ author Andreas Fischer < bantu @ owncloud . com >
2019-03-02 01:52:58 +03:00
* @ author Ari Selseng < ari @ selseng . net >
2017-11-06 17:56:42 +03:00
* @ author Artem Kochnev < MrJeos @ gmail . com >
2016-05-26 20:56:05 +03:00
* @ author Björn Schießle < bjoern @ schiessle . org >
2020-04-29 12:57:22 +03:00
* @ author Christoph Wurst < christoph @ winzerhof - wurst . at >
2015-03-26 13:44:34 +03:00
* @ author Florin Peter < github @ florin - peter . de >
2017-11-06 17:56:42 +03:00
* @ author Frédéric Fortier < frederic . fortier @ oronospolytechnique . com >
2015-06-25 12:43:55 +03:00
* @ author Jens - Christian Fischer < jens - christian . fischer @ switch . ch >
2016-07-21 18:07:57 +03:00
* @ author Joas Schilling < coding @ schilljs . com >
2015-03-26 13:44:34 +03:00
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
2016-05-26 20:56:05 +03:00
* @ author Lukas Reschke < lukas @ statuscode . ch >
2015-03-26 13:44:34 +03:00
* @ author Michael Gapczynski < GapczynskiM @ gmail . com >
* @ author Morris Jobke < hey @ morrisjobke . de >
2016-07-21 19:13:36 +03:00
* @ author Robin Appelman < robin @ icewind . nl >
2016-01-12 17:02:16 +03:00
* @ author Robin McCorkell < robin @ mccorkell . me . uk >
2016-07-21 18:07:57 +03:00
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2015-03-26 13:44:34 +03:00
* @ author Vincent Petry < pvince81 @ owncloud . com >
*
* @ 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 ,
2019-12-03 21:57:53 +03:00
* along with this program . If not , see < http :// www . gnu . org / licenses />
2015-03-26 13:44:34 +03:00
*
2012-09-16 18:52:32 +04:00
*/
2015-02-26 13:37:37 +03:00
2012-09-16 18:52:32 +04:00
namespace OC\Files\Cache ;
2019-11-22 22:52:10 +03:00
use Doctrine\DBAL\Driver\Statement ;
2018-11-12 15:43:46 +03:00
use Doctrine\DBAL\Exception\UniqueConstraintViolationException ;
2017-01-16 18:20:53 +03:00
use OCP\DB\QueryBuilder\IQueryBuilder ;
2019-01-22 19:08:32 +03:00
use OCP\Files\Cache\CacheInsertEvent ;
2019-02-18 17:47:54 +03:00
use OCP\Files\Cache\CacheUpdateEvent ;
2015-12-01 18:41:28 +03:00
use OCP\Files\Cache\ICache ;
2015-12-02 16:59:13 +03:00
use OCP\Files\Cache\ICacheEntry ;
2019-10-25 17:55:53 +03:00
use OCP\Files\FileInfo ;
2019-11-22 22:52:10 +03:00
use OCP\Files\IMimeTypeLoader ;
2017-02-02 20:20:08 +03:00
use OCP\Files\Search\ISearchQuery ;
2019-01-22 19:08:32 +03:00
use OCP\Files\Storage\IStorage ;
2015-11-05 18:25:02 +03:00
use OCP\IDBConnection ;
2015-09-03 21:48:42 +03:00
2012-10-26 14:30:25 +04:00
/**
2015-05-05 17:06:28 +03:00
* Metadata cache for a storage
2012-10-26 14:30:25 +04:00
*
2015-05-05 17:06:28 +03:00
* The cache stores the metadata for all files and folders in a storage and is kept up to date trough the following mechanisms :
*
* - Scanner : scans the storage and updates the cache where needed
* - Watcher : checks for changes made to the filesystem outside of the ownCloud instance and rescans files and folder when a change is detected
* - Updater : listens to changes made to the filesystem inside of the ownCloud instance and updates the cache where needed
* - ChangePropagator : updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater
2012-10-26 14:30:25 +04:00
*/
2015-12-01 18:41:28 +03:00
class Cache implements ICache {
2016-01-27 17:45:19 +03:00
use MoveFromCacheTrait {
MoveFromCacheTrait :: moveFromCache as moveFromCacheFallback ;
}
2012-09-16 18:52:32 +04:00
/**
* @ var array partial data for the cache
*/
2019-10-25 17:55:53 +03:00
protected $partial = [];
2012-09-26 19:52:02 +04:00
2012-11-08 20:59:08 +04:00
/**
* @ var string
*/
2014-04-29 17:14:48 +04:00
protected $storageId ;
2012-09-26 19:52:02 +04:00
2019-01-22 19:08:32 +03:00
private $storage ;
2012-12-16 02:28:07 +04:00
/**
2013-04-26 02:00:18 +04:00
* @ var Storage $storageCache
2012-12-16 02:28:07 +04:00
*/
2014-04-29 17:14:48 +04:00
protected $storageCache ;
2012-12-16 02:28:07 +04:00
2015-09-03 21:48:42 +03:00
/** @var IMimeTypeLoader */
protected $mimetypeLoader ;
2013-01-07 04:40:09 +04:00
2015-11-05 18:25:02 +03:00
/**
* @ var IDBConnection
*/
protected $connection ;
2019-01-22 19:08:32 +03:00
protected $eventDispatcher ;
2017-02-02 20:20:08 +03:00
/** @var QuerySearchHelper */
protected $querySearchHelper ;
2012-09-26 19:52:02 +04:00
/**
2019-01-22 19:08:32 +03:00
* @ param IStorage $storage
2012-09-26 19:52:02 +04:00
*/
2019-01-22 19:08:32 +03:00
public function __construct ( IStorage $storage ) {
$this -> storageId = $storage -> getId ();
$this -> storage = $storage ;
2013-02-16 00:49:40 +04:00
if ( strlen ( $this -> storageId ) > 64 ) {
$this -> storageId = md5 ( $this -> storageId );
}
2012-12-16 02:28:07 +04:00
2013-04-26 02:00:18 +04:00
$this -> storageCache = new Storage ( $storage );
2015-09-03 21:48:42 +03:00
$this -> mimetypeLoader = \OC :: $server -> getMimeTypeLoader ();
2015-11-05 18:25:02 +03:00
$this -> connection = \OC :: $server -> getDatabaseConnection ();
2019-01-22 19:08:32 +03:00
$this -> eventDispatcher = \OC :: $server -> getEventDispatcher ();
2017-02-02 20:20:08 +03:00
$this -> querySearchHelper = new QuerySearchHelper ( $this -> mimetypeLoader );
2012-12-16 02:28:07 +04:00
}
2019-10-25 17:55:53 +03:00
private function getQueryBuilder () {
return new CacheQueryBuilder (
$this -> connection ,
\OC :: $server -> getSystemConfig (),
\OC :: $server -> getLogger (),
$this
);
}
2015-05-05 17:06:28 +03:00
/**
* Get the numeric storage id for this cache ' s storage
*
* @ return int
*/
2012-12-16 02:28:07 +04:00
public function getNumericStorageId () {
2013-04-26 02:00:18 +04:00
return $this -> storageCache -> getNumericId ();
2012-09-26 19:52:02 +04:00
}
2012-09-16 18:52:32 +04:00
/**
* get the stored metadata of a file or folder
*
2015-05-05 17:06:28 +03:00
* @ param string | int $file either the path of a file or folder or the file id for a file or folder
2015-12-02 16:59:13 +03:00
* @ return ICacheEntry | false the cache entry as array of false if the file is not found in the cache
2012-09-16 18:52:32 +04:00
*/
2012-09-26 19:52:02 +04:00
public function get ( $file ) {
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> selectFileCache ();
2012-11-25 19:30:57 +04:00
if ( is_string ( $file ) or $file == '' ) {
2013-05-23 22:29:46 +04:00
// normalize file
$file = $this -> normalize ( $file );
2019-10-25 17:55:53 +03:00
$query -> whereStorageId ()
-> wherePath ( $file );
2012-09-16 18:52:32 +04:00
} else { //file id
2019-10-25 17:55:53 +03:00
$query -> whereFileId ( $file );
2012-09-16 18:52:32 +04:00
}
2012-09-22 16:40:04 +04:00
2019-10-25 17:55:53 +03:00
$data = $query -> execute () -> fetch ();
2013-06-10 13:07:41 +04:00
2012-09-22 16:40:04 +04:00
//merge partial data
2019-10-25 17:55:53 +03:00
if ( ! $data and is_string ( $file ) and isset ( $this -> partial [ $file ])) {
return $this -> partial [ $file ];
2020-04-10 11:35:09 +03:00
} elseif ( ! $data ) {
2018-11-16 19:26:42 +03:00
return $data ;
2012-09-26 19:52:02 +04:00
} else {
2016-12-13 14:53:38 +03:00
return self :: cacheEntryFromData ( $data , $this -> mimetypeLoader );
2016-11-17 16:18:47 +03:00
}
}
/**
* Create a CacheEntry from database row
*
* @ param array $data
* @ param IMimeTypeLoader $mimetypeLoader
* @ return CacheEntry
*/
2016-12-13 14:53:38 +03:00
public static function cacheEntryFromData ( $data , IMimeTypeLoader $mimetypeLoader ) {
2016-11-17 16:18:47 +03:00
//fix types
$data [ 'fileid' ] = ( int ) $data [ 'fileid' ];
$data [ 'parent' ] = ( int ) $data [ 'parent' ];
$data [ 'size' ] = 0 + $data [ 'size' ];
$data [ 'mtime' ] = ( int ) $data [ 'mtime' ];
$data [ 'storage_mtime' ] = ( int ) $data [ 'storage_mtime' ];
$data [ 'encryptedVersion' ] = ( int ) $data [ 'encrypted' ];
$data [ 'encrypted' ] = ( bool ) $data [ 'encrypted' ];
2016-12-13 14:50:17 +03:00
$data [ 'storage_id' ] = $data [ 'storage' ];
2017-02-21 06:07:37 +03:00
$data [ 'storage' ] = ( int ) $data [ 'storage' ];
2016-11-17 16:18:47 +03:00
$data [ 'mimetype' ] = $mimetypeLoader -> getMimetypeById ( $data [ 'mimetype' ]);
$data [ 'mimepart' ] = $mimetypeLoader -> getMimetypeById ( $data [ 'mimepart' ]);
if ( $data [ 'storage_mtime' ] == 0 ) {
$data [ 'storage_mtime' ] = $data [ 'mtime' ];
2012-09-22 16:40:04 +04:00
}
2016-11-17 16:18:47 +03:00
$data [ 'permissions' ] = ( int ) $data [ 'permissions' ];
2019-10-25 19:21:57 +03:00
if ( isset ( $data [ 'creation_time' ])) {
$data [ 'creation_time' ] = ( int ) $data [ 'creation_time' ];
}
if ( isset ( $data [ 'upload_time' ])) {
$data [ 'upload_time' ] = ( int ) $data [ 'upload_time' ];
}
2016-11-17 16:18:47 +03:00
return new CacheEntry ( $data );
2012-09-16 18:52:32 +04:00
}
2012-09-23 17:25:03 +04:00
/**
* get the metadata of all files stored in $folder
*
2012-09-26 19:52:02 +04:00
* @ param string $folder
2015-12-02 16:59:13 +03:00
* @ return ICacheEntry []
2012-09-23 17:25:03 +04:00
*/
2014-02-21 18:36:24 +04:00
public function getFolderContents ( $folder ) {
$fileId = $this -> getId ( $folder );
2014-02-21 18:35:12 +04:00
return $this -> getFolderContentsById ( $fileId );
}
/**
* get the metadata of all files stored in $folder
*
* @ param int $fileId the file id of the folder
2015-12-02 16:59:13 +03:00
* @ return ICacheEntry []
2014-02-21 18:35:12 +04:00
*/
public function getFolderContentsById ( $fileId ) {
2012-09-23 17:25:03 +04:00
if ( $fileId > - 1 ) {
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> selectFileCache ()
-> whereParent ( $fileId )
-> orderBy ( 'name' , 'ASC' );
$files = $query -> execute () -> fetchAll ();
2015-12-02 16:59:13 +03:00
return array_map ( function ( array $data ) {
2018-01-27 01:46:40 +03:00
return self :: cacheEntryFromData ( $data , $this -> mimetypeLoader );
2015-12-02 16:59:13 +03:00
}, $files );
2012-09-23 17:25:03 +04:00
}
2018-01-26 01:01:03 +03:00
return [];
2012-09-23 17:25:03 +04:00
}
2012-09-16 18:52:32 +04:00
/**
2016-02-02 16:41:14 +03:00
* insert or update meta data for a file or folder
2012-09-16 18:52:32 +04:00
*
2012-09-26 19:52:02 +04:00
* @ param string $file
2012-09-16 18:52:32 +04:00
* @ param array $data
*
* @ return int file id
2015-03-11 11:33:50 +03:00
* @ throws \RuntimeException
2012-09-16 18:52:32 +04:00
*/
2012-09-26 19:52:02 +04:00
public function put ( $file , array $data ) {
if (( $id = $this -> getId ( $file )) > - 1 ) {
2019-05-07 15:53:02 +03:00
$this -> update ( $id , $data );
2012-09-16 18:52:32 +04:00
return $id ;
} else {
2016-02-02 16:41:14 +03:00
return $this -> insert ( $file , $data );
}
}
2013-05-23 22:29:46 +04:00
2016-02-02 16:41:14 +03:00
/**
* insert meta data for a new file or folder
*
* @ param string $file
* @ param array $data
*
* @ return int file id
* @ throws \RuntimeException
2018-11-12 15:43:46 +03:00
*
* @ suppress SqlInjectionChecker
2016-02-02 16:41:14 +03:00
*/
public function insert ( $file , array $data ) {
// normalize file
$file = $this -> normalize ( $file );
2012-09-16 18:52:32 +04:00
2016-02-02 16:41:14 +03:00
if ( isset ( $this -> partial [ $file ])) { //add any saved partial data
$data = array_merge ( $this -> partial [ $file ], $data );
unset ( $this -> partial [ $file ]);
}
2019-10-25 17:55:53 +03:00
$requiredFields = [ 'size' , 'mtime' , 'mimetype' ];
2016-02-02 16:41:14 +03:00
foreach ( $requiredFields as $field ) {
if ( ! isset ( $data [ $field ])) { //data not complete save as partial and return
$this -> partial [ $file ] = $data ;
return - 1 ;
2012-09-16 18:52:32 +04:00
}
2016-02-02 16:41:14 +03:00
}
2012-09-16 18:52:32 +04:00
2016-02-02 16:41:14 +03:00
$data [ 'path' ] = $file ;
2020-02-15 00:08:13 +03:00
if ( ! isset ( $data [ 'parent' ])) {
$data [ 'parent' ] = $this -> getParentId ( $file );
}
2017-11-23 14:35:47 +03:00
$data [ 'name' ] = basename ( $file );
2012-09-16 18:52:32 +04:00
2019-10-25 19:21:57 +03:00
[ $values , $extensionValues ] = $this -> normalizeData ( $data );
2019-10-25 17:55:53 +03:00
$values [ 'storage' ] = $this -> getNumericStorageId ();
2018-11-12 15:43:46 +03:00
try {
$builder = $this -> connection -> getQueryBuilder ();
$builder -> insert ( 'filecache' );
foreach ( $values as $column => $value ) {
$builder -> setValue ( $column , $builder -> createNamedParameter ( $value ));
}
if ( $builder -> execute ()) {
2019-10-25 19:21:57 +03:00
$fileId = $builder -> getLastInsertId ();
2019-10-31 16:22:32 +03:00
if ( count ( $extensionValues )) {
$query = $this -> getQueryBuilder ();
$query -> insert ( 'filecache_extended' );
$query -> setValue ( 'fileid' , $query -> createNamedParameter ( $fileId , IQueryBuilder :: PARAM_INT ));
foreach ( $extensionValues as $column => $value ) {
$query -> setValue ( $column , $query -> createNamedParameter ( $value ));
}
$query -> execute ();
2019-10-25 19:21:57 +03:00
}
2019-01-22 19:08:32 +03:00
$this -> eventDispatcher -> dispatch ( CacheInsertEvent :: class , new CacheInsertEvent ( $this -> storage , $file , $fileId ));
return $fileId ;
2018-11-12 15:43:46 +03:00
}
2019-01-22 19:08:32 +03:00
} catch ( UniqueConstraintViolationException $e ) {
2018-11-12 15:43:46 +03:00
// entry exists already
2020-02-28 19:36:38 +03:00
if ( $this -> connection -> inTransaction ()) {
$this -> connection -> commit ();
$this -> connection -> beginTransaction ();
}
2016-02-02 16:41:14 +03:00
}
2012-09-16 18:52:32 +04:00
2016-02-02 16:41:14 +03:00
// The file was created in the mean time
if (( $id = $this -> getId ( $file )) > - 1 ) {
$this -> update ( $id , $data );
return $id ;
} else {
2018-11-12 15:43:46 +03:00
throw new \RuntimeException ( 'File entry could not be inserted but could also not be selected with getId() in order to perform an update. Please try again.' );
2012-09-16 18:52:32 +04:00
}
}
/**
2015-05-05 17:06:28 +03:00
* update the metadata of an existing file or folder in the cache
2012-09-16 18:52:32 +04:00
*
2015-05-05 17:06:28 +03:00
* @ param int $id the fileid of the existing file or folder
* @ param array $data [ $key => $value ] the metadata to update , only the fields provided in the array will be updated , non - provided values will remain unchanged
2012-09-16 18:52:32 +04:00
*/
2012-09-26 19:52:02 +04:00
public function update ( $id , array $data ) {
2015-01-15 19:26:12 +03:00
if ( isset ( $data [ 'path' ])) {
2013-05-25 22:35:12 +04:00
// normalize path
$data [ 'path' ] = $this -> normalize ( $data [ 'path' ]);
}
2015-01-15 19:26:12 +03:00
if ( isset ( $data [ 'name' ])) {
2013-05-25 22:35:12 +04:00
// normalize path
$data [ 'name' ] = $this -> normalize ( $data [ 'name' ]);
}
2019-10-25 19:21:57 +03:00
[ $values , $extensionValues ] = $this -> normalizeData ( $data );
2019-10-25 17:55:53 +03:00
2019-10-25 19:21:57 +03:00
if ( count ( $values )) {
$query = $this -> getQueryBuilder ();
2019-10-25 17:55:53 +03:00
2019-10-25 19:21:57 +03:00
$query -> update ( 'filecache' )
-> whereFileId ( $id )
-> andWhere ( $query -> expr () -> orX ( ... array_map ( function ( $key , $value ) use ( $query ) {
return $query -> expr () -> orX (
$query -> expr () -> neq ( $key , $query -> createNamedParameter ( $value )),
$query -> expr () -> isNull ( $key )
);
}, array_keys ( $values ), array_values ( $values ))));
foreach ( $values as $key => $value ) {
$query -> set ( $key , $query -> createNamedParameter ( $value ));
}
2019-10-25 17:55:53 +03:00
2019-10-25 19:21:57 +03:00
$query -> execute ();
2019-10-25 17:55:53 +03:00
}
2012-09-16 18:52:32 +04:00
2019-10-25 19:21:57 +03:00
if ( count ( $extensionValues )) {
2019-10-31 16:22:32 +03:00
try {
$query = $this -> getQueryBuilder ();
$query -> insert ( 'filecache_extended' );
2019-10-25 19:21:57 +03:00
2019-10-31 16:22:32 +03:00
$query -> setValue ( 'fileid' , $query -> createNamedParameter ( $id , IQueryBuilder :: PARAM_INT ));
foreach ( $extensionValues as $column => $value ) {
$query -> setValue ( $column , $query -> createNamedParameter ( $value ));
}
2019-10-25 19:21:57 +03:00
2019-10-31 16:22:32 +03:00
$query -> execute ();
} catch ( UniqueConstraintViolationException $e ) {
$query = $this -> getQueryBuilder ();
$query -> update ( 'filecache_extended' )
-> whereFileId ( $id )
-> andWhere ( $query -> expr () -> orX ( ... array_map ( function ( $key , $value ) use ( $query ) {
return $query -> expr () -> orX (
$query -> expr () -> neq ( $key , $query -> createNamedParameter ( $value )),
$query -> expr () -> isNull ( $key )
);
}, array_keys ( $extensionValues ), array_values ( $extensionValues ))));
foreach ( $extensionValues as $key => $value ) {
$query -> set ( $key , $query -> createNamedParameter ( $value ));
}
$query -> execute ();
}
2019-10-25 19:21:57 +03:00
}
2015-04-11 19:06:21 +03:00
2019-02-18 17:47:54 +03:00
$path = $this -> getPathById ( $id );
// path can still be null if the file doesn't exist
if ( $path !== null ) {
$this -> eventDispatcher -> dispatch ( CacheUpdateEvent :: class , new CacheUpdateEvent ( $this -> storage , $path , $id ));
}
2012-09-16 18:52:32 +04:00
}
/**
* extract query parts and params array from data array
*
* @ param array $data
2019-10-25 17:55:53 +03:00
* @ return array
2012-09-16 18:52:32 +04:00
*/
2019-10-25 17:55:53 +03:00
protected function normalizeData ( array $data ) : array {
$fields = [
2015-03-30 18:29:05 +03:00
'path' , 'parent' , 'name' , 'mimetype' , 'size' , 'mtime' , 'storage_mtime' , 'encrypted' ,
2019-10-25 17:55:53 +03:00
'etag' , 'permissions' , 'checksum' , 'storage' ];
2019-10-25 19:21:57 +03:00
$extensionFields = [ 'metadata_etag' , 'creation_time' , 'upload_time' ];
2015-10-16 19:28:45 +03:00
$doNotCopyStorageMTime = false ;
if ( array_key_exists ( 'mtime' , $data ) && $data [ 'mtime' ] === null ) {
// this horrific magic tells it to not copy storage_mtime to mtime
unset ( $data [ 'mtime' ]);
$doNotCopyStorageMTime = true ;
}
2019-10-25 17:55:53 +03:00
$params = [];
2019-10-25 19:21:57 +03:00
$extensionParams = [];
2012-09-16 18:52:32 +04:00
foreach ( $data as $name => $value ) {
if ( array_search ( $name , $fields ) !== false ) {
if ( $name === 'path' ) {
2019-10-25 17:55:53 +03:00
$params [ 'path_hash' ] = md5 ( $value );
2020-04-10 11:35:09 +03:00
} elseif ( $name === 'mimetype' ) {
2019-10-25 17:55:53 +03:00
$params [ 'mimepart' ] = $this -> mimetypeLoader -> getId ( substr ( $value , 0 , strpos ( $value , '/' )));
2015-09-03 21:48:42 +03:00
$value = $this -> mimetypeLoader -> getId ( $value );
2020-04-10 11:35:09 +03:00
} elseif ( $name === 'storage_mtime' ) {
2015-10-16 19:28:45 +03:00
if ( ! $doNotCopyStorageMTime && ! isset ( $data [ 'mtime' ])) {
2019-10-25 17:55:53 +03:00
$params [ 'mtime' ] = $value ;
2013-02-10 15:27:35 +04:00
}
2020-04-10 11:35:09 +03:00
} elseif ( $name === 'encrypted' ) {
2017-02-02 20:20:08 +03:00
if ( isset ( $data [ 'encryptedVersion' ])) {
2016-02-08 22:35:33 +03:00
$value = $data [ 'encryptedVersion' ];
} else {
// Boolean to integer conversion
$value = $value ? 1 : 0 ;
}
2012-09-16 18:52:32 +04:00
}
2019-10-25 17:55:53 +03:00
$params [ $name ] = $value ;
2012-09-16 18:52:32 +04:00
}
2019-10-25 19:21:57 +03:00
if ( array_search ( $name , $extensionFields ) !== false ) {
$extensionParams [ $name ] = $value ;
}
2012-09-16 18:52:32 +04:00
}
2019-11-13 13:28:14 +03:00
return [ $params , array_filter ( $extensionParams )];
2012-09-16 18:52:32 +04:00
}
/**
* get the file id for a file
*
2015-05-05 17:06:28 +03:00
* A file id is a numeric id for a file or folder that ' s unique within an owncloud instance which stays the same for the lifetime of a file
*
* File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing
*
2012-09-26 19:52:02 +04:00
* @ param string $file
2012-09-16 18:52:32 +04:00
* @ return int
*/
2012-09-26 19:52:02 +04:00
public function getId ( $file ) {
2013-05-23 22:29:46 +04:00
// normalize file
$file = $this -> normalize ( $file );
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> select ( 'fileid' )
-> from ( 'filecache' )
-> whereStorageId ()
-> wherePath ( $file );
2012-09-16 18:52:32 +04:00
2019-10-25 17:55:53 +03:00
$id = $query -> execute () -> fetchColumn ();
return $id === false ? - 1 : ( int ) $id ;
2012-09-16 18:52:32 +04:00
}
/**
* get the id of the parent folder of a file
*
2012-09-26 19:52:02 +04:00
* @ param string $file
2012-09-22 17:48:39 +04:00
* @ return int
2012-09-16 18:52:32 +04:00
*/
2012-09-26 19:52:02 +04:00
public function getParentId ( $file ) {
2012-10-03 13:23:33 +04:00
if ( $file === '' ) {
2012-09-16 18:52:32 +04:00
return - 1 ;
} else {
2015-11-10 18:14:08 +03:00
$parent = $this -> getParentPath ( $file );
2015-12-02 16:59:13 +03:00
return ( int ) $this -> getId ( $parent );
2015-11-10 18:14:08 +03:00
}
}
private function getParentPath ( $path ) {
$parent = dirname ( $path );
if ( $parent === '.' ) {
$parent = '' ;
2012-09-16 18:52:32 +04:00
}
2015-11-10 18:14:08 +03:00
return $parent ;
2012-09-16 18:52:32 +04:00
}
/**
* check if a file is available in the cache
*
2012-09-26 19:52:02 +04:00
* @ param string $file
2012-09-16 18:52:32 +04:00
* @ return bool
*/
2012-09-26 19:52:02 +04:00
public function inCache ( $file ) {
return $this -> getId ( $file ) != - 1 ;
2012-09-16 18:52:32 +04:00
}
/**
* remove a file or folder from the cache
*
2015-05-05 17:06:28 +03:00
* when removing a folder from the cache all files and folders inside the folder will be removed as well
*
2012-09-26 19:52:02 +04:00
* @ param string $file
2012-09-16 18:52:32 +04:00
*/
2012-09-26 19:52:02 +04:00
public function remove ( $file ) {
2012-10-27 20:05:40 +04:00
$entry = $this -> get ( $file );
2019-10-25 17:55:53 +03:00
if ( $entry ) {
$query = $this -> getQueryBuilder ();
$query -> delete ( 'filecache' )
-> whereFileId ( $entry -> getId ());
$query -> execute ();
2019-10-25 19:21:57 +03:00
$query = $this -> getQueryBuilder ();
$query -> delete ( 'filecache_extended' )
-> whereFileId ( $entry -> getId ());
$query -> execute ();
2019-10-25 17:55:53 +03:00
if ( $entry -> getMimeType () == FileInfo :: MIMETYPE_FOLDER ) {
$this -> removeChildren ( $entry );
}
2012-10-27 20:05:40 +04:00
}
2015-01-15 19:26:12 +03:00
}
2014-10-30 12:51:25 +03:00
2015-05-05 17:06:28 +03:00
/**
* Get all sub folders of a folder
*
2019-10-25 17:55:53 +03:00
* @ param ICacheEntry $entry the cache entry of the folder to get the subfolders for
* @ return ICacheEntry [] the cache entries for the subfolders
2015-05-05 17:06:28 +03:00
*/
2019-10-25 17:55:53 +03:00
private function getSubFolders ( ICacheEntry $entry ) {
$children = $this -> getFolderContentsById ( $entry -> getId ());
2015-01-15 19:26:12 +03:00
return array_filter ( $children , function ( $child ) {
2019-10-25 17:55:53 +03:00
return $child -> getMimeType () == FileInfo :: MIMETYPE_FOLDER ;
2015-01-15 19:26:12 +03:00
});
}
2015-05-05 17:06:28 +03:00
/**
* Recursively remove all children of a folder
*
2019-10-25 17:55:53 +03:00
* @ param ICacheEntry $entry the cache entry of the folder to remove the children of
2015-05-05 17:06:28 +03:00
* @ throws \OC\DatabaseException
*/
2019-10-25 17:55:53 +03:00
private function removeChildren ( ICacheEntry $entry ) {
2019-10-31 16:57:39 +03:00
$children = $this -> getFolderContentsById ( $entry -> getId ());
2020-04-09 14:53:40 +03:00
$childIds = array_map ( function ( ICacheEntry $cacheEntry ) {
2019-10-31 16:57:39 +03:00
return $cacheEntry -> getId ();
}, $children );
$childFolders = array_filter ( $children , function ( $child ) {
return $child -> getMimeType () == FileInfo :: MIMETYPE_FOLDER ;
});
foreach ( $childFolders as $folder ) {
2015-01-15 19:26:12 +03:00
$this -> removeChildren ( $folder );
}
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> delete ( 'filecache' )
-> whereParent ( $entry -> getId ());
$query -> execute ();
2019-10-25 19:21:57 +03:00
$query = $this -> getQueryBuilder ();
$query -> delete ( 'filecache_extended' )
2019-10-31 16:57:39 +03:00
-> where ( $query -> expr () -> in ( 'fileid' , $query -> createNamedParameter ( $childIds , IQueryBuilder :: PARAM_INT_ARRAY )));
2019-10-25 19:21:57 +03:00
$query -> execute ();
2012-09-16 18:52:32 +04:00
}
2012-11-03 01:25:33 +04:00
/**
* Move a file or folder in the cache
*
* @ param string $source
* @ param string $target
*/
public function move ( $source , $target ) {
2015-04-01 16:15:24 +03:00
$this -> moveFromCache ( $this , $source , $target );
2012-11-03 01:25:33 +04:00
}
2015-04-13 18:09:18 +03:00
/**
* Get the storage id and path needed for a move
*
* @ param string $path
* @ return array [ $storageId , $internalPath ]
*/
protected function getMoveInfo ( $path ) {
return [ $this -> getNumericStorageId (), $path ];
}
2015-04-01 16:12:59 +03:00
/**
* Move a file or folder in the cache
*
2021-03-08 20:49:08 +03:00
* @ param ICache $sourceCache
2015-04-01 16:12:59 +03:00
* @ param string $sourcePath
* @ param string $targetPath
* @ throws \OC\DatabaseException
2017-02-16 13:47:16 +03:00
* @ throws \Exception if the given storages have an invalid id
2017-07-20 23:48:13 +03:00
* @ suppress SqlInjectionChecker
2015-04-01 16:12:59 +03:00
*/
2015-12-02 16:59:13 +03:00
public function moveFromCache ( ICache $sourceCache , $sourcePath , $targetPath ) {
2016-01-27 17:45:19 +03:00
if ( $sourceCache instanceof Cache ) {
// normalize source and target
$sourcePath = $this -> normalize ( $sourcePath );
$targetPath = $this -> normalize ( $targetPath );
$sourceData = $sourceCache -> get ( $sourcePath );
$sourceId = $sourceData [ 'fileid' ];
$newParentId = $this -> getParentId ( $targetPath );
2020-02-28 19:36:38 +03:00
[ $sourceStorageId , $sourcePath ] = $sourceCache -> getMoveInfo ( $sourcePath );
[ $targetStorageId , $targetPath ] = $this -> getMoveInfo ( $targetPath );
2016-01-27 17:45:19 +03:00
2017-02-16 13:47:16 +03:00
if ( is_null ( $sourceStorageId ) || $sourceStorageId === false ) {
throw new \Exception ( 'Invalid source storage id: ' . $sourceStorageId );
}
if ( is_null ( $targetStorageId ) || $targetStorageId === false ) {
throw new \Exception ( 'Invalid target storage id: ' . $targetStorageId );
}
2017-01-16 18:20:53 +03:00
$this -> connection -> beginTransaction ();
2016-01-27 17:45:19 +03:00
if ( $sourceData [ 'mimetype' ] === 'httpd/unix-directory' ) {
2017-01-16 18:20:53 +03:00
//update all child entries
2017-07-20 17:29:50 +03:00
$sourceLength = mb_strlen ( $sourcePath );
2017-01-16 18:20:53 +03:00
$query = $this -> connection -> getQueryBuilder ();
2017-03-26 21:45:49 +03:00
$fun = $query -> func ();
2017-01-16 18:20:53 +03:00
$newPathFunction = $fun -> concat (
$query -> createNamedParameter ( $targetPath ),
$fun -> substring ( 'path' , $query -> createNamedParameter ( $sourceLength + 1 , IQueryBuilder :: PARAM_INT )) // +1 for the leading slash
);
$query -> update ( 'filecache' )
-> set ( 'storage' , $query -> createNamedParameter ( $targetStorageId , IQueryBuilder :: PARAM_INT ))
-> set ( 'path_hash' , $fun -> md5 ( $newPathFunction ))
-> set ( 'path' , $newPathFunction )
-> where ( $query -> expr () -> eq ( 'storage' , $query -> createNamedParameter ( $sourceStorageId , IQueryBuilder :: PARAM_INT )))
-> andWhere ( $query -> expr () -> like ( 'path' , $query -> createNamedParameter ( $this -> connection -> escapeLikeParameter ( $sourcePath ) . '/%' )));
try {
$query -> execute ();
2017-02-21 16:48:00 +03:00
} catch ( \OC\DatabaseException $e ) {
2017-01-16 18:20:53 +03:00
$this -> connection -> rollBack ();
throw $e ;
2016-01-27 17:45:19 +03:00
}
2015-04-01 16:12:59 +03:00
}
2017-01-16 18:20:53 +03:00
2019-10-25 19:21:57 +03:00
$query = $this -> getQueryBuilder ();
2019-10-25 17:55:53 +03:00
$query -> update ( 'filecache' )
-> set ( 'storage' , $query -> createNamedParameter ( $targetStorageId ))
-> set ( 'path' , $query -> createNamedParameter ( $targetPath ))
-> set ( 'path_hash' , $query -> createNamedParameter ( md5 ( $targetPath )))
-> set ( 'name' , $query -> createNamedParameter ( basename ( $targetPath )))
-> set ( 'parent' , $query -> createNamedParameter ( $newParentId , IQueryBuilder :: PARAM_INT ))
2019-10-25 19:21:57 +03:00
-> whereFileId ( $sourceId );
2019-10-25 17:55:53 +03:00
$query -> execute ();
2019-10-25 19:21:57 +03:00
2017-01-16 18:20:53 +03:00
$this -> connection -> commit ();
2015-10-26 18:31:26 +03:00
} else {
2016-01-27 17:45:19 +03:00
$this -> moveFromCacheFallback ( $sourceCache , $sourcePath , $targetPath );
2015-04-01 16:12:59 +03:00
}
}
2012-09-16 18:52:32 +04:00
/**
2012-09-26 19:52:02 +04:00
* remove all entries for files that are stored on the storage from the cache
2012-09-16 18:52:32 +04:00
*/
2012-09-26 19:52:02 +04:00
public function clear () {
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> delete ( 'filecache' )
2019-10-25 19:21:57 +03:00
-> whereStorageId ();
2019-10-25 17:55:53 +03:00
$query -> execute ();
2012-12-16 02:28:07 +04:00
2019-10-25 17:55:53 +03:00
$query = $this -> connection -> getQueryBuilder ();
$query -> delete ( 'storages' )
-> where ( $query -> expr () -> eq ( 'id' , $query -> createNamedParameter ( $this -> storageId )));
$query -> execute ();
2012-09-16 18:52:32 +04:00
}
2012-10-08 16:58:21 +04:00
/**
2015-05-05 17:06:28 +03:00
* Get the scan status of a file
*
* - Cache :: NOT_FOUND : File is not in the cache
* - Cache :: PARTIAL : File is not stored in the cache but some incomplete data is known
* - Cache :: SHALLOW : The folder and it ' s direct children are in the cache but not all sub folders are fully scanned
* - Cache :: COMPLETE : The file or folder , with all it ' s children ) are fully scanned
*
2012-10-08 16:58:21 +04:00
* @ param string $file
*
2015-01-16 21:31:15 +03:00
* @ return int Cache :: NOT_FOUND , Cache :: PARTIAL , Cache :: SHALLOW or Cache :: COMPLETE
2012-10-08 16:58:21 +04:00
*/
public function getStatus ( $file ) {
2013-05-25 16:56:00 +04:00
// normalize file
$file = $this -> normalize ( $file );
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> select ( 'size' )
-> from ( 'filecache' )
-> whereStorageId ()
-> wherePath ( $file );
$size = $query -> execute () -> fetchColumn ();
if ( $size !== false ) {
if (( int ) $size === - 1 ) {
2012-10-08 16:58:21 +04:00
return self :: SHALLOW ;
} else {
return self :: COMPLETE ;
}
} else {
if ( isset ( $this -> partial [ $file ])) {
return self :: PARTIAL ;
} else {
return self :: NOT_FOUND ;
}
}
}
2012-10-26 15:23:15 +04:00
/**
* search for files matching $pattern
*
2015-05-05 17:06:28 +03:00
* @ param string $pattern the search pattern using SQL search syntax ( e . g . '%searchstring%' )
2015-12-02 16:59:13 +03:00
* @ return ICacheEntry [] an array of cache entries where the name matches the search pattern
2012-10-26 15:23:15 +04:00
*/
public function search ( $pattern ) {
2013-05-25 22:35:12 +04:00
// normalize pattern
$pattern = $this -> normalize ( $pattern );
2017-03-13 18:06:19 +03:00
if ( $pattern === '%%' ) {
return [];
}
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> selectFileCache ()
-> whereStorageId ()
-> andWhere ( $query -> expr () -> iLike ( 'name' , $query -> createNamedParameter ( $pattern )));
2014-07-03 21:01:00 +04:00
2019-10-25 17:55:53 +03:00
return array_map ( function ( array $data ) {
return self :: cacheEntryFromData ( $data , $this -> mimetypeLoader );
}, $query -> execute () -> fetchAll ());
2017-02-02 20:20:08 +03:00
}
/**
* @ param Statement $result
* @ return CacheEntry []
*/
private function searchResultToCacheEntries ( Statement $result ) {
2017-02-23 04:03:32 +03:00
$files = $result -> fetchAll ();
2017-02-02 20:20:08 +03:00
return array_map ( function ( array $data ) {
2017-02-23 04:03:32 +03:00
return self :: cacheEntryFromData ( $data , $this -> mimetypeLoader );
2015-12-02 16:59:13 +03:00
}, $files );
2012-10-26 15:23:15 +04:00
}
2012-10-27 12:01:20 +04:00
2012-10-27 12:34:25 +04:00
/**
* search for files by mimetype
*
2015-05-05 17:06:28 +03:00
* @ param string $mimetype either a full mimetype to search ( 'text/plain' ) or only the first part of a mimetype ( 'image' )
2015-11-05 18:25:02 +03:00
* where it will search for all mimetypes in the group ( 'image/*' )
2015-12-02 16:59:13 +03:00
* @ return ICacheEntry [] an array of cache entries where the mimetype matches the search
2012-10-27 12:34:25 +04:00
*/
public function searchByMime ( $mimetype ) {
2019-10-25 17:55:53 +03:00
$mimeId = $this -> mimetypeLoader -> getId ( $mimetype );
$query = $this -> getQueryBuilder ();
$query -> selectFileCache ()
-> whereStorageId ();
2012-10-27 12:34:25 +04:00
if ( strpos ( $mimetype , '/' )) {
2019-10-25 17:55:53 +03:00
$query -> andWhere ( $query -> expr () -> eq ( 'mimetype' , $query -> createNamedParameter ( $mimeId , IQueryBuilder :: PARAM_INT )));
2012-10-27 12:34:25 +04:00
} else {
2019-10-25 17:55:53 +03:00
$query -> andWhere ( $query -> expr () -> eq ( 'mimepart' , $query -> createNamedParameter ( $mimeId , IQueryBuilder :: PARAM_INT )));
2012-10-27 12:34:25 +04:00
}
2017-02-23 04:03:32 +03:00
2019-10-25 17:55:53 +03:00
return array_map ( function ( array $data ) {
return self :: cacheEntryFromData ( $data , $this -> mimetypeLoader );
}, $query -> execute () -> fetchAll ());
2017-02-02 20:20:08 +03:00
}
2017-02-23 04:03:32 +03:00
2017-02-02 20:20:08 +03:00
public function searchQuery ( ISearchQuery $searchQuery ) {
2019-10-25 17:55:53 +03:00
$builder = $this -> getQueryBuilder ();
2017-02-02 20:20:08 +03:00
2019-10-25 19:21:57 +03:00
$query = $builder -> selectFileCache ( 'file' );
2017-03-08 17:17:39 +03:00
2019-10-25 17:55:53 +03:00
$query -> whereStorageId ();
2017-03-08 17:17:39 +03:00
if ( $this -> querySearchHelper -> shouldJoinTags ( $searchQuery -> getSearchOperation ())) {
$query
-> innerJoin ( 'file' , 'vcategory_to_object' , 'tagmap' , $builder -> expr () -> eq ( 'file.fileid' , 'tagmap.objid' ))
-> innerJoin ( 'tagmap' , 'vcategory' , 'tag' , $builder -> expr () -> andX (
$builder -> expr () -> eq ( 'tagmap.type' , 'tag.type' ),
$builder -> expr () -> eq ( 'tagmap.categoryid' , 'tag.id' )
))
-> andWhere ( $builder -> expr () -> eq ( 'tag.type' , $builder -> createNamedParameter ( 'files' )))
-> andWhere ( $builder -> expr () -> eq ( 'tag.uid' , $builder -> createNamedParameter ( $searchQuery -> getUser () -> getUID ())));
}
2019-11-08 17:05:21 +03:00
$searchExpr = $this -> querySearchHelper -> searchOperatorToDBExpr ( $builder , $searchQuery -> getSearchOperation ());
if ( $searchExpr ) {
$query -> andWhere ( $searchExpr );
}
2017-02-02 20:20:08 +03:00
2019-12-06 13:29:14 +03:00
if ( $searchQuery -> limitToHome () && ( $this instanceof HomeCache )) {
$query -> andWhere ( $builder -> expr () -> like ( 'path' , $query -> expr () -> literal ( 'files/%' )));
}
2017-03-15 16:46:23 +03:00
$this -> querySearchHelper -> addSearchOrdersToQuery ( $query , $searchQuery -> getOrder ());
2017-02-02 20:20:08 +03:00
if ( $searchQuery -> getLimit ()) {
$query -> setMaxResults ( $searchQuery -> getLimit ());
}
if ( $searchQuery -> getOffset ()) {
$query -> setFirstResult ( $searchQuery -> getOffset ());
}
$result = $query -> execute ();
return $this -> searchResultToCacheEntries ( $result );
2012-10-27 12:34:25 +04:00
}
2012-11-08 21:10:54 +04:00
/**
2015-05-05 17:06:28 +03:00
* Re - calculate the folder size and the size of all parent folders
2012-11-08 21:10:54 +04:00
*
2014-02-06 19:30:58 +04:00
* @ param string | boolean $path
2014-02-28 17:23:07 +04:00
* @ param array $data ( optional ) meta data of the folder
2012-11-08 21:10:54 +04:00
*/
2019-03-02 01:52:58 +03:00
public function correctFolderSize ( $path , $data = null , $isBackgroundScan = false ) {
2014-02-28 17:23:07 +04:00
$this -> calculateFolderSize ( $path , $data );
2012-11-08 21:10:54 +04:00
if ( $path !== '' ) {
$parent = dirname ( $path );
2013-04-29 17:43:48 +04:00
if ( $parent === '.' or $parent === '/' ) {
2012-11-08 21:10:54 +04:00
$parent = '' ;
}
2019-03-02 01:52:58 +03:00
if ( $isBackgroundScan ) {
$parentData = $this -> get ( $parent );
if ( $parentData [ 'size' ] !== - 1 && $this -> getIncompleteChildrenCount ( $parentData [ 'fileid' ]) === 0 ) {
$this -> correctFolderSize ( $parent , $parentData , $isBackgroundScan );
}
} else {
$this -> correctFolderSize ( $parent );
}
}
}
/**
* get the incomplete count that shares parent $folder
*
* @ param int $fileId the file id of the folder
* @ return int
*/
public function getIncompleteChildrenCount ( $fileId ) {
if ( $fileId > - 1 ) {
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> select ( $query -> func () -> count ())
-> from ( 'filecache' )
-> whereParent ( $fileId )
-> andWhere ( $query -> expr () -> lt ( 'size' , $query -> createNamedParameter ( 0 , IQueryBuilder :: PARAM_INT )));
return ( int ) $query -> execute () -> fetchColumn ();
2012-11-08 21:10:54 +04:00
}
2019-03-02 01:52:58 +03:00
return - 1 ;
2012-11-08 21:10:54 +04:00
}
2012-10-27 19:02:05 +04:00
/**
2015-05-05 17:06:28 +03:00
* calculate the size of a folder and set it in the cache
2012-10-27 19:02:05 +04:00
*
* @ param string $path
2014-02-28 17:23:07 +04:00
* @ param array $entry ( optional ) meta data of the folder
2012-10-27 19:02:05 +04:00
* @ return int
*/
2014-02-28 17:23:07 +04:00
public function calculateFolderSize ( $path , $entry = null ) {
2012-10-27 19:02:05 +04:00
$totalSize = 0 ;
2014-03-03 19:48:28 +04:00
if ( is_null ( $entry ) or ! isset ( $entry [ 'fileid' ])) {
2014-02-28 17:23:07 +04:00
$entry = $this -> get ( $path );
}
2019-10-25 17:55:53 +03:00
if ( isset ( $entry [ 'mimetype' ]) && $entry [ 'mimetype' ] === FileInfo :: MIMETYPE_FOLDER ) {
2013-07-29 00:14:49 +04:00
$id = $entry [ 'fileid' ];
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> selectAlias ( $query -> func () -> sum ( 'size' ), 'f1' )
-> selectAlias ( $query -> func () -> min ( 'size' ), 'f2' )
-> from ( 'filecache' )
-> whereStorageId ()
-> whereParent ( $id );
if ( $row = $query -> execute () -> fetch ()) {
2020-02-28 19:36:38 +03:00
[ $sum , $min ] = array_values ( $row );
2014-02-16 03:50:03 +04:00
$sum = 0 + $sum ;
$min = 0 + $min ;
2013-07-29 18:22:44 +04:00
if ( $min === - 1 ) {
$totalSize = $min ;
2013-07-29 00:14:49 +04:00
} else {
2013-07-29 18:22:44 +04:00
$totalSize = $sum ;
2013-07-29 00:14:49 +04:00
}
2013-07-29 18:22:44 +04:00
if ( $entry [ 'size' ] !== $totalSize ) {
2019-10-25 17:55:53 +03:00
$this -> update ( $id , [ 'size' => $totalSize ]);
2014-01-09 20:27:55 +04:00
}
2012-10-27 19:02:05 +04:00
}
}
return $totalSize ;
}
2012-10-27 12:01:20 +04:00
/**
* get all file ids on the files on the storage
*
* @ return int []
*/
public function getAll () {
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> select ( 'fileid' )
-> from ( 'filecache' )
-> whereStorageId ();
return array_map ( function ( $id ) {
return ( int ) $id ;
}, $query -> execute () -> fetchAll ( \PDO :: FETCH_COLUMN ));
2012-10-27 12:01:20 +04:00
}
2012-11-22 02:02:43 +04:00
/**
* find a folder in the cache which has not been fully scanned
*
2014-11-10 18:00:08 +03:00
* If multiple incomplete folders are in the cache , the one with the highest id will be returned ,
2012-11-22 02:02:43 +04:00
* use the one with the highest id gives the best result with the background scanner , since that is most
* likely the folder where we stopped scanning previously
*
* @ return string | bool the path of the folder or false when no folder matched
*/
2012-11-23 03:17:18 +04:00
public function getIncomplete () {
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> select ( 'path' )
-> from ( 'filecache' )
-> whereStorageId ()
-> andWhere ( $query -> expr () -> lt ( 'size' , $query -> createNamedParameter ( 0 , IQueryBuilder :: PARAM_INT )))
-> orderBy ( 'fileid' , 'DESC' );
return $query -> execute () -> fetchColumn ();
2012-11-22 02:02:43 +04:00
}
2013-01-27 02:59:29 +04:00
2014-03-27 19:43:34 +04:00
/**
2015-05-05 17:06:28 +03:00
* get the path of a file on this storage by it ' s file id
2014-03-27 19:43:34 +04:00
*
2015-05-05 17:06:28 +03:00
* @ param int $id the file id of the file or folder to search
* @ return string | null the path of the file ( relative to the storage ) or null if a file with the given id does not exists within this cache
2014-03-27 19:43:34 +04:00
*/
public function getPathById ( $id ) {
2019-10-25 17:55:53 +03:00
$query = $this -> getQueryBuilder ();
$query -> select ( 'path' )
-> from ( 'filecache' )
-> whereStorageId ()
-> whereFileId ( $id );
$path = $query -> execute () -> fetchColumn ();
return $path === false ? null : $path ;
2014-03-27 19:43:34 +04:00
}
2013-01-27 02:59:29 +04:00
/**
* get the storage id of the storage for a file and the internal path of the file
2014-03-31 16:29:55 +04:00
* unlike getPathById this does not limit the search to files on this storage and
* instead does a global search in the cache table
2013-01-27 02:59:29 +04:00
*
2013-04-26 02:00:18 +04:00
* @ param int $id
2015-01-16 21:31:15 +03:00
* @ return array first element holding the storage id , second the path
2019-10-25 17:55:53 +03:00
* @ deprecated use getPathById () instead
2013-01-27 02:59:29 +04:00
*/
2020-04-10 17:51:06 +03:00
public static function getById ( $id ) {
2019-10-25 17:55:53 +03:00
$query = \OC :: $server -> getDatabaseConnection () -> getQueryBuilder ();
$query -> select ( 'path' , 'storage' )
-> from ( 'filecache' )
-> where ( $query -> expr () -> eq ( 'fileid' , $query -> createNamedParameter ( $id , IQueryBuilder :: PARAM_INT )));
if ( $row = $query -> execute () -> fetch ()) {
2013-01-27 02:59:29 +04:00
$numericId = $row [ 'storage' ];
$path = $row [ 'path' ];
} else {
return null ;
}
2013-04-26 02:00:18 +04:00
if ( $id = Storage :: getStorageId ( $numericId )) {
2019-10-25 17:55:53 +03:00
return [ $id , $path ];
2013-01-27 02:59:29 +04:00
} else {
return null ;
}
}
2013-05-23 22:29:46 +04:00
/**
* normalize the given path
2015-01-15 19:26:12 +03:00
*
2014-05-12 00:51:30 +04:00
* @ param string $path
2013-05-23 22:29:46 +04:00
* @ return string
*/
public function normalize ( $path ) {
2015-01-08 21:43:02 +03:00
return trim ( \OC_Util :: normalizeUnicode ( $path ), '/' );
2013-05-23 22:29:46 +04:00
}
2021-03-08 20:49:08 +03:00
/**
* Copy a file or folder in the cache
*
* @ param ICache $sourceCache
* @ param ICacheEntry $sourceEntry
* @ param string $targetPath
* @ return int fileid of copied entry
*/
public function copyFromCache ( ICache $sourceCache , ICacheEntry $sourceEntry , string $targetPath ) : int {
$data = $this -> cacheEntryToArray ( $sourceEntry );
$fileId = $this -> put ( $targetPath , $data );
if ( $fileId <= 0 ) {
throw new \RuntimeException ( " Failed to copy to " . $targetPath . " from cache with source data " . json_encode ( $data ) . " " );
}
if ( $sourceEntry -> getMimeType () === ICacheEntry :: DIRECTORY_MIMETYPE ) {
$folderContent = $sourceCache -> getFolderContentsById ( $sourceEntry -> getId ());
foreach ( $folderContent as $subEntry ) {
$subTargetPath = $targetPath . '/' . $subEntry -> getName ();
$this -> copyFromCache ( $sourceCache , $subEntry , $subTargetPath );
}
}
return $fileId ;
}
private function cacheEntryToArray ( ICacheEntry $entry ) : array {
return [
'size' => $entry -> getSize (),
'mtime' => $entry -> getMTime (),
'storage_mtime' => $entry -> getStorageMTime (),
'mimetype' => $entry -> getMimeType (),
'mimepart' => $entry -> getMimePart (),
'etag' => $entry -> getEtag (),
'permissions' => $entry -> getPermissions (),
'encrypted' => $entry -> isEncrypted (),
'creation_time' => $entry -> getCreationTime (),
'upload_time' => $entry -> getUploadTime (),
'metadata_etag' => $entry -> getMetadataEtag (),
];
}
2019-05-07 15:53:02 +03:00
}