diff options
author | Robin Appelman <icewind@owncloud.com> | 2012-04-18 20:54:07 +0200 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2012-04-18 20:54:28 +0200 |
commit | 9a707e10bf70619bf1a553b2bc56c989f9725ab2 (patch) | |
tree | 0ee68f51262e344aa3ce08b8e76fd4f7080b077a /apps/files_external/lib/swift.php | |
parent | aceda02887eb4a52188f0308c6404cc9f201ce79 (diff) | |
download | nextcloud-server-9a707e10bf70619bf1a553b2bc56c989f9725ab2.tar.gz nextcloud-server-9a707e10bf70619bf1a553b2bc56c989f9725ab2.zip |
add SWIFT (openstack object storage) storage backend
Diffstat (limited to 'apps/files_external/lib/swift.php')
-rw-r--r-- | apps/files_external/lib/swift.php | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php new file mode 100644 index 00000000000..ec09742c449 --- /dev/null +++ b/apps/files_external/lib/swift.php @@ -0,0 +1,488 @@ +<?php +/** + * 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. + */ + +require_once('php-cloudfiles/cloudfiles.php'); + +class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ + private $host; + private $root; + private $user; + private $token; + private $secure; + /** + * @var CF_Authentication auth + */ + private $auth; + /** + * @var CF_Connection conn + */ + private $conn; + /** + * @var CF_Container rootContainer + */ + private $rootContainer; + + private static $tempFiles=array(); + + const SUBCONTAINER_FILE='.subcontainers'; + + /** + * translate directory path to container name + * @param string path + * @return string + */ + private function getContainerName($path){ + $path=trim($this->root.$path,'/'); + return md5($path); + } + + /** + * get container by path + * @param string path + * @return CF_Container + */ + private function getContainer($path){ + if($path=='' or $path=='/'){ + return $this->rootContainer; + } + try{ + $container=$this->conn->get_container($this->getContainerName($path)); + return $container; + }catch(NoSuchContainerException $e){ + return null; + } + } + + /** + * create container + * @param string path + * @return CF_Container + */ + private function createContainer($path){ + if($path=='' or $path=='/'){ + return $this->conn->create_container($this->getContainerName($path)); + } + $parent=dirname($path); + if($parent=='' or $parent=='/'){ + $parentContainer=$this->rootContainer; + }else{ + if(!$this->containerExists($parent)){ + $parentContainer=$this->createContainer($parent); + }else{ + $parentContainer=$this->getContainer($parent); + } + } + $this->addSubContainer($parentContainer,basename($path)); + return $this->conn->create_container($this->getContainerName($path)); + } + + /** + * get object by path + * @param string path + * @return CF_Object + */ + private function getObject($path){ + $container=$this->getContainer(dirname($path)); + if(is_null($container)){ + return null; + }else{ + try{ + $obj=$container->get_object(basename($path)); + return $obj; + }catch(NoSuchObjectException $e){ + return null; + } + } + } + + /** + * get the names of all objects in a container + * @param CF_Container + * @return array + */ + private function getObjects($container){ + if(is_null($container)){ + return array(); + }else{ + $files=$container->get_objects(); + foreach($files as &$file){ + $file=$file->name; + } + return $files; + } + } + + /** + * create object + * @param string path + * @return CF_Object + */ + private function createObject($path){ + $container=$this->getContainer(dirname($path)); + if(!is_null($container)){ + $container=$this->createContainer($path); + } + return $container->create_object(basename($path)); + } + + /** + * check if an object exists + * @param string + * @return bool + */ + private function objectExists($path){ + return !is_null($this->getObject($path)); + } + + /** + * check if container for path exists + * @param string path + * @return bool + */ + private function containerExists($path){ + return !is_null($this->getContainer($path)); + } + + /** + * get the list of emulated sub containers + * @param CF_Container container + * @return array + */ + private function getSubContainers($container){ + $tmpFile=OC_Helper::tmpFile(); + $obj=$this->getSubContainerFile($container); + try{ + $obj->save_to_filename($tmpFile); + }catch(Exception $e){ + return array(); + } + $obj->save_to_filename($tmpFile); + $containers=file($tmpFile); + unlink($tmpFile); + foreach($containers as &$sub){ + $sub=trim($sub); + } + return $containers; + } + + /** + * add an emulated sub container + * @param CF_Container container + * @param string name + * @return bool + */ + private function addSubContainer($container,$name){ + if(!$name){ + return false; + } + $tmpFile=OC_Helper::tmpFile(); + $obj=$this->getSubContainerFile($container); + try{ + $obj->save_to_filename($tmpFile); + $containers=file($tmpFile); + foreach($containers as &$sub){ + $sub=trim($sub); + } + if(array_search($name,$containers)!==false){ + unlink($tmpFile); + return false; + }else{ + $fh=fopen($tmpFile,'a'); + fwrite($fh,$name."\n"); + } + }catch(Exception $e){ + $containers=array(); + file_put_contents($tmpFile,$name."\n"); + } + + $obj->load_from_filename($tmpFile); + unlink($tmpFile); + return true; + } + + /** + * remove an emulated sub container + * @param CF_Container container + * @param string name + * @return bool + */ + private function removeSubContainer($container,$name){ + if(!$name){ + return false; + } + $tmpFile=OC_Helper::tmpFile(); + $obj=$this->getSubContainerFile($container); + try{ + $obj->save_to_filename($tmpFile); + $containers=file($tmpFile); + }catch(Exception $e){ + return false; + } + foreach($containers as &$sub){ + $sub=trim($sub); + } + $i=array_search($name,$containers); + if($i===false){ + unlink($tmpFile); + return false; + }else{ + unset($containers[$i]); + file_put_contents($tmpFile,implode("\n",$containers)."\n"); + } + + $obj->load_from_filename($tmpFile); + unlink($tmpFile); + return true; + } + + /** + * ensure a subcontainer file exists and return it's object + * @param CF_Container container + * @return CF_Object + */ + private function getSubContainerFile($container){ + try{ + return $container->get_object(self::SUBCONTAINER_FILE); + }catch(NoSuchObjectException $e){ + return $container->create_object(self::SUBCONTAINER_FILE); + } + } + + public function __construct($params){ + $this->token=$params['token']; + $this->host=$params['host']; + $this->user=$params['user']; + $this->root=isset($params['root'])?$params['root']:'/'; + $this->secure=isset($params['secure'])?(bool)$params['secure']:true; + if(substr($this->root,0,1)!='/'){ + $this->root='/'.$this->root; + } + $this->auth = new CF_Authentication($this->user, $this->token, null, $this->host); + $this->auth->authenticate(); + + $this->conn = new CF_Connection($this->auth); + + if(!$this->containerExists($this->root)){ + $this->rootContainer=$this->createContainer('/'); + }else{ + $this->rootContainer=$this->getContainer('/'); + } + } + + + public function mkdir($path){ + if($this->containerExists($path)){ + return false; + }else{ + $this->createContainer($path); + return true; + } + } + + public function rmdir($path){ + if(!$this->containerExists($path)){ + return false; + }else{ + $this->emptyContainer($path); + if($path!='' and $path!='/'){ + $parentContainer=$this->getContainer(dirname($path)); + $this->removeSubContainer($parentContainer,basename($path)); + } + + $this->conn->delete_container($this->getContainerName($path)); + return true; + } + } + + private function emptyContainer($path){ + $container=$this->getContainer($path); + if(is_null($container)){ + return; + } + $subContainers=$this->getSubContainers($container); + foreach($subContainers as $sub){ + if($sub){ + $this->emptyContainer($path.'/'.$sub); + $this->conn->delete_container($this->getContainerName($path.'/'.$sub)); + } + } + + $objects=$this->getObjects($container); + foreach($objects as $object){ + $container->delete_object($object); + } + } + + public function opendir($path){ + $container=$this->getContainer($path); + $files=$this->getObjects($container); + $i=array_search(self::SUBCONTAINER_FILE,$files); + if($i!==false){ + unset($files[$i]); + } + $subContainers=$this->getSubContainers($container); + $files=array_merge($files,$subContainers); + $id=$this->getContainerName($path); + OC_FakeDirStream::$dirs[$id]=$files; + return opendir('fakedir://'.$id); + } + + public function filetype($path){ + if($this->containerExists($path)){ + return 'dir'; + }else{ + return 'file'; + } + } + + public function is_readable($path){ + return true; + } + + public function is_writable($path){ + return true; + } + + public function file_exists($path){ + if($this->is_dir($path)){ + return true; + }else{ + return $this->objectExists($path); + } + } + + public function file_get_contents($path){ + $obj=$this->getObject($path); + if(is_null($obj)){ + return false; + } + return $obj->read(); + } + + public function file_put_contents($path,$content){ + $obj=$this->getObject($path); + if(is_null($obj)){ + $container=$this->getContainer(dirname($path)); + if(is_null($container)){ + return false; + } + $obj=$container->create_object(basename($path)); + } + return $obj->write($content); + } + + public function unlink($path){ + if($this->objectExists($path)){ + $container=$this->getContainer(dirname($path)); + $container->delete_object(basename($path)); + }else{ + return false; + } + } + + public function fopen($path,$mode){ + $obj=$this->getObject($path); + if(is_null($obj)){ + return false; + } + switch($mode){ + case 'r': + case 'rb': + $fp = fopen('php://temp', 'r+'); + $obj->stream($fp); + + rewind($fp); + return $fp; + case 'w': + case 'wb': + case 'a': + case 'ab': + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + $tmpFile=$this->getTmpFile($path); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + public function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->fromTmpFile($tmpFile,self::$tempFiles[$tmpFile]); + unlink($tmpFile); + } + } + + public function free_space($path){ + return 0; + } + + public function touch($path,$mtime=null){ + if(!is_null($mtime)){ + return false; + } + $obj=$this->getObject($path); + if(is_null($obj)){ + return false; + } + $fp = fopen('php://temp', 'r+'); + $obj->stream($fp); + rewind($fp); + $obj->write($fp); + fclose($fp); + } + + public function rename($path1,$path2){ + $sourceContainer=$this->getContainer(dirname($path1)); + $targetContainer=$this->getContainer(dirname($path2)); + return $sourceContainer->move_object_to(basename($path1),$targetContainer,basename($path2)); + } + + public function copy($path1,$path2){ + $sourceContainer=$this->getContainer(dirname($path1)); + $targetContainer=$this->getContainer(dirname($path2)); + return $sourceContainer->copy_object_to(basename($path1),$targetContainer,basename($path2)); + } + + public function stat($path){ + $obj=$this->getObject($path); + if(is_null($obj)){ + return false; + } + return array( + 'mtime'=>strtotime($obj->last_modified), + 'size'=>$obj->content_length, + 'ctime'=>-1, + ); + } + + private function getTmpFile($path){ + $obj=$this->getObject($path); + if(!is_null($obj)){ + $tmpFile=OC_Helper::tmpFile(); + $obj->save_to_filename($tmpFile); + return $tmpFile; + }else{ + return false; + } + } + + private function fromTmpFile($tmpFile,$path){ + $obj=$this->getObject($path); + if(is_null($obj)){ + $obj=$this->createObject($path); + } + $obj->load_from_filename($tmpFile); + } +} |