2012-01-20 03:40:52 +04:00
< ? php
/**
2012-10-10 13:54:44 +04:00
* Copyright ( c ) 2012 Robin Appelman < icewind @ owncloud . com >
* This file is licensed under the Affero General Public License version 3 or
* later .
* See the COPYING - README file .
2012-05-31 20:02:35 +04:00
*/
/**
2012-07-21 23:44:10 +04:00
* Class to provide access to ownCloud filesystem via a " view " , and methods for
* working with files within that view ( e . g . read , write , delete , etc . ) . Each
* view is restricted to a set of directories via a virtual root . The default view
* uses the currently logged in user ' s data directory as root ( parts of
2012-05-31 20:32:34 +04:00
* OC_Filesystem are merely a wrapper for OC_FilesystemView ) .
2012-07-21 23:44:10 +04:00
*
2012-05-31 20:32:34 +04:00
* Apps that need to access files outside of the user data folders ( to modify files
* belonging to a user other than the one currently logged in , for example ) should
* use this class directly rather than using OC_Filesystem , or making use of PHP ' s
2012-07-21 23:44:10 +04:00
* built - in file manipulation functions . This will ensure all hooks and proxies
2012-05-31 20:32:34 +04:00
* are triggered correctly .
2012-05-31 20:57:34 +04:00
*
2012-07-21 23:44:10 +04:00
* Filesystem functions are not called directly ; they are passed to the correct
2012-09-07 20:30:48 +04:00
* \OC\Files\Storage\Storage object
2012-05-31 20:02:35 +04:00
*/
2012-01-20 03:40:52 +04:00
2012-10-10 13:54:44 +04:00
namespace OC\Files ;
class View {
private $fakeRoot = '' ;
private $internal_path_cache = array ();
private $storage_cache = array ();
2012-03-27 04:24:52 +04:00
2012-07-21 23:44:10 +04:00
public function __construct ( $root ) {
2012-10-10 13:54:44 +04:00
$this -> fakeRoot = $root ;
2012-01-20 03:40:52 +04:00
}
2012-03-27 04:24:52 +04:00
2012-11-07 20:18:56 +04:00
public function getAbsolutePath ( $path = '/' ) {
2012-10-10 13:54:44 +04:00
if ( ! $path ) {
$path = '/' ;
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
if ( $path [ 0 ] !== '/' ) {
$path = '/' . $path ;
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
return $this -> fakeRoot . $path ;
2012-01-20 03:40:52 +04:00
}
2012-08-29 10:38:33 +04:00
2012-01-20 03:40:52 +04:00
/**
2012-10-10 14:25:46 +04:00
* change the root to a fake root
2012-10-10 13:54:44 +04:00
*
2012-10-10 14:25:46 +04:00
* @ param string $fakeRoot
2012-10-10 13:54:44 +04:00
* @ return bool
*/
2012-07-21 23:44:10 +04:00
public function chroot ( $fakeRoot ) {
2012-10-10 13:54:44 +04:00
if ( ! $fakeRoot == '' ) {
if ( $fakeRoot [ 0 ] !== '/' ) {
$fakeRoot = '/' . $fakeRoot ;
2012-01-20 03:40:52 +04:00
}
}
2012-10-10 13:54:44 +04:00
$this -> fakeRoot = $fakeRoot ;
2012-01-20 03:40:52 +04:00
}
/**
* get the fake root
2012-10-10 13:54:44 +04:00
*
2012-01-20 03:40:52 +04:00
* @ return string
*/
2012-07-21 23:44:10 +04:00
public function getRoot () {
2012-01-20 03:40:52 +04:00
return $this -> fakeRoot ;
}
2012-06-09 19:33:57 +04:00
/**
* get path relative to the root of the view
2012-10-10 13:54:44 +04:00
*
2012-10-10 14:25:46 +04:00
* @ param string $path
2012-06-09 19:33:57 +04:00
* @ return string
*/
2012-07-21 23:44:10 +04:00
public function getRelativePath ( $path ) {
2012-10-10 13:54:44 +04:00
if ( $this -> fakeRoot == '' ) {
2012-06-09 19:33:57 +04:00
return $path ;
}
2012-10-10 13:54:44 +04:00
if ( strpos ( $path , $this -> fakeRoot ) !== 0 ) {
2012-06-09 19:33:57 +04:00
return null ;
2012-10-10 13:54:44 +04:00
} else {
$path = substr ( $path , strlen ( $this -> fakeRoot ));
if ( strlen ( $path ) === 0 ) {
2012-08-14 05:07:14 +04:00
return '/' ;
2012-10-10 13:54:44 +04:00
} else {
2012-08-14 05:07:14 +04:00
return $path ;
}
2012-06-09 19:33:57 +04:00
}
}
2012-07-21 23:44:10 +04:00
2012-01-20 03:40:52 +04:00
/**
2012-10-10 13:54:44 +04:00
* get the mountpoint of the storage object for a path
2012-01-20 03:40:52 +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
2012-10-10 13:54:44 +04:00
*
2012-10-10 14:25:46 +04:00
* @ param string $path
2012-10-10 13:54:44 +04:00
* @ return string
*/
2012-07-21 23:44:10 +04:00
public function getMountPoint ( $path ) {
2012-10-10 14:25:46 +04:00
return Filesystem :: getMountPoint ( $this -> getAbsolutePath ( $path ));
2012-01-20 03:40:52 +04:00
}
2012-11-08 20:42:26 +04:00
/**
* resolve a path to a storage and internal path
*
* @ param string $path
* @ return array consisting of the storage and the internal path
*/
public function resolvePath ( $path ) {
return Filesystem :: resolvePath ( $this -> getAbsolutePath ( $path ));
}
2012-01-20 03:40:52 +04:00
/**
2012-10-10 13:54:44 +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
*
2012-10-10 14:25:46 +04:00
* @ param string $path
2012-10-10 13:54:44 +04:00
* @ return string
*/
2012-07-21 23:44:10 +04:00
public function getLocalFile ( $path ) {
2012-10-10 13:54:44 +04:00
$parent = substr ( $path , 0 , strrpos ( $path , '/' ));
2012-10-27 14:17:35 +04:00
$path = $this -> getAbsolutePath ( $path );
2012-10-26 15:23:15 +04:00
list ( $storage , $internalPath ) = Filesystem :: resolvePath ( $path );
2012-10-10 19:46:29 +04:00
if ( Filesystem :: isValidPath ( $parent ) and $storage ) {
return $storage -> getLocalFile ( $internalPath );
2012-10-10 14:25:46 +04:00
} else {
return null ;
2012-01-20 03:40:52 +04:00
}
}
2012-10-10 13:54:44 +04:00
2012-08-19 04:42:15 +04:00
/**
2012-10-10 14:25:46 +04:00
* @ param string $path
2012-08-19 04:42:15 +04:00
* @ return string
*/
public function getLocalFolder ( $path ) {
2012-10-10 13:54:44 +04:00
$parent = substr ( $path , 0 , strrpos ( $path , '/' ));
2012-10-27 14:17:35 +04:00
$path = $this -> getAbsolutePath ( $path );
2012-10-26 15:23:15 +04:00
list ( $storage , $internalPath ) = Filesystem :: resolvePath ( $path );
2012-10-10 19:46:29 +04:00
if ( Filesystem :: isValidPath ( $parent ) and $storage ) {
return $storage -> getLocalFolder ( $internalPath );
2012-10-10 14:25:46 +04:00
} else {
return null ;
2012-08-19 04:42:15 +04:00
}
}
2012-01-20 03:40:52 +04:00
/**
2012-07-21 23:44:10 +04:00
* the following functions operate with arguments and return values identical
* to those of their PHP built - in equivalents . Mostly they are merely wrappers
2012-09-07 20:30:48 +04:00
* for \OC\Files\Storage\Storage via basicOperation () .
2012-01-20 03:40:52 +04:00
*/
2012-07-21 23:44:10 +04:00
public function mkdir ( $path ) {
return $this -> basicOperation ( 'mkdir' , $path , array ( 'create' , 'write' ));
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function rmdir ( $path ) {
return $this -> basicOperation ( 'rmdir' , $path , array ( 'delete' ));
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function opendir ( $path ) {
return $this -> basicOperation ( 'opendir' , $path , array ( 'read' ));
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function readdir ( $handle ) {
2012-10-26 15:23:15 +04:00
$fsLocal = new Storage\Local ( array ( 'datadir' => '/' ));
2012-10-10 13:54:44 +04:00
return $fsLocal -> readdir ( $handle );
2012-06-19 22:42:40 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function is_dir ( $path ) {
2012-10-10 13:54:44 +04:00
if ( $path == '/' ) {
2012-01-20 03:40:52 +04:00
return true ;
}
2012-07-21 23:44:10 +04:00
return $this -> basicOperation ( 'is_dir' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function is_file ( $path ) {
2012-10-10 13:54:44 +04:00
if ( $path == '/' ) {
2012-01-20 03:40:52 +04:00
return false ;
}
2012-07-21 23:44:10 +04:00
return $this -> basicOperation ( 'is_file' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function stat ( $path ) {
return $this -> basicOperation ( 'stat' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function filetype ( $path ) {
return $this -> basicOperation ( 'filetype' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function filesize ( $path ) {
return $this -> basicOperation ( 'filesize' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function readfile ( $path ) {
2012-04-25 02:09:14 +04:00
@ ob_end_clean ();
2012-10-10 13:54:44 +04:00
$handle = $this -> fopen ( $path , 'rb' );
2012-04-01 10:38:26 +04:00
if ( $handle ) {
2012-10-10 13:54:44 +04:00
$chunkSize = 8192 ; // 8 MB chunks
2012-04-01 10:38:26 +04:00
while ( ! feof ( $handle )) {
echo fread ( $handle , $chunkSize );
flush ();
}
2012-10-10 13:54:44 +04:00
$size = $this -> filesize ( $path );
2012-04-25 02:09:14 +04:00
return $size ;
2012-02-26 06:54:21 +04:00
}
2012-04-01 10:38:26 +04:00
return false ;
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-25 01:42:07 +04:00
public function isCreatable ( $path ) {
return $this -> basicOperation ( 'isCreatable' , $path );
}
2012-10-10 13:54:44 +04:00
2012-07-25 01:42:07 +04:00
public function isReadable ( $path ) {
return $this -> basicOperation ( 'isReadable' , $path );
}
2012-10-10 13:54:44 +04:00
2012-07-25 01:42:07 +04:00
public function isUpdatable ( $path ) {
return $this -> basicOperation ( 'isUpdatable' , $path );
}
2012-10-10 13:54:44 +04:00
2012-07-25 01:42:07 +04:00
public function isDeletable ( $path ) {
return $this -> basicOperation ( 'isDeletable' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-25 01:42:07 +04:00
public function isSharable ( $path ) {
return $this -> basicOperation ( 'isSharable' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function file_exists ( $path ) {
2012-10-10 13:54:44 +04:00
if ( $path == '/' ) {
2012-01-20 03:40:52 +04:00
return true ;
}
2012-07-21 23:44:10 +04:00
return $this -> basicOperation ( 'file_exists' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function filemtime ( $path ) {
return $this -> basicOperation ( 'filemtime' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
public function touch ( $path , $mtime = null ) {
2012-10-23 18:34:58 +04:00
if ( ! is_null ( $mtime ) and ! is_numeric ( $mtime )) {
$mtime = strtotime ( $mtime );
}
2012-02-14 12:59:54 +04:00
return $this -> basicOperation ( 'touch' , $path , array ( 'write' ), $mtime );
2012-02-10 14:30:38 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function file_get_contents ( $path ) {
return $this -> basicOperation ( 'file_get_contents' , $path , array ( 'read' ));
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function file_put_contents ( $path , $data ) {
2012-10-10 13:54:44 +04:00
if ( is_resource ( $data )) { //not having to deal with streams in file_put_contents makes life easier
2012-10-10 14:25:46 +04:00
$absolutePath = Filesystem :: normalizePath ( $this -> getAbsolutePath ( $path ));
if ( \OC_FileProxy :: runPreProxies ( 'file_put_contents' , $absolutePath , $data ) && Filesystem :: isValidPath ( $path )) {
2012-07-27 06:53:55 +04:00
$path = $this -> getRelativePath ( $absolutePath );
$exists = $this -> file_exists ( $path );
$run = true ;
2012-10-10 14:25:46 +04:00
if ( $this -> fakeRoot == Filesystem :: getRoot ()) {
2012-10-10 13:54:44 +04:00
if ( ! $exists ) {
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_create ,
2012-09-18 00:12:17 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_path => $path ,
Filesystem :: signal_param_run => & $run
2012-09-18 00:12:17 +04:00
)
);
}
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_write ,
2012-07-27 06:53:55 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_path => $path ,
Filesystem :: signal_param_run => & $run
2012-07-27 06:53:55 +04:00
)
);
}
2012-10-10 13:54:44 +04:00
if ( ! $run ) {
2012-07-27 06:53:55 +04:00
return false ;
}
2012-10-10 13:54:44 +04:00
$target = $this -> fopen ( $path , 'w' );
if ( $target ) {
2012-10-10 14:25:46 +04:00
$count = \OC_Helper :: streamCopy ( $data , $target );
2012-07-27 06:53:55 +04:00
fclose ( $target );
fclose ( $data );
2012-10-10 14:25:46 +04:00
if ( $this -> fakeRoot == Filesystem :: getRoot ()) {
2012-10-10 13:54:44 +04:00
if ( ! $exists ) {
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_post_create ,
array ( Filesystem :: signal_param_path => $path )
2012-09-18 00:12:17 +04:00
);
}
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_post_write ,
array ( Filesystem :: signal_param_path => $path )
2012-07-27 06:53:55 +04:00
);
}
2012-10-10 14:25:46 +04:00
\OC_FileProxy :: runPostProxies ( 'file_put_contents' , $absolutePath , $count );
2012-07-27 06:53:55 +04:00
return $count > 0 ;
2012-10-10 13:54:44 +04:00
} else {
2012-07-27 06:53:55 +04:00
return false ;
2012-04-25 02:09:14 +04:00
}
2012-10-10 14:25:46 +04:00
} else {
return false ;
2012-02-15 19:23:00 +04:00
}
2012-10-10 13:54:44 +04:00
} else {
2012-07-21 23:44:10 +04:00
return $this -> basicOperation ( 'file_put_contents' , $path , array ( 'create' , 'write' ), $data );
2012-02-15 19:23:00 +04:00
}
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function unlink ( $path ) {
return $this -> basicOperation ( 'unlink' , $path , array ( 'delete' ));
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
public function deleteAll ( $directory , $empty = false ) {
return $this -> basicOperation ( 'deleteAll' , $directory , array ( 'delete' ), $empty );
2012-06-21 21:07:21 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function rename ( $path1 , $path2 ) {
2012-10-10 13:54:44 +04:00
$postFix1 = ( substr ( $path1 , - 1 , 1 ) === '/' ) ? '/' : '' ;
$postFix2 = ( substr ( $path2 , - 1 , 1 ) === '/' ) ? '/' : '' ;
2012-10-10 14:25:46 +04:00
$absolutePath1 = Filesystem :: normalizePath ( $this -> getAbsolutePath ( $path1 ));
$absolutePath2 = Filesystem :: normalizePath ( $this -> getAbsolutePath ( $path2 ));
if ( \OC_FileProxy :: runPreProxies ( 'rename' , $absolutePath1 , $absolutePath2 ) and Filesystem :: isValidPath ( $path2 )) {
2012-07-21 23:44:10 +04:00
$path1 = $this -> getRelativePath ( $absolutePath1 );
$path2 = $this -> getRelativePath ( $absolutePath2 );
2012-08-29 10:38:33 +04:00
2012-10-10 13:54:44 +04:00
if ( $path1 == null or $path2 == null ) {
2012-06-09 19:33:57 +04:00
return false ;
}
2012-10-10 13:54:44 +04:00
$run = true ;
2012-10-10 14:25:46 +04:00
if ( $this -> fakeRoot == Filesystem :: getRoot ()) {
\OC_Hook :: emit (
Filesystem :: CLASSNAME , Filesystem :: signal_rename ,
2012-10-10 13:54:44 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_oldpath => $path1 ,
Filesystem :: signal_param_newpath => $path2 ,
Filesystem :: signal_param_run => & $run
2012-10-10 13:54:44 +04:00
)
2012-09-18 00:12:17 +04:00
);
}
2012-10-10 13:54:44 +04:00
if ( $run ) {
$mp1 = $this -> getMountPoint ( $path1 . $postFix1 );
$mp2 = $this -> getMountPoint ( $path2 . $postFix2 );
if ( $mp1 == $mp2 ) {
2012-10-27 14:17:35 +04:00
list ( $storage , $internalPath1 ) = Filesystem :: resolvePath ( $absolutePath1 . $postFix1 );
list (, $internalPath2 ) = Filesystem :: resolvePath ( $absolutePath2 . $postFix2 );
2012-10-10 19:46:29 +04:00
if ( $storage ) {
$result = $storage -> rename ( $internalPath1 , $internalPath2 );
2012-10-10 14:25:46 +04:00
} else {
$result = false ;
2012-01-20 03:40:52 +04:00
}
2012-07-21 23:44:10 +04:00
} else {
2012-10-10 13:54:44 +04:00
$source = $this -> fopen ( $path1 . $postFix1 , 'r' );
$target = $this -> fopen ( $path2 . $postFix2 , 'w' );
2012-10-10 14:25:46 +04:00
$count = \OC_Helper :: streamCopy ( $source , $target );
2012-10-27 14:17:35 +04:00
list ( $storage1 , $internalPath1 ) = Filesystem :: resolvePath ( $absolutePath1 . $postFix1 );
2012-10-10 19:46:29 +04:00
$storage1 -> unlink ( $internalPath1 );
2012-10-10 13:54:44 +04:00
$result = $count > 0 ;
2012-08-29 10:38:33 +04:00
}
2012-10-10 14:25:46 +04:00
if ( $this -> fakeRoot == Filesystem :: getRoot ()) {
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_post_rename ,
2012-09-18 00:12:17 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_oldpath => $path1 ,
Filesystem :: signal_param_newpath => $path2
2012-09-18 00:12:17 +04:00
)
);
}
2012-01-20 03:40:52 +04:00
return $result ;
2012-10-10 14:25:46 +04:00
} else {
return false ;
2012-01-20 03:40:52 +04:00
}
2012-10-10 14:25:46 +04:00
} else {
return false ;
2012-01-20 03:40:52 +04:00
}
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function copy ( $path1 , $path2 ) {
2012-10-10 13:54:44 +04:00
$postFix1 = ( substr ( $path1 , - 1 , 1 ) === '/' ) ? '/' : '' ;
$postFix2 = ( substr ( $path2 , - 1 , 1 ) === '/' ) ? '/' : '' ;
2012-10-10 14:25:46 +04:00
$absolutePath1 = Filesystem :: normalizePath ( $this -> getAbsolutePath ( $path1 ));
$absolutePath2 = Filesystem :: normalizePath ( $this -> getAbsolutePath ( $path2 ));
if ( \OC_FileProxy :: runPreProxies ( 'copy' , $absolutePath1 , $absolutePath2 ) and Filesystem :: isValidPath ( $path2 )) {
2012-07-21 23:44:10 +04:00
$path1 = $this -> getRelativePath ( $absolutePath1 );
$path2 = $this -> getRelativePath ( $absolutePath2 );
2012-08-29 10:38:33 +04:00
2012-10-10 13:54:44 +04:00
if ( $path1 == null or $path2 == null ) {
2012-06-09 19:33:57 +04:00
return false ;
}
2012-10-10 13:54:44 +04:00
$run = true ;
2012-10-10 14:25:46 +04:00
$exists = $this -> file_exists ( $path2 );
if ( $this -> fakeRoot == Filesystem :: getRoot ()) {
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_copy ,
2012-07-21 23:44:10 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_oldpath => $path1 ,
Filesystem :: signal_param_newpath => $path2 ,
Filesystem :: signal_param_run => & $run
2012-07-21 23:44:10 +04:00
)
);
2012-10-10 13:54:44 +04:00
if ( $run and ! $exists ) {
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_create ,
2012-09-18 00:12:17 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_path => $path2 ,
Filesystem :: signal_param_run => & $run
2012-09-18 00:12:17 +04:00
)
);
}
2012-10-10 13:54:44 +04:00
if ( $run ) {
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_write ,
2012-09-18 00:12:17 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_path => $path2 ,
Filesystem :: signal_param_run => & $run
2012-09-18 00:12:17 +04:00
)
);
}
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
if ( $run ) {
$mp1 = $this -> getMountPoint ( $path1 . $postFix1 );
$mp2 = $this -> getMountPoint ( $path2 . $postFix2 );
if ( $mp1 == $mp2 ) {
2012-10-27 14:17:35 +04:00
list ( $storage , $internalPath1 ) = Filesystem :: resolvePath ( $absolutePath1 . $postFix1 );
list (, $internalPath2 ) = Filesystem :: resolvePath ( $absolutePath2 . $postFix2 );
2012-10-10 19:46:29 +04:00
if ( $storage ) {
$result = $storage -> copy ( $internalPath1 , $internalPath2 );
2012-10-10 14:25:46 +04:00
} else {
$result = false ;
2012-01-20 03:40:52 +04:00
}
2012-07-21 23:44:10 +04:00
} else {
2012-10-10 13:54:44 +04:00
$source = $this -> fopen ( $path1 . $postFix1 , 'r' );
$target = $this -> fopen ( $path2 . $postFix2 , 'w' );
2012-10-10 14:25:46 +04:00
$result = \OC_Helper :: streamCopy ( $source , $target );
2012-01-20 03:40:52 +04:00
}
2012-10-10 14:25:46 +04:00
if ( $this -> fakeRoot == Filesystem :: getRoot ()) {
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_post_copy ,
2012-09-18 00:12:17 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_oldpath => $path1 ,
Filesystem :: signal_param_newpath => $path2
2012-09-18 00:12:17 +04:00
)
);
2012-10-10 13:54:44 +04:00
if ( ! $exists ) {
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_post_create ,
array ( Filesystem :: signal_param_path => $path2 )
2012-09-18 00:12:17 +04:00
);
}
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_post_write ,
array ( Filesystem :: signal_param_path => $path2 )
2012-07-21 23:44:10 +04:00
);
2012-09-28 20:47:54 +04:00
} else { // no real copy, file comes from somewhere else, e.g. version rollback -> just update the file cache and the webdav properties without all the other post_write actions
2012-10-10 14:25:46 +04:00
Filesystem :: removeETagHook ( array ( " path " => $path2 ), $this -> fakeRoot );
2012-01-20 03:40:52 +04:00
}
return $result ;
2012-10-10 14:25:46 +04:00
} else {
return false ;
2012-01-20 03:40:52 +04:00
}
2012-10-10 14:25:46 +04:00
} else {
return false ;
2012-01-20 03:40:52 +04:00
}
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function fopen ( $path , $mode ) {
2012-10-10 13:54:44 +04:00
$hooks = array ();
switch ( $mode ) {
2012-01-20 03:40:52 +04:00
case 'r' :
2012-02-26 18:32:58 +04:00
case 'rb' :
2012-10-10 13:54:44 +04:00
$hooks [] = 'read' ;
2012-01-20 03:40:52 +04:00
break ;
case 'r+' :
2012-02-26 18:32:58 +04:00
case 'rb+' :
2012-01-20 03:40:52 +04:00
case 'w+' :
2012-02-26 18:32:58 +04:00
case 'wb+' :
2012-01-20 03:40:52 +04:00
case 'x+' :
2012-02-26 18:32:58 +04:00
case 'xb+' :
2012-01-20 03:40:52 +04:00
case 'a+' :
2012-02-26 18:32:58 +04:00
case 'ab+' :
2012-10-10 13:54:44 +04:00
$hooks [] = 'read' ;
$hooks [] = 'write' ;
2012-01-20 03:40:52 +04:00
break ;
case 'w' :
2012-02-26 18:32:58 +04:00
case 'wb' :
2012-01-20 03:40:52 +04:00
case 'x' :
2012-02-26 18:32:58 +04:00
case 'xb' :
2012-01-20 03:40:52 +04:00
case 'a' :
2012-02-26 18:32:58 +04:00
case 'ab' :
2012-10-10 13:54:44 +04:00
$hooks [] = 'write' ;
2012-01-20 03:40:52 +04:00
break ;
default :
2012-10-10 14:25:46 +04:00
\OC_Log :: write ( 'core' , 'invalid mode (' . $mode . ') for ' . $path , \OC_Log :: ERROR );
2012-01-20 03:40:52 +04:00
}
2012-07-21 23:44:10 +04:00
return $this -> basicOperation ( 'fopen' , $path , $hooks , $mode );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function toTmpFile ( $path ) {
2012-10-10 14:25:46 +04:00
if ( Filesystem :: isValidPath ( $path )) {
2012-07-21 23:44:10 +04:00
$source = $this -> fopen ( $path , 'r' );
2012-10-10 13:54:44 +04:00
if ( $source ) {
$extension = '' ;
$extOffset = strpos ( $path , '.' );
if ( $extOffset !== false ) {
$extension = substr ( $path , strrpos ( $path , '.' ));
2012-04-14 01:01:37 +04:00
}
2012-10-10 14:25:46 +04:00
$tmpFile = \OC_Helper :: tmpFile ( $extension );
2012-07-21 23:44:10 +04:00
file_put_contents ( $tmpFile , $source );
2012-03-27 04:24:52 +04:00
return $tmpFile ;
2012-10-10 14:25:46 +04:00
} else {
return false ;
2012-02-11 18:48:31 +04:00
}
2012-10-10 14:25:46 +04:00
} else {
return false ;
2012-01-20 03:40:52 +04:00
}
}
2012-10-10 13:54:44 +04:00
2012-07-21 23:44:10 +04:00
public function fromTmpFile ( $tmpFile , $path ) {
2012-10-10 14:25:46 +04:00
if ( Filesystem :: isValidPath ( $path )) {
2012-10-10 13:54:44 +04:00
if ( ! $tmpFile ) {
2012-02-21 23:48:14 +04:00
debug_print_backtrace ();
}
2012-10-10 13:54:44 +04:00
$source = fopen ( $tmpFile , 'r' );
if ( $source ) {
2012-07-21 23:44:10 +04:00
$this -> file_put_contents ( $path , $source );
2012-02-11 18:48:31 +04:00
unlink ( $tmpFile );
return true ;
2012-07-21 23:44:10 +04:00
} else {
2012-10-10 14:25:46 +04:00
return false ;
2012-01-20 03:40:52 +04:00
}
2012-07-21 23:44:10 +04:00
} else {
2012-02-21 23:48:14 +04:00
return false ;
2012-01-20 03:40:52 +04:00
}
}
2012-07-21 23:44:10 +04:00
public function getMimeType ( $path ) {
return $this -> basicOperation ( 'getMimeType' , $path );
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
2012-07-26 00:54:46 +04:00
public function hash ( $type , $path , $raw = false ) {
2012-10-10 13:54:44 +04:00
$postFix = ( substr ( $path , - 1 , 1 ) === '/' ) ? '/' : '' ;
2012-10-10 14:25:46 +04:00
$absolutePath = Filesystem :: normalizePath ( $this -> getAbsolutePath ( $path ));
if ( \OC_FileProxy :: runPreProxies ( 'hash' , $absolutePath ) && Filesystem :: isValidPath ( $path )) {
2012-07-26 00:54:46 +04:00
$path = $this -> getRelativePath ( $absolutePath );
if ( $path == null ) {
return false ;
}
2012-10-10 14:25:46 +04:00
if ( Filesystem :: $loaded && $this -> fakeRoot == Filesystem :: getRoot ()) {
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
Filesystem :: signal_read ,
array ( Filesystem :: signal_param_path => $path )
2012-07-26 00:54:46 +04:00
);
}
2012-10-27 14:17:35 +04:00
list ( $storage , $internalPath ) = Filesystem :: resolvePath ( $absolutePath . $postFix );
2012-10-10 19:46:29 +04:00
if ( $storage ) {
$result = $storage -> hash ( $type , $internalPath , $raw );
2012-10-10 14:25:46 +04:00
$result = \OC_FileProxy :: runPostProxies ( 'hash' , $absolutePath , $result );
2012-07-26 00:54:46 +04:00
return $result ;
}
}
return null ;
2012-01-20 03:40:52 +04:00
}
2012-10-10 13:54:44 +04:00
public function free_space ( $path = '/' ) {
2012-07-21 23:44:10 +04:00
return $this -> basicOperation ( 'free_space' , $path );
2012-01-20 03:40:52 +04:00
}
/**
2012-09-07 20:30:48 +04:00
* @ brief abstraction layer for basic filesystem functions : wrapper for \OC\Files\Storage\Storage
2012-01-20 03:40:52 +04:00
* @ param string $operation
2012-10-10 14:25:46 +04:00
* @ param string $path
* @ param array $hooks ( optional )
* @ param mixed $extraParam ( optional )
2012-01-20 03:40:52 +04:00
* @ return mixed
2012-07-21 23:44:10 +04:00
*
* This method takes requests for basic filesystem functions ( e . g . reading & writing
* files ), processes hooks and proxies , sanitises paths , and finally passes them on to
2012-09-07 20:30:48 +04:00
* \OC\Files\Storage\Storage for delegation to a storage backend for execution
2012-01-20 03:40:52 +04:00
*/
2012-10-10 13:54:44 +04:00
private function basicOperation ( $operation , $path , $hooks = array (), $extraParam = null ) {
$postFix = ( substr ( $path , - 1 , 1 ) === '/' ) ? '/' : '' ;
2012-10-10 14:25:46 +04:00
$absolutePath = Filesystem :: normalizePath ( $this -> getAbsolutePath ( $path ));
if ( \OC_FileProxy :: runPreProxies ( $operation , $absolutePath , $extraParam ) and Filesystem :: isValidPath ( $path )) {
2012-07-21 23:44:10 +04:00
$path = $this -> getRelativePath ( $absolutePath );
2012-10-10 13:54:44 +04:00
if ( $path == null ) {
2012-06-09 19:33:57 +04:00
return false ;
}
2012-10-10 13:54:44 +04:00
$run = $this -> runHooks ( $hooks , $path );
2012-10-27 14:17:35 +04:00
list ( $storage , $internalPath ) = Filesystem :: resolvePath ( $absolutePath . $postFix );
2012-10-10 19:46:29 +04:00
if ( $run and $storage ) {
2012-10-10 13:54:44 +04:00
if ( ! is_null ( $extraParam )) {
2012-07-21 23:44:10 +04:00
$result = $storage -> $operation ( $internalPath , $extraParam );
} else {
$result = $storage -> $operation ( $internalPath );
2012-01-20 03:40:52 +04:00
}
2012-10-10 14:25:46 +04:00
$result = \OC_FileProxy :: runPostProxies ( $operation , $this -> getAbsolutePath ( $path ), $result );
if ( Filesystem :: $loaded and $this -> fakeRoot == Filesystem :: getRoot ()) {
2012-10-10 13:54:44 +04:00
if ( $operation != 'fopen' ) { //no post hooks for fopen, the file stream is still open
$this -> runHooks ( $hooks , $path , true );
2012-01-20 03:40:52 +04:00
}
}
return $result ;
}
}
return null ;
}
2012-06-15 19:42:39 +04:00
2012-10-10 13:54:44 +04:00
private function runHooks ( $hooks , $path , $post = false ) {
$prefix = ( $post ) ? 'post_' : '' ;
$run = true ;
2012-10-10 14:25:46 +04:00
if ( Filesystem :: $loaded and $this -> fakeRoot == Filesystem :: getRoot ()) {
2012-10-10 13:54:44 +04:00
foreach ( $hooks as $hook ) {
if ( $hook != 'read' ) {
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
2012-10-10 13:54:44 +04:00
$prefix . $hook ,
2012-08-17 03:22:26 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_run => & $run ,
Filesystem :: signal_param_path => $path
2012-08-17 03:22:26 +04:00
)
);
2012-10-10 13:54:44 +04:00
} elseif ( ! $post ) {
2012-10-10 14:25:46 +04:00
\OC_Hook :: emit (
Filesystem :: CLASSNAME ,
2012-10-10 13:54:44 +04:00
$prefix . $hook ,
2012-08-17 03:22:26 +04:00
array (
2012-10-10 14:25:46 +04:00
Filesystem :: signal_param_path => $path
2012-08-17 03:22:26 +04:00
)
);
}
}
}
return $run ;
}
2012-06-15 19:42:39 +04:00
/**
* check if a file or folder has been updated since $time
2012-10-10 13:54:44 +04:00
*
2012-10-10 14:25:46 +04:00
* @ param string $path
2012-06-15 19:42:39 +04:00
* @ param int $time
* @ return bool
*/
2012-07-21 23:44:10 +04:00
public function hasUpdated ( $path , $time ) {
return $this -> basicOperation ( 'hasUpdated' , $path , array (), $time );
2012-06-15 19:42:39 +04:00
}
2012-10-26 14:30:25 +04:00
/**
* get the filesystem info
*
* @ param string $path
* @ return array
*
* returns an associative array with the following keys :
* - size
* - mtime
* - mimetype
* - encrypted
* - versioned
*/
public function getFileInfo ( $path ) {
2012-11-25 01:42:54 +04:00
$data = array ();
2012-10-26 15:23:15 +04:00
$path = Filesystem :: normalizePath ( $this -> fakeRoot . '/' . $path );
2012-10-26 14:30:25 +04:00
/**
* @ var \OC\Files\Storage\Storage $storage
2012-10-26 14:43:23 +04:00
* @ var string $internalPath
2012-10-26 14:30:25 +04:00
*/
2012-10-26 15:23:15 +04:00
list ( $storage , $internalPath ) = Filesystem :: resolvePath ( $path );
2012-11-25 01:42:54 +04:00
if ( $storage ) {
$cache = $storage -> getCache ();
2012-10-26 14:30:25 +04:00
2012-11-25 01:42:54 +04:00
if ( ! $cache -> inCache ( $internalPath )) {
$scanner = $storage -> getScanner ();
$scanner -> scan ( $internalPath , Cache\Scanner :: SCAN_SHALLOW );
} else {
$watcher = new \OC\Files\Cache\Watcher ( $storage );
$watcher -> checkUpdate ( $internalPath );
}
2012-10-26 14:30:25 +04:00
2012-11-25 01:42:54 +04:00
$data = $cache -> get ( $internalPath );
2012-10-26 14:30:25 +04:00
2012-12-11 04:06:21 +04:00
if ( $data ) {
if ( $data [ 'mimetype' ] === 'httpd/unix-directory' ) {
//add the sizes of other mountpoints to the folder
$mountPoints = Filesystem :: getMountPoints ( $path );
foreach ( $mountPoints as $mountPoint ) {
$subStorage = Filesystem :: getStorage ( $mountPoint );
$subCache = $subStorage -> getCache ();
$rootEntry = $subCache -> get ( '' );
$data [ 'size' ] += $rootEntry [ 'size' ];
}
2012-11-25 01:42:54 +04:00
}
2012-10-27 12:01:20 +04:00
2012-12-11 04:06:21 +04:00
$permissionsCache = $storage -> getPermissionsCache ();
$data [ 'permissions' ] = $permissionsCache -> get ( $data [ 'fileid' ], \OC_User :: getUser ());
}
2012-11-25 01:42:54 +04:00
}
2012-10-26 14:30:25 +04:00
return $data ;
}
/**
* get the content of a directory
*
* @ param string $directory path under datadirectory
* @ return array
*/
public function getDirectoryContent ( $directory , $mimetype_filter = '' ) {
2012-11-25 01:42:54 +04:00
$result = array ();
2012-10-26 15:23:15 +04:00
$path = Filesystem :: normalizePath ( $this -> fakeRoot . '/' . $directory );
2012-10-26 14:30:25 +04:00
/**
* @ var \OC\Files\Storage\Storage $storage
2012-10-26 14:43:23 +04:00
* @ var string $internalPath
2012-10-26 14:30:25 +04:00
*/
2012-10-26 15:23:15 +04:00
list ( $storage , $internalPath ) = Filesystem :: resolvePath ( $path );
2012-11-25 01:42:54 +04:00
if ( $storage ) {
$cache = $storage -> getCache ();
2012-10-26 14:30:25 +04:00
2012-12-15 06:20:50 +04:00
if ( $cache -> getStatus ( $internalPath ) < Cache\Cache :: COMPLETE ) {
2012-11-25 01:42:54 +04:00
$scanner = $storage -> getScanner ();
$scanner -> scan ( $internalPath , Cache\Scanner :: SCAN_SHALLOW );
} else {
$watcher = new \OC\Files\Cache\Watcher ( $storage );
$watcher -> checkUpdate ( $internalPath );
}
$files = $cache -> getFolderContents ( $internalPath ); //TODO: mimetype_filter
2012-10-26 14:30:25 +04:00
2012-11-25 01:42:54 +04:00
//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
$mountPoints = Filesystem :: getMountPoints ( $path );
$dirLength = strlen ( $path );
foreach ( $mountPoints as $mountPoint ) {
$subStorage = Filesystem :: getStorage ( $mountPoint );
if ( $subStorage ) {
$subCache = $subStorage -> getCache ();
$rootEntry = $subCache -> get ( '' );
$relativePath = trim ( substr ( $mountPoint , $dirLength ), '/' );
if ( $pos = strpos ( $relativePath , '/' )) { //mountpoint inside subfolder add size to the correct folder
$entryName = substr ( $relativePath , 0 , $pos );
foreach ( $files as & $entry ) {
if ( $entry [ 'name' ] === $entryName ) {
$entry [ 'size' ] += $rootEntry [ 'size' ];
}
}
} else { //mountpoint in this folder, add an entry for it
$rootEntry [ 'name' ] = $relativePath ;
$files [] = $rootEntry ;
2012-10-26 14:30:25 +04:00
}
}
}
2012-11-25 01:42:54 +04:00
$ids = array ();
2012-10-27 12:01:20 +04:00
2012-11-25 01:42:54 +04:00
foreach ( $files as $i => $file ) {
$files [ $i ][ 'type' ] = $file [ 'mimetype' ] === 'httpd/unix-directory' ? 'dir' : 'file' ;
$ids [] = $file [ 'fileid' ];
}
$permissionsCache = $storage -> getPermissionsCache ();
2012-10-27 12:01:20 +04:00
2012-11-25 01:42:54 +04:00
$permissions = $permissionsCache -> getMultiple ( $ids , \OC_User :: getUser ());
foreach ( $files as $i => $file ) {
$files [ $i ][ 'permissions' ] = $permissions [ $file [ 'fileid' ]];
}
2012-10-27 01:25:52 +04:00
2012-11-25 01:42:54 +04:00
if ( $mimetype_filter ) {
foreach ( $files as $file ) {
if ( strpos ( $mimetype_filter , '/' )) {
if ( $file [ 'mimetype' ] === $mimetype_filter ) {
$result [] = $file ;
}
} else {
if ( $file [ 'mimepart' ] === $mimetype_filter ) {
$result [] = $file ;
}
2012-10-27 14:17:35 +04:00
}
}
2012-11-25 01:42:54 +04:00
} else {
$result = $files ;
2012-10-27 14:17:35 +04:00
}
}
return $result ;
2012-10-26 14:30:25 +04:00
}
2012-10-26 14:43:23 +04:00
/**
* change file metadata
*
* @ param string $path
* @ param array $data
* @ return int
*
* returns the fileid of the updated file
*/
public function putFileInfo ( $path , $data ) {
2012-10-26 15:23:15 +04:00
$path = Filesystem :: normalizePath ( $this -> fakeRoot . '/' . $path );
2012-10-26 14:43:23 +04:00
/**
* @ var \OC\Files\Storage\Storage $storage
* @ var string $internalPath
*/
2012-10-26 15:23:15 +04:00
list ( $storage , $internalPath ) = Filesystem :: resolvePath ( $path );
2012-11-25 01:42:54 +04:00
if ( $storage ) {
$cache = $storage -> getCache ();
2012-10-26 14:43:23 +04:00
2012-11-25 01:42:54 +04:00
if ( ! $cache -> inCache ( $internalPath )) {
$scanner = $storage -> getScanner ();
$scanner -> scan ( $internalPath , Cache\Scanner :: SCAN_SHALLOW );
}
2012-10-26 14:43:23 +04:00
2012-11-25 01:42:54 +04:00
return $cache -> put ( $internalPath , $data );
} else {
return - 1 ;
}
2012-10-26 14:43:23 +04:00
}
2012-10-26 15:23:15 +04:00
/**
* search for files with the name matching $query
*
* @ param string $query
* @ return array
*/
public function search ( $query ) {
2012-10-27 12:34:25 +04:00
return $this -> searchCommon ( '%' . $query . '%' , 'search' );
}
/**
* search for files by mimetype
*
* @ param string $query
* @ return array
*/
public function searchByMime ( $mimetype ) {
return $this -> searchCommon ( $mimetype , 'searchByMime' );
}
/**
* @ param string $query
* @ param string $method
* @ return array
*/
private function searchCommon ( $query , $method ) {
2012-10-26 15:23:15 +04:00
$files = array ();
$rootLength = strlen ( $this -> fakeRoot );
$mountPoint = Filesystem :: getMountPoint ( $this -> fakeRoot );
$storage = Filesystem :: getStorage ( $mountPoint );
2012-11-25 01:42:54 +04:00
if ( $storage ) {
2012-10-26 15:23:15 +04:00
$cache = $storage -> getCache ();
2012-10-27 12:34:25 +04:00
$results = $cache -> $method ( $query );
2012-10-26 15:23:15 +04:00
foreach ( $results as $result ) {
2012-11-25 01:42:54 +04:00
if ( substr ( $mountPoint . $result [ 'path' ], 0 , $rootLength ) === $this -> fakeRoot ) {
$result [ 'path' ] = substr ( $mountPoint . $result [ 'path' ], $rootLength );
$files [] = $result ;
}
2012-10-26 15:23:15 +04:00
}
2012-11-25 01:42:54 +04:00
$mountPoints = Filesystem :: getMountPoints ( $this -> fakeRoot );
foreach ( $mountPoints as $mountPoint ) {
$storage = Filesystem :: getStorage ( $mountPoint );
if ( $storage ) {
$cache = $storage -> getCache ();
$relativeMountPoint = substr ( $mountPoint , $rootLength );
$results = $cache -> $method ( $query );
foreach ( $results as $result ) {
$result [ 'path' ] = $relativeMountPoint . $result [ 'path' ];
$files [] = $result ;
}
}
}
}
2012-10-26 15:23:15 +04:00
return $files ;
}
2012-11-08 20:47:00 +04:00
/**
* get the ETag for a file or folder
*
* @ param string $path
* @ return string
*/
2012-12-11 04:06:21 +04:00
public function getETag ( $path ) {
2012-11-08 20:47:00 +04:00
/**
* @ var Storage\Storage $storage
* @ var string $internalPath
*/
list ( $storage , $internalPath ) = $this -> resolvePath ( $path );
2012-11-25 01:42:54 +04:00
if ( $storage ) {
return $storage -> getETag ( $internalPath );
} else {
return null ;
}
2012-11-08 20:47:00 +04:00
}
2012-01-20 03:40:52 +04:00
}