diff options
Diffstat (limited to 'lib/private')
90 files changed, 2194 insertions, 1792 deletions
diff --git a/lib/private/activitymanager.php b/lib/private/activitymanager.php index f31b121c8e8..e0ee7c1b055 100644 --- a/lib/private/activitymanager.php +++ b/lib/private/activitymanager.php @@ -247,16 +247,28 @@ class ActivityManager implements IManager { * @return array */ function getQueryForFilter($filter) { + + $conditions = array(); + $parameters = array(); + foreach($this->extensions as $extension) { $c = $extension(); if ($c instanceof IExtension) { $result = $c->getQueryForFilter($filter); if (is_array($result)) { - return $result; + list($condition, $parameter) = $result; + if ($condition && is_array($parameter)) { + $conditions[] = $condition; + $parameters = array_merge($parameters, $parameter); + } } } } - return array(null, null); + if (empty($conditions)) { + return array(null, null); + } + + return array(' and ((' . implode(') or (', $conditions) . '))', $parameters); } } diff --git a/lib/private/api.php b/lib/private/api.php index f5576af2ad8..66b763fdc3e 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -132,7 +132,7 @@ class OC_API { * @return array|\OC_OCS_Result */ public static function mergeResponses($responses) { - // Sort into shipped and thirdparty + // Sort into shipped and third-party $shipped = array( 'succeeded' => array(), 'failed' => array(), @@ -162,7 +162,7 @@ class OC_API { if(!empty($shipped['failed'])) { // Which shipped response do we use if they all failed? // They may have failed for different reasons (different status codes) - // Which reponse code should we return? + // Which response code should we return? // Maybe any that are not OC_API::RESPOND_SERVER_ERROR // Merge failed responses if more than one $data = array(); @@ -273,26 +273,32 @@ class OC_API { // reuse existing login $loggedIn = OC_User::isLoggedIn(); - $ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false; - if ($loggedIn === true && $ocsApiRequest) { + if ($loggedIn === true) { + $ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false; + if ($ocsApiRequest) { - // initialize the user's filesystem - \OC_Util::setUpFS(\OC_User::getUser()); + // initialize the user's filesystem + \OC_Util::setUpFS(\OC_User::getUser()); - return OC_User::getUser(); + return OC_User::getUser(); + } + return false; } - // basic auth - $authUser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : ''; - $authPw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; - $return = OC_User::login($authUser, $authPw); - if ($return === true) { - self::$logoutRequired = true; + // basic auth - because OC_User::login will create a new session we shall only try to login + // if user and pass are set + if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']) ) { + $authUser = $_SERVER['PHP_AUTH_USER']; + $authPw = $_SERVER['PHP_AUTH_PW']; + $return = OC_User::login($authUser, $authPw); + if ($return === true) { + self::$logoutRequired = true; - // initialize the user's filesystem - \OC_Util::setUpFS(\OC_User::getUser()); + // initialize the user's filesystem + \OC_Util::setUpFS(\OC_User::getUser()); - return $authUser; + return $authUser; + } } return false; diff --git a/lib/private/app.php b/lib/private/app.php index bc9ca0351ea..8e36d43bfb1 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -635,63 +635,10 @@ class OC_App { } $file = self::getAppPath($appId) . '/appinfo/info.xml'; } - $data = array(); - if (!file_exists($file)) { - return null; - } - $content = @file_get_contents($file); - if (!$content) { - return null; - } - $xml = new SimpleXMLElement($content); - $data['info'] = array(); - $data['remote'] = array(); - $data['public'] = array(); - foreach ($xml->children() as $child) { - /** - * @var $child SimpleXMLElement - */ - if ($child->getName() == 'remote') { - foreach ($child->children() as $remote) { - /** - * @var $remote SimpleXMLElement - */ - $data['remote'][$remote->getName()] = (string)$remote; - } - } elseif ($child->getName() == 'public') { - foreach ($child->children() as $public) { - /** - * @var $public SimpleXMLElement - */ - $data['public'][$public->getName()] = (string)$public; - } - } elseif ($child->getName() == 'types') { - $data['types'] = array(); - foreach ($child->children() as $type) { - /** - * @var $type SimpleXMLElement - */ - $data['types'][] = $type->getName(); - } - } elseif ($child->getName() == 'description') { - $xml = (string)$child->asXML(); - $data[$child->getName()] = substr($xml, 13, -14); //script <description> tags - } elseif ($child->getName() == 'documentation') { - foreach ($child as $subChild) { - $url = (string) $subChild; - - // If it is not an absolute URL we assume it is a key - // i.e. admin-ldap will get converted to go.php?to=admin-ldap - if(!\OC::$server->getHTTPHelper()->isHTTPURL($url)) { - $url = OC_Helper::linkToDocs($url); - } - $data["documentation"][$subChild->getName()] = $url; - } - } else { - $data[$child->getName()] = (string)$child; - } - } + $parser = new \OC\App\InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator()); + $data = $parser->parse($file); + self::$appInfo[$appId] = $data; return $data; diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php new file mode 100644 index 00000000000..b4bdbea5c04 --- /dev/null +++ b/lib/private/app/infoparser.php @@ -0,0 +1,84 @@ +<?php + /** + * @author Thomas Müller + * @copyright 2014 Thomas Müller deepdiver@owncloud.com + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\App; + +use OCP\IURLGenerator; + +class InfoParser { + /** + * @var \OC\HTTPHelper + */ + private $httpHelper; + + /** + * @var IURLGenerator + */ + private $urlGenerator; + + /** + * @param \OC\HTTPHelper $httpHelper + * @param IURLGenerator $urlGenerator + */ + public function __construct(\OC\HTTPHelper $httpHelper, IURLGenerator $urlGenerator) { + $this->httpHelper = $httpHelper; + $this->urlGenerator = $urlGenerator; + } + + /** + * @param string $file the xml file to be loaded + * @return null|array where null is an indicator for an error + */ + public function parse($file) { + if (!file_exists($file)) { + return null; + } + + $loadEntities = libxml_disable_entity_loader(false); + $xml = @simplexml_load_file($file); + libxml_disable_entity_loader($loadEntities); + if ($xml == false) { + return null; + } + $array = json_decode(json_encode((array)$xml), TRUE); + if (is_null($array)) { + return null; + } + if (!array_key_exists('info', $array)) { + $array['info'] = array(); + } + if (!array_key_exists('remote', $array)) { + $array['remote'] = array(); + } + if (!array_key_exists('public', $array)) { + $array['public'] = array(); + } + + if (array_key_exists('documentation', $array)) { + foreach ($array['documentation'] as $key => $url) { + // If it is not an absolute URL we assume it is a key + // i.e. admin-ldap will get converted to go.php?to=admin-ldap + if (!$this->httpHelper->isHTTPURL($url)) { + $url = $this->urlGenerator->linkToDocs($url); + } + + $array['documentation'][$key] = $url; + } + } + if (array_key_exists('types', $array)) { + foreach ($array['types'] as $type => $v) { + unset($array['types'][$type]); + $array['types'][] = $type; + } + } + + return $array; + } +} diff --git a/lib/private/appframework/app.php b/lib/private/appframework/app.php index baf52d02054..f56ba4af870 100644 --- a/lib/private/appframework/app.php +++ b/lib/private/appframework/app.php @@ -53,7 +53,7 @@ class App { // initialize the dispatcher and run all the middleware before the controller $dispatcher = $container['Dispatcher']; - list($httpHeaders, $responseHeaders, $output) = + list($httpHeaders, $responseHeaders, $responseCookies, $output) = $dispatcher->dispatch($controller, $methodName); if(!is_null($httpHeaders)) { @@ -64,6 +64,14 @@ class App { header($name . ': ' . $value); } + foreach($responseCookies as $name => $value) { + $expireDate = null; + if($value['expireDate'] instanceof \DateTime) { + $expireDate = $value['expireDate']->getTimestamp(); + } + setcookie($name, $value['value'], $expireDate, $container->getServer()->getWebRoot(), null, $container->getServer()->getConfig()->getSystemValue('forcessl', false), true); + } + if(!is_null($output)) { header('Content-Length: ' . strlen($output)); print($output); diff --git a/lib/private/appframework/core/api.php b/lib/private/appframework/core/api.php index 279f4bf97f7..f68c677d106 100644 --- a/lib/private/appframework/core/api.php +++ b/lib/private/appframework/core/api.php @@ -49,6 +49,7 @@ class API implements IApi{ /** * Gets the userid of the current user * @return string the user id of the current user + * @deprecated Use \OC::$server->getUserSession()->getUser()->getUID() */ public function getUserId(){ return \OCP\User::getUser(); @@ -112,6 +113,7 @@ class API implements IApi{ /** * used to return and open a new event source * @return \OCP\IEventSource a new open EventSource class + * @deprecated Use \OC::$server->createEventSource(); */ public function openEventSource(){ return \OC::$server->createEventSource(); @@ -159,6 +161,7 @@ class API implements IApi{ * @param string $className full namespace and class name of the class * @param string $methodName the name of the static method that should be * called + * @deprecated Use \OC::$server->getJobList()->add(); */ public function addRegularTask($className, $methodName) { \OCP\Backgroundjob::addRegularTask($className, $methodName); diff --git a/lib/private/appframework/http/dispatcher.php b/lib/private/appframework/http/dispatcher.php index 29a661d5743..24540ef3c94 100644 --- a/lib/private/appframework/http/dispatcher.php +++ b/lib/private/appframework/http/dispatcher.php @@ -48,7 +48,7 @@ class Dispatcher { * @param Http $protocol the http protocol with contains all status headers * @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which * runs the middleware - * @param ControllerMethodReflector the reflector that is used to inject + * @param ControllerMethodReflector $reflector the reflector that is used to inject * the arguments for the controller * @param IRequest $request the incoming request */ @@ -71,6 +71,7 @@ class Dispatcher { * @return array $array[0] contains a string with the http main header, * $array[1] contains headers in the form: $key => value, $array[2] contains * the response output + * @throws \Exception */ public function dispatch(Controller $controller, $methodName) { $out = array(null, array(), null); @@ -102,13 +103,14 @@ class Dispatcher { // get the output which should be printed and run the after output // middleware to modify the response $output = $response->render(); - $out[2] = $this->middlewareDispatcher->beforeOutput( + $out[3] = $this->middlewareDispatcher->beforeOutput( $controller, $methodName, $output); // depending on the cache object the headers need to be changed $out[0] = $this->protocol->getStatusHeader($response->getStatus(), $response->getLastModified(), $response->getETag()); - $out[1] = $response->getHeaders(); + $out[1] = array_merge($response->getHeaders()); + $out[2] = $response->getCookies(); return $out; } diff --git a/lib/private/appframework/routing/routeconfig.php b/lib/private/appframework/routing/routeconfig.php index 91687b9c83c..9816b062b8d 100644 --- a/lib/private/appframework/routing/routeconfig.php +++ b/lib/private/appframework/routing/routeconfig.php @@ -69,6 +69,12 @@ class RouteConfig { $simpleRoutes = isset($routes['routes']) ? $routes['routes'] : array(); foreach ($simpleRoutes as $simpleRoute) { $name = $simpleRoute['name']; + $postfix = ''; + + if (isset($simpleRoute['postfix'])) { + $postfix = $simpleRoute['postfix']; + } + $url = $simpleRoute['url']; $verb = isset($simpleRoute['verb']) ? strtoupper($simpleRoute['verb']) : 'GET'; @@ -84,7 +90,7 @@ class RouteConfig { // register the route $handler = new RouteActionHandler($this->container, $controllerName, $actionName); - $router = $this->router->create($this->appName.'.'.$controller.'.'.$action, $url) + $router = $this->router->create($this->appName.'.'.$controller.'.'.$action . $postfix, $url) ->method($verb) ->action($handler); diff --git a/lib/private/arrayparser.php b/lib/private/arrayparser.php index dab1817c2ed..1cf3355d6fa 100644 --- a/lib/private/arrayparser.php +++ b/lib/private/arrayparser.php @@ -21,9 +21,6 @@ namespace OC; -class SyntaxException extends \Exception { -} - class ArrayParser { const TYPE_NUM = 1; const TYPE_BOOL = 2; @@ -209,7 +206,7 @@ class ArrayParser { $bracketDepth++; } elseif ($char === ')') { if ($bracketDepth <= 0) { - throw new SyntaxException; + throw new UnexpectedValueException(); } else { $bracketDepth--; } diff --git a/lib/private/contacts/localaddressbook.php b/lib/private/contacts/localaddressbook.php index 483bbee83f8..91ddb5798f2 100644 --- a/lib/private/contacts/localaddressbook.php +++ b/lib/private/contacts/localaddressbook.php @@ -91,7 +91,7 @@ class LocalAddressBook implements \OCP\IAddressBook { * @return int */ public function getPermissions() { - return \OCP\PERMISSION_READ; + return \OCP\Constants::PERMISSION_READ; } /** diff --git a/lib/private/contactsmanager.php b/lib/private/contactsmanager.php index 338cc048651..737fc4f0e3a 100644 --- a/lib/private/contactsmanager.php +++ b/lib/private/contactsmanager.php @@ -62,7 +62,7 @@ namespace OC { return null; } - if ($addressBook->getPermissions() & \OCP\PERMISSION_DELETE) { + if ($addressBook->getPermissions() & \OCP\Constants::PERMISSION_DELETE) { return null; } @@ -83,7 +83,7 @@ namespace OC { return null; } - if ($addressBook->getPermissions() & \OCP\PERMISSION_CREATE) { + if ($addressBook->getPermissions() & \OCP\Constants::PERMISSION_CREATE) { return null; } diff --git a/lib/private/databaseexception.php b/lib/private/databaseexception.php new file mode 100644 index 00000000000..1135621ead2 --- /dev/null +++ b/lib/private/databaseexception.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright (c) 2012 Frank Karlitschek <frank@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +class DatabaseException extends \Exception { + private $query; + + //FIXME getQuery seems to be unused, maybe use parent constructor with $message, $code and $previous + public function __construct($message, $query = null){ + parent::__construct($message); + $this->query = $query; + } + + public function getQuery() { + return $this->query; + } +} diff --git a/lib/private/databasesetupexception.php b/lib/private/databasesetupexception.php new file mode 100644 index 00000000000..9235cda8c0e --- /dev/null +++ b/lib/private/databasesetupexception.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +class DatabaseSetupException extends HintException { +} diff --git a/lib/private/db.php b/lib/private/db.php index b820281b8a3..f8015133682 100644 --- a/lib/private/db.php +++ b/lib/private/db.php @@ -22,20 +22,6 @@ define('MDB2_SCHEMA_DUMP_STRUCTURE', '1'); -class DatabaseException extends Exception { - private $query; - - //FIXME getQuery seems to be unused, maybe use parent constructor with $message, $code and $previous - public function __construct($message, $query = null){ - parent::__construct($message); - $this->query = $query; - } - - public function getQuery() { - return $this->query; - } -} - /** * This class manages the access to the database. It basically is a wrapper for * Doctrine with some adaptions. @@ -65,7 +51,7 @@ class OC_DB { * @param int $limit * @param int $offset * @param bool $isManipulation - * @throws DatabaseException + * @throws \OC\DatabaseException * @return OC_DB_StatementWrapper prepared SQL query * * SQL query via Doctrine prepare(), needs to be execute()'d! @@ -82,7 +68,7 @@ class OC_DB { try { $result =$connection->prepare($query, $limit, $offset); } catch (\Doctrine\DBAL\DBALException $e) { - throw new \DatabaseException($e->getMessage(), $query); + throw new \OC\DatabaseException($e->getMessage(), $query); } // differentiate between query and manipulation $result = new OC_DB_StatementWrapper($result, $isManipulation); @@ -123,7 +109,7 @@ class OC_DB { * .. or a simple sql query string * @param array $parameters * @return OC_DB_StatementWrapper - * @throws DatabaseException + * @throws \OC\DatabaseException */ static public function executeAudited( $stmt, array $parameters = null) { if (is_string($stmt)) { @@ -132,7 +118,7 @@ class OC_DB { // TODO try to convert LIMIT OFFSET notation to parameters, see fixLimitClauseForMSSQL $message = 'LIMIT and OFFSET are forbidden for portability reasons,' . ' pass an array with \'limit\' and \'offset\' instead'; - throw new DatabaseException($message); + throw new \OC\DatabaseException($message); } $stmt = array('sql' => $stmt, 'limit' => null, 'offset' => null); } @@ -140,7 +126,7 @@ class OC_DB { // convert to prepared statement if ( ! array_key_exists('sql', $stmt) ) { $message = 'statement array must at least contain key \'sql\''; - throw new DatabaseException($message); + throw new \OC\DatabaseException($message); } if ( ! array_key_exists('limit', $stmt) ) { $stmt['limit'] = null; @@ -160,7 +146,7 @@ class OC_DB { } else { $message = 'Expected a prepared statement or array got ' . gettype($stmt); } - throw new DatabaseException($message); + throw new \OC\DatabaseException($message); } return $result; } @@ -169,7 +155,7 @@ class OC_DB { * gets last value of autoincrement * @param string $table The optional table name (will replace *PREFIX*) and add sequence suffix * @return string id - * @throws DatabaseException + * @throws \OC\DatabaseException * * \Doctrine\DBAL\Connection lastInsertId * @@ -312,7 +298,7 @@ class OC_DB { * @param mixed $result * @param string $message * @return void - * @throws DatabaseException + * @throws \OC\DatabaseException */ public static function raiseExceptionOnError($result, $message = null) { if(self::isError($result)) { @@ -321,7 +307,7 @@ class OC_DB { } else { $message .= ', Root cause:' . self::getErrorMessage($result); } - throw new DatabaseException($message, self::getErrorCode($result)); + throw new \OC\DatabaseException($message, self::getErrorCode($result)); } } @@ -345,7 +331,7 @@ class OC_DB { * * @param string $table * @return bool - * @throws DatabaseException + * @throws \OC\DatabaseException */ public static function tableExists($table) { @@ -381,7 +367,7 @@ class OC_DB { $result = \OC_DB::executeAudited($sql, array($table)); break; default: - throw new DatabaseException("Unknown database type: $dbType"); + throw new \OC\DatabaseException("Unknown database type: $dbType"); } return $result->fetchOne() === $table; diff --git a/lib/private/db/connectionfactory.php b/lib/private/db/connectionfactory.php index f6253e09b95..58043b30440 100644 --- a/lib/private/db/connectionfactory.php +++ b/lib/private/db/connectionfactory.php @@ -90,7 +90,8 @@ class ConnectionFactory { $eventManager->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\OracleSessionInit); break; case 'sqlite3': - $eventManager->addEventSubscriber(new SQLiteSessionInit); + $journalMode = $additionalConnectionParams['sqlite.journal_mode']; + $eventManager->addEventSubscriber(new SQLiteSessionInit(true, $journalMode)); break; } $connection = \Doctrine\DBAL\DriverManager::getConnection( @@ -153,6 +154,7 @@ class ConnectionFactory { } $connectionParams['tablePrefix'] = $config->getSystemValue('dbtableprefix', 'oc_'); + $connectionParams['sqlite.journal_mode'] = $config->getSystemValue('sqlite.journal_mode', 'WAL'); //additional driver options, eg. for mysql ssl $driverOptions = $config->getSystemValue('dbdriveroptions', null); diff --git a/lib/private/db/mdb2schemamanager.php b/lib/private/db/mdb2schemamanager.php index 632e320576c..78267094d0e 100644 --- a/lib/private/db/mdb2schemamanager.php +++ b/lib/private/db/mdb2schemamanager.php @@ -49,7 +49,7 @@ class MDB2SchemaManager { * TODO: write more documentation */ public function createDbFromStructure($file) { - $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); + $schemaReader = new MDB2SchemaReader(\OC::$server->getConfig(), $this->conn->getDatabasePlatform()); $toSchema = $schemaReader->loadSchemaFromFile($file); return $this->executeSchemaChange($toSchema); } @@ -83,7 +83,7 @@ class MDB2SchemaManager { */ private function readSchemaFromFile($file) { $platform = $this->conn->getDatabasePlatform(); - $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $platform); + $schemaReader = new MDB2SchemaReader(\OC::$server->getConfig(), $platform); return $schemaReader->loadSchemaFromFile($file); } @@ -131,7 +131,7 @@ class MDB2SchemaManager { * @param string $file the xml file describing the tables */ public function removeDBStructure($file) { - $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); + $schemaReader = new MDB2SchemaReader(\OC::$server->getConfig(), $this->conn->getDatabasePlatform()); $fromSchema = $schemaReader->loadSchemaFromFile($file); $toSchema = clone $fromSchema; /** @var $table \Doctrine\DBAL\Schema\Table */ diff --git a/lib/private/db/mdb2schemareader.php b/lib/private/db/mdb2schemareader.php index 288eef5cda0..7dd4168fb6e 100644 --- a/lib/private/db/mdb2schemareader.php +++ b/lib/private/db/mdb2schemareader.php @@ -8,6 +8,9 @@ namespace OC\DB; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use OCP\IConfig; + class MDB2SchemaReader { /** * @var string $DBNAME @@ -25,13 +28,13 @@ class MDB2SchemaReader { protected $platform; /** - * @param \OC\Config $config + * @param \OCP\IConfig $config * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform */ - public function __construct($config, $platform) { + public function __construct(IConfig $config, AbstractPlatform $platform) { $this->platform = $platform; - $this->DBNAME = $config->getValue('dbname', 'owncloud'); - $this->DBTABLEPREFIX = $config->getValue('dbtableprefix', 'oc_'); + $this->DBNAME = $config->getSystemValue('dbname', 'owncloud'); + $this->DBTABLEPREFIX = $config->getSystemValue('dbtableprefix', 'oc_'); } /** diff --git a/lib/private/db/sqlitesessioninit.php b/lib/private/db/sqlitesessioninit.php index 7e1166be95b..1fff22b883a 100644 --- a/lib/private/db/sqlitesessioninit.php +++ b/lib/private/db/sqlitesessioninit.php @@ -19,12 +19,19 @@ class SQLiteSessionInit implements EventSubscriber { private $caseSensitiveLike; /** + * @var string + */ + private $journalMode; + + /** * Configure case sensitive like for each connection * * @param bool $caseSensitiveLike + * @param string $journalMode */ - public function __construct($caseSensitiveLike = true) { + public function __construct($caseSensitiveLike, $journalMode) { $this->caseSensitiveLike = $caseSensitiveLike; + $this->journalMode = $journalMode; } /** @@ -34,6 +41,7 @@ class SQLiteSessionInit implements EventSubscriber { public function postConnect(ConnectionEventArgs $args) { $sensitive = ($this->caseSensitiveLike) ? 'true' : 'false'; $args->getConnection()->executeUpdate('PRAGMA case_sensitive_like = ' . $sensitive); + $args->getConnection()->executeUpdate('PRAGMA journal_mode = ' . $this->journalMode); } public function getSubscribedEvents() { diff --git a/lib/private/files.php b/lib/private/files.php index 571d3215caa..98f3c52d6c6 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -24,17 +24,14 @@ // TODO: get rid of this using proper composer packages require_once 'mcnetic/phpzipstreamer/ZipStreamer.php'; -class GET_TYPE { - const FILE = 1; - const ZIP_FILES = 2; - const ZIP_DIR = 3; -} - /** * Class for file server access * */ class OC_Files { + const FILE = 1; + const ZIP_FILES = 2; + const ZIP_DIR = 3; /** * @param string $filename @@ -76,7 +73,7 @@ class OC_Files { } if (is_array($files)) { - $get_type = GET_TYPE::ZIP_FILES; + $get_type = self::ZIP_FILES; $basename = basename($dir); if ($basename) { $name = $basename . '.zip'; @@ -88,7 +85,7 @@ class OC_Files { } else { $filename = $dir . '/' . $files; if (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) { - $get_type = GET_TYPE::ZIP_DIR; + $get_type = self::ZIP_DIR; // downloading root ? if ($files === '') { $name = 'download.zip'; @@ -97,12 +94,12 @@ class OC_Files { } } else { - $get_type = GET_TYPE::FILE; + $get_type = self::FILE; $name = $files; } } - if ($get_type === GET_TYPE::FILE) { + if ($get_type === self::FILE) { $zip = false; if ($xsendfile && OC_App::isEnabled('files_encryption')) { $xsendfile = false; @@ -127,7 +124,7 @@ class OC_Files { if ($zip) { $executionTime = intval(ini_get('max_execution_time')); set_time_limit(0); - if ($get_type === GET_TYPE::ZIP_FILES) { + if ($get_type === self::ZIP_FILES) { foreach ($files as $file) { $file = $dir . '/' . $file; if (\OC\Files\Filesystem::is_file($file)) { @@ -138,7 +135,7 @@ class OC_Files { self::zipAddDir($file, $zip); } } - } elseif ($get_type === GET_TYPE::ZIP_DIR) { + } elseif ($get_type === self::ZIP_DIR) { $file = $dir . '/' . $files; self::zipAddDir($file, $zip); } diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 2c12f834518..4157da2281c 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -585,7 +585,7 @@ class Cache { /** * find a folder in the cache which has not been fully scanned * - * If multiply incomplete folders are in the cache, the one with the highest id will be returned, + * If multiple incomplete folders are in the cache, the one with the highest id will be returned, * use the one with the highest id gives the best result with the background scanner, since that is most * likely the folder where we stopped scanning previously * diff --git a/lib/private/files/cache/wrapper/cachejail.php b/lib/private/files/cache/wrapper/cachejail.php new file mode 100644 index 00000000000..7982293f5ed --- /dev/null +++ b/lib/private/files/cache/wrapper/cachejail.php @@ -0,0 +1,255 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache\Wrapper; + +/** + * Jail to a subdirectory of the wrapped cache + */ +class CacheJail extends CacheWrapper { + /** + * @var string + */ + protected $root; + + /** + * @param \OC\Files\Cache\Cache $cache + * @param string $root + */ + public function __construct($cache, $root) { + parent::__construct($cache); + $this->root = $root; + } + + protected function getSourcePath($path) { + if ($path === '') { + return $this->root; + } else { + return $this->root . '/' . $path; + } + } + + /** + * @param string $path + * @return null|string the jailed path or null if the path is outside the jail + */ + protected function getJailedPath($path) { + $rootLength = strlen($this->root) + 1; + if ($path === $this->root) { + return ''; + } else if (substr($path, 0, $rootLength) === $this->root . '/') { + return substr($path, $rootLength); + } else { + return null; + } + } + + /** + * @param array $entry + * @return array + */ + protected function formatCacheEntry($entry) { + if (isset($entry['path'])) { + $entry['path'] = $this->getJailedPath($entry['path']); + } + return $entry; + } + + protected function filterCacheEntry($entry) { + $rootLength = strlen($this->root) + 1; + return ($entry['path'] === $this->root) or (substr($entry['path'], 0, $rootLength) === $this->root . '/'); + } + + /** + * get the stored metadata of a file or folder + * + * @param string /int $file + * @return array|false + */ + public function get($file) { + if (is_string($file) or $file == '') { + $file = $this->getSourcePath($file); + } + return parent::get($file); + } + + /** + * store meta data for a file or folder + * + * @param string $file + * @param array $data + * + * @return int file id + */ + public function put($file, array $data) { + return $this->cache->put($this->getSourcePath($file), $data); + } + + /** + * update the metadata in the cache + * + * @param int $id + * @param array $data + */ + public function update($id, array $data) { + $this->cache->update($this->getSourcePath($id), $data); + } + + /** + * get the file id for a file + * + * @param string $file + * @return int + */ + public function getId($file) { + return $this->cache->getId($this->getSourcePath($file)); + } + + /** + * get the id of the parent folder of a file + * + * @param string $file + * @return int + */ + public function getParentId($file) { + if ($file === '') { + return -1; + } else { + return $this->cache->getParentId($this->getSourcePath($file)); + } + } + + /** + * check if a file is available in the cache + * + * @param string $file + * @return bool + */ + public function inCache($file) { + return $this->cache->inCache($this->getSourcePath($file)); + } + + /** + * remove a file or folder from the cache + * + * @param string $file + */ + public function remove($file) { + $this->cache->remove($this->getSourcePath($file)); + } + + /** + * Move a file or folder in the cache + * + * @param string $source + * @param string $target + */ + public function move($source, $target) { + $this->cache->move($this->getSourcePath($source), $this->getSourcePath($target)); + } + + /** + * remove all entries for files that are stored on the storage from the cache + */ + public function clear() { + $this->cache->remove($this->root); + } + + /** + * @param string $file + * + * @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE + */ + public function getStatus($file) { + return $this->cache->getStatus($this->getSourcePath($file)); + } + + private function formatSearchResults($results) { + $results = array_filter($results, array($this, 'filterCacheEntry')); + $results = array_values($results); + return array_map(array($this, 'formatCacheEntry'), $results); + } + + /** + * search for files matching $pattern + * + * @param string $pattern + * @return array an array of file data + */ + public function search($pattern) { + $results = $this->cache->search($pattern); + return $this->formatSearchResults($results); + } + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return array + */ + public function searchByMime($mimetype) { + $results = $this->cache->searchByMime($mimetype); + return $this->formatSearchResults($results); + } + + /** + * update the folder size and the size of all parent folders + * + * @param string|boolean $path + * @param array $data (optional) meta data of the folder + */ + public function correctFolderSize($path, $data = null) { + $this->cache->correctFolderSize($this->getSourcePath($path), $data); + } + + /** + * get the size of a folder and set it in the cache + * + * @param string $path + * @param array $entry (optional) meta data of the folder + * @return int + */ + public function calculateFolderSize($path, $entry = null) { + return $this->cache->calculateFolderSize($this->getSourcePath($path), $entry); + } + + /** + * get all file ids on the files on the storage + * + * @return int[] + */ + public function getAll() { + // not supported + return array(); + } + + /** + * find a folder in the cache which has not been fully scanned + * + * If multiply incomplete folders are in the cache, the one with the highest id will be returned, + * use the one with the highest id gives the best result with the background scanner, since that is most + * likely the folder where we stopped scanning previously + * + * @return string|bool the path of the folder or false when no folder matched + */ + public function getIncomplete() { + // not supported + return false; + } + + /** + * get the path of a file on this storage by it's id + * + * @param int $id + * @return string|null + */ + public function getPathById($id) { + $path = $this->cache->getPathById($id); + return $this->getJailedPath($path); + } +} diff --git a/lib/private/files/cache/wrapper/cachepermissionsmask.php b/lib/private/files/cache/wrapper/cachepermissionsmask.php new file mode 100644 index 00000000000..6ce6a4ebc44 --- /dev/null +++ b/lib/private/files/cache/wrapper/cachepermissionsmask.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache\Wrapper; + +class CachePermissionsMask extends CacheWrapper { + /** + * @var int + */ + protected $mask; + + /** + * @param \OC\Files\Cache\Cache $cache + * @param int $mask + */ + public function __construct($cache, $mask) { + parent::__construct($cache); + $this->mask = $mask; + } + + protected function formatCacheEntry($entry) { + if (isset($entry['permissions'])) { + $entry['permissions'] &= $this->mask; + } + return $entry; + } +} diff --git a/lib/private/files/cache/wrapper/cachewrapper.php b/lib/private/files/cache/wrapper/cachewrapper.php new file mode 100644 index 00000000000..040358ec657 --- /dev/null +++ b/lib/private/files/cache/wrapper/cachewrapper.php @@ -0,0 +1,247 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache\Wrapper; + +use OC\Files\Cache\Cache; + +class CacheWrapper extends Cache { + /** + * @var \OC\Files\Cache\Cache + */ + protected $cache; + + /** + * @param \OC\Files\Cache\Cache $cache + */ + public function __construct($cache) { + $this->cache = $cache; + } + + /** + * Make it easy for wrappers to modify every returned cache entry + * + * @param array $entry + * @return array + */ + protected function formatCacheEntry($entry) { + return $entry; + } + + /** + * get the stored metadata of a file or folder + * + * @param string /int $file + * @return array|false + */ + public function get($file) { + $result = $this->cache->get($file); + if ($result) { + $result = $this->formatCacheEntry($result); + } + return $result; + } + + /** + * get the metadata of all files stored in $folder + * + * @param string $folder + * @return array + */ + public function getFolderContents($folder) { + // cant do a simple $this->cache->.... call here since getFolderContentsById needs to be called on this + // and not the wrapped cache + $fileId = $this->getId($folder); + return $this->getFolderContentsById($fileId); + } + + /** + * get the metadata of all files stored in $folder + * + * @param int $fileId the file id of the folder + * @return array + */ + public function getFolderContentsById($fileId) { + $results = $this->cache->getFolderContentsById($fileId); + return array_map(array($this, 'formatCacheEntry'), $results); + } + + /** + * store meta data for a file or folder + * + * @param string $file + * @param array $data + * + * @return int file id + */ + public function put($file, array $data) { + return $this->cache->put($file, $data); + } + + /** + * update the metadata in the cache + * + * @param int $id + * @param array $data + */ + public function update($id, array $data) { + $this->cache->update($id, $data); + } + + /** + * get the file id for a file + * + * @param string $file + * @return int + */ + public function getId($file) { + return $this->cache->getId($file); + } + + /** + * get the id of the parent folder of a file + * + * @param string $file + * @return int + */ + public function getParentId($file) { + return $this->cache->getParentId($file); + } + + /** + * check if a file is available in the cache + * + * @param string $file + * @return bool + */ + public function inCache($file) { + return $this->cache->inCache($file); + } + + /** + * remove a file or folder from the cache + * + * @param string $file + */ + public function remove($file) { + $this->cache->remove($file); + } + + /** + * Move a file or folder in the cache + * + * @param string $source + * @param string $target + */ + public function move($source, $target) { + $this->cache->move($source, $target); + } + + /** + * remove all entries for files that are stored on the storage from the cache + */ + public function clear() { + $this->cache->clear(); + } + + /** + * @param string $file + * + * @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE + */ + public function getStatus($file) { + return $this->cache->getStatus($file); + } + + /** + * search for files matching $pattern + * + * @param string $pattern + * @return array an array of file data + */ + public function search($pattern) { + $results = $this->cache->search($pattern); + return array_map(array($this, 'formatCacheEntry'), $results); + } + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return array + */ + public function searchByMime($mimetype) { + $results = $this->cache->searchByMime($mimetype); + return array_map(array($this, 'formatCacheEntry'), $results); + } + + /** + * update the folder size and the size of all parent folders + * + * @param string|boolean $path + * @param array $data (optional) meta data of the folder + */ + public function correctFolderSize($path, $data = null) { + $this->cache->correctFolderSize($path, $data); + } + + /** + * get the size of a folder and set it in the cache + * + * @param string $path + * @param array $entry (optional) meta data of the folder + * @return int + */ + public function calculateFolderSize($path, $entry = null) { + return $this->cache->calculateFolderSize($path, $entry); + } + + /** + * get all file ids on the files on the storage + * + * @return int[] + */ + public function getAll() { + return $this->cache->getAll(); + } + + /** + * find a folder in the cache which has not been fully scanned + * + * If multiple incomplete folders are in the cache, the one with the highest id will be returned, + * use the one with the highest id gives the best result with the background scanner, since that is most + * likely the folder where we stopped scanning previously + * + * @return string|bool the path of the folder or false when no folder matched + */ + public function getIncomplete() { + return $this->cache->getIncomplete(); + } + + /** + * get the path of a file on this storage by it's id + * + * @param int $id + * @return string|null + */ + public function getPathById($id) { + return $this->cache->getPathById($id); + } + + /** + * get the storage id of the storage for a file and the internal path of the file + * unlike getPathById this does not limit the search to files on this storage and + * instead does a global search in the cache table + * + * @param int $id + * @return array, first element holding the storage id, second the path + */ + static public function getById($id) { + return parent::getById($id); + } +} diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index d6d6a245e44..8bab51f0737 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -173,14 +173,14 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return bool */ public function isReadable() { - return $this->checkPermissions(\OCP\PERMISSION_READ); + return $this->checkPermissions(\OCP\Constants::PERMISSION_READ); } /** * @return bool */ public function isUpdateable() { - return $this->checkPermissions(\OCP\PERMISSION_UPDATE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE); } /** @@ -189,21 +189,21 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return bool */ public function isCreatable() { - return $this->checkPermissions(\OCP\PERMISSION_CREATE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_CREATE); } /** * @return bool */ public function isDeletable() { - return $this->checkPermissions(\OCP\PERMISSION_DELETE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_DELETE); } /** * @return bool */ public function isShareable() { - return $this->checkPermissions(\OCP\PERMISSION_SHARE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_SHARE); } /** diff --git a/lib/private/files/node/file.php b/lib/private/files/node/file.php index 75d5e0166b6..81e251c20b8 100644 --- a/lib/private/files/node/file.php +++ b/lib/private/files/node/file.php @@ -16,7 +16,7 @@ class File extends Node implements \OCP\Files\File { * @throws \OCP\Files\NotPermittedException */ public function getContent() { - if ($this->checkPermissions(\OCP\PERMISSION_READ)) { + if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) { /** * @var \OC\Files\Storage\Storage $storage; */ @@ -31,7 +31,7 @@ class File extends Node implements \OCP\Files\File { * @throws \OCP\Files\NotPermittedException */ public function putContent($data) { - if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { + if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) { $this->sendHooks(array('preWrite')); $this->view->file_put_contents($this->path, $data); $this->sendHooks(array('postWrite')); @@ -55,7 +55,7 @@ class File extends Node implements \OCP\Files\File { public function fopen($mode) { $preHooks = array(); $postHooks = array(); - $requiredPermissions = \OCP\PERMISSION_READ; + $requiredPermissions = \OCP\Constants::PERMISSION_READ; switch ($mode) { case 'r+': case 'rb+': @@ -73,7 +73,7 @@ class File extends Node implements \OCP\Files\File { case 'ab': $preHooks[] = 'preWrite'; $postHooks[] = 'postWrite'; - $requiredPermissions |= \OCP\PERMISSION_UPDATE; + $requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE; break; } @@ -88,7 +88,7 @@ class File extends Node implements \OCP\Files\File { } public function delete() { - if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { + if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) { $this->sendHooks(array('preDelete')); $this->view->unlink($this->path); $nonExisting = new NonExistingFile($this->root, $this->view, $this->path); diff --git a/lib/private/files/node/folder.php b/lib/private/files/node/folder.php index 8c7acc339ae..83e20871528 100644 --- a/lib/private/files/node/folder.php +++ b/lib/private/files/node/folder.php @@ -180,7 +180,7 @@ class Folder extends Node implements \OCP\Files\Folder { * @throws \OCP\Files\NotPermittedException */ public function newFolder($path) { - if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { + if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) { $fullPath = $this->getFullPath($path); $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath); $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); @@ -201,7 +201,7 @@ class Folder extends Node implements \OCP\Files\Folder { * @throws \OCP\Files\NotPermittedException */ public function newFile($path) { - if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { + if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) { $fullPath = $this->getFullPath($path); $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath); $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); @@ -325,11 +325,11 @@ class Folder extends Node implements \OCP\Files\Folder { * @return bool */ public function isCreatable() { - return $this->checkPermissions(\OCP\PERMISSION_CREATE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_CREATE); } public function delete() { - if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { + if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) { $this->sendHooks(array('preDelete')); $this->view->rmdir($this->path); $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path); diff --git a/lib/private/files/node/node.php b/lib/private/files/node/node.php index bc075911749..c52f5bbd54f 100644 --- a/lib/private/files/node/node.php +++ b/lib/private/files/node/node.php @@ -81,7 +81,7 @@ class Node implements \OCP\Files\Node { * @throws \OCP\Files\NotPermittedException */ public function touch($mtime = null) { - if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { + if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) { $this->sendHooks(array('preTouch')); $this->view->touch($this->path, $mtime); $this->sendHooks(array('postTouch')); @@ -163,28 +163,28 @@ class Node implements \OCP\Files\Node { * @return bool */ public function isReadable() { - return $this->checkPermissions(\OCP\PERMISSION_READ); + return $this->checkPermissions(\OCP\Constants::PERMISSION_READ); } /** * @return bool */ public function isUpdateable() { - return $this->checkPermissions(\OCP\PERMISSION_UPDATE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE); } /** * @return bool */ public function isDeletable() { - return $this->checkPermissions(\OCP\PERMISSION_DELETE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_DELETE); } /** * @return bool */ public function isShareable() { - return $this->checkPermissions(\OCP\PERMISSION_SHARE); + return $this->checkPermissions(\OCP\Constants::PERMISSION_SHARE); } /** diff --git a/lib/private/files/node/root.php b/lib/private/files/node/root.php index 18e7a6b681a..1e8387dc5cb 100644 --- a/lib/private/files/node/root.php +++ b/lib/private/files/node/root.php @@ -262,7 +262,7 @@ class Root extends Folder implements Emitter { * @return int */ public function getPermissions() { - return \OCP\PERMISSION_CREATE; + return \OCP\Constants::PERMISSION_CREATE; } /** diff --git a/lib/private/files/objectstore/objectstorestorage.php b/lib/private/files/objectstore/objectstorestorage.php index ae8bff52896..b0095ad94bb 100644 --- a/lib/private/files/objectstore/objectstorestorage.php +++ b/lib/private/files/objectstore/objectstorestorage.php @@ -72,7 +72,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { 'size' => 0, 'mtime' => $mTime, 'storage_mtime' => $mTime, - 'permissions' => \OCP\PERMISSION_ALL, + 'permissions' => \OCP\Constants::PERMISSION_ALL, ); if ($dirName === '' && !$parentExists) { @@ -332,7 +332,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { 'size' => 0, 'mtime' => $mtime, 'storage_mtime' => $mtime, - 'permissions' => \OCP\PERMISSION_ALL, + 'permissions' => \OCP\Constants::PERMISSION_ALL, ); $fileId = $this->getCache()->put($path, $stat); try { @@ -357,7 +357,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { if (empty($stat)) { // create new file $stat = array( - 'permissions' => \OCP\PERMISSION_ALL, + 'permissions' => \OCP\Constants::PERMISSION_ALL, ); } // update stat with new data diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 518d3ec400c..d76c6aa031b 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -113,19 +113,19 @@ abstract class Common implements \OC\Files\Storage\Storage { public function getPermissions($path) { $permissions = 0; if ($this->isCreatable($path)) { - $permissions |= \OCP\PERMISSION_CREATE; + $permissions |= \OCP\Constants::PERMISSION_CREATE; } if ($this->isReadable($path)) { - $permissions |= \OCP\PERMISSION_READ; + $permissions |= \OCP\Constants::PERMISSION_READ; } if ($this->isUpdatable($path)) { - $permissions |= \OCP\PERMISSION_UPDATE; + $permissions |= \OCP\Constants::PERMISSION_UPDATE; } if ($this->isDeletable($path)) { - $permissions |= \OCP\PERMISSION_DELETE; + $permissions |= \OCP\Constants::PERMISSION_DELETE; } if ($this->isSharable($path)) { - $permissions |= \OCP\PERMISSION_SHARE; + $permissions |= \OCP\Constants::PERMISSION_SHARE; } return $permissions; } diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php index 26fa69408a8..a2832bce009 100644 --- a/lib/private/files/storage/dav.php +++ b/lib/private/files/storage/dav.php @@ -416,19 +416,19 @@ class DAV extends \OC\Files\Storage\Common { } public function isUpdatable($path) { - return (bool)($this->getPermissions($path) & \OCP\PERMISSION_UPDATE); + return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_UPDATE); } public function isCreatable($path) { - return (bool)($this->getPermissions($path) & \OCP\PERMISSION_CREATE); + return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_CREATE); } public function isSharable($path) { - return (bool)($this->getPermissions($path) & \OCP\PERMISSION_SHARE); + return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE); } public function isDeletable($path) { - return (bool)($this->getPermissions($path) & \OCP\PERMISSION_DELETE); + return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_DELETE); } public function getPermissions($path) { @@ -438,9 +438,9 @@ class DAV extends \OC\Files\Storage\Common { if (isset($response['{http://owncloud.org/ns}permissions'])) { return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); } else if ($this->is_dir($path)) { - return \OCP\PERMISSION_ALL; + return \OCP\Constants::PERMISSION_ALL; } else if ($this->file_exists($path)) { - return \OCP\PERMISSION_ALL - \OCP\PERMISSION_CREATE; + return \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE; } else { return 0; } @@ -451,19 +451,19 @@ class DAV extends \OC\Files\Storage\Common { * @return int */ protected function parsePermissions($permissionsString) { - $permissions = \OCP\PERMISSION_READ; + $permissions = \OCP\Constants::PERMISSION_READ; if (strpos($permissionsString, 'R') !== false) { - $permissions |= \OCP\PERMISSION_SHARE; + $permissions |= \OCP\Constants::PERMISSION_SHARE; } if (strpos($permissionsString, 'D') !== false) { - $permissions |= \OCP\PERMISSION_DELETE; + $permissions |= \OCP\Constants::PERMISSION_DELETE; } if (strpos($permissionsString, 'W') !== false) { - $permissions |= \OCP\PERMISSION_UPDATE; + $permissions |= \OCP\Constants::PERMISSION_UPDATE; } if (strpos($permissionsString, 'CK') !== false) { - $permissions |= \OCP\PERMISSION_CREATE; - $permissions |= \OCP\PERMISSION_UPDATE; + $permissions |= \OCP\Constants::PERMISSION_CREATE; + $permissions |= \OCP\Constants::PERMISSION_UPDATE; } return $permissions; } diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php index 1c5fafc12fa..7b4abf08f44 100644 --- a/lib/private/files/storage/local.php +++ b/lib/private/files/storage/local.php @@ -35,7 +35,7 @@ if (\OC_Util::runningOnWindows()) { } public function mkdir($path) { - return @mkdir($this->datadir . $path, 0777, true); + return @mkdir($this->getSourcePath($path), 0777, true); } public function rmdir($path) { @@ -44,7 +44,7 @@ if (\OC_Util::runningOnWindows()) { } try { $it = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator($this->datadir . $path), + new \RecursiveDirectoryIterator($this->getSourcePath($path)), \RecursiveIteratorIterator::CHILD_FIRST ); /** @@ -68,30 +68,30 @@ if (\OC_Util::runningOnWindows()) { } $it->next(); } - return rmdir($this->datadir . $path); + return rmdir($this->getSourcePath($path)); } catch (\UnexpectedValueException $e) { return false; } } public function opendir($path) { - return opendir($this->datadir . $path); + return opendir($this->getSourcePath($path)); } public function is_dir($path) { if (substr($path, -1) == '/') { $path = substr($path, 0, -1); } - return is_dir($this->datadir . $path); + return is_dir($this->getSourcePath($path)); } public function is_file($path) { - return is_file($this->datadir . $path); + return is_file($this->getSourcePath($path)); } public function stat($path) { clearstatcache(); - $fullPath = $this->datadir . $path; + $fullPath = $this->getSourcePath($path); $statResult = stat($fullPath); if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) { $filesize = $this->filesize($path); @@ -102,9 +102,9 @@ if (\OC_Util::runningOnWindows()) { } public function filetype($path) { - $filetype = filetype($this->datadir . $path); + $filetype = filetype($this->getSourcePath($path)); if ($filetype == 'link') { - $filetype = filetype(realpath($this->datadir . $path)); + $filetype = filetype(realpath($this->getSourcePath($path))); } return $filetype; } @@ -113,7 +113,7 @@ if (\OC_Util::runningOnWindows()) { if ($this->is_dir($path)) { return 0; } - $fullPath = $this->datadir . $path; + $fullPath = $this->getSourcePath($path); if (PHP_INT_SIZE === 4) { $helper = new \OC\LargeFileHelper; return $helper->getFilesize($fullPath); @@ -122,19 +122,19 @@ if (\OC_Util::runningOnWindows()) { } public function isReadable($path) { - return is_readable($this->datadir . $path); + return is_readable($this->getSourcePath($path)); } public function isUpdatable($path) { - return is_writable($this->datadir . $path); + return is_writable($this->getSourcePath($path)); } public function file_exists($path) { - return file_exists($this->datadir . $path); + return file_exists($this->getSourcePath($path)); } public function filemtime($path) { - return filemtime($this->datadir . $path); + return filemtime($this->getSourcePath($path)); } public function touch($path, $mtime = null) { @@ -145,30 +145,30 @@ if (\OC_Util::runningOnWindows()) { return false; } if (!is_null($mtime)) { - $result = touch($this->datadir . $path, $mtime); + $result = touch($this->getSourcePath($path), $mtime); } else { - $result = touch($this->datadir . $path); + $result = touch($this->getSourcePath($path)); } if ($result) { - clearstatcache(true, $this->datadir . $path); + clearstatcache(true, $this->getSourcePath($path)); } return $result; } public function file_get_contents($path) { - return file_get_contents($this->datadir . $path); + return file_get_contents($this->getSourcePath($path)); } - public function file_put_contents($path, $data) { //trigger_error("$path = ".var_export($path, 1)); - return file_put_contents($this->datadir . $path, $data); + public function file_put_contents($path, $data) { + return file_put_contents($this->getSourcePath($path), $data); } public function unlink($path) { if ($this->is_dir($path)) { return $this->rmdir($path); } else if ($this->is_file($path)) { - return unlink($this->datadir . $path); + return unlink($this->getSourcePath($path)); } else { return false; } @@ -200,27 +200,27 @@ if (\OC_Util::runningOnWindows()) { $this->unlink($path2); } - return rename($this->datadir . $path1, $this->datadir . $path2); + return rename($this->getSourcePath($path1), $this->getSourcePath($path2)); } public function copy($path1, $path2) { if ($this->is_dir($path1)) { return parent::copy($path1, $path2); } else { - return copy($this->datadir . $path1, $this->datadir . $path2); + return copy($this->getSourcePath($path1), $this->getSourcePath($path2)); } } public function fopen($path, $mode) { - return fopen($this->datadir . $path, $mode); + return fopen($this->getSourcePath($path), $mode); } public function hash($type, $path, $raw = false) { - return hash_file($type, $this->datadir . $path, $raw); + return hash_file($type, $this->getSourcePath($path), $raw); } public function free_space($path) { - $space = @disk_free_space($this->datadir . $path); + $space = @disk_free_space($this->getSourcePath($path)); if ($space === false || is_null($space)) { return \OCP\Files\FileInfo::SPACE_UNKNOWN; } @@ -232,11 +232,11 @@ if (\OC_Util::runningOnWindows()) { } public function getLocalFile($path) { - return $this->datadir . $path; + return $this->getSourcePath($path); } public function getLocalFolder($path) { - return $this->datadir . $path; + return $this->getSourcePath($path); } /** @@ -244,12 +244,16 @@ if (\OC_Util::runningOnWindows()) { */ protected function searchInDir($query, $dir = '') { $files = array(); - foreach (scandir($this->datadir . $dir) as $item) { - if ($item == '.' || $item == '..') continue; + $physicalDir = $this->getSourcePath($dir); + foreach (scandir($physicalDir) as $item) { + if ($item == '.' || $item == '..') + continue; + $physicalItem = $physicalDir . '/' . $item; + if (strstr(strtolower($item), strtolower($query)) !== false) { $files[] = $dir . '/' . $item; } - if (is_dir($this->datadir . $dir . '/' . $item)) { + if (is_dir($physicalItem)) { $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); } } @@ -272,6 +276,17 @@ if (\OC_Util::runningOnWindows()) { } /** + * Get the source path (on disk) of a given path + * + * @param string $path + * @return string + */ + protected function getSourcePath($path) { + $fullPath = $this->datadir . $path; + return $fullPath; + } + + /** * {@inheritdoc} */ public function isLocal() { diff --git a/lib/private/files/storage/mappedlocal.php b/lib/private/files/storage/mappedlocal.php index 0a21d2938b7..fe6fff4ebdb 100644 --- a/lib/private/files/storage/mappedlocal.php +++ b/lib/private/files/storage/mappedlocal.php @@ -24,9 +24,6 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function __destruct() { - if (defined('PHPUNIT_RUN')) { - $this->mapper->removePath($this->datadir, true, true); - } } public function getId() { @@ -34,7 +31,7 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function mkdir($path) { - return @mkdir($this->buildPath($path), 0777, true); + return @mkdir($this->getSourcePath($path), 0777, true); } public function rmdir($path) { @@ -43,7 +40,7 @@ class MappedLocal extends \OC\Files\Storage\Common { } try { $it = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator($this->buildPath($path)), + new \RecursiveDirectoryIterator($this->getSourcePath($path)), \RecursiveIteratorIterator::CHILD_FIRST ); /** @@ -67,7 +64,7 @@ class MappedLocal extends \OC\Files\Storage\Common { } $it->next(); } - if ($result = @rmdir($this->buildPath($path))) { + if ($result = @rmdir($this->getSourcePath($path))) { $this->cleanMapper($path); } return $result; @@ -78,7 +75,7 @@ class MappedLocal extends \OC\Files\Storage\Common { public function opendir($path) { $files = array('.', '..'); - $physicalPath = $this->buildPath($path); + $physicalPath = $this->getSourcePath($path); $logicalPath = $this->mapper->physicalToLogic($physicalPath); $dh = opendir($physicalPath); @@ -104,15 +101,16 @@ class MappedLocal extends \OC\Files\Storage\Common { if (substr($path, -1) == '/') { $path = substr($path, 0, -1); } - return is_dir($this->buildPath($path)); + return is_dir($this->getSourcePath($path)); } public function is_file($path) { - return is_file($this->buildPath($path)); + return is_file($this->getSourcePath($path)); } public function stat($path) { - $fullPath = $this->buildPath($path); + clearstatcache(); + $fullPath = $this->getSourcePath($path); $statResult = stat($fullPath); if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) { $filesize = $this->filesize($path); @@ -123,9 +121,9 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function filetype($path) { - $filetype = filetype($this->buildPath($path)); + $filetype = filetype($this->getSourcePath($path)); if ($filetype == 'link') { - $filetype = filetype(realpath($this->buildPath($path))); + $filetype = filetype(realpath($this->getSourcePath($path))); } return $filetype; } @@ -134,7 +132,7 @@ class MappedLocal extends \OC\Files\Storage\Common { if ($this->is_dir($path)) { return 0; } - $fullPath = $this->buildPath($path); + $fullPath = $this->getSourcePath($path); if (PHP_INT_SIZE === 4) { $helper = new \OC\LargeFileHelper; return $helper->getFilesize($fullPath); @@ -143,43 +141,46 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function isReadable($path) { - return is_readable($this->buildPath($path)); + return is_readable($this->getSourcePath($path)); } public function isUpdatable($path) { - return is_writable($this->buildPath($path)); + return is_writable($this->getSourcePath($path)); } public function file_exists($path) { - return file_exists($this->buildPath($path)); + return file_exists($this->getSourcePath($path)); } public function filemtime($path) { - return filemtime($this->buildPath($path)); + return filemtime($this->getSourcePath($path)); } public function touch($path, $mtime = null) { // sets the modification time of the file to the given value. // If mtime is nil the current time is set. // note that the access time of the file always changes to the current time. + if ($this->file_exists($path) and !$this->isUpdatable($path)) { + return false; + } if (!is_null($mtime)) { - $result = touch($this->buildPath($path), $mtime); + $result = touch($this->getSourcePath($path), $mtime); } else { - $result = touch($this->buildPath($path)); + $result = touch($this->getSourcePath($path)); } if ($result) { - clearstatcache(true, $this->buildPath($path)); + clearstatcache(true, $this->getSourcePath($path)); } return $result; } public function file_get_contents($path) { - return file_get_contents($this->buildPath($path)); + return file_get_contents($this->getSourcePath($path)); } public function file_put_contents($path, $data) { - return file_put_contents($this->buildPath($path), $data); + return file_put_contents($this->getSourcePath($path), $data); } public function unlink($path) { @@ -211,8 +212,8 @@ class MappedLocal extends \OC\Files\Storage\Common { $this->unlink($path2); } - $physicPath1 = $this->buildPath($path1); - $physicPath2 = $this->buildPath($path2); + $physicPath1 = $this->getSourcePath($path1); + $physicPath2 = $this->getSourcePath($path2); if ($return = rename($physicPath1, $physicPath2)) { // mapper needs to create copies or all children $this->copyMapping($path1, $path2); @@ -240,7 +241,7 @@ class MappedLocal extends \OC\Files\Storage\Common { closedir($dir); return true; } else { - if ($return = copy($this->buildPath($path1), $this->buildPath($path2))) { + if ($return = copy($this->getSourcePath($path1), $this->getSourcePath($path2))) { $this->copyMapping($path1, $path2); } return $return; @@ -248,7 +249,7 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function fopen($path, $mode) { - return fopen($this->buildPath($path), $mode); + return fopen($this->getSourcePath($path), $mode); } /** @@ -259,7 +260,7 @@ class MappedLocal extends \OC\Files\Storage\Common { private function delTree($dir, $isLogicPath = true) { $dirRelative = $dir; if ($isLogicPath) { - $dir = $this->buildPath($dir); + $dir = $this->getSourcePath($dir); } if (!file_exists($dir)) { return true; @@ -291,11 +292,15 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function hash($type, $path, $raw = false) { - return hash_file($type, $this->buildPath($path), $raw); + return hash_file($type, $this->getSourcePath($path), $raw); } public function free_space($path) { - return @disk_free_space($this->buildPath($path)); + $space = @disk_free_space($this->getSourcePath($path)); + if ($space === false || is_null($space)) { + return \OCP\Files\FileInfo::SPACE_UNKNOWN; + } + return $space; } public function search($query) { @@ -303,11 +308,11 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function getLocalFile($path) { - return $this->buildPath($path); + return $this->getSourcePath($path); } public function getLocalFolder($path) { - return $this->buildPath($path); + return $this->getSourcePath($path); } /** @@ -315,7 +320,7 @@ class MappedLocal extends \OC\Files\Storage\Common { */ protected function searchInDir($query, $dir = '') { $files = array(); - $physicalDir = $this->buildPath($dir); + $physicalDir = $this->getSourcePath($dir); foreach (scandir($physicalDir) as $item) { if ($item == '.' || $item == '..') continue; @@ -340,18 +345,30 @@ class MappedLocal extends \OC\Files\Storage\Common { * @return bool */ public function hasUpdated($path, $time) { - return $this->filemtime($path) > $time; + if ($this->file_exists($path)) { + return $this->filemtime($path) > $time; + } else { + return true; + } } /** + * Get the source path (on disk) of a given path + * * @param string $path - * @param bool $create * @return string */ - private function buildPath($path, $create = true) { + protected function getSourcePath($path) { $path = $this->stripLeading($path); $fullPath = $this->datadir . $path; - return $this->mapper->logicToPhysical($fullPath, $create); + return $this->mapper->logicToPhysical($fullPath, true); + } + + /** + * {@inheritdoc} + */ + public function isLocal() { + return true; } /** diff --git a/lib/private/files/storage/wrapper/jail.php b/lib/private/files/storage/wrapper/jail.php new file mode 100644 index 00000000000..22b96765757 --- /dev/null +++ b/lib/private/files/storage/wrapper/jail.php @@ -0,0 +1,413 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage\Wrapper; + +use OC\Files\Cache\Wrapper\CacheJail; + +/** + * Jail to a subdirectory of the wrapped storage + * + * This restricts access to a subfolder of the wrapped storage with the subfolder becoming the root folder new storage + */ +class Jail extends Wrapper { + /** + * @var string + */ + protected $rootPath; + + /** + * @param array $arguments ['storage' => $storage, 'mask' => $root] + * + * $storage: The storage that will be wrapper + * $root: The folder in the wrapped storage that will become the root folder of the wrapped storage + */ + public function __construct($arguments) { + parent::__construct($arguments); + $this->rootPath = $arguments['root']; + } + + protected function getSourcePath($path) { + if ($path === '') { + return $this->rootPath; + } else { + return $this->rootPath . '/' . $path; + } + } + + public function getId() { + return 'link:' . parent::getId() . ':' . $this->rootPath; + } + + /** + * see http://php.net/manual/en/function.mkdir.php + * + * @param string $path + * @return bool + */ + public function mkdir($path) { + return $this->storage->mkdir($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.rmdir.php + * + * @param string $path + * @return bool + */ + public function rmdir($path) { + return $this->storage->rmdir($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.opendir.php + * + * @param string $path + * @return resource + */ + public function opendir($path) { + return $this->storage->opendir($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.is_dir.php + * + * @param string $path + * @return bool + */ + public function is_dir($path) { + return $this->storage->is_dir($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.is_file.php + * + * @param string $path + * @return bool + */ + public function is_file($path) { + return $this->storage->is_file($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.stat.php + * only the following keys are required in the result: size and mtime + * + * @param string $path + * @return array + */ + public function stat($path) { + return $this->storage->stat($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.filetype.php + * + * @param string $path + * @return bool + */ + public function filetype($path) { + return $this->storage->filetype($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.filesize.php + * The result for filesize when called on a folder is required to be 0 + * + * @param string $path + * @return int + */ + public function filesize($path) { + return $this->storage->filesize($this->getSourcePath($path)); + } + + /** + * check if a file can be created in $path + * + * @param string $path + * @return bool + */ + public function isCreatable($path) { + return $this->storage->isCreatable($this->getSourcePath($path)); + } + + /** + * check if a file can be read + * + * @param string $path + * @return bool + */ + public function isReadable($path) { + return $this->storage->isReadable($this->getSourcePath($path)); + } + + /** + * check if a file can be written to + * + * @param string $path + * @return bool + */ + public function isUpdatable($path) { + return $this->storage->isUpdatable($this->getSourcePath($path)); + } + + /** + * check if a file can be deleted + * + * @param string $path + * @return bool + */ + public function isDeletable($path) { + return $this->storage->isDeletable($this->getSourcePath($path)); + } + + /** + * check if a file can be shared + * + * @param string $path + * @return bool + */ + public function isSharable($path) { + return $this->storage->isSharable($this->getSourcePath($path)); + } + + /** + * get the full permissions of a path. + * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php + * + * @param string $path + * @return int + */ + public function getPermissions($path) { + return $this->storage->getPermissions($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.file_exists.php + * + * @param string $path + * @return bool + */ + public function file_exists($path) { + return $this->storage->file_exists($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.filemtime.php + * + * @param string $path + * @return int + */ + public function filemtime($path) { + return $this->storage->filemtime($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.file_get_contents.php + * + * @param string $path + * @return string + */ + public function file_get_contents($path) { + return $this->storage->file_get_contents($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.file_put_contents.php + * + * @param string $path + * @param string $data + * @return bool + */ + public function file_put_contents($path, $data) { + return $this->storage->file_put_contents($this->getSourcePath($path), $data); + } + + /** + * see http://php.net/manual/en/function.unlink.php + * + * @param string $path + * @return bool + */ + public function unlink($path) { + return $this->storage->unlink($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.rename.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function rename($path1, $path2) { + return $this->storage->rename($this->getSourcePath($path1), $this->getSourcePath($path2)); + } + + /** + * see http://php.net/manual/en/function.copy.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function copy($path1, $path2) { + return $this->storage->copy($this->getSourcePath($path1), $this->getSourcePath($path2)); + } + + /** + * see http://php.net/manual/en/function.fopen.php + * + * @param string $path + * @param string $mode + * @return resource + */ + public function fopen($path, $mode) { + return $this->storage->fopen($this->getSourcePath($path), $mode); + } + + /** + * get the mimetype for a file or folder + * The mimetype for a folder is required to be "httpd/unix-directory" + * + * @param string $path + * @return string + */ + public function getMimeType($path) { + return $this->storage->getMimeType($this->getSourcePath($path)); + } + + /** + * see http://php.net/manual/en/function.hash.php + * + * @param string $type + * @param string $path + * @param bool $raw + * @return string + */ + public function hash($type, $path, $raw = false) { + return $this->storage->hash($type, $this->getSourcePath($path), $raw); + } + + /** + * see http://php.net/manual/en/function.free_space.php + * + * @param string $path + * @return int + */ + public function free_space($path) { + return $this->storage->free_space($this->getSourcePath($path)); + } + + /** + * search for occurrences of $query in file names + * + * @param string $query + * @return array + */ + public function search($query) { + return $this->storage->search($query); + } + + /** + * see http://php.net/manual/en/function.touch.php + * If the backend does not support the operation, false should be returned + * + * @param string $path + * @param int $mtime + * @return bool + */ + public function touch($path, $mtime = null) { + return $this->storage->touch($this->getSourcePath($path), $mtime); + } + + /** + * get the path to a local version of the file. + * The local version of the file can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFile($path) { + return $this->storage->getLocalFile($this->getSourcePath($path)); + } + + /** + * get the path to a local version of the folder. + * The local version of the folder can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFolder($path) { + return $this->storage->getLocalFolder($this->getSourcePath($path)); + } + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + public function hasUpdated($path, $time) { + return $this->storage->hasUpdated($this->getSourcePath($path), $time); + } + + /** + * get a cache instance for the storage + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache + * @return \OC\Files\Cache\Cache + */ + public function getCache($path = '', $storage = null) { + if (!$storage) { + $storage = $this; + } + $sourceCache = $this->storage->getCache($this->getSourcePath($path), $storage); + return new CacheJail($sourceCache, $this->rootPath); + } + + /** + * get the user id of the owner of a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path) { + return $this->storage->getOwner($this->getSourcePath($path)); + } + + /** + * get a watcher instance for the cache + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Watcher + */ + public function getWatcher($path = '', $storage = null) { + if (!$storage) { + $storage = $this; + } + return $this->storage->getWatcher($this->getSourcePath($path), $storage); + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path) { + return $this->storage->getETag($this->getSourcePath($path)); + } +} diff --git a/lib/private/files/storage/wrapper/permissionsmask.php b/lib/private/files/storage/wrapper/permissionsmask.php new file mode 100644 index 00000000000..955cb54591b --- /dev/null +++ b/lib/private/files/storage/wrapper/permissionsmask.php @@ -0,0 +1,111 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage\Wrapper; + +use OC\Files\Cache\Wrapper\CachePermissionsMask; +use OCP\Constants; + +/** + * Mask the permissions of a storage + * + * This can be used to restrict update, create, delete and/or share permissions of a storage + * + * Note that the read permissions cant be masked + */ +class PermissionsMask extends Wrapper { + /** + * @var int the permissions bits we want to keep + */ + private $mask; + + /** + * @param array $arguments ['storage' => $storage, 'mask' => $mask] + * + * $storage: The storage the permissions mask should be applied on + * $mask: The permission bits that should be kept, a combination of the \OCP\Constant::PERMISSION_ constants + */ + public function __construct($arguments) { + parent::__construct($arguments); + $this->mask = $arguments['mask']; + } + + private function checkMask($permissions) { + return ($this->mask & $permissions) === $permissions; + } + + public function isUpdatable($path) { + return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::isUpdatable($path); + } + + public function isCreatable($path) { + return $this->checkMask(Constants::PERMISSION_CREATE) and parent::isCreatable($path); + } + + public function isDeletable($path) { + return $this->checkMask(Constants::PERMISSION_DELETE) and parent::isDeletable($path); + } + + public function getPermissions($path) { + return $this->storage->getPermissions($path) & $this->mask; + } + + public function rename($path1, $path2) { + return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($path1, $path2); + } + + public function copy($path1, $path2) { + return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($path1, $path2); + } + + public function touch($path, $mtime = null) { + $permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; + return $this->checkMask($permissions) and parent::touch($path, $mtime); + } + + public function mkdir($path) { + return $this->checkMask(Constants::PERMISSION_CREATE) and parent::mkdir($path); + } + + public function rmdir($path) { + return $this->checkMask(Constants::PERMISSION_DELETE) and parent::rmdir($path); + } + + public function unlink($path) { + return $this->checkMask(Constants::PERMISSION_DELETE) and parent::unlink($path); + } + + public function file_put_contents($path, $data) { + $permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; + return $this->checkMask($permissions) and parent::file_put_contents($path, $data); + } + + public function fopen($path, $mode) { + if ($mode === 'r' or $mode === 'rb') { + return parent::fopen($path, $mode); + } else { + $permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; + return $this->checkMask($permissions) ? parent::fopen($path, $mode) : false; + } + } + + /** + * get a cache instance for the storage + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache + * @return \OC\Files\Cache\Cache + */ + public function getCache($path = '', $storage = null) { + if (!$storage) { + $storage = $this; + } + $sourceCache = parent::getCache($path, $storage); + return new CachePermissionsMask($sourceCache, $this->mask); + } +} diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 19676524a0e..331ab9ba6cd 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -933,7 +933,7 @@ class View { } if ($mount instanceof MoveableMount && $internalPath === '') { - $data['permissions'] |= \OCP\PERMISSION_DELETE | \OCP\PERMISSION_UPDATE; + $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE; } $data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data); @@ -988,7 +988,7 @@ class View { } // if sharing was disabled for the user we remove the share permissions if (\OCP\Util::isSharingDisabledForUser()) { - $content['permissions'] = $content['permissions'] & ~\OCP\PERMISSION_SHARE; + $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content); } @@ -1025,9 +1025,9 @@ class View { // do not allow renaming/deleting the mount point if they are not shared files/folders // for shared files/folders we use the permissions given by the owner if ($mount instanceof MoveableMount) { - $rootEntry['permissions'] = $permissions | \OCP\PERMISSION_UPDATE | \OCP\PERMISSION_DELETE; + $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE; } else { - $rootEntry['permissions'] = $permissions & (\OCP\PERMISSION_ALL - (\OCP\PERMISSION_UPDATE | \OCP\PERMISSION_DELETE)); + $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)); } //remove any existing entry with the same name @@ -1041,7 +1041,7 @@ class View { // if sharing was disabled for the user we remove the share permissions if (\OCP\Util::isSharingDisabledForUser()) { - $content['permissions'] = $content['permissions'] & ~\OCP\PERMISSION_SHARE; + $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry); diff --git a/lib/private/group/backend.php b/lib/private/group/backend.php index ab694268bb3..9348463a53c 100644 --- a/lib/private/group/backend.php +++ b/lib/private/group/backend.php @@ -23,29 +23,51 @@ /** * error code for functions not provided by the group backend + * @deprecated Use \OC_Group_Backend::NOT_IMPLEMENTED instead */ define('OC_GROUP_BACKEND_NOT_IMPLEMENTED', -501); /** * actions that user backends can define */ +/** @deprecated Use \OC_Group_Backend::CREATE_GROUP instead */ define('OC_GROUP_BACKEND_CREATE_GROUP', 0x00000001); +/** @deprecated Use \OC_Group_Backend::DELETE_GROUP instead */ define('OC_GROUP_BACKEND_DELETE_GROUP', 0x00000010); +/** @deprecated Use \OC_Group_Backend::ADD_TO_GROUP instead */ define('OC_GROUP_BACKEND_ADD_TO_GROUP', 0x00000100); +/** @deprecated Use \OC_Group_Backend::REMOVE_FROM_GOUP instead */ define('OC_GROUP_BACKEND_REMOVE_FROM_GOUP', 0x00001000); +/** @deprecated Obsolete */ define('OC_GROUP_BACKEND_GET_DISPLAYNAME', 0x00010000); //OBSOLETE +/** @deprecated Use \OC_Group_Backend::COUNT_USERS instead */ define('OC_GROUP_BACKEND_COUNT_USERS', 0x00100000); /** * Abstract base class for user management */ abstract class OC_Group_Backend implements OC_Group_Interface { + /** + * error code for functions not provided by the group backend + */ + const NOT_IMPLEMENTED = -501; + + /** + * actions that user backends can define + */ + const CREATE_GROUP = 0x00000001; + const DELETE_GROUP = 0x00000010; + const ADD_TO_GROUP = 0x00000100; + const REMOVE_FROM_GOUP = 0x00001000; + //OBSOLETE const GET_DISPLAYNAME = 0x00010000; + const COUNT_USERS = 0x00100000; + protected $possibleActions = array( - OC_GROUP_BACKEND_CREATE_GROUP => 'createGroup', - OC_GROUP_BACKEND_DELETE_GROUP => 'deleteGroup', - OC_GROUP_BACKEND_ADD_TO_GROUP => 'addToGroup', - OC_GROUP_BACKEND_REMOVE_FROM_GOUP => 'removeFromGroup', - OC_GROUP_BACKEND_COUNT_USERS => 'countUsersInGroup', + self::CREATE_GROUP => 'createGroup', + self::DELETE_GROUP => 'deleteGroup', + self::ADD_TO_GROUP => 'addToGroup', + self::REMOVE_FROM_GOUP => 'removeFromGroup', + self::COUNT_USERS => 'countUsersInGroup', ); /** diff --git a/lib/private/group/database.php b/lib/private/group/database.php index 6bad55c8d5e..2069e99599f 100644 --- a/lib/private/group/database.php +++ b/lib/private/group/database.php @@ -220,7 +220,7 @@ class OC_Group_Database extends OC_Group_Backend { * @param string $gid * @param string $search * @return int|false - * @throws DatabaseException + * @throws \OC\DatabaseException */ public function countUsersInGroup($gid, $search = '') { $stmt = OC_DB::prepare('SELECT COUNT(`uid`) AS `count` FROM `*PREFIX*group_user` WHERE `gid` = ? AND `uid` LIKE ?'); diff --git a/lib/private/group/group.php b/lib/private/group/group.php index 6f8b84dff1a..6111051ea09 100644 --- a/lib/private/group/group.php +++ b/lib/private/group/group.php @@ -118,7 +118,7 @@ class Group implements IGroup { $this->emitter->emit('\OC\Group', 'preAddUser', array($this, $user)); } foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_ADD_TO_GROUP)) { + if ($backend->implementsActions(\OC_Group_Backend::ADD_TO_GROUP)) { $backend->addToGroup($user->getUID(), $this->gid); if ($this->users) { $this->users[$user->getUID()] = $user; @@ -142,7 +142,7 @@ class Group implements IGroup { $this->emitter->emit('\OC\Group', 'preRemoveUser', array($this, $user)); } foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_REMOVE_FROM_GOUP) and $backend->inGroup($user->getUID(), $this->gid)) { + if ($backend->implementsActions(\OC_Group_Backend::REMOVE_FROM_GOUP) and $backend->inGroup($user->getUID(), $this->gid)) { $backend->removeFromGroup($user->getUID(), $this->gid); $result = true; } @@ -191,7 +191,7 @@ class Group implements IGroup { public function count($search = '') { $users = false; foreach ($this->backends as $backend) { - if($backend->implementsActions(OC_GROUP_BACKEND_COUNT_USERS)) { + if($backend->implementsActions(\OC_Group_Backend::COUNT_USERS)) { if($users === false) { //we could directly add to a bool variable, but this would //be ugly @@ -234,7 +234,7 @@ class Group implements IGroup { $this->emitter->emit('\OC\Group', 'preDelete', array($this)); } foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_DELETE_GROUP)) { + if ($backend->implementsActions(\OC_Group_Backend::DELETE_GROUP)) { $result = true; $backend->deleteGroup($this->gid); } diff --git a/lib/private/group/interface.php b/lib/private/group/interface.php index ee5c2d635d6..ee2d718e5dd 100644 --- a/lib/private/group/interface.php +++ b/lib/private/group/interface.php @@ -28,7 +28,7 @@ interface OC_Group_Interface { * @return boolean * * Returns the supported actions as int to be - * compared with OC_GROUP_BACKEND_CREATE_GROUP etc. + * compared with \OC_Group_Backend::CREATE_GROUP etc. */ public function implementsActions($actions); diff --git a/lib/private/group/manager.php b/lib/private/group/manager.php index 417be79ab30..be7bf972693 100644 --- a/lib/private/group/manager.php +++ b/lib/private/group/manager.php @@ -134,7 +134,7 @@ class Manager extends PublicEmitter implements IGroupManager { } else { $this->emit('\OC\Group', 'preCreate', array($gid)); foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_CREATE_GROUP)) { + if ($backend->implementsActions(\OC_Group_Backend::CREATE_GROUP)) { $backend->createGroup($gid); $group = $this->getGroupObject($gid); $this->emit('\OC\Group', 'postCreate', array($group)); diff --git a/lib/private/helper.php b/lib/private/helper.php index 5b1d31bfc59..0e302275540 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -58,12 +58,11 @@ class OC_Helper { } /** - * @param $key + * @param string $key * @return string url to the online documentation */ public static function linkToDocs($key) { - $theme = new OC_Defaults(); - return $theme->buildDocLinkToKey($key); + return OC::$server->getURLGenerator()->linkToDocs($key); } /** @@ -873,6 +872,23 @@ class OC_Helper { } /** + * Try to find a program + * Note: currently windows is not supported + * + * @param string $program + * @return null|string + */ + public static function findBinaryPath($program) { + if (!\OC_Util::runningOnWindows() && self::is_function_enabled('exec')) { + exec('command -v ' . escapeshellarg($program) . ' 2> /dev/null', $output, $returnCode); + if ($returnCode === 0 && count($output) > 0) { + return escapeshellcmd($output[0]); + } + } + return null; + } + + /** * Calculate the disc space for the given path * * @param string $path @@ -957,4 +973,12 @@ class OC_Helper { return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); } + + /** + * Returns whether the config file is set manually to read-only + * @return bool + */ + public static function isReadOnlyConfigEnabled() { + return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false); + } } diff --git a/lib/private/image.php b/lib/private/image.php index bab91745c05..ecdad084c02 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -311,6 +311,10 @@ class OC_Image { * @return int The orientation or -1 if no EXIF data is available. */ public function getOrientation() { + if ($this->imageType !== IMAGETYPE_JPEG) { + OC_Log::write('core', 'OC_Image->fixOrientation() Image is not a JPEG.', OC_Log::DEBUG); + return -1; + } if(!is_callable('exif_read_data')) { OC_Log::write('core', 'OC_Image->fixOrientation() Exif module not enabled.', OC_Log::DEBUG); return -1; diff --git a/lib/private/installer.php b/lib/private/installer.php index cd1d8ce392f..60ed06ae352 100644 --- a/lib/private/installer.php +++ b/lib/private/installer.php @@ -558,8 +558,8 @@ class OC_Installer{ // is the code checker enabled? if(OC_Config::getValue('appcodechecker', true)) { // check if grep is installed - $grep = exec('command -v grep'); - if($grep=='') { + $grep = \OC_Helper::findBinaryPath('grep'); + if (!$grep) { OC_Log::write('core', 'grep not installed. So checking the code of the app "'.$appname.'" was not possible', OC_Log::ERROR); @@ -568,7 +568,7 @@ class OC_Installer{ // iterate the bad patterns foreach($blacklist as $bl) { - $cmd = 'grep -ri '.escapeshellarg($bl).' '.$folder.''; + $cmd = 'grep --include \\*.php -ri '.escapeshellarg($bl).' '.$folder.''; $result = exec($cmd); // bad pattern found if($result<>'') { diff --git a/lib/private/l10n.php b/lib/private/l10n.php index 6ec4e967c7f..bc4e53e975c 100644 --- a/lib/private/l10n.php +++ b/lib/private/l10n.php @@ -7,19 +7,9 @@ * @copyright 2012 Frank Karlitschek frank@owncloud.org * @copyright 2013 Jakob Sack * - * 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/>. - * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ /** @@ -30,6 +20,7 @@ class OC_L10N implements \OCP\IL10N { * cache */ protected static $cache = array(); + protected static $availableLanguages = array(); /** * The best language @@ -89,7 +80,8 @@ class OC_L10N implements \OCP\IL10N { } /** - * @param string $transFile + * @param $transFile + * @param bool $mergeTranslations * @return bool */ public function load($transFile, $mergeTranslations = false) { @@ -141,8 +133,8 @@ class OC_L10N implements \OCP\IL10N { // load the translations file if($this->load($transFile)) { //merge with translations from theme - $theme = OC_Config::getValue( "theme" ); - if (!is_null($theme)) { + $theme = \OC::$server->getConfig()->getSystemValue('theme'); + if (!empty($theme)) { $transFile = OC::$SERVERROOT.'/themes/'.$theme.substr($transFile, strlen(OC::$SERVERROOT)); if (file_exists($transFile)) { $this->load($transFile, true); @@ -285,7 +277,8 @@ class OC_L10N implements \OCP\IL10N { * Localization * @param string $type Type of localization * @param array|int|string $data parameters for this localization - * @return String or false + * @param array $options + * @return string|false * * Returns the localized data. * @@ -393,8 +386,8 @@ class OC_L10N implements \OCP\IL10N { return self::$language; } - if(OC_User::getUser() && OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang')) { - $lang = OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang'); + if(OC_User::getUser() && \OC::$server->getConfig()->getUserValue(OC_User::getUser(), 'core', 'lang')) { + $lang = \OC::$server->getConfig()->getUserValue(OC_User::getUser(), 'core', 'lang'); self::$language = $lang; if(is_array($app)) { $available = $app; @@ -407,7 +400,7 @@ class OC_L10N implements \OCP\IL10N { } } - $default_language = OC_Config::getValue('default_language', false); + $default_language = \OC::$server->getConfig()->getSystemValue('default_language', false); if($default_language !== false) { return $default_language; @@ -457,17 +450,17 @@ class OC_L10N implements \OCP\IL10N { */ protected static function findI18nDir($app) { // find the i18n dir - $i18ndir = OC::$SERVERROOT.'/core/l10n/'; + $i18nDir = OC::$SERVERROOT.'/core/l10n/'; if($app != '') { // Check if the app is in the app folder if(file_exists(OC_App::getAppPath($app).'/l10n/')) { - $i18ndir = OC_App::getAppPath($app).'/l10n/'; + $i18nDir = OC_App::getAppPath($app).'/l10n/'; } else{ - $i18ndir = OC::$SERVERROOT.'/'.$app.'/l10n/'; + $i18nDir = OC::$SERVERROOT.'/'.$app.'/l10n/'; } } - return $i18ndir; + return $i18nDir; } /** @@ -476,6 +469,9 @@ class OC_L10N implements \OCP\IL10N { * @return array an array of available languages */ public static function findAvailableLanguages($app=null) { + if(!empty(self::$availableLanguages)) { + return self::$availableLanguages; + } $available=array('en');//english is always available $dir = self::findI18nDir($app); if(is_dir($dir)) { @@ -487,6 +483,8 @@ class OC_L10N implements \OCP\IL10N { } } } + + self::$availableLanguages = $available; return $available; } @@ -496,7 +494,7 @@ class OC_L10N implements \OCP\IL10N { * @return bool */ public static function languageExists($app, $lang) { - if ($lang == 'en') {//english is always available + if ($lang === 'en') {//english is always available return true; } $dir = self::findI18nDir($app); diff --git a/lib/private/legacy/config.php b/lib/private/legacy/config.php index 13ff0dbe040..7b711204256 100644 --- a/lib/private/legacy/config.php +++ b/lib/private/legacy/config.php @@ -23,14 +23,6 @@ class OC_Config { public static $object; /** - * Returns the config instance - * @return \OC\Config - */ - public static function getObject() { - return self::$object; - } - - /** * Lists all available config keys * @return array an array of key names * diff --git a/lib/private/migrate.php b/lib/private/migrate.php deleted file mode 100644 index 8351155aa55..00000000000 --- a/lib/private/migrate.php +++ /dev/null @@ -1,626 +0,0 @@ -<?php -/** - * ownCloud - * - * @author Tom Needham - * @copyright 2012 Tom Needham tom@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/>. - * - */ - - -/** - * provides an interface to migrate users and whole ownclouds - */ -class OC_Migrate{ - - - // Array of OC_Migration_Provider objects - static private $providers=array(); - // User id of the user to import/export - static private $uid=false; - // Holds the ZipArchive object - static private $zip=false; - // Stores the type of export - static private $exporttype=false; - // Holds the db object - static private $migration_database=false; - // Path to the sqlite db - static private $dbpath=false; - // Holds the path to the zip file - static private $zippath=false; - // Holds the OC_Migration_Content object - static private $content=false; - - /** - * register a new migration provider - * @param OC_Migration_Provider $provider - */ - public static function registerProvider($provider) { - self::$providers[]=$provider; - } - - /** - * finds and loads the providers - */ - static private function findProviders() { - // Find the providers - $apps = OC_App::getAllApps(); - - foreach($apps as $app) { - $path = OC_App::getAppPath($app) . '/appinfo/migrate.php'; - if( file_exists( $path ) ) { - include_once $path; - } - } - } - - /** - * exports a user, or owncloud instance - * @param string $uid user id of user to export if export type is user, defaults to current - * @param string $type type of export, defualts to user - * @param string $path path to zip output folder - * @return string on error, path to zip on success - */ - public static function export( $uid=null, $type='user', $path=null ) { - $datadir = OC_Config::getValue( 'datadirectory' ); - // Validate export type - $types = array( 'user', 'instance', 'system', 'userfiles' ); - if( !in_array( $type, $types ) ) { - OC_Log::write( 'migration', 'Invalid export type', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - self::$exporttype = $type; - // Userid? - if( self::$exporttype == 'user' ) { - // Check user exists - self::$uid = is_null($uid) ? OC_User::getUser() : $uid; - if(!OC_User::userExists(self::$uid)) { - return json_encode( array( 'success' => false) ); - } - } - // Calculate zipname - if( self::$exporttype == 'user' ) { - $zipname = 'oc_export_' . self::$uid . '_' . date("y-m-d_H-i-s") . '.zip'; - } else { - $zipname = 'oc_export_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '.zip'; - } - // Calculate path - if( self::$exporttype == 'user' ) { - self::$zippath = $datadir . '/' . self::$uid . '/' . $zipname; - } else { - if( !is_null( $path ) ) { - // Validate custom path - if( !file_exists( $path ) || !is_writeable( $path ) ) { - OC_Log::write( 'migration', 'Path supplied is invalid.', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - self::$zippath = $path . $zipname; - } else { - // Default path - self::$zippath = get_temp_dir() . '/' . $zipname; - } - } - // Create the zip object - if( !self::createZip() ) { - return json_encode( array( 'success' => false ) ); - } - // Do the export - self::findProviders(); - $exportdata = array(); - switch( self::$exporttype ) { - case 'user': - // Connect to the db - self::$dbpath = $datadir . '/' . self::$uid . '/migration.db'; - if( !self::connectDB() ) { - return json_encode( array( 'success' => false ) ); - } - self::$content = new OC_Migration_Content( self::$zip, self::$migration_database ); - // Export the app info - $exportdata = self::exportAppData(); - // Add the data dir to the zip - self::$content->addDir(OC_User::getHome(self::$uid), true, '/' ); - break; - case 'instance': - self::$content = new OC_Migration_Content( self::$zip ); - // Creates a zip that is compatable with the import function - $dbfile = tempnam( get_temp_dir(), "owncloud_export_data_" ); - OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL'); - - // Now add in *dbname* and *dbprefix* - $dbexport = file_get_contents( $dbfile ); - $dbnamestring = "<database>\n\n <name>" . OC_Config::getValue( "dbname", "owncloud" ); - $dbtableprefixstring = "<table>\n\n <name>" . OC_Config::getValue( "dbtableprefix", "oc_" ); - $dbexport = str_replace( $dbnamestring, "<database>\n\n <name>*dbname*", $dbexport ); - $dbexport = str_replace( $dbtableprefixstring, "<table>\n\n <name>*dbprefix*", $dbexport ); - // Add the export to the zip - self::$content->addFromString( $dbexport, "dbexport.xml" ); - // Add user data - foreach(OC_User::getUsers() as $user) { - self::$content->addDir(OC_User::getHome($user), true, "/userdata/" ); - } - break; - case 'userfiles': - self::$content = new OC_Migration_Content( self::$zip ); - // Creates a zip with all of the users files - foreach(OC_User::getUsers() as $user) { - self::$content->addDir(OC_User::getHome($user), true, "/" ); - } - break; - case 'system': - self::$content = new OC_Migration_Content( self::$zip ); - // Creates a zip with the owncloud system files - self::$content->addDir( OC::$SERVERROOT . '/', false, '/'); - foreach (array( - ".git", - "3rdparty", - "apps", - "core", - "files", - "l10n", - "lib", - "ocs", - "search", - "settings", - "tests" - ) as $dir) { - self::$content->addDir( OC::$SERVERROOT . '/' . $dir, true, "/"); - } - break; - } - if( !$info = self::getExportInfo( $exportdata ) ) { - return json_encode( array( 'success' => false ) ); - } - // Add the export info json to the export zip - self::$content->addFromString( $info, 'export_info.json' ); - if( !self::$content->finish() ) { - return json_encode( array( 'success' => false ) ); - } - return json_encode( array( 'success' => true, 'data' => self::$zippath ) ); - } - - /** - * imports a user, or owncloud instance - * @param string $path path to zip - * @param string $type type of import (user or instance) - * @param string|null|int $uid userid of new user - * @return string - */ - public static function import( $path, $type='user', $uid=null ) { - - $datadir = OC_Config::getValue( 'datadirectory' ); - // Extract the zip - if( !$extractpath = self::extractZip( $path ) ) { - return json_encode( array( 'success' => false ) ); - } - // Get export_info.json - $scan = scandir( $extractpath ); - // Check for export_info.json - if( !in_array( 'export_info.json', $scan ) ) { - OC_Log::write( 'migration', 'Invalid import file, export_info.json not found', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - $json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) ); - if( $json->exporttype != $type ) { - OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - self::$exporttype = $type; - - $currentuser = OC_User::getUser(); - - // Have we got a user if type is user - if( self::$exporttype == 'user' ) { - self::$uid = !is_null($uid) ? $uid : $currentuser; - } - - // We need to be an admin if we are not importing our own data - if(($type == 'user' && self::$uid != $currentuser) || $type != 'user' ) { - if( !OC_User::isAdminUser($currentuser)) { - // Naughty. - OC_Log::write( 'migration', 'Import not permitted.', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - } - - // Handle export types - switch( self::$exporttype ) { - case 'user': - // Check user availability - if( !OC_User::userExists( self::$uid ) ) { - OC_Log::write( 'migration', 'User doesn\'t exist', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Check if the username is valid - if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $json->exporteduser )) { - OC_Log::write( 'migration', 'Username is not valid', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Copy data - $userfolder = $extractpath . $json->exporteduser; - $newuserfolder = $datadir . '/' . self::$uid; - foreach(scandir($userfolder) as $file){ - if($file !== '.' && $file !== '..' && is_dir($userfolder.'/'.$file)) { - $file = str_replace(array('/', '\\'), '', $file); - - // Then copy the folder over - OC_Helper::copyr($userfolder.'/'.$file, $newuserfolder.'/'.$file); - } - } - // Import user app data - if(file_exists($extractpath . $json->exporteduser . '/migration.db')) { - if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', - $json, - self::$uid ) ) { - return json_encode( array( 'success' => false ) ); - } - } - // All done! - if( !self::unlink_r( $extractpath ) ) { - OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR ); - } - return json_encode( array( 'success' => true, 'data' => $appsimported ) ); - break; - case 'instance': - /* - * EXPERIMENTAL - // Check for new data dir and dbexport before doing anything - // TODO - - // Delete current data folder. - OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO ); - if( !self::unlink_r( $datadir, false ) ) { - OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Copy over data - if( !self::copy_r( $extractpath . 'userdata', $datadir ) ) { - OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Import the db - if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ) { - return json_encode( array( 'success' => false ) ); - } - // Done - return json_encode( array( 'success' => true ) ); - */ - break; - } - - } - - /** - * recursively deletes a directory - * @param string $dir path of dir to delete - * @param bool $deleteRootToo delete the root directory - * @return bool - */ - private static function unlink_r( $dir, $deleteRootToo=true ) { - if( !$dh = @opendir( $dir ) ) { - return false; - } - while (false !== ($obj = readdir($dh))) { - if($obj == '.' || $obj == '..') { - continue; - } - if (!@unlink($dir . '/' . $obj)) { - self::unlink_r($dir.'/'.$obj, true); - } - } - closedir($dh); - if ( $deleteRootToo ) { - @rmdir($dir); - } - return true; - } - - /** - * tries to extract the import zip - * @param string $path path to the zip - * @return string path to extract location (with a trailing slash) or false on failure - */ - static private function extractZip( $path ) { - self::$zip = new ZipArchive; - // Validate path - if( !file_exists( $path ) ) { - OC_Log::write( 'migration', 'Zip not found', OC_Log::ERROR ); - return false; - } - if ( self::$zip->open( $path ) != true ) { - OC_Log::write( 'migration', "Failed to open zip file", OC_Log::ERROR ); - return false; - } - $to = get_temp_dir() . '/oc_import_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '/'; - if( !self::$zip->extractTo( $to ) ) { - return false; - } - self::$zip->close(); - return $to; - } - - /** - * creates a migration.db in the users data dir with their app data in - * @return bool whether operation was successfull - */ - private static function exportAppData( ) { - - $success = true; - $return = array(); - - // Foreach provider - foreach( self::$providers as $provider ) { - // Check if the app is enabled - if( OC_App::isEnabled( $provider->getID() ) ) { - $success = true; - // Does this app use the database? - if( file_exists( OC_App::getAppPath($provider->getID()).'/appinfo/database.xml' ) ) { - // Create some app tables - $tables = self::createAppTables( $provider->getID() ); - if( is_array( $tables ) ) { - // Save the table names - foreach($tables as $table) { - $return['apps'][$provider->getID()]['tables'][] = $table; - } - } else { - // It failed to create the tables - $success = false; - } - } - - // Run the export function? - if( $success ) { - // Set the provider properties - $provider->setData( self::$uid, self::$content ); - $return['apps'][$provider->getID()]['success'] = $provider->export(); - } else { - $return['apps'][$provider->getID()]['success'] = false; - $return['apps'][$provider->getID()]['message'] = 'failed to create the app tables'; - } - - // Now add some app info the the return array - $appinfo = OC_App::getAppInfo( $provider->getID() ); - $return['apps'][$provider->getID()]['version'] = OC_App::getAppVersion($provider->getID()); - } - } - - return $return; - - } - - - /** - * generates json containing export info, and merges any data supplied - * @param array $array of data to include in the returned json - * @return string - */ - static private function getExportInfo( $array=array() ) { - $info = array( - 'ocversion' => OC_Util::getVersion(), - 'exporttime' => time(), - 'exportedby' => OC_User::getUser(), - 'exporttype' => self::$exporttype, - 'exporteduser' => self::$uid - ); - - if( !is_array( $array ) ) { - OC_Log::write( 'migration', 'Supplied $array was not an array in getExportInfo()', OC_Log::ERROR ); - } - // Merge in other data - $info = array_merge( $info, (array)$array ); - // Create json - $json = json_encode( $info ); - return $json; - } - - /** - * connects to migration.db, or creates if not found - * @param string $path to migration.db, defaults to user data dir - * @return bool whether the operation was successful - */ - static private function connectDB( $path=null ) { - // Has the dbpath been set? - self::$dbpath = !is_null( $path ) ? $path : self::$dbpath; - if( !self::$dbpath ) { - OC_Log::write( 'migration', 'connectDB() was called without dbpath being set', OC_Log::ERROR ); - return false; - } - // Already connected - if(!self::$migration_database) { - $datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - $connectionParams = array( - 'path' => self::$dbpath, - 'driver' => 'pdo_sqlite', - ); - $connectionParams['adapter'] = '\OC\DB\AdapterSqlite'; - $connectionParams['wrapperClass'] = 'OC\DB\Connection'; - $connectionParams['tablePrefix'] = ''; - - // Try to establish connection - self::$migration_database = \Doctrine\DBAL\DriverManager::getConnection($connectionParams); - } - return true; - - } - - /** - * creates the tables in migration.db from an apps database.xml - * @param string $appid id of the app - * @return bool whether the operation was successful - */ - static private function createAppTables( $appid ) { - $schema_manager = new OC\DB\MDB2SchemaManager(self::$migration_database); - - // There is a database.xml file - $content = file_get_contents(OC_App::getAppPath($appid) . '/appinfo/database.xml' ); - - $file2 = 'static://db_scheme'; - // TODO get the relative path to migration.db from the data dir - // For now just cheat - $path = pathinfo( self::$dbpath ); - $content = str_replace( '*dbname*', self::$uid.'/migration', $content ); - $content = str_replace( '*dbprefix*', '', $content ); - - $xml = new SimpleXMLElement($content); - foreach($xml->table as $table) { - $tables[] = (string)$table->name; - } - - file_put_contents( $file2, $content ); - - // Try to create tables - try { - $schema_manager->createDbFromStructure($file2); - } catch(Exception $e) { - unlink( $file2 ); - OC_Log::write( 'migration', 'Failed to create tables for: '.$appid, OC_Log::FATAL ); - OC_Log::write( 'migration', $e->getMessage(), OC_Log::FATAL ); - return false; - } - - return $tables; - } - - /** - * tries to create the zip - * @return bool - */ - static private function createZip() { - self::$zip = new ZipArchive; - // Check if properties are set - if( !self::$zippath ) { - OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR); - return false; - } - if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== true ) { - OC_Log::write('migration', - 'Failed to create the zip with error: '.self::$zip->getStatusString(), - OC_Log::ERROR); - return false; - } else { - return true; - } - } - - /** - * returns an array of apps that support migration - * @return array - */ - static public function getApps() { - $allapps = OC_App::getAllApps(); - foreach($allapps as $app) { - $path = self::getAppPath($app) . '/lib/migrate.php'; - if( file_exists( $path ) ) { - $supportsmigration[] = $app; - } - } - return $supportsmigration; - } - - /** - * imports a new user - * @param string $db string path to migration.db - * @param object $info object of migration info - * @param string|null|int $uid uid to use - * @return array an array of apps with import statuses, or false on failure. - */ - public static function importAppData( $db, $info, $uid=null ) { - // Check if the db exists - if( file_exists( $db ) ) { - // Connect to the db - if(!self::connectDB( $db )) { - OC_Log::write('migration', 'Failed to connect to migration.db', OC_Log::ERROR); - return false; - } - } else { - OC_Log::write('migration', 'Migration.db not found at: '.$db, OC_Log::FATAL ); - return false; - } - - // Find providers - self::findProviders(); - - // Generate importinfo array - $importinfo = array( - 'olduid' => $info->exporteduser, - 'newuid' => self::$uid - ); - - foreach( self::$providers as $provider) { - // Is the app in the export? - $id = $provider->getID(); - if( isset( $info->apps->$id ) ) { - // Is the app installed - if( !OC_App::isEnabled( $id ) ) { - OC_Log::write( 'migration', - 'App: ' . $id . ' is not installed, can\'t import data.', - OC_Log::INFO ); - $appsstatus[$id] = 'notsupported'; - } else { - // Did it succeed on export? - if( $info->apps->$id->success ) { - // Give the provider the content object - if( !self::connectDB( $db ) ) { - return false; - } - $content = new OC_Migration_Content( self::$zip, self::$migration_database ); - $provider->setData( self::$uid, $content, $info ); - // Then do the import - if( !$appsstatus[$id] = $provider->import( $info->apps->$id, $importinfo ) ) { - // Failed to import app - OC_Log::write( 'migration', - 'Failed to import app data for user: ' . self::$uid . ' for app: ' . $id, - OC_Log::ERROR ); - } - } else { - // Add to failed list - $appsstatus[$id] = false; - } - } - } - } - - return $appsstatus; - - } - - /** - * creates a new user in the database - * @param string $uid user_id of the user to be created - * @param string $hash hash of the user to be created - * @return bool result of user creation - */ - public static function createUser( $uid, $hash ) { - - // Check if userid exists - if(OC_User::userExists( $uid )) { - return false; - } - - // Create the user - $query = OC_DB::prepare( "INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )" ); - $result = $query->execute( array( $uid, $hash)); - if( !$result ) { - OC_Log::write('migration', 'Failed to create the new user "'.$uid."", OC_Log::ERROR); - } - return $result ? true : false; - - } - -} diff --git a/lib/private/migration/content.php b/lib/private/migration/content.php deleted file mode 100644 index cb5d9ad1472..00000000000 --- a/lib/private/migration/content.php +++ /dev/null @@ -1,246 +0,0 @@ -<?php -/** - * ownCloud - * - * @author Tom Needham - * @copyright 2012 Tom Needham tom@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/>. - * - */ - - -/** - * provides methods to add and access data from the migration - */ -class OC_Migration_Content{ - - private $zip=false; - // Holds the database object - private $db=null; - // Holds an array of tmpfiles to delete after zip creation - private $tmpfiles=array(); - - /** - * sets up the - * @param ZipArchive $zip ZipArchive object - * @param object $db a database object (required for exporttype user) - * @return bool|null - */ - public function __construct( $zip, $db=null ) { - - $this->zip = $zip; - $this->db = $db; - - } - - /** - * prepares the db - * @param string $query the sql query to prepare - */ - public function prepare( $query ) { - - // Only add database to tmpfiles if actually used - if( !is_null( $this->db ) ) { - // Get db path - $db = $this->db->getDatabase(); - if(!in_array($db, $this->tmpfiles)) { - $this->tmpfiles[] = $db; - } - } - - // Optimize the query - $query = $this->processQuery( $query ); - - // Optimize the query - $query = $this->db->prepare( $query ); - $query = new OC_DB_StatementWrapper($query, false); - - return $query; - } - - /** - * processes the db query - * @param string $query the query to process - * @return string of processed query - */ - private function processQuery( $query ) { - $query = str_replace( '`', '\'', $query ); - $query = str_replace( 'NOW()', 'datetime(\'now\')', $query ); - $query = str_replace( 'now()', 'datetime(\'now\')', $query ); - // remove table prefixes - $query = str_replace( '*PREFIX*', '', $query ); - return $query; - } - - /** - * copys rows to migration.db from the main database - * @param array $options array of options. - * @return bool - */ - public function copyRows( $options ) { - if( !array_key_exists( 'table', $options ) ) { - return false; - } - - $return = array(); - - // Need to include 'where' in the query? - if( array_key_exists( 'matchval', $options ) && array_key_exists( 'matchcol', $options ) ) { - - // If only one matchval, create an array - if(!is_array($options['matchval'])) { - $options['matchval'] = array( $options['matchval'] ); - } - - foreach( $options['matchval'] as $matchval ) { - // Run the query for this match value (where x = y value) - $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '` WHERE `' . $options['matchcol'] . '` = ?'; - $query = OC_DB::prepare( $sql ); - $results = $query->execute( array( $matchval ) ); - $newreturns = $this->insertData( $results, $options ); - $return = array_merge( $return, $newreturns ); - } - - } else { - // Just get everything - $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '`'; - $query = OC_DB::prepare( $sql ); - $results = $query->execute(); - $return = $this->insertData( $results, $options ); - - } - - return $return; - - } - - /** - * saves a sql data set into migration.db - * @param OC_DB_StatementWrapper $data a sql data set returned from self::prepare()->query() - * @param array $options array of copyRows options - * @return void - */ - private function insertData( $data, $options ) { - $return = array(); - // Foreach row of data to insert - while( $row = $data->fetchRow() ) { - // Now save all this to the migration.db - foreach($row as $field=>$value) { - $fields[] = $field; - $values[] = $value; - } - - // Generate some sql - $sql = "INSERT INTO `" . $options['table'] . '` ( `'; - $fieldssql = implode( '`, `', $fields ); - $sql .= $fieldssql . "` ) VALUES( "; - $valuessql = substr( str_repeat( '?, ', count( $fields ) ), 0, -2 ); - $sql .= $valuessql . " )"; - // Make the query - $query = $this->prepare( $sql ); - $query->execute( $values ); - // Do we need to return some values? - if( array_key_exists( 'idcol', $options ) ) { - // Yes we do - $return[] = $row[$options['idcol']]; - } else { - // Take a guess and return the first field :) - $return[] = reset($row); - } - $fields = ''; - $values = ''; - } - return $return; - } - - /** - * adds a directory to the zip object - * @param boolean|string $dir string path of the directory to add - * @param bool $recursive - * @param string $internaldir path of folder to add dir to in zip - * @return bool - */ - public function addDir( $dir, $recursive=true, $internaldir='' ) { - $dirname = basename($dir); - $this->zip->addEmptyDir($internaldir . $dirname); - $internaldir.=$dirname.='/'; - if( !file_exists( $dir ) ) { - return false; - } - $dirhandle = opendir($dir); - if(is_resource($dirhandle)) { - while (false !== ( $file = readdir($dirhandle))) { - - if (( $file != '.' ) && ( $file != '..' )) { - - if (is_dir($dir . '/' . $file) && $recursive) { - $this->addDir($dir . '/' . $file, $recursive, $internaldir); - } elseif (is_file($dir . '/' . $file)) { - $this->zip->addFile($dir . '/' . $file, $internaldir . $file); - } - } - } - closedir($dirhandle); - } else { - OC_Log::write('admin_export', "Was not able to open directory: " . $dir, OC_Log::ERROR); - return false; - } - return true; - } - - /** - * adds a file to the zip from a given string - * @param string $data string of data to add - * @param string $path the relative path inside of the zip to save the file to - * @return bool - */ - public function addFromString( $data, $path ) { - // Create a temp file - $file = tempnam( get_temp_dir(). '/', 'oc_export_tmp_' ); - $this->tmpfiles[] = $file; - if( !file_put_contents( $file, $data ) ) { - OC_Log::write( 'migation', 'Failed to save data to a temporary file', OC_Log::ERROR ); - return false; - } - // Add file to the zip - $this->zip->addFile( $file, $path ); - return true; - } - - /** - * closes the zip, removes temp files - * @return bool - */ - public function finish() { - if( !$this->zip->close() ) { - OC_Log::write( 'migration', - 'Failed to write the zip file with error: '.$this->zip->getStatusString(), - OC_Log::ERROR ); - return false; - } - $this->cleanup(); - return true; - } - - /** - * cleans up after the zip - */ - private function cleanup() { - // Delete tmp files - foreach($this->tmpfiles as $i) { - unlink( $i ); - } - } -} diff --git a/lib/private/migration/provider.php b/lib/private/migration/provider.php deleted file mode 100644 index a7c611dcdd4..00000000000 --- a/lib/private/migration/provider.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php -/** - * provides search functionalty - */ -abstract class OC_Migration_Provider{ - - protected $id=false; - protected $content=false; - protected $uid=false; - protected $olduid=false; - protected $appinfo=false; - - public function __construct( $appid ) { - // Set the id - $this->id = $appid; - OC_Migrate::registerProvider( $this ); - } - - /** - * exports data for apps - * @return array appdata to be exported - */ - abstract function export( ); - - /** - * imports data for the app - * @return void - */ - abstract function import( ); - - /** - * sets the OC_Migration_Content object to $this->content - * @param OC_Migration_Content $content a OC_Migration_Content object - */ - public function setData( $uid, $content, $info=null ) { - $this->content = $content; - $this->uid = $uid; - $id = $this->id; - if( !is_null( $info ) ) { - $this->olduid = $info->exporteduser; - $this->appinfo = $info->apps->$id; - } - } - - /** - * returns the appid of the provider - * @return string - */ - public function getID() { - return $this->id; - } -} diff --git a/lib/private/naturalsort.php b/lib/private/naturalsort.php index eb00f99a672..6e259630f79 100644 --- a/lib/private/naturalsort.php +++ b/lib/private/naturalsort.php @@ -9,16 +9,6 @@ namespace OC; -class NaturalSort_DefaultCollator { - - public function compare($a, $b) { - if ($a === $b) { - return 0; - } - return ($a < $b) ? -1 : 1; - } -} - class NaturalSort { private static $instance; private $collator; @@ -114,4 +104,3 @@ class NaturalSort { return self::$instance; } } - diff --git a/lib/private/naturalsort_defaultcollator.php b/lib/private/naturalsort_defaultcollator.php new file mode 100644 index 00000000000..e1007f8d7b4 --- /dev/null +++ b/lib/private/naturalsort_defaultcollator.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright (c) 2014 Vincent Petry <PVince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OC; + +class NaturalSort_DefaultCollator { + public function compare($a, $b) { + if ($a === $b) { + return 0; + } + return ($a < $b) ? -1 : 1; + } +} diff --git a/lib/private/preview.php b/lib/private/preview.php index f50bdcb4c9e..f6c8c485d03 100644 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -16,14 +16,6 @@ namespace OC; use OC\Preview\Provider; use OCP\Files\NotFoundException; -require_once 'preview/image.php'; -require_once 'preview/movies.php'; -require_once 'preview/mp3.php'; -require_once 'preview/svg.php'; -require_once 'preview/txt.php'; -require_once 'preview/office.php'; -require_once 'preview/bitmap.php'; - class Preview { //the thumbnail folder const THUMBNAILS_FOLDER = 'thumbnails'; @@ -713,7 +705,7 @@ class Preview { * - OC\Preview\OpenDocument * - OC\Preview\StarOffice * - OC\Preview\SVG - * - OC\Preview\Movies + * - OC\Preview\Movie * - OC\Preview\PDF * - OC\Preview\TIFF * - OC\Preview\Illustrator @@ -744,10 +736,11 @@ class Preview { return; } - if (count(self::$providers) > 0) { + if (!empty(self::$providers)) { return; } + self::registerCoreProviders(); foreach (self::$registeredProviders as $provider) { $class = $provider['class']; $options = $provider['options']; @@ -759,7 +752,74 @@ class Preview { $keys = array_map('strlen', array_keys(self::$providers)); array_multisort($keys, SORT_DESC, self::$providers); + } + + protected static function registerCoreProviders() { + self::registerProvider('OC\Preview\TXT'); + self::registerProvider('OC\Preview\MarkDown'); + self::registerProvider('OC\Preview\Image'); + self::registerProvider('OC\Preview\MP3'); + + // SVG, Office and Bitmap require imagick + if (extension_loaded('imagick')) { + $checkImagick = new \Imagick(); + + $imagickProviders = array( + 'SVG' => 'OC\Preview\SVG', + 'TIFF' => 'OC\Preview\TIFF', + 'PDF' => 'OC\Preview\PDF', + 'AI' => 'OC\Preview\Illustrator', + 'PSD' => 'OC\Preview\Photoshop', + // Requires adding 'eps' => array('application/postscript', null), to lib/private/mimetypes.list.php + 'EPS' => 'OC\Preview\Postscript', + ); + + foreach ($imagickProviders as $queryFormat => $provider) { + if (count($checkImagick->queryFormats($queryFormat)) === 1) { + self::registerProvider($provider); + } + } + + if (count($checkImagick->queryFormats('PDF')) === 1) { + // Office previews are currently not supported on Windows + if (!\OC_Util::runningOnWindows() && \OC_Helper::is_function_enabled('shell_exec')) { + $officeFound = is_string(\OC::$server->getConfig()->getSystemValue('preview_libreoffice_path', null)); + + if (!$officeFound) { + //let's see if there is libreoffice or openoffice on this machine + $whichLibreOffice = shell_exec('command -v libreoffice'); + $officeFound = !empty($whichLibreOffice); + if (!$officeFound) { + $whichOpenOffice = shell_exec('command -v openoffice'); + $officeFound = !empty($whichOpenOffice); + } + } + + if ($officeFound) { + self::registerProvider('OC\Preview\MSOfficeDoc'); + self::registerProvider('OC\Preview\MSOffice2003'); + self::registerProvider('OC\Preview\MSOffice2007'); + self::registerProvider('OC\Preview\OpenDocument'); + self::registerProvider('OC\Preview\StarOffice'); + } + } + } + } + + // Video requires avconv or ffmpeg and is therefor + // currently not supported on Windows. + if (!\OC_Util::runningOnWindows()) { + $avconvBinary = \OC_Helper::findBinaryPath('avconv'); + $ffmpegBinary = ($avconvBinary) ? null : \OC_Helper::findBinaryPath('ffmpeg'); + if ($avconvBinary || $ffmpegBinary) { + // FIXME // a bit hacky but didn't want to use subclasses + \OC\Preview\Movie::$avconvBinary = $avconvBinary; + \OC\Preview\Movie::$ffmpegBinary = $ffmpegBinary; + + self::registerProvider('OC\Preview\Movie'); + } + } } /** @@ -892,16 +952,6 @@ class Preview { self::initProviders(); } - // FIXME: Ugly hack to prevent SVG of being returned if the SVG - // provider is not enabled. - // This is required because the preview system is designed in a - // bad way and relies on opt-in with asterisks (i.e. image/*) - // which will lead to the fact that a SVG will also match the image - // provider. - if($mimeType === 'image/svg+xml' && !array_key_exists('/image\/svg\+xml/', self::$providers)) { - return false; - } - foreach(self::$providers as $supportedMimetype => $provider) { if(preg_match($supportedMimetype, $mimeType)) { return true; diff --git a/lib/private/preview/bitmap.php b/lib/private/preview/bitmap.php index 748a63a6afa..25f65cf7fc9 100644 --- a/lib/private/preview/bitmap.php +++ b/lib/private/preview/bitmap.php @@ -5,113 +5,33 @@ * later. * See the COPYING-README file. */ -namespace OC\Preview; - -use Imagick; - -if (extension_loaded('imagick')) { - - $checkImagick = new Imagick(); - - class Bitmap extends Provider { - - public function getMimeType() { - return null; - } - - public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - $tmpPath = $fileview->toTmpFile($path); - //create imagick object from bitmap or vector file - try{ - // Layer 0 contains either the bitmap or - // a flat representation of all vector layers - $bp = new Imagick($tmpPath . '[0]'); - - $bp->setImageFormat('png'); - } catch (\Exception $e) { - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; - } - - unlink($tmpPath); - - //new bitmap image object - $image = new \OC_Image($bp); - //check if image object is valid - return $image->valid() ? $image : false; - } - - } - - if(count($checkImagick->queryFormats('PDF')) === 1) { - - //.pdf - class PDF extends Bitmap { - - public function getMimeType() { - return '/application\/pdf/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\PDF'); - } - - if(count($checkImagick->queryFormats('TIFF')) === 1) { - - //.tiff - class TIFF extends Bitmap { - - public function getMimeType() { - return '/image\/tiff/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\TIFF'); - } - - if(count($checkImagick->queryFormats('AI')) === 1) { - - //.ai - class Illustrator extends Bitmap { - - public function getMimeType() { - return '/application\/illustrator/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\Illustrator'); - } - - // Requires adding 'eps' => array('application/postscript', null), to lib/private/mimetypes.list.php - if(count($checkImagick->queryFormats('EPS')) === 1) { - - //.eps - class Postscript extends Bitmap { - - public function getMimeType() { - return '/application\/postscript/'; - } +namespace OC\Preview; +abstract class Bitmap extends Provider { + /** + * {@inheritDoc} + */ + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $tmpPath = $fileview->toTmpFile($path); + + //create imagick object from bitmap or vector file + try { + // Layer 0 contains either the bitmap or + // a flat representation of all vector layers + $bp = new \Imagick($tmpPath . '[0]'); + + $bp->setImageFormat('png'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; } - \OC\Preview::registerProvider('OC\Preview\Postscript'); - } - - if(count($checkImagick->queryFormats('PSD')) === 1) { - - //.psd - class Photoshop extends Bitmap { - - public function getMimeType() { - return '/application\/x-photoshop/'; - } + unlink($tmpPath); - } - - \OC\Preview::registerProvider('OC\Preview\Photoshop'); + //new bitmap image object + $image = new \OC_Image($bp); + //check if image object is valid + return $image->valid() ? $image : false; } } diff --git a/lib/private/preview/illustrator.php b/lib/private/preview/illustrator.php new file mode 100644 index 00000000000..e88c305f708 --- /dev/null +++ b/lib/private/preview/illustrator.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright (c) 2013-2014 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Preview; + +//.ai +class Illustrator extends Bitmap { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/illustrator/'; + } +} diff --git a/lib/private/preview/image.php b/lib/private/preview/image.php index ec5b87befea..986a44b48fd 100644 --- a/lib/private/preview/image.php +++ b/lib/private/preview/image.php @@ -9,11 +9,16 @@ namespace OC\Preview; class Image extends Provider { - + /** + * {@inheritDoc} + */ public function getMimeType() { - return '/image\/.*/'; + return '/image\/(?!tiff$)(?!svg.*).*/'; } + /** + * {@inheritDoc} + */ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { //get fileinfo $fileInfo = $fileview->getFileInfo($path); @@ -35,5 +40,3 @@ class Image extends Provider { } } - -\OC\Preview::registerProvider('OC\Preview\Image'); diff --git a/lib/private/preview/markdown.php b/lib/private/preview/markdown.php new file mode 100644 index 00000000000..1be01fcdd4c --- /dev/null +++ b/lib/private/preview/markdown.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Preview; + +class MarkDown extends TXT { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/text\/(x-)?markdown/'; + } + +} diff --git a/lib/private/preview/movie.php b/lib/private/preview/movie.php new file mode 100644 index 00000000000..06353ddebb7 --- /dev/null +++ b/lib/private/preview/movie.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright (c) 2013 Frank Karlitschek frank@owncloud.org + * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Preview; + +class Movie extends Provider { + public static $avconvBinary; + public static $ffmpegBinary; + + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/video\/.*/'; + } + + /** + * {@inheritDoc} + */ + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + // TODO: use proc_open() and stream the source file ? + + $fileInfo = $fileview->getFileInfo($path); + $useFileDirectly = (!$fileInfo->isEncrypted() && !$fileInfo->isMounted()); + + if ($useFileDirectly) { + $absPath = $fileview->getLocalFile($path); + } else { + $absPath = \OC_Helper::tmpFile(); + + $handle = $fileview->fopen($path, 'rb'); + + // we better use 5MB (1024 * 1024 * 5 = 5242880) instead of 1MB. + // in some cases 1MB was no enough to generate thumbnail + $firstmb = stream_get_contents($handle, 5242880); + file_put_contents($absPath, $firstmb); + } + + $result = $this->generateThumbNail($maxX, $maxY, $absPath, 5); + if ($result === false) { + $result = $this->generateThumbNail($maxX, $maxY, $absPath, 1); + if ($result === false) { + $result = $this->generateThumbNail($maxX, $maxY, $absPath, 0); + } + } + + if (!$useFileDirectly) { + unlink($absPath); + } + + return $result; + } + + /** + * @param int $maxX + * @param int $maxY + * @param string $absPath + * @param int $second + * @return bool|\OC_Image + */ + private function generateThumbNail($maxX, $maxY, $absPath, $second) { + $tmpPath = \OC_Helper::tmpFile(); + + if (self::$avconvBinary) { + $cmd = self::$avconvBinary . ' -an -y -ss ' . escapeshellarg($second) . + ' -i ' . escapeshellarg($absPath) . + ' -f mjpeg -vframes 1 -vsync 1 ' . escapeshellarg($tmpPath) . + ' > /dev/null 2>&1'; + } else { + $cmd = self::$ffmpegBinary . ' -y -ss ' . escapeshellarg($second) . + ' -i ' . escapeshellarg($absPath) . + ' -f mjpeg -vframes 1' . + ' -s ' . escapeshellarg($maxX) . 'x' . escapeshellarg($maxY) . + ' ' . escapeshellarg($tmpPath) . + ' > /dev/null 2>&1'; + } + + exec($cmd, $output, $returnCode); + + if ($returnCode === 0) { + $image = new \OC_Image(); + $image->loadFromFile($tmpPath); + unlink($tmpPath); + return $image->valid() ? $image : false; + } + unlink($tmpPath); + return false; + } +} diff --git a/lib/private/preview/movies.php b/lib/private/preview/movies.php deleted file mode 100644 index 2a23c2141c1..00000000000 --- a/lib/private/preview/movies.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php -/** - * Copyright (c) 2013 Frank Karlitschek frank@owncloud.org - * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ -namespace OC\Preview; - -function findBinaryPath($program) { - exec('command -v ' . escapeshellarg($program) . ' 2> /dev/null', $output, $returnCode); - if ($returnCode === 0 && count($output) > 0) { - return escapeshellcmd($output[0]); - } - return null; -} - -// movie preview is currently not supported on Windows -if (!\OC_Util::runningOnWindows()) { - $isExecEnabled = \OC_Helper::is_function_enabled('exec'); - $ffmpegBinary = null; - $avconvBinary = null; - - if ($isExecEnabled) { - $avconvBinary = findBinaryPath('avconv'); - if (!$avconvBinary) { - $ffmpegBinary = findBinaryPath('ffmpeg'); - } - } - - if($isExecEnabled && ( $avconvBinary || $ffmpegBinary )) { - - class Movie extends Provider { - public static $avconvBinary; - public static $ffmpegBinary; - - public function getMimeType() { - return '/video\/.*/'; - } - - public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - // TODO: use proc_open() and stream the source file ? - - $fileInfo = $fileview->getFileInfo($path); - $useFileDirectly = (!$fileInfo->isEncrypted() && !$fileInfo->isMounted()); - - if ($useFileDirectly) { - $absPath = $fileview->getLocalFile($path); - } else { - $absPath = \OC_Helper::tmpFile(); - - $handle = $fileview->fopen($path, 'rb'); - - // we better use 5MB (1024 * 1024 * 5 = 5242880) instead of 1MB. - // in some cases 1MB was no enough to generate thumbnail - $firstmb = stream_get_contents($handle, 5242880); - file_put_contents($absPath, $firstmb); - } - - $result = $this->generateThumbNail($maxX, $maxY, $absPath, 5); - if ($result === false) { - $result = $this->generateThumbNail($maxX, $maxY, $absPath, 1); - if ($result === false) { - $result = $this->generateThumbNail($maxX, $maxY, $absPath, 0); - } - } - - if (!$useFileDirectly) { - unlink($absPath); - } - - return $result; - } - - /** - * @param int $maxX - * @param int $maxY - * @param string $absPath - * @param string $tmpPath - * @param int $second - * @return bool|\OC_Image - */ - private function generateThumbNail($maxX, $maxY, $absPath, $second) - { - $tmpPath = \OC_Helper::tmpFile(); - - if (self::$avconvBinary) { - $cmd = self::$avconvBinary . ' -an -y -ss ' . escapeshellarg($second) . - ' -i ' . escapeshellarg($absPath) . - ' -f mjpeg -vframes 1 -vsync 1 ' . escapeshellarg($tmpPath) . - ' > /dev/null 2>&1'; - } else { - $cmd = self::$ffmpegBinary . ' -y -ss ' . escapeshellarg($second) . - ' -i ' . escapeshellarg($absPath) . - ' -f mjpeg -vframes 1' . - ' -s ' . escapeshellarg($maxX) . 'x' . escapeshellarg($maxY) . - ' ' . escapeshellarg($tmpPath) . - ' > /dev/null 2>&1'; - } - - exec($cmd, $output, $returnCode); - - if ($returnCode === 0) { - $image = new \OC_Image(); - $image->loadFromFile($tmpPath); - unlink($tmpPath); - return $image->valid() ? $image : false; - } - unlink($tmpPath); - return false; - } - } - - // a bit hacky but didn't want to use subclasses - Movie::$avconvBinary = $avconvBinary; - Movie::$ffmpegBinary = $ffmpegBinary; - - \OC\Preview::registerProvider('OC\Preview\Movie'); - } -} - diff --git a/lib/private/preview/mp3.php b/lib/private/preview/mp3.php index bb4d3dfce86..f1a50d99e13 100644 --- a/lib/private/preview/mp3.php +++ b/lib/private/preview/mp3.php @@ -8,11 +8,16 @@ namespace OC\Preview; class MP3 extends Provider { - + /** + * {@inheritDoc} + */ public function getMimeType() { return '/audio\/mpeg/'; } + /** + * {@inheritDoc} + */ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { $getID3 = new \getID3(); @@ -31,6 +36,12 @@ class MP3 extends Provider { return $this->getNoCoverThumbnail(); } + /** + * Generates a default image when the file has no cover + * + * @return false|\OC_Image False if the default image is missing or invalid, + * otherwise the image is returned as \OC_Image + */ private function getNoCoverThumbnail() { $icon = \OC::$SERVERROOT . '/core/img/filetypes/audio.png'; @@ -44,5 +55,3 @@ class MP3 extends Provider { } } - -\OC\Preview::registerProvider('OC\Preview\MP3'); diff --git a/lib/private/preview/msoffice2003.php b/lib/private/preview/msoffice2003.php new file mode 100644 index 00000000000..55fbe708435 --- /dev/null +++ b/lib/private/preview/msoffice2003.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Preview; + +//.docm, .dotm, .xls(m), .xlt(m), .xla(m), .ppt(m), .pot(m), .pps(m), .ppa(m) +class MSOffice2003 extends Office { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/vnd.ms-.*/'; + } +} diff --git a/lib/private/preview/msoffice2007.php b/lib/private/preview/msoffice2007.php new file mode 100644 index 00000000000..ace246eb6d9 --- /dev/null +++ b/lib/private/preview/msoffice2007.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Preview; + +//.docx, .dotx, .xlsx, .xltx, .pptx, .potx, .ppsx +class MSOffice2007 extends Office { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.*/'; + } +} diff --git a/lib/private/preview/msofficedoc.php b/lib/private/preview/msofficedoc.php new file mode 100644 index 00000000000..42507af2233 --- /dev/null +++ b/lib/private/preview/msofficedoc.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Preview; + +//.doc, .dot +class MSOfficeDoc extends Office { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/msword/'; + } +} diff --git a/lib/private/preview/office-cl.php b/lib/private/preview/office-cl.php deleted file mode 100644 index f5c791e37f2..00000000000 --- a/lib/private/preview/office-cl.php +++ /dev/null @@ -1,138 +0,0 @@ -<?php -/** - * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ -namespace OC\Preview; - -// office preview is currently not supported on Windows -if (!\OC_Util::runningOnWindows()) { - - //we need imagick to convert - class Office extends Provider { - - private $cmd; - - public function getMimeType() { - return null; - } - - public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - $this->initCmd(); - if(is_null($this->cmd)) { - return false; - } - - $absPath = $fileview->toTmpFile($path); - - $tmpDir = get_temp_dir(); - - $defaultParameters = ' -env:UserInstallation=file://' . escapeshellarg($tmpDir . '/owncloud-' . \OC_Util::getInstanceId().'/') . ' --headless --nologo --nofirststartwizard --invisible --norestore --convert-to pdf --outdir '; - $clParameters = \OCP\Config::getSystemValue('preview_office_cl_parameters', $defaultParameters); - - $exec = $this->cmd . $clParameters . escapeshellarg($tmpDir) . ' ' . escapeshellarg($absPath); - - shell_exec($exec); - - //create imagick object from pdf - try{ - $pdf = new \imagick($absPath . '.pdf' . '[0]'); - $pdf->setImageFormat('jpg'); - } catch (\Exception $e) { - unlink($absPath); - unlink($absPath . '.pdf'); - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; - } - - $image = new \OC_Image(); - $image->loadFromData($pdf); - - unlink($absPath); - unlink($absPath . '.pdf'); - - return $image->valid() ? $image : false; - } - - private function initCmd() { - $cmd = ''; - - if(is_string(\OC_Config::getValue('preview_libreoffice_path', null))) { - $cmd = \OC_Config::getValue('preview_libreoffice_path', null); - } - - $whichLibreOffice = shell_exec('command -v libreoffice'); - if($cmd === '' && !empty($whichLibreOffice)) { - $cmd = 'libreoffice'; - } - - $whichOpenOffice = shell_exec('command -v openoffice'); - if($cmd === '' && !empty($whichOpenOffice)) { - $cmd = 'openoffice'; - } - - if($cmd === '') { - $cmd = null; - } - - $this->cmd = $cmd; - } - } - - //.doc, .dot - class MSOfficeDoc extends Office { - - public function getMimeType() { - return '/application\/msword/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\MSOfficeDoc'); - - //.docm, .dotm, .xls(m), .xlt(m), .xla(m), .ppt(m), .pot(m), .pps(m), .ppa(m) - class MSOffice2003 extends Office { - - public function getMimeType() { - return '/application\/vnd.ms-.*/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\MSOffice2003'); - - //.docx, .dotx, .xlsx, .xltx, .pptx, .potx, .ppsx - class MSOffice2007 extends Office { - - public function getMimeType() { - return '/application\/vnd.openxmlformats-officedocument.*/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\MSOffice2007'); - - //.odt, .ott, .oth, .odm, .odg, .otg, .odp, .otp, .ods, .ots, .odc, .odf, .odb, .odi, .oxt - class OpenDocument extends Office { - - public function getMimeType() { - return '/application\/vnd.oasis.opendocument.*/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\OpenDocument'); - - //.sxw, .stw, .sxc, .stc, .sxd, .std, .sxi, .sti, .sxg, .sxm - class StarOffice extends Office { - - public function getMimeType() { - return '/application\/vnd.sun.xml.*/'; - } - - } - - \OC\Preview::registerProvider('OC\Preview\StarOffice'); -} diff --git a/lib/private/preview/office.php b/lib/private/preview/office.php index b47cbc6e08f..5bd61bde3be 100644 --- a/lib/private/preview/office.php +++ b/lib/private/preview/office.php @@ -5,24 +5,72 @@ * later. * See the COPYING-README file. */ -//both, libreoffice backend and php fallback, need imagick -if (extension_loaded('imagick')) { - - $checkImagick = new Imagick(); - - if(count($checkImagick->queryFormats('PDF')) === 1) { - $isShellExecEnabled = \OC_Helper::is_function_enabled('shell_exec'); - - // LibreOffice preview is currently not supported on Windows - if (!\OC_Util::runningOnWindows()) { - $whichLibreOffice = ($isShellExecEnabled ? shell_exec('command -v libreoffice') : ''); - $isLibreOfficeAvailable = !empty($whichLibreOffice); - $whichOpenOffice = ($isShellExecEnabled ? shell_exec('command -v openoffice') : ''); - $isOpenOfficeAvailable = !empty($whichOpenOffice); - //let's see if there is libreoffice or openoffice on this machine - if($isShellExecEnabled && ($isLibreOfficeAvailable || $isOpenOfficeAvailable || is_string(\OC_Config::getValue('preview_libreoffice_path', null)))) { - require_once('office-cl.php'); - } +namespace OC\Preview; + +abstract class Office extends Provider { + private $cmd; + + /** + * {@inheritDoc} + */ + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $this->initCmd(); + if(is_null($this->cmd)) { + return false; + } + + $absPath = $fileview->toTmpFile($path); + + $tmpDir = get_temp_dir(); + + $defaultParameters = ' -env:UserInstallation=file://' . escapeshellarg($tmpDir . '/owncloud-' . \OC_Util::getInstanceId().'/') . ' --headless --nologo --nofirststartwizard --invisible --norestore --convert-to pdf --outdir '; + $clParameters = \OCP\Config::getSystemValue('preview_office_cl_parameters', $defaultParameters); + + $exec = $this->cmd . $clParameters . escapeshellarg($tmpDir) . ' ' . escapeshellarg($absPath); + + shell_exec($exec); + + //create imagick object from pdf + try{ + $pdf = new \imagick($absPath . '.pdf' . '[0]'); + $pdf->setImageFormat('jpg'); + } catch (\Exception $e) { + unlink($absPath); + unlink($absPath . '.pdf'); + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; } + + $image = new \OC_Image(); + $image->loadFromData($pdf); + + unlink($absPath); + unlink($absPath . '.pdf'); + + return $image->valid() ? $image : false; + } + + private function initCmd() { + $cmd = ''; + + if(is_string(\OC_Config::getValue('preview_libreoffice_path', null))) { + $cmd = \OC_Config::getValue('preview_libreoffice_path', null); + } + + $whichLibreOffice = shell_exec('command -v libreoffice'); + if($cmd === '' && !empty($whichLibreOffice)) { + $cmd = 'libreoffice'; + } + + $whichOpenOffice = shell_exec('command -v openoffice'); + if($cmd === '' && !empty($whichOpenOffice)) { + $cmd = 'openoffice'; + } + + if($cmd === '') { + $cmd = null; + } + + $this->cmd = $cmd; } } diff --git a/lib/private/preview/opendocument.php b/lib/private/preview/opendocument.php new file mode 100644 index 00000000000..fe1468ee941 --- /dev/null +++ b/lib/private/preview/opendocument.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Preview; + +//.odt, .ott, .oth, .odm, .odg, .otg, .odp, .otp, .ods, .ots, .odc, .odf, .odb, .odi, .oxt +class OpenDocument extends Office { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/vnd.oasis.opendocument.*/'; + } +} diff --git a/lib/private/preview/pdf.php b/lib/private/preview/pdf.php new file mode 100644 index 00000000000..cb13074ff60 --- /dev/null +++ b/lib/private/preview/pdf.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright (c) 2013-2014 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Preview; + +//.pdf +class PDF extends Bitmap { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/pdf/'; + } +} diff --git a/lib/private/preview/photoshop.php b/lib/private/preview/photoshop.php new file mode 100644 index 00000000000..f5f60ce4de8 --- /dev/null +++ b/lib/private/preview/photoshop.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright (c) 2013-2014 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Preview; + +//.psd +class Photoshop extends Bitmap { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/x-photoshop/'; + } +} diff --git a/lib/private/preview/postscript.php b/lib/private/preview/postscript.php new file mode 100644 index 00000000000..7c8b089d92e --- /dev/null +++ b/lib/private/preview/postscript.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright (c) 2013-2014 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Preview; + +//.eps +class Postscript extends Bitmap { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/postscript/'; + } +} diff --git a/lib/private/preview/provider.php b/lib/private/preview/provider.php index f544c2c4b13..ead67eaeef7 100644 --- a/lib/private/preview/provider.php +++ b/lib/private/preview/provider.php @@ -5,18 +5,21 @@ abstract class Provider { private $options; public function __construct($options) { - $this->options=$options; + $this->options = $options; } + /** + * @return string Regex with the mimetypes that are supported by this provider + */ abstract public function getMimeType(); /** * Check if a preview can be generated for $path * - * @param string $path + * @param \OC\Files\FileInfo $file * @return bool */ - public function isAvailable($path) { + public function isAvailable($file) { return true; } @@ -26,11 +29,10 @@ abstract class Provider { * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image * @param bool $scalingup Disable/Enable upscaling of previews - * @param object $fileview fileview object of user folder + * @param \OC\Files\View $fileview fileview object of user folder * @return mixed * false if no preview was generated * OC_Image object of the preview */ abstract public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview); - } diff --git a/lib/private/preview/staroffice.php b/lib/private/preview/staroffice.php new file mode 100644 index 00000000000..73ad368b341 --- /dev/null +++ b/lib/private/preview/staroffice.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Preview; + +//.sxw, .stw, .sxc, .stc, .sxd, .std, .sxi, .sti, .sxg, .sxm +class StarOffice extends Office { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/application\/vnd.sun.xml.*/'; + } +} diff --git a/lib/private/preview/svg.php b/lib/private/preview/svg.php index 0b5dbc9716f..561e87a6500 100644 --- a/lib/private/preview/svg.php +++ b/lib/private/preview/svg.php @@ -7,52 +7,43 @@ */ namespace OC\Preview; -use Imagick; - -if (extension_loaded('imagick')) { - - $checkImagick = new Imagick(); - - if(count($checkImagick->queryFormats('SVG')) === 1) { - - class SVG extends Provider { +class SVG extends Provider { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/image\/svg\+xml/'; + } - public function getMimeType() { - return '/image\/svg\+xml/'; + /** + * {@inheritDoc} + */ + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + try{ + $svg = new \Imagick(); + $svg->setBackgroundColor(new \ImagickPixel('transparent')); + + $content = stream_get_contents($fileview->fopen($path, 'r')); + if(substr($content, 0, 5) !== '<?xml') { + $content = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . $content; } - public function getThumbnail($path,$maxX,$maxY,$scalingup,$fileview) { - try{ - $svg = new Imagick(); - $svg->setBackgroundColor(new \ImagickPixel('transparent')); - - $content = stream_get_contents($fileview->fopen($path, 'r')); - if(substr($content, 0, 5) !== '<?xml') { - $content = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . $content; - } - - // Do not parse SVG files with references - if(stripos($content, 'xlink:href') !== false) { - return false; - } - - $svg->readImageBlob($content); - $svg->setImageFormat('png32'); - } catch (\Exception $e) { - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; - } - - - //new image object - $image = new \OC_Image(); - $image->loadFromData($svg); - //check if image object is valid - return $image->valid() ? $image : false; + // Do not parse SVG files with references + if(stripos($content, 'xlink:href') !== false) { + return false; } + $svg->readImageBlob($content); + $svg->setImageFormat('png32'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; } - \OC\Preview::registerProvider('OC\Preview\SVG'); + //new image object + $image = new \OC_Image(); + $image->loadFromData($svg); + //check if image object is valid + return $image->valid() ? $image : false; } } diff --git a/lib/private/preview/tiff.php b/lib/private/preview/tiff.php new file mode 100644 index 00000000000..0a1e8e8ecec --- /dev/null +++ b/lib/private/preview/tiff.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright (c) 2013-2014 Georg Ehrke georg@ownCloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Preview; + +//.tiff +class TIFF extends Bitmap { + /** + * {@inheritDoc} + */ + public function getMimeType() { + return '/image\/tiff/'; + } +} diff --git a/lib/private/preview/txt.php b/lib/private/preview/txt.php index 7f01b980c0e..8b414dc5726 100644 --- a/lib/private/preview/txt.php +++ b/lib/private/preview/txt.php @@ -8,31 +8,24 @@ namespace OC\Preview; class TXT extends Provider { - + /** + * {@inheritDoc} + */ public function getMimeType() { return '/text\/plain/'; } /** - * Check if a preview can be generated for $path - * - * @param \OC\Files\FileInfo $file - * @return bool + * {@inheritDoc} */ public function isAvailable($file) { return $file->getSize() > 5; } /** - * @param string $path - * @param int $maxX - * @param int $maxY - * @param boolean $scalingup - * @param \OC\Files\View $fileview - * @return bool|\OC_Image + * {@inheritDoc} */ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - $content = $fileview->fopen($path, 'r'); $content = stream_get_contents($content,3000); @@ -79,15 +72,3 @@ class TXT extends Provider { return $image->valid() ? $image : false; } } - -\OC\Preview::registerProvider('OC\Preview\TXT'); - -class MarkDown extends TXT { - - public function getMimeType() { - return '/text\/(x-)?markdown/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\MarkDown'); diff --git a/lib/private/repair.php b/lib/private/repair.php index 081aeb32c66..be607b44ed8 100644 --- a/lib/private/repair.php +++ b/lib/private/repair.php @@ -93,14 +93,15 @@ class Repair extends BasicEmitter { $steps = array( new InnoDB(), new Collation(\OC::$server->getConfig(), \OC_DB::getConnection()), - new SearchLuceneTables() + new SearchLuceneTables(), + new RepairConfig() ); //There is no need to delete all previews on every single update //only 7.0.0 through 7.0.2 generated broken previews $currentVersion = \OC::$server->getConfig()->getSystemValue('version'); if (version_compare($currentVersion, '7.0.0.0', '>=') && - version_compare($currentVersion, '7.0.2.2', '<=')) { + version_compare($currentVersion, '7.0.3.4', '<=')) { $steps[] = new \OC\Repair\Preview(); } diff --git a/lib/private/request.php b/lib/private/request.php index 1cfa4a150c5..d079dc110d1 100644 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -12,8 +12,7 @@ class OC_Request { // Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#'; const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#'; - - const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost)(:[0-9]+|)$/'; + const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost)$/'; static protected $reqId; /** @@ -76,13 +75,26 @@ class OC_Request { * have been configured */ public static function isTrustedDomain($domain) { - $trustedList = \OC_Config::getValue('trusted_domains', array()); + // Extract port from domain if needed + $pos = strrpos($domain, ':'); + if ($pos !== false) { + $port = substr($domain, $pos + 1); + if (is_numeric($port)) { + $domain = substr($domain, 0, $pos); + } + } + + // FIXME: Empty config array defaults to true for now. - Deprecate this behaviour with ownCloud 8. + $trustedList = \OC::$server->getConfig()->getSystemValue('trusted_domains', array()); if (empty($trustedList)) { return true; } + + // Always allow access from localhost if (preg_match(self::REGEX_LOCALHOST, $domain) === 1) { return true; } + return in_array($domain, $trustedList); } diff --git a/lib/private/server.php b/lib/private/server.php index c413ee8bf6d..7bd7f8ca45d 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -29,19 +29,27 @@ use OC\Tagging\TagMapper; * TODO: hookup all manager classes */ class Server extends SimpleContainer implements IServerContainer { - function __construct() { + /** @var string */ + private $webRoot; + + /** + * @param string $webRoot + */ + function __construct($webRoot) { + $this->webRoot = $webRoot; + $this->registerService('ContactsManager', function ($c) { return new ContactsManager(); }); - $this->registerService('Request', function ($c) { + $this->registerService('Request', function (Server $c) { if (isset($c['urlParams'])) { $urlParams = $c['urlParams']; } else { $urlParams = array(); } - if (\OC::$server->getSession()->exists('requesttoken')) { - $requestToken = \OC::$server->getSession()->get('requesttoken'); + if ($c->getSession()->exists('requesttoken')) { + $requestToken = $c->getSession()->get('requesttoken'); } else { $requestToken = false; } @@ -205,7 +213,7 @@ class Server extends SimpleContainer implements IServerContainer { $factory = new \OC\DB\ConnectionFactory(); $type = $c->getConfig()->getSystemValue('dbtype', 'sqlite'); if (!$factory->isValidType($type)) { - throw new \DatabaseException('Invalid database type'); + throw new \OC\DatabaseException('Invalid database type'); } $connectionParams = $factory->createConnectionParams($c->getConfig()); $connection = $factory->getConnection($type, $connectionParams); @@ -233,8 +241,7 @@ class Server extends SimpleContainer implements IServerContainer { return new NullQueryLogger(); } }); - $this->registerService('TempManager', function ($c) { - /** @var Server $c */ + $this->registerService('TempManager', function (Server $c) { return new TempManager(get_temp_dir(), $c->getLogger()); }); $this->registerService('AppManager', function(Server $c) { @@ -631,4 +638,13 @@ class Server extends SimpleContainer implements IServerContainer { function getAppManager() { return $this->query('AppManager'); } + + /** + * Get the webroot + * + * @return string + */ + function getWebRoot() { + return $this->webRoot; + } } diff --git a/lib/private/setup.php b/lib/private/setup.php index 1125933c8e9..1443de18546 100644 --- a/lib/private/setup.php +++ b/lib/private/setup.php @@ -8,9 +8,6 @@ use OCP\IConfig; -class DatabaseSetupException extends \OC\HintException { -} - class OC_Setup { /** @var IConfig */ protected $config; @@ -91,7 +88,7 @@ class OC_Setup { ) ); $configuredDatabases = $this->config->getSystemValue('supportedDatabases', - array('sqlite', 'mysql', 'pgsql', 'oci', 'mssql')); + array('sqlite', 'mysql', 'pgsql')); if(!is_array($configuredDatabases)) { throw new Exception('Supported databases are not properly configured.'); } @@ -195,7 +192,7 @@ class OC_Setup { try { $dbSetup->initialize($options); $dbSetup->setupDatabase($username); - } catch (DatabaseSetupException $e) { + } catch (\OC\DatabaseSetupException $e) { $error[] = array( 'error' => $e->getMessage(), 'hint' => $e->getHint() diff --git a/lib/private/setup/mssql.php b/lib/private/setup/mssql.php index b8329f99079..5143545b76f 100644 --- a/lib/private/setup/mssql.php +++ b/lib/private/setup/mssql.php @@ -17,7 +17,7 @@ class MSSQL extends AbstractDatabase { } else { $entry = ''; } - throw new \DatabaseSetupException($this->trans->t('MS SQL username and/or password not valid: %s', array($entry)), + throw new \OC\DatabaseSetupException($this->trans->t('MS SQL username and/or password not valid: %s', array($entry)), $this->trans->t('You need to enter either an existing account or the administrator.')); } diff --git a/lib/private/setup/mysql.php b/lib/private/setup/mysql.php index 5558a2d1e51..8f8d86d388c 100644 --- a/lib/private/setup/mysql.php +++ b/lib/private/setup/mysql.php @@ -9,7 +9,7 @@ class MySQL extends AbstractDatabase { //check if the database user has admin right $connection = @mysql_connect($this->dbhost, $this->dbuser, $this->dbpassword); if(!$connection) { - throw new \DatabaseSetupException($this->trans->t('MySQL/MariaDB username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('MySQL/MariaDB username and/or password not valid'), $this->trans->t('You need to enter either an existing account or the administrator.')); } //user already specified in config @@ -96,13 +96,13 @@ class MySQL extends AbstractDatabase { $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; $result = mysql_query($query, $connection); if (!$result) { - throw new \DatabaseSetupException($this->trans->t("MySQL/MariaDB user '%s'@'localhost' exists already.", array($name)), + throw new \OC\DatabaseSetupException($this->trans->t("MySQL/MariaDB user '%s'@'localhost' exists already.", array($name)), $this->trans->t("Drop this user from MySQL/MariaDB", array($name))); } $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; $result = mysql_query($query, $connection); if (!$result) { - throw new \DatabaseSetupException($this->trans->t("MySQL/MariaDB user '%s'@'%%' already exists", array($name)), + throw new \OC\DatabaseSetupException($this->trans->t("MySQL/MariaDB user '%s'@'%%' already exists", array($name)), $this->trans->t("Drop this user from MySQL/MariaDB.")); } } diff --git a/lib/private/setup/oci.php b/lib/private/setup/oci.php index 23b5232438a..b75b658bae2 100644 --- a/lib/private/setup/oci.php +++ b/lib/private/setup/oci.php @@ -45,14 +45,14 @@ class OCI extends AbstractDatabase { if(!$connection) { $errorMessage = $this->getLastError(); if ($errorMessage) { - throw new \DatabaseSetupException($this->trans->t('Oracle connection could not be established'), + throw new \OC\DatabaseSetupException($this->trans->t('Oracle connection could not be established'), $errorMessage.' Check environment: ORACLE_HOME='.getenv('ORACLE_HOME') .' ORACLE_SID='.getenv('ORACLE_SID') .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH') .' NLS_LANG='.getenv('NLS_LANG') .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable'); } - throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), 'Check environment: ORACLE_HOME='.getenv('ORACLE_HOME') .' ORACLE_SID='.getenv('ORACLE_SID') .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH') @@ -124,7 +124,7 @@ class OCI extends AbstractDatabase { } $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string); if(!$connection) { - throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), $this->trans->t('You need to enter either an existing account or the administrator.')); } $query = "SELECT count(*) FROM user_tables WHERE table_name = :un"; diff --git a/lib/private/setup/postgresql.php b/lib/private/setup/postgresql.php index 4d0c9b52a4d..3777d1620bc 100644 --- a/lib/private/setup/postgresql.php +++ b/lib/private/setup/postgresql.php @@ -27,7 +27,7 @@ class PostgreSQL extends AbstractDatabase { $connection = @pg_connect($connection_string); if(!$connection) - throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), $this->trans->t('You need to enter either an existing account or the administrator.')); } $e_user = pg_escape_string($this->dbuser); @@ -80,7 +80,7 @@ class PostgreSQL extends AbstractDatabase { $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) { - throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), $this->trans->t('You need to enter either an existing account or the administrator.')); } $query = "select count(*) FROM pg_class WHERE relname='".$this->tableprefix."users' limit 1"; diff --git a/lib/private/share/helper.php b/lib/private/share/helper.php index 2418535c9d5..6bbb101db3a 100644 --- a/lib/private/share/helper.php +++ b/lib/private/share/helper.php @@ -189,20 +189,23 @@ class Helper extends \OC\Share\Constants { public static function calculateExpireDate($defaultExpireSettings, $creationTime, $userExpireDate = null) { $expires = false; + $defaultExpires = null; if (!empty($defaultExpireSettings['defaultExpireDateSet'])) { - $expires = $creationTime + $defaultExpireSettings['expireAfterDays'] * 86400; + $defaultExpires = $creationTime + $defaultExpireSettings['expireAfterDays'] * 86400; } if (isset($userExpireDate)) { // if the admin decided to enforce the default expire date then we only take // the user defined expire date of it is before the default expire date - if ($expires && !empty($defaultExpireSettings['enforceExpireDate'])) { - $expires = min($userExpireDate, $expires); + if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) { + $expires = min($userExpireDate, $defaultExpires); } else { $expires = $userExpireDate; } + } else if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) { + $expires = $defaultExpires; } return $expires; diff --git a/lib/private/share/share.php b/lib/private/share/share.php index cd5decf6f71..c6fd1604ac7 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -287,12 +287,12 @@ class Share extends \OC\Share\Constants { * Get the item of item type shared with a given user by source * @param string $itemType * @param string $itemSource - * @param string $user User user to whom the item was shared + * @param string $user User to whom the item was shared + * @param string $owner Owner of the share * @param int $shareType only look for a specific share type * @return array Return list of items with file_target, permissions and expiration */ - public static function getItemSharedWithUser($itemType, $itemSource, $user, $shareType = null) { - + public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) { $shares = array(); $fileDependend = false; @@ -320,6 +320,11 @@ class Share extends \OC\Share\Constants { $arguments[] = $shareType; } + if ($owner !== null) { + $where .= ' AND `uid_owner` = ? '; + $arguments[] = $owner; + } + $query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $where); $result = \OC_DB::executeAudited($query, $arguments); @@ -542,7 +547,7 @@ class Share extends \OC\Share\Constants { // single file shares should never have delete permissions if ($itemType === 'file') { - $permissions = (int)$permissions & ~\OCP\PERMISSION_DELETE; + $permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE; } // Verify share type and sharing conditions are met @@ -633,9 +638,7 @@ class Share extends \OC\Share\Constants { // Generate hash of password - same method as user passwords if (!empty($shareWith)) { - $forcePortable = (CRYPT_BLOWFISH != 1); - $hasher = new \PasswordHash(8, $forcePortable); - $shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', '')); + $shareWith = \OC::$server->getHasher()->hash($shareWith); } else { // reuse the already set password, but only if we change permissions // otherwise the user disabled the password protection @@ -703,7 +706,7 @@ class Share extends \OC\Share\Constants { // check if it is a valid itemType self::getBackend($itemType); - $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $shareType); + $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, null, $shareType); $toDelete = array(); $newParent = null; @@ -926,7 +929,7 @@ class Share extends \OC\Share\Constants { // Check if permissions were removed if ($item['permissions'] & ~$permissions) { // If share permission is removed all reshares must be deleted - if (($item['permissions'] & \OCP\PERMISSION_SHARE) && (~$permissions & \OCP\PERMISSION_SHARE)) { + if (($item['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) { Helper::delete($item['id'], true); } else { $ids = array(); @@ -1455,8 +1458,8 @@ class Share extends \OC\Share\Constants { } // Switch ids if sharing permission is granted on only // one share to ensure correct parent is used if resharing - if (~(int)$items[$id]['permissions'] & \OCP\PERMISSION_SHARE - && (int)$row['permissions'] & \OCP\PERMISSION_SHARE) { + if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE + && (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) { $items[$row['id']] = $items[$id]; $switchedItems[$id] = $row['id']; unset($items[$id]); @@ -1513,7 +1516,7 @@ class Share extends \OC\Share\Constants { } // Check if resharing is allowed, if not remove share permission if (isset($row['permissions']) && (!self::isResharingAllowed() | \OC_Util::isSharingDisabledForUser())) { - $row['permissions'] &= ~\OCP\PERMISSION_SHARE; + $row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE; } // Add display names to result if ( isset($row['share_with']) && $row['share_with'] != '' && @@ -1631,7 +1634,7 @@ class Share extends \OC\Share\Constants { // Need to find a solution which works for all back-ends $collectionItems = array(); $collectionBackend = self::getBackend('folder'); - $sharedParents = $collectionBackend->getParents($item, $shareWith); + $sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner); foreach ($sharedParents as $parent) { $collectionItems[] = $parent; } @@ -1908,7 +1911,7 @@ class Share extends \OC\Share\Constants { } // Check if share permissions is granted - if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\PERMISSION_SHARE) { + if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) { if (~(int)$checkReshare['permissions'] & $permissions) { $message = 'Sharing %s failed, because the permissions exceed permissions granted to %s'; $message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner)); diff --git a/lib/private/urlgenerator.php b/lib/private/urlgenerator.php index e50e9eed6af..d263d25aeef 100644 --- a/lib/private/urlgenerator.php +++ b/lib/private/urlgenerator.php @@ -8,6 +8,7 @@ */ namespace OC; +use OC_Defaults; use OCP\IURLGenerator; use RuntimeException; @@ -156,7 +157,7 @@ class URLGenerator implements IURLGenerator { /** * Makes an URL absolute - * @param string $url the url in the owncloud host + * @param string $url the url in the ownCloud host * @return string the absolute version of the url */ public function getAbsoluteURL($url) { @@ -173,4 +174,13 @@ class URLGenerator implements IURLGenerator { return \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost(). $webRoot . $separator . $url; } + + /** + * @param string $key + * @return string url to the online documentation + */ + public function linkToDocs($key) { + $theme = new OC_Defaults(); + return $theme->buildDocLinkToKey($key); + } } diff --git a/lib/private/user/backend.php b/lib/private/user/backend.php index 1f0a524117d..5e0eef4771a 100644 --- a/lib/private/user/backend.php +++ b/lib/private/user/backend.php @@ -25,19 +25,28 @@ /** * error code for functions not provided by the user backend + * @deprecated Use \OC_User_Backend::NOT_IMPLEMENTED instead */ define('OC_USER_BACKEND_NOT_IMPLEMENTED', -501); /** * actions that user backends can define */ +/** @deprecated Use \OC_User_Backend::CREATE_USER instead */ define('OC_USER_BACKEND_CREATE_USER', 1 << 0); +/** @deprecated Use \OC_User_Backend::SET_PASSWORD instead */ define('OC_USER_BACKEND_SET_PASSWORD', 1 << 4); +/** @deprecated Use \OC_User_Backend::CHECK_PASSWORD instead */ define('OC_USER_BACKEND_CHECK_PASSWORD', 1 << 8); +/** @deprecated Use \OC_User_Backend::GET_HOME instead */ define('OC_USER_BACKEND_GET_HOME', 1 << 12); +/** @deprecated Use \OC_User_Backend::GET_DISPLAYNAME instead */ define('OC_USER_BACKEND_GET_DISPLAYNAME', 1 << 16); +/** @deprecated Use \OC_User_Backend::SET_DISPLAYNAME instead */ define('OC_USER_BACKEND_SET_DISPLAYNAME', 1 << 20); +/** @deprecated Use \OC_User_Backend::PROVIDE_AVATAR instead */ define('OC_USER_BACKEND_PROVIDE_AVATAR', 1 << 24); +/** @deprecated Use \OC_User_Backend::COUNT_USERS instead */ define('OC_USER_BACKEND_COUNT_USERS', 1 << 28); /** @@ -47,16 +56,32 @@ define('OC_USER_BACKEND_COUNT_USERS', 1 << 28); * Subclass this for your own backends, and see OC_User_Example for descriptions */ abstract class OC_User_Backend implements OC_User_Interface { + /** + * error code for functions not provided by the user backend + */ + const NOT_IMPLEMENTED = -501; + + /** + * actions that user backends can define + */ + const CREATE_USER = 1; // 1 << 0 + const SET_PASSWORD = 16; // 1 << 4 + const CHECK_PASSWORD = 256; // 1 << 8 + const GET_HOME = 4096; // 1 << 12 + const GET_DISPLAYNAME = 65536; // 1 << 16 + const SET_DISPLAYNAME = 1048576; // 1 << 20 + const PROVIDE_AVATAR = 16777216; // 1 << 24 + const COUNT_USERS = 268435456; // 1 << 28 protected $possibleActions = array( - OC_USER_BACKEND_CREATE_USER => 'createUser', - OC_USER_BACKEND_SET_PASSWORD => 'setPassword', - OC_USER_BACKEND_CHECK_PASSWORD => 'checkPassword', - OC_USER_BACKEND_GET_HOME => 'getHome', - OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName', - OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName', - OC_USER_BACKEND_PROVIDE_AVATAR => 'canChangeAvatar', - OC_USER_BACKEND_COUNT_USERS => 'countUsers', + self::CREATE_USER => 'createUser', + self::SET_PASSWORD => 'setPassword', + self::CHECK_PASSWORD => 'checkPassword', + self::GET_HOME => 'getHome', + self::GET_DISPLAYNAME => 'getDisplayName', + self::SET_DISPLAYNAME => 'setDisplayName', + self::PROVIDE_AVATAR => 'canChangeAvatar', + self::COUNT_USERS => 'countUsers', ); /** @@ -64,7 +89,7 @@ abstract class OC_User_Backend implements OC_User_Interface { * @return int bitwise-or'ed actions * * Returns the supported actions as int to be - * compared with OC_USER_BACKEND_CREATE_USER etc. + * compared with self::CREATE_USER etc. */ public function getSupportedActions() { $actions = 0; @@ -83,7 +108,7 @@ abstract class OC_User_Backend implements OC_User_Interface { * @return boolean * * Returns the supported actions as int to be - * compared with OC_USER_BACKEND_CREATE_USER etc. + * compared with self::CREATE_USER etc. */ public function implementsActions($actions) { return (bool)($this->getSupportedActions() & $actions); diff --git a/lib/private/user/interface.php b/lib/private/user/interface.php index 4cdc47479a3..624d36e6fe5 100644 --- a/lib/private/user/interface.php +++ b/lib/private/user/interface.php @@ -25,11 +25,11 @@ interface OC_User_Interface { /** * Check if backend implements actions - * @param $actions bitwise-or'ed actions + * @param int $actions bitwise-or'ed actions * @return boolean * * Returns the supported actions as int to be - * compared with OC_USER_BACKEND_CREATE_USER etc. + * compared with \OC_User_Backend::CREATE_USER etc. */ public function implementsActions($actions); diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php index 4d1612a35ce..0c01f957bd3 100644 --- a/lib/private/user/manager.php +++ b/lib/private/user/manager.php @@ -143,7 +143,7 @@ class Manager extends PublicEmitter implements IUserManager { */ public function checkPassword($loginname, $password) { foreach ($this->backends as $backend) { - if ($backend->implementsActions(\OC_USER_BACKEND_CHECK_PASSWORD)) { + if ($backend->implementsActions(\OC_User_Backend::CHECK_PASSWORD)) { $uid = $backend->checkPassword($loginname, $password); if ($uid !== false) { return $this->getUserObject($uid, $backend); @@ -246,7 +246,7 @@ class Manager extends PublicEmitter implements IUserManager { $this->emit('\OC\User', 'preCreateUser', array($uid, $password)); foreach ($this->backends as $backend) { - if ($backend->implementsActions(\OC_USER_BACKEND_CREATE_USER)) { + if ($backend->implementsActions(\OC_User_Backend::CREATE_USER)) { $backend->createUser($uid, $password); $user = $this->getUserObject($uid, $backend); $this->emit('\OC\User', 'postCreateUser', array($user, $password)); @@ -264,7 +264,7 @@ class Manager extends PublicEmitter implements IUserManager { public function countUsers() { $userCountStatistics = array(); foreach ($this->backends as $backend) { - if ($backend->implementsActions(\OC_USER_BACKEND_COUNT_USERS)) { + if ($backend->implementsActions(\OC_User_Backend::COUNT_USERS)) { $backendusers = $backend->countUsers(); if($backendusers !== false) { if(isset($userCountStatistics[get_class($backend)])) { diff --git a/lib/private/user/session.php b/lib/private/user/session.php index ca0265dfb23..94abaca3e76 100644 --- a/lib/private/user/session.php +++ b/lib/private/user/session.php @@ -88,15 +88,6 @@ class Session implements IUserSession, Emitter { * @return \OCP\ISession */ public function getSession() { - // fetch the deprecated \OC::$session if it changed for backwards compatibility - if (isset(\OC::$session) && \OC::$session !== $this->session) { - \OC::$server->getLogger()->warning( - 'One of your installed apps still seems to use the deprecated ' . - '\OC::$session and has replaced it with a new instance. Please file a bug against it.' . - 'Closing and replacing session in UserSession instance.' - ); - $this->setSession(\OC::$session); - } return $this->session; } @@ -111,14 +102,6 @@ class Session implements IUserSession, Emitter { } $this->session = $session; $this->activeUser = null; - - // maintain deprecated \OC::$session - if (\OC::$session !== $this->session) { - if (\OC::$session instanceof \OCP\ISession) { - \OC::$session->close(); - } - \OC::$session = $session; - } } /** diff --git a/lib/private/user/user.php b/lib/private/user/user.php index 729abdc6227..9ad2f5f0d3a 100644 --- a/lib/private/user/user.php +++ b/lib/private/user/user.php @@ -90,7 +90,7 @@ class User implements IUser { public function getDisplayName() { if (!isset($this->displayName)) { $displayName = ''; - if ($this->backend and $this->backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) { + if ($this->backend and $this->backend->implementsActions(\OC_User_Backend::GET_DISPLAYNAME)) { // get display name and strip whitespace from the beginning and end of it $backendDisplayName = $this->backend->getDisplayName($this->uid); if (is_string($backendDisplayName)) { @@ -115,7 +115,7 @@ class User implements IUser { */ public function setDisplayName($displayName) { $displayName = trim($displayName); - if ($this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME) && !empty($displayName)) { + if ($this->backend->implementsActions(\OC_User_Backend::SET_DISPLAYNAME) && !empty($displayName)) { $this->displayName = $displayName; $result = $this->backend->setDisplayName($this->uid, $displayName); return $result !== false; @@ -170,7 +170,7 @@ class User implements IUser { if ($this->emitter) { $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword)); } - if ($this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD)) { + if ($this->backend->implementsActions(\OC_User_Backend::SET_PASSWORD)) { $result = $this->backend->setPassword($this->uid, $password); if ($this->emitter) { $this->emitter->emit('\OC\User', 'postSetPassword', array($this, $password, $recoveryPassword)); @@ -188,7 +188,7 @@ class User implements IUser { */ public function getHome() { if (!$this->home) { - if ($this->backend->implementsActions(\OC_USER_BACKEND_GET_HOME) and $home = $this->backend->getHome($this->uid)) { + if ($this->backend->implementsActions(\OC_User_Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) { $this->home = $home; } elseif ($this->config) { $this->home = $this->config->getSystemValue('datadirectory') . '/' . $this->uid; @@ -205,7 +205,7 @@ class User implements IUser { * @return bool */ public function canChangeAvatar() { - if ($this->backend->implementsActions(\OC_USER_BACKEND_PROVIDE_AVATAR)) { + if ($this->backend->implementsActions(\OC_User_Backend::PROVIDE_AVATAR)) { return $this->backend->canChangeAvatar($this->uid); } return true; @@ -217,7 +217,7 @@ class User implements IUser { * @return bool */ public function canChangePassword() { - return $this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD); + return $this->backend->implementsActions(\OC_User_Backend::SET_PASSWORD); } /** @@ -229,7 +229,7 @@ class User implements IUser { if ($this->config and $this->config->getSystemValue('allow_user_to_change_display_name') === false) { return false; } else { - return $this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME); + return $this->backend->implementsActions(\OC_User_Backend::SET_DISPLAYNAME); } } diff --git a/lib/private/util.php b/lib/private/util.php index bee0a579192..a18a4e44232 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -562,6 +562,7 @@ class OC_Util { 'classes' => array( 'ZipArchive' => 'zip', 'DOMDocument' => 'dom', + 'XMLWriter' => 'XMLWriter' ), 'functions' => array( 'xml_parser_create' => 'libxml', @@ -1335,7 +1336,7 @@ class OC_Util { return false; } foreach (str_split($trimmed) as $char) { - if (strpos(\OCP\FILENAME_INVALID_CHARS, $char) !== false) { + if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) { return false; } } |