2011-11-09 21:41:57 +04:00
< ? php
/**
* @ author Robin Appelman
* @ copyright 2011 Robin Appelman icewind1991 @ gmail . com
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library 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 along with this library . If not , see < http :// www . gnu . org / licenses />.
*
*/
/**
* provide caching for filesystem info in the database
*
* not used by OC_Filesystem for reading filesystem info ,
* instread apps should use OC_FileCache :: get where possible
*
* It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache
*/
class OC_FileCache {
2012-02-21 23:48:14 +04:00
private static $savedData = array ();
2011-11-09 21:41:57 +04:00
/**
* get the filesystem info from the cache
* @ param string path
2012-02-02 22:04:13 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
* @ return array
*
* returns an assiciative array with the following keys :
* - size
* - mtime
* - ctime
* - mimetype
2011-11-12 04:00:04 +04:00
* - encrypted
* - versioned
2011-11-09 21:41:57 +04:00
*/
2012-02-02 22:04:13 +04:00
public static function get ( $path , $root = '' ){
2012-02-05 04:25:36 +04:00
if ( self :: isUpdated ( $path , $root )){
if ( ! $root ){ //filesystem hooks are only valid for the default root
OC_Hook :: emit ( 'OC_Filesystem' , 'post_write' , array ( 'path' => $path ));
} else {
self :: fileSystemWatcherWrite ( array ( 'path' => $path ), $root );
}
}
2012-02-02 22:04:13 +04:00
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
2012-02-05 04:25:36 +04:00
if ( $root == '/' ){
$root = '' ;
}
2012-02-02 22:04:13 +04:00
$path = $root . $path ;
2012-03-30 20:12:33 +04:00
$query = OC_DB :: prepare ( 'SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?' );
$result = $query -> execute ( array ( md5 ( $path ))) -> fetchRow ();
2011-11-09 21:41:57 +04:00
if ( is_array ( $result )){
return $result ;
} else {
2012-04-25 02:10:02 +04:00
OC_Log :: write ( 'files' , 'get(): file not found in cache (' . $path . ')' , OC_Log :: DEBUG );
2011-11-09 21:41:57 +04:00
return false ;
}
}
/**
* put filesystem info in the cache
* @ param string $path
* @ param array data
2012-02-02 22:04:13 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
*
* $data is an assiciative array in the same format as returned by get
*/
2012-02-02 22:04:13 +04:00
public static function put ( $path , $data , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
2012-02-05 04:25:36 +04:00
if ( $root == '/' ){
$root = '' ;
}
2012-02-02 22:04:13 +04:00
$path = $root . $path ;
2011-11-09 21:41:57 +04:00
if ( $path == '/' ){
$parent =- 1 ;
} else {
$parent = self :: getFileId ( dirname ( $path ));
}
2011-11-12 04:00:04 +04:00
$id = self :: getFileId ( $path );
if ( $id !=- 1 ){
self :: update ( $id , $data );
return ;
}
2012-02-21 23:48:14 +04:00
if ( isset ( self :: $savedData [ $path ])){
$data = array_merge ( $data , self :: $savedData [ $path ]);
unset ( self :: $savedData [ $path ]);
}
if ( ! isset ( $data [ 'size' ]) or ! isset ( $data [ 'mtime' ])){ //save incomplete data for the next time we write it
self :: $savedData [ $path ] = $data ;
return ;
}
2011-11-12 04:00:04 +04:00
if ( ! isset ( $data [ 'encrypted' ])){
$data [ 'encrypted' ] = false ;
}
if ( ! isset ( $data [ 'versioned' ])){
$data [ 'versioned' ] = false ;
}
2011-11-09 21:41:57 +04:00
$mimePart = dirname ( $data [ 'mimetype' ]);
2012-05-04 01:16:18 +04:00
$data [ 'size' ] = ( int ) $data [ 'size' ];
$data [ 'ctime' ] = ( int ) $data [ 'mtime' ];
$data [ 'writable' ] = ( int ) $data [ 'writable' ];
$data [ 'encrypted' ] = ( int ) $data [ 'encrypted' ];
$data [ 'versioned' ] = ( int ) $data [ 'versioned' ];
2012-01-31 19:12:49 +04:00
$user = OC_User :: getUser ();
2012-05-04 01:16:18 +04:00
$query = OC_DB :: prepare ( 'INSERT INTO *PREFIX*fscache(parent, name, path, path_hash, size, mtime, ctime, mimetype, mimepart,`user`,writable,encrypted,versioned) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)' );
2012-03-30 20:12:33 +04:00
$result = $query -> execute ( array ( $parent , basename ( $path ), $path , md5 ( $path ), $data [ 'size' ], $data [ 'mtime' ], $data [ 'ctime' ], $data [ 'mimetype' ], $mimePart , $user , $data [ 'writable' ], $data [ 'encrypted' ], $data [ 'versioned' ]));
2012-02-25 23:27:16 +04:00
if ( OC_DB :: isError ( $result )){
OC_Log :: write ( 'files' , 'error while writing file(' . $path . ') to cache' , OC_Log :: ERROR );
}
2011-11-09 21:41:57 +04:00
}
/**
* update filesystem info of a file
* @ param int $id
* @ param array $data
*/
private static function update ( $id , $data ){
2011-11-12 04:00:04 +04:00
$arguments = array ();
$queryParts = array ();
2012-02-05 17:04:10 +04:00
foreach ( array ( 'size' , 'mtime' , 'ctime' , 'mimetype' , 'encrypted' , 'versioned' , 'writable' ) as $attribute ){
2011-11-12 04:00:04 +04:00
if ( isset ( $data [ $attribute ])){
$arguments [] = $data [ $attribute ];
$queryParts [] = $attribute . '=?' ;
}
}
if ( isset ( $data [ 'mimetype' ])){
$arguments [] = dirname ( $data [ 'mimetype' ]);
$queryParts [] = 'mimepart=?' ;
}
$arguments [] = $id ;
2012-02-10 14:30:38 +04:00
$sql = 'UPDATE *PREFIX*fscache SET ' . implode ( ' , ' , $queryParts ) . ' WHERE id=?' ;
$query = OC_DB :: prepare ( $sql );
2012-02-25 23:27:16 +04:00
$result = $query -> execute ( $arguments );
if ( OC_DB :: isError ( $result )){
OC_Log :: write ( 'files' , 'error while updating file(' . $path . ') in cache' , OC_Log :: ERROR );
}
2011-11-09 21:41:57 +04:00
}
/**
* register a file move in the cache
* @ param string oldPath
* @ param string newPath
2012-02-02 22:04:13 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
*/
2012-02-02 22:04:13 +04:00
public static function move ( $oldPath , $newPath , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
2012-02-05 04:25:36 +04:00
if ( $root == '/' ){
$root = '' ;
}
2012-02-02 22:04:13 +04:00
$oldPath = $root . $oldPath ;
$newPath = $root . $newPath ;
2011-11-09 21:41:57 +04:00
$newParent = self :: getParentId ( $newPath );
2012-03-30 20:12:33 +04:00
$query = OC_DB :: prepare ( 'UPDATE *PREFIX*fscache SET parent=? ,name=?, path=?, path_hash=? WHERE path_hash=?' );
$query -> execute ( array ( $newParent , basename ( $newPath ), $newPath , md5 ( $newPath ), md5 ( $oldPath )));
2012-06-04 19:59:21 +04:00
$query = OC_DB :: prepare ( 'SELECT path FROM *PREFIX*fscache WHERE path LIKE ?' );
$oldLength = strlen ( $oldPath );
$updateQuery = OC_DB :: prepare ( 'UPDATE *PREFIX*fscache SET path=?, path_hash=? WHERE path_hash=?' );
while ( $row = $query -> execute ( array ( $oldPath . '/%' )) -> fetchRow ()){
$old = $row [ 'path' ];
$new = $newPath . substr ( $old , $oldLength );
$updateQuery -> execute ( array ( $new , md5 ( $new ), md5 ( $old )));
}
2011-11-09 21:41:57 +04:00
}
/**
* delete info from the cache
2012-03-03 21:23:53 +04:00
* @ param string / int $file
2012-02-02 22:04:13 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
*/
2012-03-03 21:23:53 +04:00
public static function delete ( $file , $root = '' ){
if ( ! is_numeric ( $file )){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
if ( $root == '/' ){
$root = '' ;
}
$path = $root . $file ;
self :: delete ( self :: getFileId ( $path ));
} elseif ( $file !=- 1 ){
$query = OC_DB :: prepare ( 'SELECT id FROM *PREFIX*fscache WHERE parent=?' );
2012-03-12 00:48:35 +04:00
$result = $query -> execute ( array ( $file ));
while ( $child = $result -> fetchRow ()){
2012-03-03 21:23:53 +04:00
self :: delete ( intval ( $child [ 'id' ]));
}
$query = OC_DB :: prepare ( 'DELETE FROM *PREFIX*fscache WHERE id=?' );
$query -> execute ( array ( $file ));
2012-02-05 04:25:36 +04:00
}
2011-11-09 21:41:57 +04:00
}
/**
* return array of filenames matching the querty
* @ param string $query
2012-01-31 19:12:49 +04:00
* @ param boolean $returnData
2012-02-02 22:04:13 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
* @ return array of filepaths
*/
2012-02-02 22:04:13 +04:00
public static function search ( $search , $returnData = false , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
2012-02-05 04:25:36 +04:00
if ( $root == '/' ){
$root = '' ;
}
2012-01-31 19:12:49 +04:00
$rootLen = strlen ( $root );
if ( ! $returnData ){
2012-05-04 01:16:18 +04:00
$query = OC_DB :: prepare ( 'SELECT path FROM *PREFIX*fscache WHERE name LIKE ? AND `user`=?' );
2012-01-31 19:12:49 +04:00
} else {
2012-05-04 01:16:18 +04:00
$query = OC_DB :: prepare ( 'SELECT * FROM *PREFIX*fscache WHERE name LIKE ? AND `user`=?' );
2012-01-31 19:12:49 +04:00
}
$result = $query -> execute ( array ( " % $search % " , OC_User :: getUser ()));
2011-11-09 21:41:57 +04:00
$names = array ();
while ( $row = $result -> fetchRow ()){
2012-01-31 19:12:49 +04:00
if ( ! $returnData ){
$names [] = substr ( $row [ 'path' ], $rootLen );
} else {
$row [ 'path' ] = substr ( $row [ 'path' ], $rootLen );
$names [] = $row ;
}
2011-11-09 21:41:57 +04:00
}
return $names ;
}
/**
* get all files and folders in a folder
* @ param string path
2012-02-02 22:04:13 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
* @ return array
*
* returns an array of assiciative arrays with the following keys :
* - name
* - size
* - mtime
* - ctime
* - mimetype
2011-11-12 04:00:04 +04:00
* - encrypted
* - versioned
2011-11-09 21:41:57 +04:00
*/
2012-04-06 01:18:44 +04:00
public static function getFolderContent ( $path , $root = '' , $mimetype_filter = '' ){
2012-02-05 04:25:36 +04:00
if ( self :: isUpdated ( $path , $root )){
self :: updateFolder ( $path , $root );
}
2012-02-02 22:04:13 +04:00
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
2012-02-05 04:25:36 +04:00
if ( $root == '/' ){
$root = '' ;
}
2012-02-02 22:04:13 +04:00
$path = $root . $path ;
2011-11-09 21:41:57 +04:00
$parent = self :: getFileId ( $path );
2012-04-06 01:18:44 +04:00
$query = OC_DB :: prepare ( 'SELECT name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=? AND (mimetype LIKE ? OR mimetype = ?)' );
$result = $query -> execute ( array ( $parent , $mimetype_filter . '%' , 'httpd/unix-directory' )) -> fetchAll ();
2011-11-09 21:41:57 +04:00
if ( is_array ( $result )){
return $result ;
} else {
2012-04-25 02:10:02 +04:00
OC_Log :: write ( 'files' , 'getFolderContent(): file not found in cache (' . $path . ')' , OC_Log :: DEBUG );
2011-11-09 21:41:57 +04:00
return false ;
}
}
/**
* check if a file or folder is in the cache
* @ param string $path
2012-02-02 22:04:13 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
* @ return bool
*/
2012-02-02 22:04:13 +04:00
public static function inCache ( $path , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
2012-02-05 04:25:36 +04:00
if ( $root == '/' ){
$root = '' ;
}
2012-02-02 22:04:13 +04:00
$path = $root . $path ;
2012-02-05 04:25:36 +04:00
return self :: getFileId ( $path ) !=- 1 ;
2011-11-09 21:41:57 +04:00
}
/**
* get the file id as used in the cache
2012-04-15 13:44:04 +04:00
* unlike the public getId , full paths are used here ( / usename / files / foo instead of / foo )
2011-11-09 21:41:57 +04:00
* @ param string $path
* @ return int
*/
private static function getFileId ( $path ){
2012-03-30 20:12:33 +04:00
$query = OC_DB :: prepare ( 'SELECT id FROM *PREFIX*fscache WHERE path_hash=?' );
2012-02-25 23:27:16 +04:00
if ( OC_DB :: isError ( $query )){
OC_Log :: write ( 'files' , 'error while getting file id of ' . $path , OC_Log :: ERROR );
return - 1 ;
}
2012-03-30 20:12:33 +04:00
$result = $query -> execute ( array ( md5 ( $path )));
2012-02-25 23:27:16 +04:00
if ( OC_DB :: isError ( $result )){
OC_Log :: write ( 'files' , 'error while getting file id of ' . $path , OC_Log :: ERROR );
return - 1 ;
}
$result = $result -> fetchRow ();
2011-11-09 21:41:57 +04:00
if ( is_array ( $result )){
return $result [ 'id' ];
} else {
2012-04-25 02:10:02 +04:00
OC_Log :: write ( 'files' , 'getFileId(): file not found in cache (' . $path . ')' , OC_Log :: DEBUG );
2011-11-09 21:41:57 +04:00
return - 1 ;
}
}
2012-04-15 13:44:04 +04:00
/**
* get the file id as used in the cache
* @ param string path
* @ param string root ( optional )
* @ return int
*/
public static function getId ( $path , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
if ( $root == '/' ){
$root = '' ;
}
$path = $root . $path ;
return self :: getFileId ( $path );
}
/**
* get the file path from the id , relative to the home folder of the user
* @ param int id
* @ param string user ( optional )
* @ return string
*/
public static function getPath ( $id , $user = '' ){
if ( ! $user ){
$user = OC_User :: getUser ();
}
2012-05-04 01:16:18 +04:00
$query = OC_DB :: prepare ( 'SELECT path FROM *PREFIX*fscache WHERE id=? AND `user`=?' );
2012-04-15 13:44:04 +04:00
$result = $query -> execute ( array ( $id , $user ));
$row = $result -> fetchRow ();
2012-04-16 12:06:52 +04:00
$path = $row [ 'path' ];
$root = '/' . $user . '/files' ;
if ( substr ( $path , 0 , strlen ( $root )) != $root ){
return false ;
}
return substr ( $path , strlen ( $root ));
2012-04-15 13:44:04 +04:00
}
2011-11-09 21:41:57 +04:00
/**
* get the file id of the parent folder , taking into account '/' has no parent
* @ param string $path
* @ return int
*/
private static function getParentId ( $path ){
if ( $path == '/' ){
return - 1 ;
} else {
return self :: getFileId ( dirname ( $path ));
}
}
/**
* called when changes are made to files
2012-02-05 04:25:36 +04:00
* @ param array $params
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
*/
2012-02-05 04:25:36 +04:00
public static function fileSystemWatcherWrite ( $params , $root = '' ){
if ( ! $root ){
$view = OC_Filesystem :: getView ();
} else {
$view = new OC_FilesystemView (( $root == '/' ) ? '' : $root );
}
2012-02-10 14:30:38 +04:00
2011-11-09 21:41:57 +04:00
$path = $params [ 'path' ];
2012-02-05 04:25:36 +04:00
$fullPath = $view -> getRoot () . $path ;
$mimetype = $view -> getMimeType ( $path );
2012-03-03 21:02:07 +04:00
$dir = $view -> is_dir ( $path . '/' );
2012-02-05 04:25:36 +04:00
//dont use self::get here, we don't want inifinte loops when a file has changed
$cachedSize = self :: getCachedSize ( $path , $root );
2012-02-06 22:33:37 +04:00
$size = 0 ;
2012-03-03 21:02:07 +04:00
if ( $dir ){
2012-02-05 04:25:36 +04:00
if ( self :: inCache ( $path , $root )){
$parent = self :: getFileId ( $fullPath );
$query = OC_DB :: prepare ( 'SELECT size FROM *PREFIX*fscache WHERE parent=?' );
2012-02-09 00:39:09 +04:00
$result = $query -> execute ( array ( $parent ));
while ( $row = $result -> fetchRow ()){
2012-02-05 04:25:36 +04:00
$size += $row [ 'size' ];
}
$mtime = $view -> filemtime ( $path );
$ctime = $view -> filectime ( $path );
2012-02-05 17:04:10 +04:00
$writable = $view -> is_writable ( $path );
self :: put ( $path , array ( 'size' => $size , 'mtime' => $mtime , 'ctime' => $ctime , 'mimetype' => $mimetype , 'writable' => $writable ));
2011-11-09 21:41:57 +04:00
} else {
2012-02-06 22:33:37 +04:00
$count = 0 ;
self :: scan ( $path , null , $count , $root );
2011-11-09 21:41:57 +04:00
}
2012-02-05 04:25:36 +04:00
} else {
$size = self :: scanFile ( $path , $root );
}
self :: increaseSize ( dirname ( $fullPath ), $size - $cachedSize );
}
2012-02-21 23:48:14 +04:00
public static function getCached ( $path , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
} else {
if ( $root == '/' ){
$root = '' ;
}
}
$path = $root . $path ;
2012-03-30 20:12:33 +04:00
$query = OC_DB :: prepare ( 'SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?' );
$result = $query -> execute ( array ( md5 ( $path ))) -> fetchRow ();
2012-02-21 23:48:14 +04:00
if ( is_array ( $result )){
if ( isset ( self :: $savedData [ $path ])){
$result = array_merge ( $result , self :: $savedData [ $path ]);
}
return $result ;
} else {
2012-06-01 23:15:05 +04:00
OC_Log :: write ( 'files' , 'getCached(): file not found in cache (' . $path . ')' , OC_Log :: DEBUG );
2012-04-25 02:10:02 +04:00
if ( isset ( self :: $savedData [ $path ])){
return self :: $savedData [ $path ];
} else {
return array ();
}
2012-02-21 23:48:14 +04:00
}
}
2012-02-05 04:25:36 +04:00
private static function getCachedSize ( $path , $root ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
} else {
if ( $root == '/' ){
$root = '' ;
}
}
2012-02-21 23:48:14 +04:00
$path = $root . $path ;
2012-03-30 20:12:33 +04:00
$query = OC_DB :: prepare ( 'SELECT size FROM *PREFIX*fscache WHERE path_hash=?' );
$result = $query -> execute ( array ( md5 ( $path )));
2012-02-09 00:39:09 +04:00
if ( $row = $result -> fetchRow ()){
2012-02-05 04:25:36 +04:00
return $row [ 'size' ];
} else { //file not in cache
return 0 ;
2011-11-09 21:41:57 +04:00
}
}
/**
* called when files are deleted
2012-02-05 04:25:36 +04:00
* @ param array $params
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
*/
2012-02-05 04:25:36 +04:00
public static function fileSystemWatcherDelete ( $params , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
if ( $root == '/' ){
$root = '' ;
}
2011-11-09 21:41:57 +04:00
$path = $params [ 'path' ];
2012-02-05 04:25:36 +04:00
$fullPath = $root . $path ;
2011-11-09 21:41:57 +04:00
if ( self :: getFileId ( $fullPath ) ==- 1 ){
return ;
}
2012-02-05 04:25:36 +04:00
$size = self :: getCachedSize ( $path , $root );
2011-11-09 21:41:57 +04:00
self :: increaseSize ( dirname ( $fullPath ), - $size );
self :: delete ( $path );
}
/**
* called when files are deleted
2012-02-05 04:25:36 +04:00
* @ param array $params
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
*/
2012-02-05 04:25:36 +04:00
public static function fileSystemWatcherRename ( $params , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
}
if ( $root == '/' ){
$root = '' ;
}
2011-11-09 21:41:57 +04:00
$oldPath = $params [ 'oldpath' ];
$newPath = $params [ 'newpath' ];
2012-02-05 04:25:36 +04:00
$fullOldPath = $root . $oldPath ;
$fullNewPath = $root . $newPath ;
2011-11-09 21:41:57 +04:00
if (( $id = self :: getFileId ( $fullOldPath )) !=- 1 ){
2012-02-15 17:42:37 +04:00
$oldSize = self :: getCachedSize ( $oldPath , $root );
2011-11-09 21:41:57 +04:00
} else {
return ;
}
2012-04-15 18:04:21 +04:00
$size = OC_Filesystem :: filesize ( $newPath );
2011-11-09 21:41:57 +04:00
self :: increaseSize ( dirname ( $fullOldPath ), - $oldSize );
self :: increaseSize ( dirname ( $fullNewPath ), $oldSize );
self :: move ( $oldPath , $newPath );
}
/**
* adjust the size of the parent folders
* @ param string $path
* @ param int $sizeDiff
*/
private static function increaseSize ( $path , $sizeDiff ){
2012-02-05 04:25:36 +04:00
if ( $sizeDiff == 0 ) return ;
while (( $id = self :: getFileId ( $path )) !=- 1 ){ //walk up the filetree increasing the size of all parent folders
2011-11-09 21:41:57 +04:00
$query = OC_DB :: prepare ( 'UPDATE *PREFIX*fscache SET size=size+? WHERE id=?' );
$query -> execute ( array ( $sizeDiff , $id ));
$path = dirname ( $path );
}
}
/**
* recursively scan the filesystem and fill the cache
* @ param string $path
2012-02-02 22:04:13 +04:00
* @ param OC_EventSource $enventSource ( optional )
* @ param int count ( optional )
2012-02-05 04:25:36 +04:00
* @ param string root ( optionak )
2011-11-09 21:41:57 +04:00
*/
2012-02-05 04:25:36 +04:00
public static function scan ( $path , $eventSource = false , & $count = 0 , $root = '' ){
2012-03-31 18:24:53 +04:00
if ( $eventSource ){
$eventSource -> send ( 'scanning' , array ( 'file' => $path , 'count' => $count ));
}
$lastSend = $count ;
2012-02-02 22:04:13 +04:00
if ( ! $root ){
2012-02-05 04:25:36 +04:00
$view = OC_Filesystem :: getView ();
} else {
$view = new OC_FilesystemView (( $root == '/' ) ? '' : $root );
2011-11-09 21:41:57 +04:00
}
2012-02-05 04:25:36 +04:00
self :: scanFile ( $path , $root );
2012-04-29 18:11:17 +04:00
$dh = $view -> opendir ( $path . '/' );
$totalSize = 0 ;
if ( $dh ){
while (( $filename = readdir ( $dh )) !== false ) {
if ( $filename != '.' and $filename != '..' ){
$file = $path . '/' . $filename ;
if ( $view -> is_dir ( $file . '/' )){
self :: scan ( $file , $eventSource , $count , $root );
} else {
$totalSize += self :: scanFile ( $file , $root );
$count ++ ;
if ( $count > $lastSend + 25 and $eventSource ){
$lastSend = $count ;
$eventSource -> send ( 'scanning' , array ( 'file' => $path , 'count' => $count ));
2012-03-31 18:24:53 +04:00
}
2011-11-09 21:41:57 +04:00
}
}
}
}
2012-04-29 18:11:17 +04:00
self :: cleanFolder ( $path , $root );
self :: increaseSize ( $view -> getRoot () . $path , $totalSize );
2012-02-05 04:25:36 +04:00
}
/**
* scan a single file
* @ param string path
* @ param string root ( optional )
* @ return int size of the scanned file
*/
public static function scanFile ( $path , $root = '' ){
if ( ! $root ){
$view = OC_Filesystem :: getView ();
} else {
$view = new OC_FilesystemView (( $root == '/' ) ? '' : $root );
}
if ( ! $view -> is_readable ( $path )) return ; //cant read, nothing we can do
2012-04-25 02:10:02 +04:00
clearstatcache ();
2012-02-05 04:25:36 +04:00
$mimetype = $view -> getMimeType ( $path );
2012-05-17 03:47:58 +04:00
$stat = $view -> stat ( $path );
if ( $mimetype == 'httpd/unix-directory' ){
$writable = $view -> is_writable ( $path . '/' );
} else {
$writable = $view -> is_writable ( $path );
}
2012-02-05 04:25:36 +04:00
$stat [ 'mimetype' ] = $mimetype ;
2012-02-05 17:04:10 +04:00
$stat [ 'writable' ] = $writable ;
2012-02-05 04:25:36 +04:00
if ( $path == '/' ){
$path = '' ;
}
self :: put ( $path , $stat , $root );
return $stat [ 'size' ];
2011-11-09 21:41:57 +04:00
}
/**
2012-03-15 03:09:06 +04:00
* find files by mimetype
2011-11-09 21:41:57 +04:00
* @ param string $part1
* @ param string $part2 ( optional )
2012-02-08 20:29:54 +04:00
* @ param string root ( optional )
2011-11-09 21:41:57 +04:00
* @ return array of file paths
*
* $part1 and $part2 together form the complete mimetype .
* e . g . searchByMime ( 'text' , 'plain' )
*
* seccond mimetype part can be ommited
* e . g . searchByMime ( 'audio' )
*/
2012-03-09 19:28:26 +04:00
public static function searchByMime ( $part1 , $part2 = null , $root = null ){
2012-02-08 20:29:54 +04:00
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
2012-03-09 19:28:26 +04:00
} elseif ( $root == '/' ){
2012-02-08 20:29:54 +04:00
$root = '' ;
}
2012-03-09 19:47:53 +04:00
$rootLen = strlen ( $root );
$root .= '%' ;
2012-02-08 20:29:54 +04:00
$user = OC_User :: getUser ();
if ( ! $part2 ){
2012-05-04 01:16:18 +04:00
$query = OC_DB :: prepare ( 'SELECT path FROM *PREFIX*fscache WHERE mimepart=? AND `user`=? AND path LIKE ?' );
2012-03-09 19:47:53 +04:00
$result = $query -> execute ( array ( $part1 , $user , $root ));
2011-11-09 21:41:57 +04:00
} else {
2012-05-04 01:16:18 +04:00
$query = OC_DB :: prepare ( 'SELECT path FROM *PREFIX*fscache WHERE mimetype=? AND `user`=? AND path LIKE ? ' );
2012-03-09 19:45:57 +04:00
$result = $query -> execute ( array ( $part1 . '/' . $part2 , $user , $root ));
2011-11-09 21:41:57 +04:00
}
$names = array ();
while ( $row = $result -> fetchRow ()){
2012-02-08 20:29:54 +04:00
$names [] = substr ( $row [ 'path' ], $rootLen );
2011-11-09 21:41:57 +04:00
}
return $names ;
}
2012-02-05 04:25:36 +04:00
/**
* check if a file or folder is updated outside owncloud
* @ param string path
* @ param string root ( optional )
* @ return bool
*/
public static function isUpdated ( $path , $root = '' ){
if ( ! $root ){
$root = OC_Filesystem :: getRoot ();
$view = OC_Filesystem :: getView ();
} else {
if ( $root == '/' ){
$root = '' ;
}
$view = new OC_FilesystemView ( $root );
}
2012-02-11 19:06:34 +04:00
if ( ! $view -> file_exists ( $path )){
return false ;
}
2012-02-05 04:25:36 +04:00
$mtime = $view -> filemtime ( $path );
$isDir = $view -> is_dir ( $path );
2012-05-11 22:49:19 +04:00
$fullPath = $root . $path ;
2012-03-30 20:12:33 +04:00
$query = OC_DB :: prepare ( 'SELECT mtime FROM *PREFIX*fscache WHERE path_hash=?' );
2012-05-11 22:49:19 +04:00
$result = $query -> execute ( array ( md5 ( $fullPath )));
2012-02-09 00:39:09 +04:00
if ( $row = $result -> fetchRow ()){
2012-02-05 04:25:36 +04:00
$cachedMTime = $row [ 'mtime' ];
return ( $mtime > $cachedMTime );
} else { //file not in cache, so it has to be updated
2012-05-11 22:49:19 +04:00
if ( $path == '/' or $path == '' ){ //dont auto update the root folder, it will be scanned
return false ;
}
2012-05-09 22:35:12 +04:00
return true ;
2012-02-05 04:25:36 +04:00
}
}
/**
* update the cache according to changes in the folder
* @ param string path
* @ param string root ( optional )
*/
private static function updateFolder ( $path , $root = '' ){
if ( ! $root ){
$view = OC_Filesystem :: getView ();
} else {
$view = new OC_FilesystemView (( $root == '/' ) ? '' : $root );
}
2012-05-07 04:11:10 +04:00
$dh = $view -> opendir ( $path . '/' );
2012-02-05 04:25:36 +04:00
if ( $dh ){ //check for changed/new files
while (( $filename = readdir ( $dh )) !== false ) {
if ( $filename != '.' and $filename != '..' ){
$file = $path . '/' . $filename ;
if ( self :: isUpdated ( $file , $root )){
if ( ! $root ){ //filesystem hooks are only valid for the default root
OC_Hook :: emit ( 'OC_Filesystem' , 'post_write' , array ( 'path' => $file ));
} else {
self :: fileSystemWatcherWrite ( array ( 'path' => $file ), $root );
}
}
}
}
}
2012-04-29 18:11:17 +04:00
self :: cleanFolder ( $path , $root );
//update the folder last, so we can calculate the size correctly
if ( ! $root ){ //filesystem hooks are only valid for the default root
OC_Hook :: emit ( 'OC_Filesystem' , 'post_write' , array ( 'path' => $path ));
} else {
self :: fileSystemWatcherWrite ( array ( 'path' => $path ), $root );
}
}
2012-02-05 04:25:36 +04:00
2012-04-29 18:11:17 +04:00
/**
* delete non existing files from the cache
*/
private static function cleanFolder ( $path , $root = '' ){
if ( ! $root ){
$view = OC_Filesystem :: getView ();
} else {
$view = new OC_FilesystemView (( $root == '/' ) ? '' : $root );
}
2012-02-05 04:25:36 +04:00
//check for removed files, not using getFolderContent to prevent loops
$parent = self :: getFileId ( $view -> getRoot () . $path );
$query = OC_DB :: prepare ( 'SELECT name FROM *PREFIX*fscache WHERE parent=?' );
$result = $query -> execute ( array ( $parent ));
2012-02-09 00:25:20 +04:00
while ( $row = $result -> fetchRow ()){
2012-02-05 04:25:36 +04:00
$file = $path . '/' . $row [ 'name' ];
if ( ! $view -> file_exists ( $file )){
if ( ! $root ){ //filesystem hooks are only valid for the default root
OC_Hook :: emit ( 'OC_Filesystem' , 'post_delete' , array ( 'path' => $file ));
} else {
self :: fileSystemWatcherDelete ( array ( 'path' => $file ), $root );
}
}
}
}
2012-03-30 21:44:38 +04:00
/**
* clean old pre - path_hash entries
*/
public static function clean (){
$query = OC_DB :: prepare ( 'DELETE FROM *PREFIX*fscache WHERE LENGTH(path_hash)<30' );
$query -> execute ();
}
2011-11-09 21:41:57 +04:00
}
//watch for changes and try to keep the cache up to date
OC_Hook :: connect ( 'OC_Filesystem' , 'post_write' , 'OC_FileCache' , 'fileSystemWatcherWrite' );
2012-02-05 04:25:36 +04:00
OC_Hook :: connect ( 'OC_Filesystem' , 'post_delete' , 'OC_FileCache' , 'fileSystemWatcherDelete' );
OC_Hook :: connect ( 'OC_Filesystem' , 'post_rename' , 'OC_FileCache' , 'fileSystemWatcherRename' );