2012-09-16 14:52:32 +00:00
< ? php
/**
2015-03-26 10:44:34 +00:00
* @ author Andreas Fischer < bantu @ owncloud . com >
* @ author Bart Visscher < bartv @ thisnet . nl >
* @ author Björn Schießle < schiessle @ owncloud . com >
* @ author Florin Peter < github @ florin - peter . de >
* @ author Joas Schilling < nickvergessen @ owncloud . com >
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
* @ author Michael Gapczynski < GapczynskiM @ gmail . com >
* @ author Morris Jobke < hey @ morrisjobke . de >
* @ author Robin Appelman < icewind @ owncloud . com >
* @ author Robin McCorkell < rmccorkell @ karoshi . org . uk >
* @ author TheSFReader < TheSFReader @ gmail . com >
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
* @ author Victor Dubiniuk < dubiniuk @ owncloud . com >
* @ 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 />
*
2012-09-16 14:52:32 +00:00
*/
2015-02-26 10:37:37 +00:00
2012-09-16 14:52:32 +00:00
namespace OC\Files\Cache ;
2012-10-26 10:30:25 +00:00
/**
* Metadata cache for the filesystem
*
* don ' t use this class directly if you need to get metadata , use \OC\Files\Filesystem :: getFileInfo instead
*/
2012-09-16 14:52:32 +00:00
class Cache {
2012-10-08 12:58:21 +00:00
const NOT_FOUND = 0 ;
const PARTIAL = 1 ; //only partial data available, file not cached in the database
const SHALLOW = 2 ; //folder in cache, but not all child files are completely scanned
const COMPLETE = 3 ;
2012-09-16 14:52:32 +00:00
/**
* @ var array partial data for the cache
*/
2014-04-29 13:14:48 +00:00
protected $partial = array ();
2012-09-26 15:52:02 +00:00
2012-11-08 16:59:08 +00:00
/**
* @ var string
*/
2014-04-29 13:14:48 +00:00
protected $storageId ;
2012-09-26 15:52:02 +00:00
2012-12-15 22:28:07 +00:00
/**
2013-04-25 22:00:18 +00:00
* @ var Storage $storageCache
2012-12-15 22:28:07 +00:00
*/
2014-04-29 13:14:48 +00:00
protected $storageCache ;
2012-12-15 22:28:07 +00:00
2014-04-29 13:14:48 +00:00
protected static $mimetypeIds = array ();
protected static $mimetypes = array ();
2013-01-07 00:40:09 +00:00
2012-09-26 15:52:02 +00:00
/**
2012-11-08 16:59:08 +00:00
* @ param \OC\Files\Storage\Storage | string $storage
2012-09-26 15:52:02 +00:00
*/
2012-11-08 16:59:08 +00:00
public function __construct ( $storage ) {
2012-11-22 23:17:18 +00:00
if ( $storage instanceof \OC\Files\Storage\Storage ) {
2012-11-08 16:59:08 +00:00
$this -> storageId = $storage -> getId ();
2012-11-22 23:17:18 +00:00
} else {
2012-11-08 16:59:08 +00:00
$this -> storageId = $storage ;
}
2013-02-15 20:49:40 +00:00
if ( strlen ( $this -> storageId ) > 64 ) {
$this -> storageId = md5 ( $this -> storageId );
}
2012-12-15 22:28:07 +00:00
2013-04-25 22:00:18 +00:00
$this -> storageCache = new Storage ( $storage );
2012-12-15 22:28:07 +00:00
}
public function getNumericStorageId () {
2013-04-25 22:00:18 +00:00
return $this -> storageCache -> getNumericId ();
2012-09-26 15:52:02 +00:00
}
2012-09-16 14:52:32 +00:00
2013-01-07 00:40:09 +00:00
/**
* normalize mimetypes
*
* @ param string $mime
* @ return int
*/
public function getMimetypeId ( $mime ) {
2013-10-29 13:18:42 +00:00
if ( empty ( $mime )) {
// Can not insert empty string into Oracle NOT NULL column.
$mime = 'application/octet-stream' ;
}
2013-10-04 15:09:42 +00:00
if ( empty ( self :: $mimetypeIds )) {
2013-10-04 13:17:19 +00:00
$this -> loadMimetypes ();
}
2014-10-30 09:51:25 +00:00
2013-10-04 15:09:42 +00:00
if ( ! isset ( self :: $mimetypeIds [ $mime ])) {
2015-01-15 16:26:12 +00:00
try {
2015-01-29 14:24:53 +00:00
$connection = \OC_DB :: getConnection ();
$connection -> insertIfNotExist ( '*PREFIX*mimetypes' , [
'mimetype' => $mime ,
]);
$this -> loadMimetypes ();
2015-01-15 16:26:12 +00:00
} catch ( \Doctrine\DBAL\DBALException $e ) {
2013-10-21 12:48:08 +00:00
\OC_Log :: write ( 'core' , 'Exception during mimetype insertion: ' . $e -> getmessage (), \OC_Log :: DEBUG );
return - 1 ;
}
2014-10-30 09:51:25 +00:00
}
2013-10-04 15:09:42 +00:00
return self :: $mimetypeIds [ $mime ];
2013-01-07 00:40:09 +00:00
}
public function getMimetype ( $id ) {
2013-10-04 15:09:42 +00:00
if ( empty ( self :: $mimetypes )) {
2013-10-04 13:17:19 +00:00
$this -> loadMimetypes ();
2013-01-07 00:40:09 +00:00
}
2013-10-04 13:17:19 +00:00
2013-10-04 15:09:42 +00:00
return isset ( self :: $mimetypes [ $id ]) ? self :: $mimetypes [ $id ] : null ;
2013-10-04 13:17:19 +00:00
}
2013-10-21 12:48:08 +00:00
2015-01-15 16:26:12 +00:00
public function loadMimetypes () {
2015-01-29 14:24:53 +00:00
self :: $mimetypeIds = self :: $mimetypes = array ();
2015-01-15 16:26:12 +00:00
$result = \OC_DB :: executeAudited ( 'SELECT `id`, `mimetype` FROM `*PREFIX*mimetypes`' , array ());
if ( $result ) {
while ( $row = $result -> fetchRow ()) {
self :: $mimetypeIds [ $row [ 'mimetype' ]] = $row [ 'id' ];
self :: $mimetypes [ $row [ 'id' ]] = $row [ 'mimetype' ];
2013-10-04 13:17:19 +00:00
}
2015-01-15 16:26:12 +00:00
}
2013-01-07 00:40:09 +00:00
}
2012-09-16 14:52:32 +00:00
/**
* get the stored metadata of a file or folder
*
2015-01-15 16:26:12 +00:00
* @ param string / int $file
2014-05-11 17:28:45 +00:00
* @ return array | false
2012-09-16 14:52:32 +00:00
*/
2012-09-26 15:52:02 +00:00
public function get ( $file ) {
2012-11-25 15:30:57 +00:00
if ( is_string ( $file ) or $file == '' ) {
2013-05-23 18:29:46 +00:00
// normalize file
$file = $this -> normalize ( $file );
2012-09-16 14:52:32 +00:00
$where = 'WHERE `storage` = ? AND `path_hash` = ?' ;
2013-04-25 22:00:18 +00:00
$params = array ( $this -> getNumericStorageId (), md5 ( $file ));
2012-09-16 14:52:32 +00:00
} else { //file id
$where = 'WHERE `fileid` = ?' ;
$params = array ( $file );
}
2013-06-07 12:11:05 +00:00
$sql = ' SELECT `fileid` , `storage` , `path` , `parent` , `name` , `mimetype` , `mimepart` , `size` , `mtime` ,
2015-03-30 15:29:05 +00:00
`storage_mtime` , `encrypted` , `etag` , `permissions`
2013-06-07 12:11:05 +00:00
FROM `*PREFIX*filecache` ' . $where ;
$result = \OC_DB :: executeAudited ( $sql , $params );
2012-09-22 13:43:48 +00:00
$data = $result -> fetchRow ();
2012-09-22 12:40:04 +00:00
2013-06-10 09:07:41 +00:00
//FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO
//PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false
if ( $data === null ) {
$data = false ;
}
2012-09-22 12:40:04 +00:00
//merge partial data
2015-01-15 16:26:12 +00:00
if ( ! $data and is_string ( $file )) {
2012-09-26 15:52:02 +00:00
if ( isset ( $this -> partial [ $file ])) {
$data = $this -> partial [ $file ];
2012-09-22 13:43:48 +00:00
}
2012-09-26 15:52:02 +00:00
} else {
//fix types
$data [ 'fileid' ] = ( int ) $data [ 'fileid' ];
2014-02-15 23:50:03 +00:00
$data [ 'size' ] = 0 + $data [ 'size' ];
2012-09-26 15:52:02 +00:00
$data [ 'mtime' ] = ( int ) $data [ 'mtime' ];
2013-10-25 10:39:50 +00:00
$data [ 'storage_mtime' ] = ( int ) $data [ 'storage_mtime' ];
2012-10-02 21:34:45 +00:00
$data [ 'encrypted' ] = ( bool ) $data [ 'encrypted' ];
2013-01-21 21:01:22 +00:00
$data [ 'storage' ] = $this -> storageId ;
2013-01-07 00:40:09 +00:00
$data [ 'mimetype' ] = $this -> getMimetype ( $data [ 'mimetype' ]);
$data [ 'mimepart' ] = $this -> getMimetype ( $data [ 'mimepart' ]);
2013-02-10 11:27:35 +00:00
if ( $data [ 'storage_mtime' ] == 0 ) {
$data [ 'storage_mtime' ] = $data [ 'mtime' ];
}
2014-06-03 15:57:56 +00:00
$data [ 'permissions' ] = ( int ) $data [ 'permissions' ];
2012-09-22 12:40:04 +00:00
}
2012-09-26 15:52:02 +00:00
2012-09-22 13:43:48 +00:00
return $data ;
2012-09-16 14:52:32 +00:00
}
2012-09-23 13:25:03 +00:00
/**
* get the metadata of all files stored in $folder
*
2012-09-26 15:52:02 +00:00
* @ param string $folder
2012-09-23 13:25:03 +00:00
* @ return array
*/
2014-02-21 14:36:24 +00:00
public function getFolderContents ( $folder ) {
$fileId = $this -> getId ( $folder );
2014-02-21 14:35:12 +00:00
return $this -> getFolderContentsById ( $fileId );
}
/**
* get the metadata of all files stored in $folder
*
* @ param int $fileId the file id of the folder
* @ return array
*/
public function getFolderContentsById ( $fileId ) {
2012-09-23 13:25:03 +00:00
if ( $fileId > - 1 ) {
2013-06-07 12:11:05 +00:00
$sql = ' SELECT `fileid` , `storage` , `path` , `parent` , `name` , `mimetype` , `mimepart` , `size` , `mtime` ,
2015-03-30 15:29:05 +00:00
`storage_mtime` , `encrypted` , `etag` , `permissions`
2013-06-07 12:11:05 +00:00
FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC ' ;
2015-01-15 16:26:12 +00:00
$result = \OC_DB :: executeAudited ( $sql , array ( $fileId ));
2013-01-07 00:40:09 +00:00
$files = $result -> fetchAll ();
foreach ( $files as & $file ) {
$file [ 'mimetype' ] = $this -> getMimetype ( $file [ 'mimetype' ]);
$file [ 'mimepart' ] = $this -> getMimetype ( $file [ 'mimepart' ]);
2013-02-10 11:27:35 +00:00
if ( $file [ 'storage_mtime' ] == 0 ) {
$file [ 'storage_mtime' ] = $file [ 'mtime' ];
}
2014-06-03 15:57:56 +00:00
$file [ 'permissions' ] = ( int ) $file [ 'permissions' ];
2014-09-10 14:49:58 +00:00
$file [ 'mtime' ] = ( int ) $file [ 'mtime' ];
$file [ 'storage_mtime' ] = ( int ) $file [ 'storage_mtime' ];
$file [ 'size' ] = 0 + $file [ 'size' ];
2013-01-07 00:40:09 +00:00
}
return $files ;
2012-09-23 13:25:03 +00:00
} else {
return array ();
}
}
2012-09-16 14:52:32 +00:00
/**
* store meta data for a file or folder
*
2012-09-26 15:52:02 +00:00
* @ param string $file
2012-09-16 14:52:32 +00:00
* @ param array $data
*
* @ return int file id
2015-03-11 08:33:50 +00:00
* @ throws \RuntimeException
2012-09-16 14:52:32 +00:00
*/
2012-09-26 15:52:02 +00:00
public function put ( $file , array $data ) {
if (( $id = $this -> getId ( $file )) > - 1 ) {
$this -> update ( $id , $data );
2012-09-16 14:52:32 +00:00
return $id ;
} else {
2013-05-23 18:29:46 +00:00
// normalize file
$file = $this -> normalize ( $file );
2012-09-26 15:52:02 +00:00
if ( isset ( $this -> partial [ $file ])) { //add any saved partial data
$data = array_merge ( $this -> partial [ $file ], $data );
unset ( $this -> partial [ $file ]);
2012-09-16 14:52:32 +00:00
}
$requiredFields = array ( 'size' , 'mtime' , 'mimetype' );
foreach ( $requiredFields as $field ) {
if ( ! isset ( $data [ $field ])) { //data not complete save as partial and return
2012-09-26 15:52:02 +00:00
$this -> partial [ $file ] = $data ;
2012-09-16 14:52:32 +00:00
return - 1 ;
}
}
2012-09-26 15:52:02 +00:00
$data [ 'path' ] = $file ;
$data [ 'parent' ] = $this -> getParentId ( $file );
2013-07-29 16:24:05 +00:00
$data [ 'name' ] = \OC_Util :: basename ( $file );
2012-09-16 14:52:32 +00:00
2012-09-26 15:52:02 +00:00
list ( $queryParts , $params ) = $this -> buildParts ( $data );
2012-09-16 14:52:32 +00:00
$queryParts [] = '`storage`' ;
2013-04-25 22:00:18 +00:00
$params [] = $this -> getNumericStorageId ();
2012-09-16 14:52:32 +00:00
2015-03-06 14:32:58 +00:00
$queryParts = array_map ( function ( $item ) {
return trim ( $item , " ` " );
}, $queryParts );
$values = array_combine ( $queryParts , $params );
2015-03-09 17:20:51 +00:00
if ( \OC :: $server -> getDatabaseConnection () -> insertIfNotExist ( '*PREFIX*filecache' , $values , [
'storage' ,
'path_hash' ,
])) {
2015-03-06 14:32:58 +00:00
return ( int ) \OC_DB :: insertid ( '*PREFIX*filecache' );
}
2012-09-16 14:52:32 +00:00
2015-03-09 17:20:51 +00:00
// The file was created in the mean time
2015-03-11 08:33:50 +00:00
if (( $id = $this -> getId ( $file )) > - 1 ) {
$this -> update ( $id , $data );
return $id ;
} else {
2015-04-02 16:37:33 +00:00
throw new \RuntimeException ( 'File entry could not be inserted with insertIfNotExist() but could also not be selected with getId() in order to perform an update. Please try again.' );
2015-03-11 08:33:50 +00:00
}
2012-09-16 14:52:32 +00:00
}
}
/**
* update the metadata in the cache
*
* @ param int $id
* @ param array $data
*/
2012-09-26 15:52:02 +00:00
public function update ( $id , array $data ) {
2013-05-25 18:35:12 +00:00
2015-01-15 16:26:12 +00:00
if ( isset ( $data [ 'path' ])) {
2013-05-25 18:35:12 +00:00
// normalize path
$data [ 'path' ] = $this -> normalize ( $data [ 'path' ]);
}
2015-01-15 16:26:12 +00:00
if ( isset ( $data [ 'name' ])) {
2013-05-25 18:35:12 +00:00
// normalize path
$data [ 'name' ] = $this -> normalize ( $data [ 'name' ]);
}
2012-09-26 15:52:02 +00:00
list ( $queryParts , $params ) = $this -> buildParts ( $data );
2012-09-16 14:52:32 +00:00
$params [] = $id ;
2013-06-07 12:11:05 +00:00
$sql = 'UPDATE `*PREFIX*filecache` SET ' . implode ( ' = ?, ' , $queryParts ) . '=? WHERE `fileid` = ?' ;
2013-06-12 21:01:52 +00:00
\OC_DB :: executeAudited ( $sql , $params );
2012-09-16 14:52:32 +00:00
}
/**
* extract query parts and params array from data array
*
* @ param array $data
* @ return array
*/
2013-01-07 00:40:09 +00:00
function buildParts ( array $data ) {
2014-06-03 15:57:56 +00:00
$fields = array (
2015-03-30 15:29:05 +00:00
'path' , 'parent' , 'name' , 'mimetype' , 'size' , 'mtime' , 'storage_mtime' , 'encrypted' ,
2014-06-03 15:57:56 +00:00
'etag' , 'permissions' );
2012-09-16 14:52:32 +00:00
$params = array ();
$queryParts = array ();
foreach ( $data as $name => $value ) {
if ( array_search ( $name , $fields ) !== false ) {
if ( $name === 'path' ) {
$params [] = md5 ( $value );
$queryParts [] = '`path_hash`' ;
} elseif ( $name === 'mimetype' ) {
2013-01-07 00:40:09 +00:00
$params [] = $this -> getMimetypeId ( substr ( $value , 0 , strpos ( $value , '/' )));
2012-09-16 14:52:32 +00:00
$queryParts [] = '`mimepart`' ;
2013-01-07 00:40:09 +00:00
$value = $this -> getMimetypeId ( $value );
2013-02-10 11:27:35 +00:00
} elseif ( $name === 'storage_mtime' ) {
if ( ! isset ( $data [ 'mtime' ])) {
$params [] = $value ;
$queryParts [] = '`mtime`' ;
}
2013-09-21 00:20:01 +00:00
} elseif ( $name === 'encrypted' ) {
// Boolean to integer conversion
$value = $value ? 1 : 0 ;
2012-09-16 14:52:32 +00:00
}
2013-01-07 00:40:09 +00:00
$params [] = $value ;
$queryParts [] = '`' . $name . '`' ;
2012-09-16 14:52:32 +00:00
}
}
return array ( $queryParts , $params );
}
/**
* get the file id for a file
*
2012-09-26 15:52:02 +00:00
* @ param string $file
2012-09-16 14:52:32 +00:00
* @ return int
*/
2012-09-26 15:52:02 +00:00
public function getId ( $file ) {
2013-05-23 18:29:46 +00:00
// normalize file
$file = $this -> normalize ( $file );
2012-09-26 15:52:02 +00:00
$pathHash = md5 ( $file );
2012-09-16 14:52:32 +00:00
2013-06-07 12:11:05 +00:00
$sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?' ;
$result = \OC_DB :: executeAudited ( $sql , array ( $this -> getNumericStorageId (), $pathHash ));
2012-09-16 14:52:32 +00:00
if ( $row = $result -> fetchRow ()) {
2012-09-22 13:43:48 +00:00
return $row [ 'fileid' ];
2012-09-16 14:52:32 +00:00
} else {
return - 1 ;
}
}
/**
* get the id of the parent folder of a file
*
2012-09-26 15:52:02 +00:00
* @ param string $file
2012-09-22 13:48:39 +00:00
* @ return int
2012-09-16 14:52:32 +00:00
*/
2012-09-26 15:52:02 +00:00
public function getParentId ( $file ) {
2012-10-03 09:23:33 +00:00
if ( $file === '' ) {
2012-09-16 14:52:32 +00:00
return - 1 ;
} else {
2012-10-03 09:23:33 +00:00
$parent = dirname ( $file );
if ( $parent === '.' ) {
$parent = '' ;
}
return $this -> getId ( $parent );
2012-09-16 14:52:32 +00:00
}
}
/**
* check if a file is available in the cache
*
2012-09-26 15:52:02 +00:00
* @ param string $file
2012-09-16 14:52:32 +00:00
* @ return bool
*/
2012-09-26 15:52:02 +00:00
public function inCache ( $file ) {
return $this -> getId ( $file ) != - 1 ;
2012-09-16 14:52:32 +00:00
}
/**
* remove a file or folder from the cache
*
2012-09-26 15:52:02 +00:00
* @ param string $file
2012-09-16 14:52:32 +00:00
*/
2012-09-26 15:52:02 +00:00
public function remove ( $file ) {
2012-10-27 16:05:40 +00:00
$entry = $this -> get ( $file );
2015-01-15 16:26:12 +00:00
$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?' ;
\OC_DB :: executeAudited ( $sql , array ( $entry [ 'fileid' ]));
2012-10-27 16:05:40 +00:00
if ( $entry [ 'mimetype' ] === 'httpd/unix-directory' ) {
2015-01-15 16:26:12 +00:00
$this -> removeChildren ( $entry );
2012-10-27 16:05:40 +00:00
}
2015-01-15 16:26:12 +00:00
}
2014-10-30 09:51:25 +00:00
2015-01-15 16:26:12 +00:00
private function getSubFolders ( $entry ) {
$children = $this -> getFolderContentsById ( $entry [ 'fileid' ]);
return array_filter ( $children , function ( $child ) {
return $child [ 'mimetype' ] === 'httpd/unix-directory' ;
});
}
private function removeChildren ( $entry ) {
$subFolders = $this -> getSubFolders ( $entry );
foreach ( $subFolders as $folder ) {
$this -> removeChildren ( $folder );
}
$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `parent` = ?' ;
2013-06-07 12:11:05 +00:00
\OC_DB :: executeAudited ( $sql , array ( $entry [ 'fileid' ]));
2012-09-16 14:52:32 +00:00
}
2012-11-02 21:25:33 +00:00
/**
* Move a file or folder in the cache
*
* @ param string $source
* @ param string $target
*/
public function move ( $source , $target ) {
2013-05-25 12:56:00 +00:00
// normalize source and target
$source = $this -> normalize ( $source );
$target = $this -> normalize ( $target );
2013-04-19 13:03:59 +00:00
$sourceData = $this -> get ( $source );
$sourceId = $sourceData [ 'fileid' ];
2012-11-02 21:25:33 +00:00
$newParentId = $this -> getParentId ( $target );
2013-04-19 13:03:59 +00:00
if ( $sourceData [ 'mimetype' ] === 'httpd/unix-directory' ) {
//find all child entries
2013-06-07 12:11:05 +00:00
$sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?' ;
$result = \OC_DB :: executeAudited ( $sql , array ( $this -> getNumericStorageId (), $source . '/%' ));
2013-04-19 13:03:59 +00:00
$childEntries = $result -> fetchAll ();
$sourceLength = strlen ( $source );
2015-02-06 14:20:53 +00:00
\OC_DB :: beginTransaction ();
2013-04-19 13:03:59 +00:00
$query = \OC_DB :: prepare ( 'UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?' );
foreach ( $childEntries as $child ) {
$targetPath = $target . substr ( $child [ 'path' ], $sourceLength );
2013-06-07 12:11:05 +00:00
\OC_DB :: executeAudited ( $query , array ( $targetPath , md5 ( $targetPath ), $child [ 'fileid' ]));
2013-04-19 13:03:59 +00:00
}
2015-02-06 14:20:53 +00:00
\OC_DB :: commit ();
2012-11-02 21:25:33 +00:00
}
2013-06-07 12:11:05 +00:00
$sql = 'UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?' ;
\OC_DB :: executeAudited ( $sql , array ( $target , md5 ( $target ), basename ( $target ), $newParentId , $sourceId ));
2012-11-02 21:25:33 +00:00
}
2015-04-01 13:12:59 +00:00
/**
* Move a file or folder in the cache
*
* @ param \OC\Files\Cache\Cache $sourceCache
* @ param string $sourcePath
* @ param string $targetPath
* @ throws \OC\DatabaseException
*/
public function moveFromCache ( Cache $sourceCache , $sourcePath , $targetPath ) {
// normalize source and target
$sourcePath = $this -> normalize ( $sourcePath );
$targetPath = $this -> normalize ( $targetPath );
$sourceData = $sourceCache -> get ( $sourcePath );
$sourceId = $sourceData [ 'fileid' ];
$newParentId = $this -> getParentId ( $targetPath );
if ( $sourceData [ 'mimetype' ] === 'httpd/unix-directory' ) {
//find all child entries
$sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?' ;
$result = \OC_DB :: executeAudited ( $sql , [ $sourceCache -> getNumericStorageId (), $sourcePath . '/%' ]);
$childEntries = $result -> fetchAll ();
$sourceLength = strlen ( $sourcePath );
\OC_DB :: beginTransaction ();
$query = \OC_DB :: prepare ( 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?' );
foreach ( $childEntries as $child ) {
$newTargetPath = $targetPath . substr ( $child [ 'path' ], $sourceLength );
\OC_DB :: executeAudited ( $query , [ $this -> getNumericStorageId (), $newTargetPath , md5 ( $newTargetPath ), $child [ 'fileid' ]]);
}
\OC_DB :: commit ();
}
$sql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?' ;
\OC_DB :: executeAudited ( $sql , [ $this -> getNumericStorageId (), $targetPath , md5 ( $targetPath ), basename ( $targetPath ), $newParentId , $sourceId ]);
}
2012-09-16 14:52:32 +00:00
/**
2012-09-26 15:52:02 +00:00
* remove all entries for files that are stored on the storage from the cache
2012-09-16 14:52:32 +00:00
*/
2012-09-26 15:52:02 +00:00
public function clear () {
2013-06-07 12:11:05 +00:00
$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?' ;
\OC_DB :: executeAudited ( $sql , array ( $this -> getNumericStorageId ()));
2012-12-15 22:28:07 +00:00
2013-06-07 12:11:05 +00:00
$sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?' ;
\OC_DB :: executeAudited ( $sql , array ( $this -> storageId ));
2012-09-16 14:52:32 +00:00
}
2012-10-08 12:58:21 +00:00
/**
* @ param string $file
*
2015-01-16 18:31:15 +00:00
* @ return int Cache :: NOT_FOUND , Cache :: PARTIAL , Cache :: SHALLOW or Cache :: COMPLETE
2012-10-08 12:58:21 +00:00
*/
public function getStatus ( $file ) {
2013-05-25 12:56:00 +00:00
// normalize file
$file = $this -> normalize ( $file );
2012-10-08 12:58:21 +00:00
$pathHash = md5 ( $file );
2013-06-07 12:11:05 +00:00
$sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?' ;
$result = \OC_DB :: executeAudited ( $sql , array ( $this -> getNumericStorageId (), $pathHash ));
2012-10-08 12:58:21 +00:00
if ( $row = $result -> fetchRow ()) {
if (( int ) $row [ 'size' ] === - 1 ) {
return self :: SHALLOW ;
} else {
return self :: COMPLETE ;
}
} else {
if ( isset ( $this -> partial [ $file ])) {
return self :: PARTIAL ;
} else {
return self :: NOT_FOUND ;
}
}
}
2012-10-26 11:23:15 +00:00
/**
* search for files matching $pattern
*
* @ param string $pattern
2014-05-11 17:13:51 +00:00
* @ return array an array of file data
2012-10-26 11:23:15 +00:00
*/
public function search ( $pattern ) {
2013-05-25 18:35:12 +00:00
// normalize pattern
$pattern = $this -> normalize ( $pattern );
2014-07-03 17:01:00 +00:00
$sql = '
SELECT `fileid` , `storage` , `path` , `parent` , `name` ,
`mimetype` , `mimepart` , `size` , `mtime` , `encrypted` ,
2015-03-30 15:29:05 +00:00
`etag` , `permissions`
2014-07-03 17:01:00 +00:00
FROM `*PREFIX*filecache`
2014-09-17 14:12:54 +00:00
WHERE `storage` = ? AND `name` ILIKE ? ' ;
2014-07-03 17:01:00 +00:00
$result = \OC_DB :: executeAudited ( $sql ,
array ( $this -> getNumericStorageId (), $pattern )
);
2012-10-26 11:23:15 +00:00
$files = array ();
while ( $row = $result -> fetchRow ()) {
2013-01-07 00:40:09 +00:00
$row [ 'mimetype' ] = $this -> getMimetype ( $row [ 'mimetype' ]);
$row [ 'mimepart' ] = $this -> getMimetype ( $row [ 'mimepart' ]);
2012-10-26 11:23:15 +00:00
$files [] = $row ;
}
return $files ;
}
2012-10-27 08:01:20 +00:00
2012-10-27 08:34:25 +00:00
/**
* search for files by mimetype
*
2012-11-02 21:25:33 +00:00
* @ param string $mimetype
2012-10-27 08:34:25 +00:00
* @ return array
*/
public function searchByMime ( $mimetype ) {
if ( strpos ( $mimetype , '/' )) {
$where = '`mimetype` = ?' ;
} else {
$where = '`mimepart` = ?' ;
}
2015-03-30 15:29:05 +00:00
$sql = ' SELECT `fileid` , `storage` , `path` , `parent` , `name` , `mimetype` , `mimepart` , `size` , `mtime` , `encrypted` , `etag` , `permissions`
2013-06-07 12:11:05 +00:00
FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ? ' ;
2013-01-07 00:40:09 +00:00
$mimetype = $this -> getMimetypeId ( $mimetype );
2013-06-07 12:11:05 +00:00
$result = \OC_DB :: executeAudited ( $sql , array ( $mimetype , $this -> getNumericStorageId ()));
2013-02-03 10:06:26 +00:00
$files = array ();
while ( $row = $result -> fetchRow ()) {
$row [ 'mimetype' ] = $this -> getMimetype ( $row [ 'mimetype' ]);
$row [ 'mimepart' ] = $this -> getMimetype ( $row [ 'mimepart' ]);
$files [] = $row ;
}
return $files ;
2012-10-27 08:34:25 +00:00
}
2014-12-04 13:01:15 +00:00
/**
* Search for files by tag of a given users .
*
* Note that every user can tag files differently .
*
* @ param string | int $tag name or tag id
* @ param string $userId owner of the tags
* @ return array file data
*/
2014-12-12 10:18:35 +00:00
public function searchByTag ( $tag , $userId ) {
2014-12-04 13:01:15 +00:00
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
'`mimetype`, `mimepart`, `size`, `mtime`, ' .
2015-03-30 15:29:05 +00:00
'`encrypted`, `etag`, `permissions` ' .
2014-12-04 13:01:15 +00:00
'FROM `*PREFIX*filecache` `file`, ' .
'`*PREFIX*vcategory_to_object` `tagmap`, ' .
'`*PREFIX*vcategory` `tag` ' .
// JOIN filecache to vcategory_to_object
2015-01-15 16:26:12 +00:00
'WHERE `file`.`fileid` = `tagmap`.`objid` ' .
2014-12-04 13:01:15 +00:00
// JOIN vcategory_to_object to vcategory
'AND `tagmap`.`type` = `tag`.`type` ' .
'AND `tagmap`.`categoryid` = `tag`.`id` ' .
// conditions
2015-01-15 16:26:12 +00:00
'AND `file`.`storage` = ? ' .
2014-12-04 13:01:15 +00:00
'AND `tag`.`type` = \'files\' ' .
'AND `tag`.`uid` = ? ' ;
if ( is_int ( $tag )) {
$sql .= 'AND `tag`.`id` = ? ' ;
} else {
$sql .= 'AND `tag`.`category` = ? ' ;
}
$result = \OC_DB :: executeAudited (
$sql ,
array (
$this -> getNumericStorageId (),
$userId ,
$tag
)
);
$files = array ();
while ( $row = $result -> fetchRow ()) {
$files [] = $row ;
}
return $files ;
}
2012-11-08 17:10:54 +00:00
/**
* update the folder size and the size of all parent folders
*
2014-02-06 15:30:58 +00:00
* @ param string | boolean $path
2014-02-28 13:23:07 +00:00
* @ param array $data ( optional ) meta data of the folder
2012-11-08 17:10:54 +00:00
*/
2014-02-28 13:23:07 +00:00
public function correctFolderSize ( $path , $data = null ) {
$this -> calculateFolderSize ( $path , $data );
2012-11-08 17:10:54 +00:00
if ( $path !== '' ) {
$parent = dirname ( $path );
2013-04-29 13:43:48 +00:00
if ( $parent === '.' or $parent === '/' ) {
2012-11-08 17:10:54 +00:00
$parent = '' ;
}
$this -> correctFolderSize ( $parent );
}
}
2012-10-27 15:02:05 +00:00
/**
* get the size of a folder and set it in the cache
*
* @ param string $path
2014-02-28 13:23:07 +00:00
* @ param array $entry ( optional ) meta data of the folder
2012-10-27 15:02:05 +00:00
* @ return int
*/
2014-02-28 13:23:07 +00:00
public function calculateFolderSize ( $path , $entry = null ) {
2012-10-27 15:02:05 +00:00
$totalSize = 0 ;
2014-03-03 15:48:28 +00:00
if ( is_null ( $entry ) or ! isset ( $entry [ 'fileid' ])) {
2014-02-28 13:23:07 +00:00
$entry = $this -> get ( $path );
}
2015-01-19 14:04:53 +00:00
if ( isset ( $entry [ 'mimetype' ]) && $entry [ 'mimetype' ] === 'httpd/unix-directory' ) {
2013-07-28 20:14:49 +00:00
$id = $entry [ 'fileid' ];
2015-03-30 15:29:05 +00:00
$sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' .
2014-01-09 16:27:55 +00:00
'FROM `*PREFIX*filecache` ' .
2013-07-29 14:22:44 +00:00
'WHERE `parent` = ? AND `storage` = ?' ;
2013-07-28 20:14:49 +00:00
$result = \OC_DB :: executeAudited ( $sql , array ( $id , $this -> getNumericStorageId ()));
2013-07-29 14:22:44 +00:00
if ( $row = $result -> fetchRow ()) {
2014-11-28 08:35:31 +00:00
$result -> closeCursor ();
2015-03-30 15:29:05 +00:00
list ( $sum , $min ) = array_values ( $row );
2014-02-15 23:50:03 +00:00
$sum = 0 + $sum ;
$min = 0 + $min ;
2013-07-29 14:22:44 +00:00
if ( $min === - 1 ) {
$totalSize = $min ;
2013-07-28 20:14:49 +00:00
} else {
2013-07-29 14:22:44 +00:00
$totalSize = $sum ;
2013-07-28 20:14:49 +00:00
}
2014-01-09 16:27:55 +00:00
$update = array ();
2013-07-29 14:22:44 +00:00
if ( $entry [ 'size' ] !== $totalSize ) {
2014-01-09 16:27:55 +00:00
$update [ 'size' ] = $totalSize ;
}
if ( count ( $update ) > 0 ) {
$this -> update ( $id , $update );
}
2014-11-28 08:35:31 +00:00
} else {
$result -> closeCursor ();
2012-10-27 15:02:05 +00:00
}
}
return $totalSize ;
}
2012-10-27 08:01:20 +00:00
/**
* get all file ids on the files on the storage
*
* @ return int []
*/
public function getAll () {
2013-06-07 12:11:05 +00:00
$sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?' ;
$result = \OC_DB :: executeAudited ( $sql , array ( $this -> getNumericStorageId ()));
2012-10-27 08:01:20 +00:00
$ids = array ();
while ( $row = $result -> fetchRow ()) {
$ids [] = $row [ 'fileid' ];
}
return $ids ;
}
2012-11-21 22:02:43 +00:00
/**
* find a folder in the cache which has not been fully scanned
*
2014-11-10 15:00:08 +00:00
* If multiple incomplete folders are in the cache , the one with the highest id will be returned ,
2012-11-21 22:02:43 +00: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-22 23:17:18 +00:00
public function getIncomplete () {
2013-02-11 16:44:02 +00:00
$query = \OC_DB :: prepare ( 'SELECT `path` FROM `*PREFIX*filecache`'
2015-01-15 16:26:12 +00:00
. ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC' , 1 );
2013-06-07 12:11:05 +00:00
$result = \OC_DB :: executeAudited ( $query , array ( $this -> getNumericStorageId ()));
2013-02-14 20:59:24 +00:00
if ( $row = $result -> fetchRow ()) {
2012-11-21 22:02:43 +00:00
return $row [ 'path' ];
2012-11-22 23:17:18 +00:00
} else {
2012-11-21 22:02:43 +00:00
return false ;
}
}
2013-01-26 22:59:29 +00:00
2014-03-27 15:43:34 +00:00
/**
2014-03-31 12:29:55 +00:00
* get the path of a file on this storage by it ' s id
2014-03-27 15:43:34 +00:00
*
* @ param int $id
2014-05-11 17:28:45 +00:00
* @ return string | null
2014-03-27 15:43:34 +00:00
*/
public function getPathById ( $id ) {
$sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?' ;
$result = \OC_DB :: executeAudited ( $sql , array ( $id , $this -> getNumericStorageId ()));
if ( $row = $result -> fetchRow ()) {
2014-05-08 11:33:55 +00:00
// Oracle stores empty strings as null...
if ( $row [ 'path' ] === null ) {
return '' ;
}
2014-03-27 15:43:34 +00:00
return $row [ 'path' ];
} else {
return null ;
}
}
2013-01-26 22:59:29 +00:00
/**
* get the storage id of the storage for a file and the internal path of the file
2014-03-31 12:29:55 +00: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-26 22:59:29 +00:00
*
2013-04-25 22:00:18 +00:00
* @ param int $id
2015-01-16 18:31:15 +00:00
* @ return array first element holding the storage id , second the path
2013-01-26 22:59:29 +00:00
*/
static public function getById ( $id ) {
2013-06-07 12:11:05 +00:00
$sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?' ;
$result = \OC_DB :: executeAudited ( $sql , array ( $id ));
2013-01-26 22:59:29 +00:00
if ( $row = $result -> fetchRow ()) {
$numericId = $row [ 'storage' ];
$path = $row [ 'path' ];
} else {
return null ;
}
2013-04-25 22:00:18 +00:00
if ( $id = Storage :: getStorageId ( $numericId )) {
return array ( $id , $path );
2013-01-26 22:59:29 +00:00
} else {
return null ;
}
}
2013-05-23 18:29:46 +00:00
/**
* normalize the given path
2015-01-15 16:26:12 +00:00
*
2014-05-11 20:51:30 +00:00
* @ param string $path
2013-05-23 18:29:46 +00:00
* @ return string
*/
public function normalize ( $path ) {
2015-01-08 18:43:02 +00:00
return trim ( \OC_Util :: normalizeUnicode ( $path ), '/' );
2013-05-23 18:29:46 +00:00
}
2012-09-16 14:52:32 +00:00
}