2010-05-08 00:50:59 +04:00
< ? php
/**
* ownCloud
*
* @ author Frank Karlitschek
* @ copyright 2010 Frank Karlitschek karlitschek @ kde . org
*
* 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 .
*
2011-02-09 17:50:27 +03:00
* You should have received a copy of the GNU Affero General Public
2010-05-08 00:50:59 +04:00
* License along with this library . If not , see < http :// www . gnu . org / licenses />.
*
*/
/**
* Class for abstraction of filesystem functions
* This class won ' t call any filesystem functions for itself but but will pass them to the correct OC_FILESTORAGE object
* this class should also handle all the file premission related stuff
2011-04-18 14:16:47 +04:00
*
* Hooks provided :
* read ( path )
* write ( path )
* create ( path ) ( when a file is created both , write and create will be emited )
* delete ( path )
* rename ( oldpath , newpath )
2010-05-08 00:50:59 +04:00
*/
class OC_FILESYSTEM {
static private $storages = array ();
2010-09-02 22:47:15 +04:00
static private $fakeRoot = '' ;
2010-09-06 22:02:17 +04:00
static private $storageTypes = array ();
/**
* register a storage type
* @ param string type
* @ param string classname
* @ param array arguments an associative array in the form of name => type ( eg array ( 'datadir' => 'string' ))
*/
static public function registerStorageType ( $type , $classname , $arguments ){
self :: $storageTypes [ $type ] = array ( 'type' => $type , 'classname' => $classname , 'arguments' => $arguments );
}
/**
* check if the filesystem supports a specific storagetype
* @ param string type
* @ return bool
*/
static public function hasStorageType ( $type ){
return isset ( self :: $storageTypes [ $type ]);
}
/**
* get the list of names of storagetypes that the filesystem supports
* @ return array
*/
static public function getStorageTypeNames (){
return array_keys ( self :: $storageTypes );
}
/**
* create a new storage of a specific type
* @ param string type
* @ param array arguments
* @ return OC_FILESTORAGE
*/
static public function createStorage ( $type , $arguments ){
if ( ! self :: hasStorageType ( $type )){
return false ;
}
$className = self :: $storageTypes [ $type ][ 'classname' ];
if ( class_exists ( $className )){
return new $className ( $arguments );
} else {
return false ;
}
}
2010-09-02 22:47:15 +04:00
/**
* change the root to a fake toor
* @ param string fakeRoot
* @ return bool
*/
static public function chroot ( $fakeRoot ){
if ( $fakeRoot [ 0 ] !== '/' ){
$fakeRoot = '/' . $fakeRoot ;
}
self :: $fakeRoot = $fakeRoot ;
}
/**
* get the part of the path relative to the mountpoint of the storage it ' s stored in
* @ param string path
* @ return bool
*/
static public function getInternalPath ( $path ){
$mountPoint = self :: getMountPoint ( $path );
$path = self :: $fakeRoot . $path ;
$internalPath = substr ( $path , strlen ( $mountPoint ));
return $internalPath ;
}
2010-05-08 00:50:59 +04:00
/**
* check if the current users has the right premissions to read a file
* @ param string path
* @ return bool
*/
2010-06-25 15:24:27 +04:00
static private function canRead ( $path ){
if ( substr ( $path , 0 , 1 ) !== '/' ){
$path = '/' . $path ;
}
2011-01-04 01:46:18 +03:00
if ( strstr ( $path , '/../' ) || strrchr ( $path , '/' ) === '/..' ){
2010-06-25 15:24:27 +04:00
return false ;
}
2010-05-08 00:50:59 +04:00
return true ; //dummy untill premissions are correctly implemented, also the correcty value because for now users are locked in their seperate data dir and can read/write everything in there
}
/**
* check if the current users has the right premissions to write a file
* @ param string path
* @ return bool
*/
2010-06-25 15:24:27 +04:00
static private function canWrite ( $path ){
if ( substr ( $path , 0 , 1 ) !== '/' ){
$path = '/' . $path ;
}
2011-01-04 01:58:49 +03:00
if ( strstr ( $path , '/../' ) || strrchr ( $path , '/' ) === '/..' ){
2010-06-25 15:24:27 +04:00
return false ;
}
2010-05-08 00:50:59 +04:00
return true ; //dummy untill premissions are correctly implemented, also the correcty value because for now users are locked in their seperate data dir and can read/write everything in there
}
/**
* mount an OC_FILESTORAGE in our virtual filesystem
* @ param OC_FILESTORAGE storage
* @ param string mountpoint
*/
static public function mount ( $storage , $mountpoint ){
if ( substr ( $mountpoint , 0 , 1 ) !== '/' ){
$mountpoint = '/' . $mountpoint ;
}
2010-09-02 22:47:15 +04:00
self :: $storages [ self :: $fakeRoot . $mountpoint ] = $storage ;
2010-05-08 00:50:59 +04:00
}
/**
* get the storage object for a path
* @ param string path
* @ return OC_FILESTORAGE
*/
static private function getStorage ( $path ){
$mountpoint = self :: getMountPoint ( $path );
if ( $mountpoint ){
return self :: $storages [ $mountpoint ];
}
}
/**
* get the mountpoint of the storage object for a path
2010-09-02 22:47:15 +04:00
( note : because a storage is not always mounted inside the fakeroot , the returned mountpoint is relative to the absolute root of the filesystem and doesn ' t take the chroot into account
*
2010-05-08 00:50:59 +04:00
* @ param string path
* @ return string
*/
static private function getMountPoint ( $path ){
if ( ! $path ){
$path = '/' ;
}
if ( substr ( $path , 0 , 1 ) !== '/' ){
$path = '/' . $path ;
}
2010-10-04 03:07:55 +04:00
if ( substr ( $path , - 1 ) !== '/' ){
$path = $path . '/' ;
}
2010-09-02 22:47:15 +04:00
$path = self :: $fakeRoot . $path ;
2010-05-08 00:50:59 +04:00
$foundMountPoint = '' ;
foreach ( self :: $storages as $mountpoint => $storage ){
2010-10-04 03:07:55 +04:00
if ( substr ( $mountpoint , - 1 ) !== '/' ){
$mountpoint = $mountpoint . '/' ;
}
2010-05-08 00:50:59 +04:00
if ( $mountpoint == $path ){
return $mountpoint ;
}
if ( strpos ( $path , $mountpoint ) === 0 and strlen ( $mountpoint ) > strlen ( $foundMountPoint )){
$foundMountPoint = $mountpoint ;
}
}
return $foundMountPoint ;
}
2011-04-22 19:50:04 +04:00
/**
* return the path to a local version of the file
* we need this because we can ' t know if a file is stored local or not from outside the filestorage and for some purposes a local file is needed
* @ param string path
* @ return string
*/
static public function getLocalFile ( $path ){
$parent = substr ( $path , 0 , strrpos ( $path , '/' ));
if ( self :: canRead ( $parent ) and $storage = self :: getStorage ( $path )){
return $storage -> getLocalFile ( self :: getInternalPath ( $path ));
}
}
2010-05-08 00:50:59 +04:00
static public function mkdir ( $path ){
$parent = substr ( $path , 0 , strrpos ( $path , '/' ));
if ( self :: canWrite ( $parent ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'create' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> mkdir ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function rmdir ( $path ){
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'delete' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> rmdir ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function opendir ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'read' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> opendir ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function is_dir ( $path ){
if ( $path == '/' ){
return true ;
}
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> is_dir ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function is_file ( $path ){
if ( $path == '/' ){
return false ;
}
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> is_file ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function stat ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> stat ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function filetype ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> filetype ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function filesize ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> filesize ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function readfile ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'read' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> readfile ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function is_readable ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> is_readable ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
return false ;
}
static public function is_writeable ( $path ){
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> is_writeable ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
return false ;
}
static public function file_exists ( $path ){
if ( $path == '/' ){
return true ;
}
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> file_exists ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
return false ;
}
static public function filectime ( $path ){
if ( $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> filectime ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function filemtime ( $path ){
if ( $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> filemtime ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function fileatime ( $path ){
if ( $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> fileatime ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function file_get_contents ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'read' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> file_get_contents ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
2010-07-07 14:30:30 +04:00
static public function file_put_contents ( $path , $data ){
2010-05-08 00:50:59 +04:00
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'write' , array ( 'path' => $path ));
if ( ! self :: file_exists ( $path )){
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'create' , array ( 'path' => $path ));
}
2010-10-18 20:21:47 +04:00
return $storage -> file_put_contents ( self :: getInternalPath ( $path ), $data );
2010-05-08 00:50:59 +04:00
}
}
static public function unlink ( $path ){
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'delete' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> unlink ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function rename ( $path1 , $path2 ){
if ( self :: canWrite ( $path1 ) and self :: canWrite ( $path2 )){
$mp1 = self :: getMountPoint ( $path1 );
$mp2 = self :: getMountPoint ( $path2 );
if ( $mp1 == $mp2 ){
if ( $storage = self :: getStorage ( $path1 )){
2010-09-02 22:47:15 +04:00
return $storage -> rename ( self :: getInternalPath ( $path1 ), self :: getInternalPath ( $path2 ));
2010-05-08 00:50:59 +04:00
}
} elseif ( $storage1 = self :: getStorage ( $path1 ) and $storage2 = self :: getStorage ( $path2 )){
2010-09-02 22:47:15 +04:00
$tmpFile = $storage1 -> toTmpFile ( self :: getInternalPath ( $path1 ));
$result = $storage2 -> fromTmpFile ( self :: getInternalPath ( $path2 ));
$storage1 -> unlink ( self :: getInternalPath ( $path1 ));
2010-05-08 00:50:59 +04:00
return $result ;
}
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'rename' , array ( 'oldpath' => $path1 , 'newpath' => $path2 ));
2010-05-08 00:50:59 +04:00
}
}
static public function copy ( $path1 , $path2 ){
if ( self :: canRead ( $path1 ) and self :: canWrite ( $path2 )){
$mp1 = self :: getMountPoint ( $path1 );
$mp2 = self :: getMountPoint ( $path2 );
if ( $mp1 == $mp2 ){
if ( $storage = self :: getStorage ( $path1 )){
2010-09-02 22:47:15 +04:00
return $storage -> copy ( self :: getInternalPath ( $path1 ), self :: getInternalPath ( $path2 ));
2010-05-08 00:50:59 +04:00
}
} elseif ( $storage1 = self :: getStorage ( $path1 ) and $storage2 = self :: getStorage ( $path2 )){
2010-09-02 22:47:15 +04:00
$tmpFile = $storage1 -> toTmpFile ( self :: getInternalPath ( $path1 ));
return $storage2 -> fromTmpFile ( self :: getInternalPath ( $path2 ));
2010-05-08 00:50:59 +04:00
}
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'create' , array ( 'path' => $path2 ));
2010-05-08 00:50:59 +04:00
}
}
static public function fopen ( $path , $mode ){
$allowed = (( strpos ( $path , 'r' ) === false and strpos ( $path , 'r+' ) !== false and self :: canRead ) or self :: canWrite ( $path ));
if ( $allowed ){
if ( $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
switch ( $mode ){
case 'r' :
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'read' , array ( 'path' => $path ));
break ;
case 'r+' :
case 'w+' :
case 'x+' :
case 'a+' :
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'read' , array ( 'path' => $path ));
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'write' , array ( 'path' => $path ));
if ( ! self :: file_exists ( $path )){
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'create' , array ( 'path' => $path ));
}
break ;
case 'w' :
case 'x' :
case 'a' :
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'write' , array ( 'path' => $path ));
if ( ! self :: file_exists ( $path )){
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'create' , array ( 'path' => $path ));
}
break ;
}
2010-09-02 22:47:15 +04:00
return $storage -> fopen ( self :: getInternalPath ( $path ), $mode );
2010-05-08 00:50:59 +04:00
}
}
}
static public function toTmpFile ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'read' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> toTmpFile ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function fromTmpFile ( $tmpFile , $path ){
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'write' , array ( 'path' => $path ));
if ( ! self :: file_exists ( $path )){
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'create' , array ( 'path' => $path ));
}
2010-09-06 19:59:35 +04:00
return $storage -> fromTmpFile ( $tmpFile , self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
2011-04-17 03:17:34 +04:00
static public function fromUploadedFile ( $tmpFile , $path ){
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'write' , array ( 'path' => $path ));
if ( ! self :: file_exists ( $path )){
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'create' , array ( 'path' => $path ));
}
2011-04-17 03:17:34 +04:00
return $storage -> fromUploadedFile ( $tmpFile , self :: getInternalPath ( $path ));
}
}
2010-05-08 00:50:59 +04:00
static public function getMimeType ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2010-09-02 22:47:15 +04:00
return $storage -> getMimeType ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function delTree ( $path ){
if ( self :: canWrite ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'delete' , array ( 'path' => $path ));
2010-09-02 22:47:15 +04:00
return $storage -> delTree ( self :: getInternalPath ( $path ));
2010-05-08 00:50:59 +04:00
}
}
static public function find ( $path ){
if ( $storage = self :: getStorage ( $path )){
2010-05-23 00:08:08 +04:00
$mp = self :: getMountPoint ( $path );
2010-09-02 22:47:15 +04:00
$return = $storage -> find ( self :: getInternalPath ( $path ));
2010-05-23 00:08:08 +04:00
foreach ( $return as & $file ){
$file = $mp . $file ;
}
2010-05-08 00:50:59 +04:00
}
2010-05-23 00:08:08 +04:00
return $return ;
2010-05-08 00:50:59 +04:00
}
2010-07-04 20:08:35 +04:00
static public function getTree ( $path ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
$mp = self :: getMountPoint ( $path );
2010-09-02 22:47:15 +04:00
$return = $storage -> getTree ( self :: getInternalPath ( $path ));
2010-07-04 20:08:35 +04:00
foreach ( $return as & $file ){
if ( substr ( $file , 0 , 1 ) == '/' ){
$file = substr ( $file , 1 );
}
$file = $mp . $file ;
2010-09-29 01:07:13 +04:00
$file = substr ( $file , strlen ( self :: $fakeRoot ));
2011-01-04 19:42:57 +03:00
if ( $file === '' || $file === false ){
$file = '/' ;
}
2010-07-04 20:08:35 +04:00
}
return $return ;
}
}
2011-03-16 19:28:01 +03:00
static public function hash ( $type , $path , $raw = false ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
2011-04-18 14:16:47 +04:00
OC_HOOK :: emit ( 'OC_FILESYSTEM' , 'read' , array ( 'path' => $path ));
2011-03-16 19:28:01 +03:00
return $storage -> hash ( $type , self :: getInternalPath ( $path ), $raw );
}
}
2011-04-17 18:40:44 +04:00
static public function free_space ( $path = '/' ){
if ( self :: canRead ( $path ) and $storage = self :: getStorage ( $path )){
return $storage -> free_space ( $path );
}
}
2011-04-24 18:09:07 +04:00
static public function search ( $query ){
$files = array ();
$fakeRootLength = strlen ( self :: $fakeRoot );
foreach ( self :: $storages as $mountpoint => $storage ){
$results = $storage -> search ( $query );
foreach ( $results as $result ){
$file = str_replace ( '//' , '/' , $mountpoint . $result );
$file = substr ( $file , $fakeRootLength );
$files [] = $file ;
}
}
return $files ;
}
2010-05-08 00:50:59 +04:00
}
?>