]> source.dussan.org Git - nextcloud-server.git/commitdiff
change architecture from inheritance to composition
authorJörn Friedrich Dreyer <jfd@butonic.de>
Tue, 17 Jun 2014 20:06:56 +0000 (22:06 +0200)
committerJörn Friedrich Dreyer <jfd@butonic.de>
Wed, 18 Jun 2014 10:53:20 +0000 (12:53 +0200)
lib/private/files/filesystem.php
lib/private/files/objectstore/abstractobjectstore.php [deleted file]
lib/private/files/objectstore/homeobjectstorestorage.php [new file with mode: 0644]
lib/private/files/objectstore/objectstorestorage.php [new file with mode: 0644]
lib/private/files/objectstore/swift.php
lib/private/util.php
lib/public/files/objectstore/iobjectstore.php [new file with mode: 0644]
tests/lib/files/objectstore/swift.php

index 71d70bbf2a56e20fd1932a9fd5f6dcd3babf9b30..4774d25ad9ec7fb2f348a5a7cc8b3cf2edf9d0d4 100644 (file)
@@ -325,32 +325,36 @@ class Filesystem {
                $userObject = \OC_User::getManager()->get($user);
 
                if (!is_null($userObject)) {
-                       $homeStorage = \OC_Config::getValue( 'objectstore', array(
-                               //default home storage configuration:
-                               'class' => '\OC\Files\Storage\Home',
-                               'arguments' => array()
-                       ));
-                       // sanity checks
-                       if (empty($homeStorage['class'])) {
-                               \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
-                       }
-                       if (!isset($homeStorage['arguments'])) {
-                               $homeStorage['arguments'] = array();
+                       $homeStorage = \OC_Config::getValue( 'objectstore' );
+                       if (!empty($homeStorage)) {
+                               // sanity checks
+                               if (empty($homeStorage['class'])) {
+                                       \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
+                               }
+                               if (!isset($homeStorage['arguments'])) {
+                                       $homeStorage['arguments'] = array();
+                               }
+                               // instantiate object store implementation
+                               $homeStorage['arguments']['objectstore'] = new $homeStorage['class']($homeStorage['arguments']);
+                               // mount with home object store implementation
+                               $homeStorage['class'] = '\OC\Files\ObjectStore\HomeObjectStoreStorage';
+                       } else {
+                               $homeStorage = array(
+                                       //default home storage configuration:
+                                       'class' => '\OC\Files\Storage\Home',
+                                       'arguments' => array()
+                               );
                        }
                        $homeStorage['arguments']['user'] = $userObject;
+
                        // check for legacy home id (<= 5.0.12)
                        if (\OC\Files\Cache\Storage::exists('local::' . $root . '/')) {
                                $homeStorage['arguments']['legacy'] = true;
                        }
+
                        self::mount($homeStorage['class'], $homeStorage['arguments'], $user);
 
                        $home = \OC\Files\Filesystem::getStorage($user);
-                       if ( $home->instanceOfStorage('\OC\Files\ObjectStore\AbstractObjectStore') ) {
-                               //create the files folder in the cache when mounting the objectstore for a user
-                               if ( ! $home->is_dir('files') ) {
-                                       $home->mkdir('files');
-                               }
-                       }
                }
                else {
                        self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user);
diff --git a/lib/private/files/objectstore/abstractobjectstore.php b/lib/private/files/objectstore/abstractobjectstore.php
deleted file mode 100644 (file)
index de82003..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-<?php
-/**
- * @author Jörn Friedrich Dreyer
- * @copyright (c) 2014 Jörn Friedrich Dreyer <jfd@owncloud.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/>.
- *
- */
-
-namespace OC\Files\ObjectStore;
-
-abstract class AbstractObjectStore extends \OC\Files\Storage\Common {
-
-       /**
-        * @param string $urn the unified resource name used to identify the object
-        * @param string $tmpFile path to the local temporary file that the object
-        *        should be loaded from
-        * @return void
-        * @throws Exception when something goes wrong, message will be logged
-        */
-       abstract protected function createObject($urn, $tmpFile = null);
-
-       /**
-        * @param string $urn the unified resource name used to identify the object
-        * @param string $tmpFile path to the local temporary file that should be
-        *        used to store the object
-        * @return void
-        * @throws Exception when something goes wrong, message will be logged
-        */
-       abstract protected function getObject($urn, $tmpFile);
-
-       /**
-        * @param string $urn the unified resource name used to identify the object
-        * @return void
-        * @throws Exception when something goes wrong, message will be logged
-        */
-       abstract protected function deleteObject($urn);
-
-       /**
-        * @var \OC\User\User $user
-        */
-       protected $user;
-
-       /**
-        * @var array
-        */
-       private static $tmpFiles = array();
-
-       public function __construct($params) {
-               if (isset($params['user']) && is_object($params['user'])) {
-                       $this->user = $params['user'];
-               } else {
-                       $this->user = null;
-               }
-               //initialize cache with root directory in cache
-               if ( ! $this->is_dir('/') ) {
-                       $this->mkdir('/');
-               }
-       }
-
-       /**
-        * Object Stores use a NoopScanner because metadata is directly stored in
-        * the file cache and cannot really scan the filesystem
-        * @param string $path
-        * @return \OC\Files\ObjectStore\NoopScanner
-        */
-       public function getScanner($path = '') {
-               if (!isset($this->scanner)) {
-                       $this->scanner = new NoopScanner($this);
-               }
-               return $this->scanner;
-       }
-       
-       /**
-        * get the owner of a path
-        *
-        * @param string $path The path to get the owner
-        * @return false|string uid
-        */
-       public function getOwner($path) {
-               if (is_object($this->user)) {
-                       return $this->user->getUID();
-               }
-               return false;
-       }
-
-       /**
-        * @param string $path, optional
-        * @return \OC\User\User
-        */
-       public function getUser($path = null) {
-               return $this->user;
-       }
-       
-       /**
-        * @param string $path
-        * @return string
-        */
-       private function normalizePath($path) {
-               $path = trim($path, '/');
-               //FIXME why do we sometimes get a path like 'files//username'?
-               $path = str_replace('//', '/', $path);
-
-               if (!$path) {
-                       $path = '.';
-               }
-
-               return $path;
-       }
-
-       public function getId () {
-               if (is_object($this->user)) {
-                       return 'objstore::user:' . $this->user->getUID();
-               }
-               return 'objstore::root';
-       }
-
-       public function mkdir($path) {
-               $path = $this->normalizePath($path);
-
-               if($this->is_dir($path)) {
-                       return false;
-               }
-
-               $dirName = dirname($path);
-               $parentExists = $this->is_dir($dirName);
-
-               $mTime = time();
-
-               $data = array(
-                       'mimetype' => 'httpd/unix-directory',
-                       'size' => 0,
-                       'mtime' => $mTime,
-                       'storage_mtime' => $mTime,
-                       'permissions' => \OCP\PERMISSION_ALL,
-               );
-
-               if ($dirName === '.' && ! $parentExists ) {
-                       //create root on the fly
-                       $data['etag'] = $this->getETag($dirName);
-                       $this->getCache()->put('', $data);
-                       $parentExists = true;
-               }
-
-               if ($parentExists) {
-                       $data['etag'] = $this->getETag($path);
-                       $this->getCache()->put($path, $data);
-                       return true;
-               }
-               return false;
-       }
-
-       public function file_exists($path) {
-               $path = $this->normalizePath($path);
-               return (bool)$this->stat($path);
-       }
-
-       private function rmObjects($path) {
-               $children = $this->getCache()->getFolderContents($path);
-               foreach ($children as $child) {
-                       if ($child['mimetype'] === 'httpd/unix-directory') {
-                               $this->rmObjects($child['path']);
-                       } else {
-                               $this->unlink($child['path']);
-                       }
-               }
-       }
-
-       public function rmdir($path) {
-               $path = $this->normalizePath($path);
-
-               if (!$this->is_dir($path)) {
-                       return false;
-               }
-
-               $this->rmObjects($path);
-
-               $this->getCache()->remove($path);
-
-               return true;
-       }
-
-       public function opendir($path) {
-               $path = $this->normalizePath($path);
-               
-               if ($path === '.') {
-                       $path = '';
-               } else if ($path) {
-                       $path .= '/';
-               }
-
-               try {
-                       $files = array();
-                       $folderContents = $this->getCache()->getFolderContents($path);
-                       foreach ($folderContents as $file) {
-                               $files[] = $file['name'];
-                       }
-                       
-                       \OC\Files\Stream\Dir::register('objstore' . $path, $files);
-
-                       return opendir('fakedir://objstore' . $path);
-               } catch (Exception $e) {
-                       \OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
-                       return false;
-               }
-       }
-
-       public function stat($path) {
-               return $this->getCache()->get($path);
-       }
-
-       public function filetype($path) {
-               $path = $this->normalizePath($path);
-               $stat = $this->stat($path);
-               if ($stat) {
-                       if ($stat['mimetype'] === 'httpd/unix-directory') {
-                               return 'dir';
-                       }
-                       return 'file';
-               } else {
-                       return false;
-               }
-       }
-
-       
-       public function unlink($path) {
-               $path = $this->normalizePath($path);
-               $stat = $this->stat($path);
-
-               if ($stat && isset($stat['fileid'])) {
-                       if ($stat['mimetype'] === 'httpd/unix-directory') {
-                               return $this->rmdir($path);
-                       }
-                       try {
-                               $this->deleteObject($this->getURN($stat['fileid']));
-                       } catch (\Exception $ex) {
-                               if ($ex->getCode() !== 404) {
-                                       \OCP\Util::writeLog('objectstore', 'Could not delete object: '.$ex->getMessage(), \OCP\Util::ERROR);
-                                       return false;
-                               } else {
-                                       //removing from cache is ok as it does not exist in the objectstore anyway
-                               }
-                       }
-                       $this->getCache()->remove($path);
-                       return true;
-               }
-               return false;
-       }
-       
-       public function fopen($path, $mode) {
-               $path = $this->normalizePath($path);
-
-               switch ($mode) {
-                       case 'r':
-                       case 'rb':
-                               $stat = $this->stat($path);
-                               if (is_array($stat)) {
-                                       $tmpFile = \OC_Helper::tmpFile();
-                                       self::$tmpFiles[$tmpFile] = $path;
-                                       try {
-                                               $this->getObject($this->getURN($stat['fileid']), $tmpFile);
-                                       } catch (\Exception $ex) {
-                                               \OCP\Util::writeLog('objectstore', 'Could not get object: '.$ex->getMessage(), \OCP\Util::ERROR);
-                                               return false;
-                                       }
-                                       return fopen($tmpFile, 'r');
-                               } else {
-                                       return false;
-                               }
-                       case 'w':
-                       case 'wb':
-                       case 'a':
-                       case 'ab':
-                       case 'r+':
-                       case 'w+':
-                       case 'wb+':
-                       case 'a+':
-                       case 'x':
-                       case 'x+':
-                       case 'c':
-                       case 'c+':
-                               if (strrpos($path, '.') !== false) {
-                                       $ext = substr($path, strrpos($path, '.'));
-                               } else {
-                                       $ext = '';
-                               }
-                               $tmpFile = \OC_Helper::tmpFile($ext);
-                               \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
-                               if ($this->file_exists($path)) {
-                                       $source = $this->fopen($path, 'r');
-                                       file_put_contents($tmpFile, $source);
-                               }
-                               self::$tmpFiles[$tmpFile] = $path;
-
-                               return fopen('close://' . $tmpFile, $mode);
-               }
-               return false;
-       }
-
-       public function rename($path1, $path2) {
-               $path1 = $this->normalizePath($path1);
-               $path2 = $this->normalizePath($path2);
-               $stat1 = $this->stat($path1);
-               if (is_array($stat1)) {
-                       $parent = $this->stat(dirname($path2));
-                       if (is_array($parent)) {
-                               $stat2 = $this->stat($path2);
-                               if (is_array($stat2)) {
-                                       $this->unlink($path2);
-                               }
-                               $stat1['parent'] = $parent['fileid'];
-                               $stat1['path'] = $path2;
-                               $stat1['path_hash'] = md5($path2);
-                               $stat1['name'] = \OC_Util::basename($path2);
-                               $stat1['mtime'] = time();
-                               $stat1['etag'] = $this->getETag($path2);
-                               $this->getCache()->update($stat1['fileid'], $stat1);
-                               return true;
-                       } else {
-                               return false;
-                       }
-                       
-               } else {
-                       return false;
-               }
-       }
-       
-       public function getMimeType($path) {
-               $path = $this->normalizePath($path);
-               $stat = $this->stat($path);
-               if (is_array($stat)) {
-                       return $stat['mimetype'];
-               } else {
-                       return false;
-               }
-       }
-       
-       public function touch($path, $mtime = null) {
-               if (is_null($mtime)) {
-                       $mtime = time();
-               }
-
-               $path = $this->normalizePath($path);
-               $dirName = dirname($path);
-               $parentExists = $this->is_dir($dirName);
-               if (!$parentExists) {
-                       return false;
-               }
-
-               $stat = $this->stat($path);
-               if (is_array($stat)) {
-                       // update existing mtime in db
-                       $stat['mtime'] = $mtime;
-                       $this->getCache()->update($stat['fileid'], $stat);
-               } else {
-                       $mimeType = \OC_Helper::getFileNameMimeType($path);
-                       // create new file
-                       $stat = array(
-                               'etag' => $this->getETag($path),
-                               'mimetype' => $mimeType,
-                               'size' => 0,
-                               'mtime' => $mtime,
-                               'storage_mtime' => $mtime,
-                               'permissions' => \OCP\PERMISSION_ALL,
-                       );
-                       $fileId = $this->getCache()->put($path, $stat);
-                       try {
-                               $this->createObject($this->getURN($fileId));
-                       } catch (\Exception $ex) {
-                               $this->getCache()->remove($path);
-                               \OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
-                               return false;
-                       }
-               }
-               return true;
-       }
-
-       /**
-        * Override this method if you need a different unique resource identifier for your object storage implementation.
-        * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
-        * You may need a mapping table to store your URN if it cannot be generated from the fileid.
-        * @param int $fileId the fileid
-        * @return null|string the unified resource name used to identify the object
-        */
-       protected function getURN($fileId) {
-               if (is_numeric($fileId)) {
-                       return 'urn:oid:'.$fileId;
-               }
-               return null;
-       }
-
-       public function writeBack($tmpFile) {
-               if (!isset(self::$tmpFiles[$tmpFile])) {
-                       return false;
-               }
-
-               $path = self::$tmpFiles[$tmpFile];
-               $stat = $this->stat($path);
-               if (empty($stat)) {
-                       // create new file
-                       $stat = array(
-                               'etag' => $this->getETag($path),
-                               'permissions' => \OCP\PERMISSION_ALL,
-                       );
-               }
-               // update stat with new data
-               $mTime = time();
-               $stat['size'] = filesize($tmpFile);
-               $stat['mtime'] = $mTime;
-               $stat['storage_mtime'] = $mTime;
-               $stat['mimetype'] = \OC_Helper::getMimeType($tmpFile);
-
-               $fileId = $this->getCache()->put($path, $stat);
-               try {
-                       //upload to object storage
-                       $this->createObject($this->getURN($fileId), $tmpFile);
-               } catch (\Exception $ex) {
-                       $this->getCache()->remove($path);
-                       \OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
-                       return false;
-               }
-               return true;
-       }
-
-}
\ No newline at end of file
diff --git a/lib/private/files/objectstore/homeobjectstorestorage.php b/lib/private/files/objectstore/homeobjectstorestorage.php
new file mode 100644 (file)
index 0000000..0c88972
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Jörn Friedrich Dreyer
+ * @copyright (c) 2014 Jörn Friedrich Dreyer <jfd@owncloud.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/>.
+ *
+ */
+
+namespace OC\Files\ObjectStore;
+
+class HomeObjectStoreStorage extends ObjectStoreStorage {
+
+       public function __construct($params) {
+               parent::__construct($params);
+
+               //initialize cache with root directory in cache
+               if ( ! $this->is_dir('files') ) {
+                       $this->mkdir('files');
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/lib/private/files/objectstore/objectstorestorage.php b/lib/private/files/objectstore/objectstorestorage.php
new file mode 100644 (file)
index 0000000..6b48e2d
--- /dev/null
@@ -0,0 +1,423 @@
+<?php
+/**
+ * @author Jörn Friedrich Dreyer
+ * @copyright (c) 2014 Jörn Friedrich Dreyer <jfd@owncloud.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/>.
+ *
+ */
+
+namespace OC\Files\ObjectStore;
+
+use OCP\Files\ObjectStore\IObjectStore;
+
+class ObjectStoreStorage extends \OC\Files\Storage\Common {
+
+       /**
+        * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
+        */
+       protected $objectStore;
+
+       /**
+        * @var \OC\User\User $user
+        */
+       protected $user;
+
+       /**
+        * @var array
+        */
+       private static $tmpFiles = array();
+
+       public function __construct($params) {
+               if (isset($params['user']) && $params['user'] instanceof \OC\User\User) {
+                       $this->user = $params['user'];
+               } else {
+                       $this->user = null;
+               }
+               if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
+                       $this->objectStore = $params['objectstore'];
+               } else {
+                       throw new \Exception('missing IObjectStore instance');
+               }
+               //initialize cache with root directory in cache
+               if ( ! $this->is_dir('/') ) {
+                       $this->mkdir('/');
+               }
+       }
+
+       /**
+        * Object Stores use a NoopScanner because metadata is directly stored in
+        * the file cache and cannot really scan the filesystem
+        * @param string $path
+        * @return \OC\Files\ObjectStore\NoopScanner
+        */
+       public function getScanner($path = '') {
+               if (!isset($this->scanner)) {
+                       $this->scanner = new NoopScanner($this);
+               }
+               return $this->scanner;
+       }
+       
+       /**
+        * get the owner of a path
+        *
+        * @param string $path The path to get the owner
+        * @return false|string uid
+        */
+       public function getOwner($path) {
+               if (is_object($this->user)) {
+                       return $this->user->getUID();
+               }
+               return false;
+       }
+
+       /**
+        * @param string $path, optional
+        * @return \OC\User\User
+        */
+       public function getUser($path = null) {
+               return $this->user;
+       }
+       
+       /**
+        * @param string $path
+        * @return string
+        */
+       private function normalizePath($path) {
+               $path = trim($path, '/');
+               //FIXME why do we sometimes get a path like 'files//username'?
+               $path = str_replace('//', '/', $path);
+
+               if (!$path) {
+                       $path = '.';
+               }
+
+               return $path;
+       }
+
+       public function getId () {
+               if (is_object($this->user)) {
+                       return 'objstore::user:' . $this->user->getUID();
+               }
+               return 'objstore::root';
+       }
+
+       public function mkdir($path) {
+               $path = $this->normalizePath($path);
+
+               if($this->is_dir($path)) {
+                       return false;
+               }
+
+               $dirName = dirname($path);
+               $parentExists = $this->is_dir($dirName);
+
+               $mTime = time();
+
+               $data = array(
+                       'mimetype' => 'httpd/unix-directory',
+                       'size' => 0,
+                       'mtime' => $mTime,
+                       'storage_mtime' => $mTime,
+                       'permissions' => \OCP\PERMISSION_ALL,
+               );
+
+               if ($dirName === '.' && ! $parentExists ) {
+                       //create root on the fly
+                       $data['etag'] = $this->getETag($dirName);
+                       $this->getCache()->put('', $data);
+                       $parentExists = true;
+               }
+
+               if ($parentExists) {
+                       $data['etag'] = $this->getETag($path);
+                       $this->getCache()->put($path, $data);
+                       return true;
+               }
+               return false;
+       }
+
+       public function file_exists($path) {
+               $path = $this->normalizePath($path);
+               return (bool)$this->stat($path);
+       }
+
+       private function rmObjects($path) {
+               $children = $this->getCache()->getFolderContents($path);
+               foreach ($children as $child) {
+                       if ($child['mimetype'] === 'httpd/unix-directory') {
+                               $this->rmObjects($child['path']);
+                       } else {
+                               $this->unlink($child['path']);
+                       }
+               }
+       }
+
+       public function rmdir($path) {
+               $path = $this->normalizePath($path);
+
+               if (!$this->is_dir($path)) {
+                       return false;
+               }
+
+               $this->rmObjects($path);
+
+               $this->getCache()->remove($path);
+
+               return true;
+       }
+
+       public function opendir($path) {
+               $path = $this->normalizePath($path);
+               
+               if ($path === '.') {
+                       $path = '';
+               } else if ($path) {
+                       $path .= '/';
+               }
+
+               try {
+                       $files = array();
+                       $folderContents = $this->getCache()->getFolderContents($path);
+                       foreach ($folderContents as $file) {
+                               $files[] = $file['name'];
+                       }
+                       
+                       \OC\Files\Stream\Dir::register('objstore' . $path, $files);
+
+                       return opendir('fakedir://objstore' . $path);
+               } catch (Exception $e) {
+                       \OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
+                       return false;
+               }
+       }
+
+       public function stat($path) {
+               return $this->getCache()->get($path);
+       }
+
+       public function filetype($path) {
+               $path = $this->normalizePath($path);
+               $stat = $this->stat($path);
+               if ($stat) {
+                       if ($stat['mimetype'] === 'httpd/unix-directory') {
+                               return 'dir';
+                       }
+                       return 'file';
+               } else {
+                       return false;
+               }
+       }
+
+       
+       public function unlink($path) {
+               $path = $this->normalizePath($path);
+               $stat = $this->stat($path);
+
+               if ($stat && isset($stat['fileid'])) {
+                       if ($stat['mimetype'] === 'httpd/unix-directory') {
+                               return $this->rmdir($path);
+                       }
+                       try {
+                               $this->objectStore->deleteObject($this->getURN($stat['fileid']));
+                       } catch (\Exception $ex) {
+                               if ($ex->getCode() !== 404) {
+                                       \OCP\Util::writeLog('objectstore', 'Could not delete object: '.$ex->getMessage(), \OCP\Util::ERROR);
+                                       return false;
+                               } else {
+                                       //removing from cache is ok as it does not exist in the objectstore anyway
+                               }
+                       }
+                       $this->getCache()->remove($path);
+                       return true;
+               }
+               return false;
+       }
+       
+       public function fopen($path, $mode) {
+               $path = $this->normalizePath($path);
+
+               switch ($mode) {
+                       case 'r':
+                       case 'rb':
+                               $stat = $this->stat($path);
+                               if (is_array($stat)) {
+                                       $tmpFile = \OC_Helper::tmpFile();
+                                       self::$tmpFiles[$tmpFile] = $path;
+                                       try {
+                                               $this->objectStore->getObject($this->getURN($stat['fileid']), $tmpFile);
+                                       } catch (\Exception $ex) {
+                                               \OCP\Util::writeLog('objectstore', 'Could not get object: '.$ex->getMessage(), \OCP\Util::ERROR);
+                                               return false;
+                                       }
+                                       return fopen($tmpFile, 'r');
+                               } else {
+                                       return false;
+                               }
+                       case 'w':
+                       case 'wb':
+                       case 'a':
+                       case 'ab':
+                       case 'r+':
+                       case 'w+':
+                       case 'wb+':
+                       case 'a+':
+                       case 'x':
+                       case 'x+':
+                       case 'c':
+                       case 'c+':
+                               if (strrpos($path, '.') !== false) {
+                                       $ext = substr($path, strrpos($path, '.'));
+                               } else {
+                                       $ext = '';
+                               }
+                               $tmpFile = \OC_Helper::tmpFile($ext);
+                               \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
+                               if ($this->file_exists($path)) {
+                                       $source = $this->fopen($path, 'r');
+                                       file_put_contents($tmpFile, $source);
+                               }
+                               self::$tmpFiles[$tmpFile] = $path;
+
+                               return fopen('close://' . $tmpFile, $mode);
+               }
+               return false;
+       }
+
+       public function rename($path1, $path2) {
+               $path1 = $this->normalizePath($path1);
+               $path2 = $this->normalizePath($path2);
+               $stat1 = $this->stat($path1);
+               if (is_array($stat1)) {
+                       $parent = $this->stat(dirname($path2));
+                       if (is_array($parent)) {
+                               $stat2 = $this->stat($path2);
+                               if (is_array($stat2)) {
+                                       $this->unlink($path2);
+                               }
+                               $stat1['parent'] = $parent['fileid'];
+                               $stat1['path'] = $path2;
+                               $stat1['path_hash'] = md5($path2);
+                               $stat1['name'] = \OC_Util::basename($path2);
+                               $stat1['mtime'] = time();
+                               $stat1['etag'] = $this->getETag($path2);
+                               $this->getCache()->update($stat1['fileid'], $stat1);
+                               return true;
+                       } else {
+                               return false;
+                       }
+                       
+               } else {
+                       return false;
+               }
+       }
+       
+       public function getMimeType($path) {
+               $path = $this->normalizePath($path);
+               $stat = $this->stat($path);
+               if (is_array($stat)) {
+                       return $stat['mimetype'];
+               } else {
+                       return false;
+               }
+       }
+       
+       public function touch($path, $mtime = null) {
+               if (is_null($mtime)) {
+                       $mtime = time();
+               }
+
+               $path = $this->normalizePath($path);
+               $dirName = dirname($path);
+               $parentExists = $this->is_dir($dirName);
+               if (!$parentExists) {
+                       return false;
+               }
+
+               $stat = $this->stat($path);
+               if (is_array($stat)) {
+                       // update existing mtime in db
+                       $stat['mtime'] = $mtime;
+                       $this->getCache()->update($stat['fileid'], $stat);
+               } else {
+                       $mimeType = \OC_Helper::getFileNameMimeType($path);
+                       // create new file
+                       $stat = array(
+                               'etag' => $this->getETag($path),
+                               'mimetype' => $mimeType,
+                               'size' => 0,
+                               'mtime' => $mtime,
+                               'storage_mtime' => $mtime,
+                               'permissions' => \OCP\PERMISSION_ALL,
+                       );
+                       $fileId = $this->getCache()->put($path, $stat);
+                       try {
+                               $this->objectStore->updateObject($this->getURN($fileId));
+                       } catch (\Exception $ex) {
+                               $this->getCache()->remove($path);
+                               \OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       /**
+        * Override this method if you need a different unique resource identifier for your object storage implementation.
+        * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
+        * You may need a mapping table to store your URN if it cannot be generated from the fileid.
+        * @param int $fileId the fileid
+        * @return null|string the unified resource name used to identify the object
+        */
+       protected function getURN($fileId) {
+               if (is_numeric($fileId)) {
+                       return 'urn:oid:'.$fileId;
+               }
+               return null;
+       }
+
+       public function writeBack($tmpFile) {
+               if (!isset(self::$tmpFiles[$tmpFile])) {
+                       return false;
+               }
+
+               $path = self::$tmpFiles[$tmpFile];
+               $stat = $this->stat($path);
+               if (empty($stat)) {
+                       // create new file
+                       $stat = array(
+                               'etag' => $this->getETag($path),
+                               'permissions' => \OCP\PERMISSION_ALL,
+                       );
+               }
+               // update stat with new data
+               $mTime = time();
+               $stat['size'] = filesize($tmpFile);
+               $stat['mtime'] = $mTime;
+               $stat['storage_mtime'] = $mTime;
+               $stat['mimetype'] = \OC_Helper::getMimeType($tmpFile);
+
+               $fileId = $this->getCache()->put($path, $stat);
+               try {
+                       //upload to object storage
+                       $this->objectStore->updateObject($this->getURN($fileId), $tmpFile);
+               } catch (\Exception $ex) {
+                       $this->getCache()->remove($path);
+                       \OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
+                       return false;
+               }
+               return true;
+       }
+
+}
\ No newline at end of file
index 53367367af0ea93d278127f00806b170e150f31c..f66b03889d25484ec0145697206a8379f306b044 100644 (file)
@@ -23,7 +23,7 @@ namespace OC\Files\ObjectStore;
 use Guzzle\Http\Exception\ClientErrorResponseException;
 use OpenCloud\OpenStack;
 
-class Swift extends AbstractObjectStore {
+class Swift implements \OCP\Files\ObjectStore\IObjectStore {
 
        /**
         * @var \OpenCloud\ObjectStore\Service
@@ -78,19 +78,22 @@ class Swift extends AbstractObjectStore {
                                throw $ex;
                        }
                }
-
-               //set the user via parent constructor, also initializes the root of the filecache
-               parent::__construct($params);
        }
 
+
        /**
         * @param string $urn Unified Resource Name
+        * @param string $tmpFile
         * @return void
         * @throws Exception from openstack lib when something goes wrong
         */
-       protected function deleteObject($urn) {
-               $object = $this->container->getObject($urn);
-               $object->delete();
+       public function updateObject($urn, $tmpFile = null) {
+               $fileData = '';
+               if ($tmpFile) {
+                       $fileData = fopen($tmpFile, 'r');
+               }
+
+               $this->container->uploadObject($urn, $fileData);
        }
 
        /**
@@ -99,7 +102,7 @@ class Swift extends AbstractObjectStore {
         * @return void
         * @throws Exception from openstack lib when something goes wrong
         */
-       protected function getObject($urn, $tmpFile) {
+       public function getObject($urn, $tmpFile) {
                $object = $this->container->getObject($urn);
 
                /** @var $objectContent \Guzzle\Http\EntityBody **/
@@ -112,17 +115,12 @@ class Swift extends AbstractObjectStore {
 
        /**
         * @param string $urn Unified Resource Name
-        * @param string $tmpFile
         * @return void
         * @throws Exception from openstack lib when something goes wrong
         */
-       protected function createObject($urn, $tmpFile = null) {
-               $fileData = '';
-               if ($tmpFile) {
-                       $fileData = fopen($tmpFile, 'r');
-               }
-
-               $this->container->uploadObject($urn, $fileData);
+       public function deleteObject($urn) {
+               $object = $this->container->getObject($urn);
+               $object->delete();
        }
 
        public function deleteContainer($recursive = false) {
index f2ecdcbded6a3994d17245d038ff4d28618e6b9d..d384eda5f7fd31eeb161edeae6f6ea92fded262b 100755 (executable)
@@ -32,11 +32,17 @@ class OC_Util {
        private static function initObjectStoreRootFS($config) {
                // check misconfiguration
                if (empty($config['class'])) {
-                       //FIXME log error?
+                       \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
                }
                if (!isset($config['arguments'])) {
                        $config['arguments'] = array();
                }
+
+               // instantiate object store implementation
+               $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
+               // mount with plain / root object store implementation
+               $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
+
                // mount object storage as root
                \OC\Files\Filesystem::initMounts();
                if(!self::$rootMounted) {
@@ -94,7 +100,7 @@ class OC_Util {
                                 * @var \OC\Files\Storage\Storage $storage
                                 */
                                if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
-                                       || $storage->instanceOfStorage('\OC\Files\ObjectStore\AbstractObjectStore')
+                                       || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
                                ) {
                                        if (is_object($storage->getUser())) {
                                                $user = $storage->getUser()->getUID();
diff --git a/lib/public/files/objectstore/iobjectstore.php b/lib/public/files/objectstore/iobjectstore.php
new file mode 100644 (file)
index 0000000..ecc35fa
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+namespace OCP\Files\ObjectStore;
+
+interface IObjectStore {
+
+       /**
+        * @param string $urn the unified resource name used to identify the object
+        * @param string $tmpFile path to the local temporary file that should be
+        *        used to store the object
+        * @return void
+        * @throws Exception when something goes wrong, message will be logged
+        */
+       function getObject($urn, $tmpFile);
+       /**
+        * @param string $urn the unified resource name used to identify the object
+        * @param string $tmpFile path to the local temporary file that the object
+        *        should be loaded from
+        * @return void
+        * @throws Exception when something goes wrong, message will be logged
+        */
+       function updateObject($urn, $tmpFile = null);
+
+
+       /**
+        * @param string $urn the unified resource name used to identify the object
+        * @return void
+        * @throws Exception when something goes wrong, message will be logged
+        */
+        function deleteObject($urn);
+
+}
\ No newline at end of file
index 497ea7f241c265aafa64c1e45920c2f35f8fabe7..d05af4d65877bf6341b5dcac9f3b326c316d76cc 100644 (file)
@@ -20,6 +20,7 @@
 
 namespace OCA\ObjectStore\Tests\Unit;
 
+use OC\Files\ObjectStore\ObjectStoreStorage;
 use OC\Files\ObjectStore\Swift as ObjectStoreToTest;
 
 use PHPUnit_Framework_TestCase;
@@ -30,6 +31,8 @@ class Swift extends PHPUnit_Framework_TestCase {
         * @var \OC\Files\ObjectStore\Swift $storage
         */
        private $storage;
+
+       private $objectStorage;
        
        public function setUp() {
                
@@ -67,14 +70,16 @@ class Swift extends PHPUnit_Framework_TestCase {
                        'serviceName' => 'swift', //trystack uses swift by default, the lib defaults to 'cloudFiles' if omitted
                        'user' => \OC_User::getManager()->get($userName)
                );
-               $this->storage = new ObjectStoreToTest($params);
+               $this->objectStorage = new ObjectStoreToTest($params);
+               $params['objectstore'] = $this->objectStorage;
+               $this->storage = new ObjectStoreStorage($params);
        }
 
        public function tearDown() {
                if (is_null($this->storage)) {
                        return;
                }
-               $this->storage->deleteContainer(true);
+               $this->objectStorage->deleteContainer(true);
                $this->storage->getCache()->clear();
                //TODO how do I clear hooks?
        }