2012-04-18 22:54:07 +04:00
< ? php
2013-10-22 16:59:09 +04:00
2012-04-18 22:54:07 +04:00
/**
2013-10-22 16:59:09 +04:00
* ownCloud
*
* @ author Christian Berendt
* @ copyright 2013 Christian Berendt berendt @ b1 - systems . de
*
* 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 />.
2012-04-18 22:54:07 +04:00
*/
2012-09-07 20:30:48 +04:00
namespace OC\Files\Storage ;
2013-10-22 16:59:09 +04:00
set_include_path ( get_include_path () . PATH_SEPARATOR .
\OC_App :: getAppPath ( 'files_external' ) . '/3rdparty/php-opencloud/lib' );
require_once 'openstack.php' ;
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
use \OpenCloud ;
use \OpenCloud\Common\Exceptions ;
class Swift extends \OC\Files\Storage\Common {
/**
* @ var \OpenCloud\ObjectStore
*/
private $connection ;
/**
* @ var \OpenCloud\ObjectStore\Container
*/
private $container ;
/**
* @ var \OpenCloud\OpenStack
*/
private $anchor ;
/**
* @ var string
*/
private $bucket ;
/**
* @ var array
*/
private static $tmpFiles = array ();
2014-02-06 19:30:58 +04:00
/**
* @ param string $path
*/
2013-10-22 16:59:09 +04:00
private function normalizePath ( $path ) {
$path = trim ( $path , '/' );
if ( ! $path ) {
$path = '.' ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
return $path ;
2012-04-18 22:54:07 +04:00
}
2013-06-01 13:28:02 +04:00
/**
* check if curl is installed
*/
public static function checkDependencies () {
if ( function_exists ( 'curl_init' )) {
return true ;
} else {
$l = new \OC_L10N ( 'files_external' );
return $l -> t ( '<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of OpenStack Swift is not possible. Please ask your system administrator to install it.' );
}
}
2014-02-06 19:30:58 +04:00
/**
* @ param string $path
*/
2013-10-22 16:59:09 +04:00
private function doesObjectExist ( $path ) {
try {
$object = $this -> container -> DataObject ( $path );
return true ;
} catch ( Exceptions\ObjFetchError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
} catch ( Exceptions\HttpError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
2012-04-18 22:54:07 +04:00
}
}
2013-10-22 16:59:09 +04:00
public function __construct ( $params ) {
if (( ! isset ( $params [ 'key' ]) and ! isset ( $params [ 'password' ]))
or ! isset ( $params [ 'user' ]) or ! isset ( $params [ 'bucket' ])
or ! isset ( $params [ 'region' ])) {
throw new \Exception ( " API Key or password, Username, Bucket and Region have to be configured. " );
2012-04-25 02:11:10 +04:00
}
2013-10-22 16:59:09 +04:00
$this -> id = 'swift::' . $params [ 'user' ] . md5 ( $params [ 'bucket' ]);
$this -> bucket = $params [ 'bucket' ];
if ( ! isset ( $params [ 'url' ])) {
$params [ 'url' ] = 'https://identity.api.rackspacecloud.com/v2.0/' ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
if ( ! isset ( $params [ 'service_name' ])) {
$params [ 'service_name' ] = 'cloudFiles' ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
$settings = array (
'username' => $params [ 'user' ],
);
if ( isset ( $params [ 'password' ])) {
$settings [ 'password' ] = $params [ 'password' ];
} else if ( isset ( $params [ 'key' ])) {
$settings [ 'apiKey' ] = $params [ 'key' ];
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
if ( isset ( $params [ 'tenant' ])) {
$settings [ 'tenantName' ] = $params [ 'tenant' ];
}
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
$this -> anchor = new \OpenCloud\OpenStack ( $params [ 'url' ], $settings );
2013-10-24 18:19:17 +04:00
if ( isset ( $params [ 'timeout' ])) {
$this -> anchor -> setHttpTimeout ( $params [ 'timeout' ]);
}
2013-10-22 16:59:09 +04:00
$this -> connection = $this -> anchor -> ObjectStore ( $params [ 'service_name' ], $params [ 'region' ], 'publicURL' );
2012-04-18 22:54:07 +04:00
2012-11-30 19:27:11 +04:00
try {
2013-10-22 16:59:09 +04:00
$this -> container = $this -> connection -> Container ( $this -> bucket );
} catch ( Exceptions\ContainerNotFoundError $e ) {
$this -> container = $this -> connection -> Container ();
$this -> container -> Create ( array ( 'name' => $this -> bucket ));
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
if ( ! $this -> file_exists ( '.' )) {
$this -> mkdir ( '.' );
2012-04-18 22:54:07 +04:00
}
}
2013-10-22 16:59:09 +04:00
public function mkdir ( $path ) {
$path = $this -> normalizePath ( $path );
if ( $this -> is_dir ( $path )) {
2012-04-18 22:54:07 +04:00
return false ;
}
2013-10-22 16:59:09 +04:00
if ( $path !== '.' ) {
$path .= '/' ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
2012-11-30 19:27:11 +04:00
try {
2013-10-22 16:59:09 +04:00
$object = $this -> container -> DataObject ();
$object -> Create ( array (
'name' => $path ,
'content_type' => 'httpd/unix-directory'
));
} catch ( Exceptions\CreateUpdateError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
2012-04-18 22:54:07 +04:00
return false ;
}
return true ;
}
2013-10-22 16:59:09 +04:00
public function file_exists ( $path ) {
$path = $this -> normalizePath ( $path );
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
if ( $path !== '.' && $this -> is_dir ( $path )) {
$path .= '/' ;
2012-04-18 22:54:07 +04:00
}
2012-08-29 10:42:49 +04:00
2013-10-22 16:59:09 +04:00
return $this -> doesObjectExist ( $path );
2012-10-22 00:04:45 +04:00
}
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
public function rmdir ( $path ) {
$path = $this -> normalizePath ( $path );
if ( ! $this -> is_dir ( $path )) {
return false ;
2012-10-22 00:04:45 +04:00
}
2013-10-22 16:59:09 +04:00
$dh = $this -> opendir ( $path );
while ( $file = readdir ( $dh )) {
if ( $file === '.' || $file === '..' ) {
continue ;
}
2012-08-29 10:42:49 +04:00
2013-10-22 16:59:09 +04:00
if ( $this -> is_dir ( $path . '/' . $file )) {
$this -> rmdir ( $path . '/' . $file );
} else {
$this -> unlink ( $path . '/' . $file );
}
}
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
try {
$object = $this -> container -> DataObject ( $path . '/' );
$object -> Delete ();
} catch ( Exceptions\DeleteError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
return true ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
public function opendir ( $path ) {
$path = $this -> normalizePath ( $path );
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
if ( $path === '.' ) {
$path = '' ;
2012-11-30 19:27:11 +04:00
} else {
2013-10-22 16:59:09 +04:00
$path .= '/' ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
try {
$files = array ();
$objects = $this -> container -> ObjectList ( array (
2013-10-23 10:07:59 +04:00
'prefix' => $path ,
'delimiter' => '/'
2013-10-22 16:59:09 +04:00
));
while ( $object = $objects -> Next ()) {
$file = basename ( $object -> Name ());
if ( $file !== basename ( $path )) {
$files [] = $file ;
}
2012-04-18 22:54:07 +04:00
}
2012-08-29 10:42:49 +04:00
2013-10-22 16:59:09 +04:00
\OC\Files\Stream\Dir :: register ( 'swift' . $path , $files );
return opendir ( 'fakedir://swift' . $path );
} catch ( Exception $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
public function stat ( $path ) {
$path = $this -> normalizePath ( $path );
if ( $this -> is_dir ( $path ) && $path != '.' ) {
$path .= '/' ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
try {
$object = $this -> container -> DataObject ( $path );
} catch ( Exceptions\ObjFetchError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
$mtime = $object -> extra_headers [ 'X-Timestamp' ];
if ( isset ( $object -> extra_headers [ 'X-Object-Meta-Timestamp' ])) {
$mtime = $object -> extra_headers [ 'X-Object-Meta-Timestamp' ];
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
2014-03-26 20:20:40 +04:00
if ( ! empty ( $mtime )) {
$mtime = floor ( $mtime );
}
2013-10-22 16:59:09 +04:00
$stat = array ();
$stat [ 'size' ] = $object -> content_length ;
$stat [ 'mtime' ] = $mtime ;
$stat [ 'atime' ] = time ();
return $stat ;
2012-04-18 22:54:07 +04:00
}
2012-09-07 17:22:01 +04:00
public function filetype ( $path ) {
2013-10-22 16:59:09 +04:00
$path = $this -> normalizePath ( $path );
if ( $path !== '.' && $this -> doesObjectExist ( $path )) {
2012-04-18 22:54:07 +04:00
return 'file' ;
}
2013-10-22 16:59:09 +04:00
if ( $path !== '.' ) {
$path .= '/' ;
}
if ( $this -> doesObjectExist ( $path )) {
return 'dir' ;
}
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
public function unlink ( $path ) {
$path = $this -> normalizePath ( $path );
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
try {
$object = $this -> container -> DataObject ( $path );
$object -> Delete ();
} catch ( Exceptions\DeleteError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
2012-04-18 22:54:07 +04:00
return false ;
2013-10-22 16:59:09 +04:00
} catch ( Exceptions\ObjFetchError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
2012-04-18 22:54:07 +04:00
return false ;
}
2013-10-22 16:59:09 +04:00
return true ;
2012-04-18 22:54:07 +04:00
}
2012-11-02 22:53:02 +04:00
public function fopen ( $path , $mode ) {
2013-10-22 16:59:09 +04:00
$path = $this -> normalizePath ( $path );
switch ( $mode ) {
2012-04-18 22:54:07 +04:00
case 'r' :
case 'rb' :
2013-10-22 16:59:09 +04:00
$tmpFile = \OC_Helper :: tmpFile ();
self :: $tmpFiles [ $tmpFile ] = $path ;
try {
$object = $this -> container -> DataObject ( $path );
} catch ( Exceptions\ObjFetchError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
2012-10-11 17:52:21 +04:00
return false ;
}
2013-10-22 16:59:09 +04:00
try {
$object -> SaveToFilename ( $tmpFile );
} catch ( Exceptions\IOError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
}
return fopen ( $tmpFile , 'r' );
2012-04-18 22:54:07 +04:00
case 'w' :
case 'wb' :
case 'a' :
case 'ab' :
case 'r+' :
case 'w+' :
case 'wb+' :
case 'a+' :
case 'x' :
case 'x+' :
case 'c' :
case 'c+' :
2013-10-22 16:59:09 +04:00
if ( strrpos ( $path , '.' ) !== false ) {
$ext = substr ( $path , strrpos ( $path , '.' ));
} else {
$ext = '' ;
}
$tmpFile = \OC_Helper :: tmpFile ( $ext );
2013-01-28 18:34:15 +04:00
\OC\Files\Stream\Close :: registerCallback ( $tmpFile , array ( $this , 'writeBack' ));
2013-10-22 16:59:09 +04:00
if ( $this -> file_exists ( $path )) {
$source = $this -> fopen ( $path , 'r' );
file_put_contents ( $tmpFile , $source );
}
self :: $tmpFiles [ $tmpFile ] = $path ;
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
return fopen ( 'close://' . $tmpFile , $mode );
2012-04-18 22:54:07 +04:00
}
}
2013-10-22 16:59:09 +04:00
public function getMimeType ( $path ) {
$path = $this -> normalizePath ( $path );
2012-08-29 10:42:49 +04:00
2013-10-22 16:59:09 +04:00
if ( $this -> is_dir ( $path )) {
return 'httpd/unix-directory' ;
} else if ( $this -> file_exists ( $path )) {
$object = $this -> container -> DataObject ( $path );
return $object -> extra_headers [ " Content-Type " ];
}
return false ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
public function touch ( $path , $mtime = null ) {
$path = $this -> normalizePath ( $path );
if ( $this -> file_exists ( $path )) {
if ( $this -> is_dir ( $path ) && $path != '.' ) {
$path .= '/' ;
}
$object = $this -> container -> DataObject ( $path );
if ( is_null ( $mtime )) {
$mtime = time ();
}
$settings = array (
'name' => $path ,
'extra_headers' => array (
'X-Object-Meta-Timestamp' => $mtime
)
);
2014-03-27 15:34:30 +04:00
return $object -> UpdateMetadata ( $settings );
2013-10-22 16:59:09 +04:00
} else {
$object = $this -> container -> DataObject ();
if ( is_null ( $mtime )) {
$mtime = time ();
}
$settings = array (
'name' => $path ,
'content_type' => 'text/plain' ,
'extra_headers' => array (
'X-Object-Meta-Timestamp' => $mtime
)
);
2013-11-25 15:44:27 +04:00
return $object -> Create ( $settings );
2012-04-19 02:25:47 +04:00
}
2012-04-18 22:54:07 +04:00
}
2012-11-02 22:53:02 +04:00
public function copy ( $path1 , $path2 ) {
2013-10-22 16:59:09 +04:00
$path1 = $this -> normalizePath ( $path1 );
$path2 = $this -> normalizePath ( $path2 );
2012-04-18 22:54:07 +04:00
2013-10-22 16:59:09 +04:00
if ( $this -> is_file ( $path1 )) {
try {
$source = $this -> container -> DataObject ( $path1 );
$target = $this -> container -> DataObject ();
$target -> Create ( array (
'name' => $path2 ,
));
$source -> Copy ( $target );
} catch ( Exceptions\ObjectCopyError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
}
} else {
if ( $this -> file_exists ( $path2 )) {
return false ;
}
2012-10-11 17:52:21 +04:00
2013-10-22 16:59:09 +04:00
try {
$source = $this -> container -> DataObject ( $path1 . '/' );
$target = $this -> container -> DataObject ();
$target -> Create ( array (
'name' => $path2 . '/' ,
));
$source -> Copy ( $target );
} catch ( Exceptions\ObjectCopyError $e ) {
\OCP\Util :: writeLog ( 'files_external' , $e -> getMessage (), \OCP\Util :: ERROR );
return false ;
}
2012-10-11 17:52:21 +04:00
2013-10-22 16:59:09 +04:00
$dh = $this -> opendir ( $path1 );
while ( $file = readdir ( $dh )) {
if ( $file === '.' || $file === '..' ) {
continue ;
}
2012-04-19 02:25:47 +04:00
2013-10-22 16:59:09 +04:00
$source = $path1 . '/' . $file ;
$target = $path2 . '/' . $file ;
$this -> copy ( $source , $target );
}
2012-04-19 02:25:47 +04:00
}
2013-10-22 16:59:09 +04:00
return true ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
public function rename ( $path1 , $path2 ) {
$path1 = $this -> normalizePath ( $path1 );
$path2 = $this -> normalizePath ( $path2 );
if ( $this -> is_file ( $path1 )) {
if ( $this -> copy ( $path1 , $path2 ) === false ) {
return false ;
}
if ( $this -> unlink ( $path1 ) === false ) {
$this -> unlink ( $path2 );
return false ;
}
2012-11-30 19:27:11 +04:00
} else {
2013-10-22 16:59:09 +04:00
if ( $this -> file_exists ( $path2 )) {
return false ;
}
if ( $this -> copy ( $path1 , $path2 ) === false ) {
return false ;
}
if ( $this -> rmdir ( $path1 ) === false ) {
$this -> rmdir ( $path2 );
return false ;
}
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
return true ;
2012-04-18 22:54:07 +04:00
}
2013-10-22 16:59:09 +04:00
public function getId () {
return $this -> id ;
2012-04-19 02:25:47 +04:00
}
2013-10-22 16:59:09 +04:00
public function getConnection () {
return $this -> connection ;
}
public function writeBack ( $tmpFile ) {
if ( ! isset ( self :: $tmpFiles [ $tmpFile ])) {
return false ;
2012-04-19 02:25:47 +04:00
}
2013-10-22 16:59:09 +04:00
$object = $this -> container -> DataObject ();
$object -> Create ( array (
'name' => self :: $tmpFiles [ $tmpFile ],
'content_type' => \OC_Helper :: getMimeType ( $tmpFile )
), $tmpFile );
unlink ( $tmpFile );
2012-04-18 22:54:07 +04:00
}
}