diff options
Diffstat (limited to 'lib/private')
25 files changed, 721 insertions, 56 deletions
diff --git a/lib/private/api.php b/lib/private/api.php index 66b763fdc3e..c58d2620684 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -47,6 +47,7 @@ class OC_API { */ protected static $actions = array(); private static $logoutRequired = false; + private static $isLoggedIn = false; /** * registers an api call @@ -269,7 +270,10 @@ class OC_API { * http basic auth * @return string|false (username, or false on failure) */ - private static function loginUser(){ + private static function loginUser() { + if(self::$isLoggedIn === true) { + return \OC_User::getUser(); + } // reuse existing login $loggedIn = OC_User::isLoggedIn(); @@ -279,6 +283,7 @@ class OC_API { // initialize the user's filesystem \OC_Util::setUpFS(\OC_User::getUser()); + self::$isLoggedIn = true; return OC_User::getUser(); } @@ -296,8 +301,9 @@ class OC_API { // initialize the user's filesystem \OC_Util::setUpFS(\OC_User::getUser()); + self::$isLoggedIn = true; - return $authUser; + return \OC_User::getUser(); } } diff --git a/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php index ec5f82f9daa..c878e5ee4b4 100644 --- a/lib/private/connector/sabre/directory.php +++ b/lib/private/connector/sabre/directory.php @@ -25,6 +25,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota { /** + * Cached directory content + * + * @var \OCP\Files\FileInfo[] + */ + private $dirContent; + + /** * Creates a new file in the directory * * Data will either be supplied as a stream resource, or in certain cases @@ -72,7 +79,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node $path = $this->fileView->getAbsolutePath($this->path) . '/' . $name; // using a dummy FileInfo is acceptable here since it will be refreshed after the put is complete - $info = new \OC\Files\FileInfo($path, null, null, array()); + $info = new \OC\Files\FileInfo($path, null, null, array(), null); $node = new OC_Connector_Sabre_File($this->fileView, $info); return $node->put($data); } catch (\OCP\Files\StorageNotAvailableException $e) { @@ -138,13 +145,20 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node * @return \Sabre\DAV\INode[] */ public function getChildren() { + if (!is_null($this->dirContent)) { + return $this->dirContent; + } + $folderContent = $this->fileView->getDirectoryContent($this->path); - $folder_content = $this->fileView->getDirectoryContent($this->path); + $properties = array(); $paths = array(); - foreach($folder_content as $info) { - $paths[] = $this->path.'/'.$info['name']; - $properties[$this->path.'/'.$info['name']][self::GETETAG_PROPERTYNAME] = '"' . $info['etag'] . '"'; + foreach($folderContent as $info) { + $name = $info->getName(); + $paths[] = $this->path . '/' . $name; + $properties[$this->path.'/' . $name][self::GETETAG_PROPERTYNAME] = '"' . $info->getEtag() . '"'; } + // TODO: move this to a beforeGetPropertiesForPath event to pre-cache properties + // TODO: only fetch the requested properties if(count($paths)>0) { // // the number of arguments within IN conditions are limited in most databases @@ -169,12 +183,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node } $nodes = array(); - foreach($folder_content as $info) { + foreach($folderContent as $info) { $node = $this->getChild($info->getName(), $info); - $node->setPropertyCache($properties[$this->path.'/'.$info['name']]); + $node->setPropertyCache($properties[$this->path . '/' . $info->getName()]); $nodes[] = $node; } - return $nodes; + $this->dirContent = $nodes; + return $this->dirContent; } /** diff --git a/lib/private/connector/sabre/node.php b/lib/private/connector/sabre/node.php index a22dc9c5fbe..3173ab8a30f 100644 --- a/lib/private/connector/sabre/node.php +++ b/lib/private/connector/sabre/node.php @@ -1,5 +1,7 @@ <?php + use Sabre\DAV\URLUtil; +use OC\Connector\Sabre\TagList; /** * ownCloud @@ -227,6 +229,15 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I } /** + * Returns the cache's file id + * + * @return int + */ + public function getId() { + return $this->info->getId(); + } + + /** * @return string|null */ public function getFileId() { diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index 14a55b5cada..d2759d7a3ba 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -71,7 +71,9 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { if (pathinfo($path, PATHINFO_EXTENSION) === 'part') { // read from storage $absPath = $this->fileView->getAbsolutePath($path); - list($storage, $internalPath) = Filesystem::resolvePath('/' . $absPath); + $mount = $this->fileView->getMount($path); + $storage = $mount->getStorage(); + $internalPath = $mount->getInternalPath($absPath); if ($storage) { /** * @var \OC\Files\Storage\Storage $storage @@ -79,7 +81,7 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { $scanner = $storage->getScanner($internalPath); // get data directly $data = $scanner->getData($internalPath); - $info = new FileInfo($absPath, $storage, $internalPath, $data); + $info = new FileInfo($absPath, $storage, $internalPath, $data, $mount); } else { $info = null; } diff --git a/lib/private/connector/sabre/server.php b/lib/private/connector/sabre/server.php index 137082eea67..a836af2a0b8 100644 --- a/lib/private/connector/sabre/server.php +++ b/lib/private/connector/sabre/server.php @@ -144,6 +144,13 @@ class OC_Connector_Sabre_Server extends Sabre\DAV\Server { $path = rtrim($path,'/'); + // This event allows people to intercept these requests early on in the + // process. + // + // We're not doing anything with the result, but this can be helpful to + // pre-fetch certain expensive live properties. + $this->broadCastEvent('beforeGetPropertiesForPath', array($path, $propertyNames, $depth)); + $returnPropertyList = array(); $parentNode = $this->tree->getNodeForPath($path); diff --git a/lib/private/connector/sabre/taglist.php b/lib/private/connector/sabre/taglist.php new file mode 100644 index 00000000000..56cab393fea --- /dev/null +++ b/lib/private/connector/sabre/taglist.php @@ -0,0 +1,102 @@ +<?php +/** + * ownCloud + * + * @author Vincent Petry + * @copyright 2014 Vincent Petry <pvince81@owncloud.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Connector\Sabre; + +use Sabre\DAV; + +/** + * TagList property + * + * This property contains multiple "tag" elements, each containing a tag name. + */ +class TagList extends DAV\Property { + const NS_OWNCLOUD = 'http://owncloud.org/ns'; + + /** + * tags + * + * @var array + */ + private $tags; + + /** + * @param array $tags + */ + public function __construct(array $tags) { + $this->tags = $tags; + } + + /** + * Returns the tags + * + * @return array + */ + public function getTags() { + + return $this->tags; + + } + + /** + * Serializes this property. + * + * @param DAV\Server $server + * @param \DOMElement $dom + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $dom) { + + $prefix = $server->xmlNamespaces[self::NS_OWNCLOUD]; + + foreach($this->tags as $tag) { + + $elem = $dom->ownerDocument->createElement($prefix . ':tag'); + $elem->appendChild($dom->ownerDocument->createTextNode($tag)); + + $dom->appendChild($elem); + } + + } + + /** + * Unserializes this property from a DOM Element + * + * This method returns an instance of this class. + * It will only decode tag values. + * + * @param \DOMElement $dom + * @return \OC\Connector\Sabre\TagList + */ + static function unserialize(\DOMElement $dom) { + + $tags = array(); + foreach($dom->childNodes as $child) { + if (DAV\XMLUtil::toClarkNotation($child)==='{' . self::NS_OWNCLOUD . '}tag') { + $tags[] = $child->textContent; + } + } + return new self($tags); + + } + +} diff --git a/lib/private/connector/sabre/tagsplugin.php b/lib/private/connector/sabre/tagsplugin.php new file mode 100644 index 00000000000..dd0b5172bd6 --- /dev/null +++ b/lib/private/connector/sabre/tagsplugin.php @@ -0,0 +1,289 @@ +<?php + +namespace OC\Connector\Sabre; + +/** + * ownCloud + * + * @author Vincent Petry + * @copyright 2014 Vincent Petry <pvince81@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/>. + * + */ + +class TagsPlugin extends \Sabre\DAV\ServerPlugin +{ + + // namespace + const NS_OWNCLOUD = 'http://owncloud.org/ns'; + const TAGS_PROPERTYNAME = '{http://owncloud.org/ns}tags'; + const FAVORITE_PROPERTYNAME = '{http://owncloud.org/ns}favorite'; + const TAG_FAVORITE = '_$!<Favorite>!$_'; + + /** + * Reference to main server object + * + * @var \Sabre\DAV\Server + */ + private $server; + + /** + * @var \OCP\ITagManager + */ + private $tagManager; + + /** + * @var \OCP\ITags + */ + private $tagger; + + /** + * Array of file id to tags array + * The null value means the cache wasn't initialized. + * + * @var array + */ + private $cachedTags; + + /** + * @param \OCP\ITagManager $tagManager tag manager + */ + public function __construct(\Sabre\DAV\ObjectTree $objectTree, \OCP\ITagManager $tagManager) { + $this->objectTree = $objectTree; + $this->tagManager = $tagManager; + $this->tagger = null; + $this->cachedTags = null; + } + + /** + * This initializes the plugin. + * + * This function is called by \Sabre\DAV\Server, after + * addPlugin is called. + * + * This method should set up the required event subscriptions. + * + * @param \Sabre\DAV\Server $server + * @return void + */ + public function initialize(\Sabre\DAV\Server $server) { + + $server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc'; + $server->propertyMap[self::TAGS_PROPERTYNAME] = 'OC\\Connector\\Sabre\\TagList'; + + $this->server = $server; + $this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties')); + $this->server->subscribeEvent('beforeGetPropertiesForPath', array($this, 'beforeGetPropertiesForPath')); + $this->server->subscribeEvent('updateProperties', array($this, 'updateProperties')); + } + + /** + * Searches and removes a value from the given array + * + * @param array $requestedProps + * @param string $propName to remove + * @return boolean true if the property was present, false otherwise + */ + private function findAndRemoveProperty(&$requestedProps, $propName) { + $index = array_search($propName, $requestedProps); + if ($index !== false) { + unset($requestedProps[$index]); + return true; + } + return false; + } + + /** + * Returns the tagger + * + * @return \OCP\ITags tagger + */ + private function getTagger() { + if (!$this->tagger) { + $this->tagger = $this->tagManager->load('files'); + } + return $this->tagger; + } + + /** + * Returns tags and favorites. + * + * @param integer $fileId file id + * @return array list($tags, $favorite) with $tags as tag array + * and $favorite is a boolean whether the file was favorited + */ + private function getTagsAndFav($fileId) { + $isFav = false; + $tags = $this->getTags($fileId); + if ($tags) { + $favPos = array_search(self::TAG_FAVORITE, $tags); + if ($favPos !== false) { + $isFav = true; + unset($tags[$favPos]); + } + } + return array($tags, $isFav); + } + + /** + * Returns tags for the given file id + * + * @param integer $fileId file id + * @return array list of tags for that file + */ + private function getTags($fileId) { + if (isset($this->cachedTags[$fileId])) { + return $this->cachedTags[$fileId]; + } else { + $tags = $this->getTagger()->getTagsForObjects(array($fileId)); + if ($tags) { + return current($tags); + } + } + return null; + } + + /** + * Updates the tags of the given file id + * + * @param int $fileId + * @param array $tags array of tag strings + */ + private function updateTags($fileId, $tags) { + $tagger = $this->getTagger(); + $currentTags = $this->getTags($fileId); + + $newTags = array_diff($tags, $currentTags); + foreach ($newTags as $tag) { + if ($tag === self::TAG_FAVORITE) { + continue; + } + $tagger->tagAs($fileId, $tag); + } + $deletedTags = array_diff($currentTags, $tags); + foreach ($deletedTags as $tag) { + if ($tag === self::TAG_FAVORITE) { + continue; + } + $tagger->unTag($fileId, $tag); + } + } + + /** + * Pre-fetch tags info + * + * @param string $path + * @param array $requestedProperties + * @param integer $depth + * @return void + */ + public function beforeGetPropertiesForPath( + $path, + array $requestedProperties, + $depth + ) { + $node = $this->objectTree->getNodeForPath($path); + if (!($node instanceof \OC_Connector_Sabre_Directory)) { + return; + } + + if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME) + || $this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME) + ) { + $fileIds = array(); + // note: pre-fetching only supported for depth <= 1 + $folderContent = $node->getChildren(); + // TODO: refactor somehow with the similar array that is created + // in getChildren() + foreach ($folderContent as $info) { + $fileIds[] = $info->getId(); + } + $tags = $this->getTagger()->getTagsForObjects($fileIds); + if ($tags) { + $this->cachedTags = $tags; + } + } + } + + /** + * Adds tags and favorites properties to the response, + * if requested. + * + * @param string $path + * @param \Sabre\DAV\INode $node + * @param array $requestedProperties + * @param array $returnedProperties + * @return void + */ + public function beforeGetProperties( + $path, + \Sabre\DAV\INode $node, + array &$requestedProperties, + array &$returnedProperties + ) { + if (!($node instanceof \OC_Connector_Sabre_Node)) { + return; + } + + $tags = null; + $isFav = null; + if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME)) { + list($tags, $isFav) = $this->getTagsAndFav($node->getId()); + $returnedProperties[200][self::TAGS_PROPERTYNAME] = new TagList($tags); + } + if ($this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME)) { + if (is_null($tags)) { + list($tags, $isFav) = $this->getTagsAndFav($node->getId()); + } + $returnedProperties[200][self::FAVORITE_PROPERTYNAME] = $isFav; + } + } + + /** + * Updates tags and favorites properties, if applicable. + * + * @param string $path + * @param \Sabre\DAV\INode $node + * @param array $requestedProperties + * @param array $returnedProperties + * @return bool success status + */ + public function updateProperties(array &$properties, array &$result, \Sabre\DAV\INode $node) { + if (!($node instanceof \OC_Connector_Sabre_Node)) { + return; + } + + $fileId = $node->getId(); + if (isset($properties[self::TAGS_PROPERTYNAME])) { + $tagsProp = $properties[self::TAGS_PROPERTYNAME]; + unset($properties[self::TAGS_PROPERTYNAME]); + $this->updateTags($fileId, $tagsProp->getTags()); + $result[200][self::TAGS_PROPERTYNAME] = new TagList($tagsProp->getTags()); + } + if (isset($properties[self::FAVORITE_PROPERTYNAME])) { + $favState = $properties[self::FAVORITE_PROPERTYNAME]; + unset($properties[self::FAVORITE_PROPERTYNAME]); + if ((int)$favState === 1 || $favState === 'true') { + $favState = true; + $this->getTagger()->tagAs($fileId, self::TAG_FAVORITE); + } else { + $favState = false; + $this->getTagger()->unTag($fileId, self::TAG_FAVORITE); + } + $result[200][self::FAVORITE_PROPERTYNAME] = $favState; + } + return true; + } +} diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index 8bab51f0737..e4a397dcca2 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -30,14 +30,23 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { private $internalPath; /** + * @var \OCP\Files\Mount\IMountPoint + */ + private $mount; + + /** * @param string|boolean $path * @param Storage\Storage $storage + * @param string $internalPath + * @param array $data + * @param \OCP\Files\Mount\IMountPoint $mount */ - public function __construct($path, $storage, $internalPath, $data) { + public function __construct($path, $storage, $internalPath, $data, $mount) { $this->path = $path; $this->storage = $storage; $this->internalPath = $internalPath; $this->data = $data; + $this->mount = $mount; } public function offsetSet($offset, $value) { @@ -208,6 +217,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { /** * Check if a file or folder is shared + * * @return bool */ public function isShared() { @@ -229,4 +239,13 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { return false; } + + /** + * Get the mountpoint the file belongs to + * + * @return \OCP\Files\Mount\IMountPoint + */ + public function getMountPoint() { + return $this->mount; + } } diff --git a/lib/private/files/mount/mountpoint.php b/lib/private/files/mount/mountpoint.php index b2c50f9d881..77a51a17020 100644 --- a/lib/private/files/mount/mountpoint.php +++ b/lib/private/files/mount/mountpoint.php @@ -20,10 +20,23 @@ class MountPoint implements IMountPoint { protected $storage = null; protected $class; protected $storageId; + + /** + * Configuration options for the storage backend + * + * @var array + */ protected $arguments = array(); protected $mountPoint; /** + * Mount specific options + * + * @var array + */ + protected $mountOptions = array(); + + /** * @var \OC\Files\Storage\StorageFactory $loader */ private $loader; @@ -31,10 +44,11 @@ class MountPoint implements IMountPoint { /** * @param string|\OC\Files\Storage\Storage $storage * @param string $mountpoint - * @param array $arguments (optional)\ + * @param array $arguments (optional) configuration for the storage backend * @param \OCP\Files\Storage\IStorageFactory $loader + * @param array $mountOptions mount specific options */ - public function __construct($storage, $mountpoint, $arguments = null, $loader = null) { + public function __construct($storage, $mountpoint, $arguments = null, $loader = null, $mountOptions = null) { if (is_null($arguments)) { $arguments = array(); } @@ -44,6 +58,10 @@ class MountPoint implements IMountPoint { $this->loader = $loader; } + if (!is_null($mountOptions)) { + $this->mountOptions = $mountOptions; + } + $mountpoint = $this->formatPath($mountpoint); if ($storage instanceof Storage) { $this->class = get_class($storage); @@ -161,4 +179,15 @@ class MountPoint implements IMountPoint { public function wrapStorage($wrapper) { $this->storage = $wrapper($this->mountPoint, $this->getStorage()); } + + /** + * Get a mount option + * + * @param string $name Name of the mount option to get + * @param mixed $default Default value for the mount option + * @return mixed + */ + public function getOption($name, $default) { + return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; + } } diff --git a/lib/private/files/node/node.php b/lib/private/files/node/node.php index 87d4a4b9156..17907a53044 100644 --- a/lib/private/files/node/node.php +++ b/lib/private/files/node/node.php @@ -288,4 +288,8 @@ class Node implements \OCP\Files\Node, FileInfo { public function isEncrypted() { return $this->getFileInfo()->isEncrypted(); } + + public function getMountPoint() { + return $this->getFileInfo()->getMountPoint(); + } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index c01763cdad3..f1c15e197d9 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -113,6 +113,19 @@ class View { } /** + * get the mountpoint of the storage object for a path + * ( note: because a storage is not always mounted inside the fakeroot, the + * returned mountpoint is relative to the absolute root of the filesystem + * and doesn't take the chroot into account ) + * + * @param string $path + * @return \OCP\Files\Mount\IMountPoint + */ + public function getMount($path) { + return Filesystem::getMountManager()->find($this->getAbsolutePath($path)); + } + + /** * resolve a path to a storage and internal path * * @param string $path @@ -280,6 +293,11 @@ class View { } public function isDeletable($path) { + $absolutePath = $this->getAbsolutePath($path); + $mount = Filesystem::getMountManager()->find($absolutePath); + if ($mount->getInternalPath($absolutePath) === '') { + return $mount instanceof MoveableMount; + } return $this->basicOperation('isDeletable', $path); } @@ -938,7 +956,7 @@ class View { $data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data); - return new FileInfo($path, $storage, $internalPath, $data); + return new FileInfo($path, $storage, $internalPath, $data, $mount); } /** @@ -955,8 +973,10 @@ class View { return $result; } $path = $this->getAbsolutePath($directory); - /** @var \OC\Files\Storage\Storage $storage */ - list($storage, $internalPath) = $this->resolvePath($directory); + $path = Filesystem::normalizePath($path); + $mount = $this->getMount($directory); + $storage = $mount->getStorage(); + $internalPath = $mount->getInternalPath($path); if ($storage) { $cache = $storage->getCache($internalPath); $user = \OC_User::getUser(); @@ -990,7 +1010,7 @@ class View { if (\OCP\Util::isSharingDisabledForUser()) { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } - $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content); + $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount); } //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders @@ -998,7 +1018,7 @@ class View { $dirLength = strlen($path); foreach ($mounts as $mount) { $mountPoint = $mount->getMountPoint(); - $subStorage = Filesystem::getStorage($mountPoint); + $subStorage = $mount->getStorage(); if ($subStorage) { $subCache = $subStorage->getCache(''); @@ -1044,7 +1064,7 @@ class View { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } - $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry); + $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount); } } } @@ -1154,8 +1174,9 @@ class View { $files = array(); $rootLength = strlen($this->fakeRoot); - $mountPoint = Filesystem::getMountPoint($this->fakeRoot); - $storage = Filesystem::getStorage($mountPoint); + $mount = $this->getMount(''); + $mountPoint = $mount->getMountPoint(); + $storage = $mount->getStorage(); if ($storage) { $cache = $storage->getCache(''); @@ -1165,13 +1186,14 @@ class View { $internalPath = $result['path']; $path = $mountPoint . $result['path']; $result['path'] = substr($mountPoint . $result['path'], $rootLength); - $files[] = new FileInfo($path, $storage, $internalPath, $result); + $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount); } } - $mountPoints = Filesystem::getMountPoints($this->fakeRoot); - foreach ($mountPoints as $mountPoint) { - $storage = Filesystem::getStorage($mountPoint); + $mounts = Filesystem::getMountManager()->findIn($this->fakeRoot); + foreach ($mounts as $mount) { + $mountPoint = $mount->getMountPoint(); + $storage = $mount->getStorage(); if ($storage) { $cache = $storage->getCache(''); @@ -1182,7 +1204,7 @@ class View { $internalPath = $result['path']; $result['path'] = rtrim($relativeMountPoint . $result['path'], '/'); $path = rtrim($mountPoint . $internalPath, '/'); - $files[] = new FileInfo($path, $storage, $internalPath, $result); + $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount); } } } diff --git a/lib/private/image.php b/lib/private/image.php index 78cacc84452..07cfb0f72d3 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -37,7 +37,7 @@ class OC_Image { */ static public function getMimeTypeForFile($filePath) { // exif_imagetype throws "read error!" if file is less than 12 byte - if (filesize($filePath) > 11) { + if ($filePath !== null && filesize($filePath) > 11) { $imageType = exif_imagetype($filePath); } else { $imageType = false; diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php index 332bbfead00..2c0a93db321 100644 --- a/lib/private/memcache/apc.php +++ b/lib/private/memcache/apc.php @@ -32,7 +32,7 @@ class APC extends Cache { public function clear($prefix = '') { $ns = $this->getPrefix() . $prefix; $ns = preg_quote($ns, '/'); - $iter = new \APCIterator('user', '/^' . $ns . '/'); + $iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY); return apc_delete($iter); } diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index 8e47a8899fc..dba9e8a0e00 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -37,6 +37,8 @@ class Factory implements ICacheFactory { return new APCu($prefix); } elseif (APC::isAvailable()) { return new APC($prefix); + } elseif (Redis::isAvailable()) { + return new Redis($prefix); } elseif (Memcached::isAvailable()) { return new Memcached($prefix); } else { @@ -50,7 +52,7 @@ class Factory implements ICacheFactory { * @return bool */ public function isAvailable() { - return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Memcached::isAvailable(); + return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Redis::isAvailable() || Memcached::isAvailable(); } /** diff --git a/lib/private/memcache/memcached.php b/lib/private/memcache/memcached.php index cd8e2e8d0b6..042fead3347 100644 --- a/lib/private/memcache/memcached.php +++ b/lib/private/memcache/memcached.php @@ -74,7 +74,13 @@ class Memcached extends Cache { $keys[] = $key; } } - self::$cache->deleteMulti($keys); + if (method_exists(self::$cache, 'deleteMulti')) { + self::$cache->deleteMulti($keys); + } else { + foreach ($keys as $key) { + self::$cache->delete($key); + } + } return true; } diff --git a/lib/private/memcache/redis.php b/lib/private/memcache/redis.php new file mode 100644 index 00000000000..f21619887d0 --- /dev/null +++ b/lib/private/memcache/redis.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright (c) 2014 Jörn Friedrich Dreyer <jfd@butonic.de> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class Redis extends Cache { + + /** + * @var \Redis $cache + */ + private static $cache = null; + + public function __construct($prefix = '') { + parent::__construct($prefix); + if (is_null(self::$cache)) { + // TODO allow configuring a RedisArray, see https://github.com/nicolasff/phpredis/blob/master/arrays.markdown#redis-arrays + self::$cache = new \Redis(); + $config = \OC::$server->getSystemConfig()->getValue('redis', array()); + if (isset($config['host'])) { + $host = $config['host']; + } else { + $host = '127.0.0.1'; + } + if (isset($config['port'])) { + $port = $config['port']; + } else { + $port = 6379; + } + if (isset($config['timeout'])) { + $timeout = $config['timeout']; + } else { + $timeout = 0.0; // unlimited + } + self::$cache->connect( $host, $port, $timeout ); + } + } + + /** + * entries in redis get namespaced to prevent collisions between ownCloud instances and users + */ + protected function getNameSpace() { + return $this->prefix; + } + + public function get($key) { + $result = self::$cache->get($this->getNamespace() . $key); + if ($result === false and ! self::$cache->exists($this->getNamespace() . $key)) { + return null; + } else { + return $result; + } + } + + public function set($key, $value, $ttl = 0) { + if ($ttl > 0) { + return self::$cache->setex($this->getNamespace() . $key, $ttl, $value); + } else { + return self::$cache->set($this->getNamespace() . $key, $value); + } + } + + public function hasKey($key) { + return self::$cache->exists($this->getNamespace() . $key); + } + + public function remove($key) { + if (self::$cache->delete($this->getNamespace() . $key)) { + return true; + } else { + return false; + } + + } + + public function clear($prefix = '') { + $prefix = $this->getNamespace() . $prefix.'*'; + $it = null; + self::$cache->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); + while($keys = self::$cache->scan($it, $prefix)) { + self::$cache->delete($keys); + } + return true; + } + + static public function isAvailable() { + return extension_loaded('redis'); + } +} + diff --git a/lib/private/preview.php b/lib/private/preview.php index 7305bf1cc0e..a586c94fd11 100644 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -922,6 +922,11 @@ class Preview { return false; } + $mount = $file->getMountPoint(); + if ($mount and !$mount->getOption('previews', true)){ + return false; + } + //check if there are preview backends if (empty(self::$providers)) { self::initProviders(); diff --git a/lib/private/template.php b/lib/private/template.php index bda802fd2e2..78ebb506385 100644 --- a/lib/private/template.php +++ b/lib/private/template.php @@ -122,7 +122,7 @@ class OC_Template extends \OC\Template\Base { foreach(OC_Util::$headers as $header) { $headers .= '<'.OC_Util::sanitizeHTML($header['tag']); foreach($header['attributes'] as $name=>$value) { - $headers .= ' "'.OC_Util::sanitizeHTML($name).'"="'.OC_Util::sanitizeHTML($value).'"'; + $headers .= ' '.OC_Util::sanitizeHTML($name).'="'.OC_Util::sanitizeHTML($value).'"'; } if ($header['text'] !== null) { $headers .= '>'.OC_Util::sanitizeHTML($header['text']).'</'.OC_Util::sanitizeHTML($header['tag']).'>'; diff --git a/lib/private/user.php b/lib/private/user.php index 516b789d430..d66354b247d 100644 --- a/lib/private/user.php +++ b/lib/private/user.php @@ -212,9 +212,6 @@ class OC_User { * Log in a user and regenerate a new session - if the password is ok */ public static function login($loginname, $password) { - $loginname = str_replace("\0", '', $loginname); - $password = str_replace("\0", '', $password); - session_regenerate_id(true); $result = self::getUserSession()->login($loginname, $password); if ($result) { @@ -320,6 +317,15 @@ class OC_User { } /** + * Tries to login the user with HTTP Basic Authentication + */ + public static function tryBasicAuthLogin() { + if(!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_USER'])) { + \OC_User::login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); + } + } + + /** * Check if the user is logged in, considers also the HTTP basic credentials * @return bool */ @@ -328,11 +334,6 @@ class OC_User { return self::userExists(\OC::$server->getSession()->get('user_id')); } - // Check whether the user has authenticated using Basic Authentication - if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { - return \OC_User::login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); - } - return false; } diff --git a/lib/private/user/database.php b/lib/private/user/database.php index a6289066f05..de6c72e4745 100644 --- a/lib/private/user/database.php +++ b/lib/private/user/database.php @@ -36,7 +36,7 @@ /** * Class for user management in a SQL Database (e.g. MySQL, SQLite) */ -class OC_User_Database extends OC_User_Backend { +class OC_User_Database extends OC_User_Backend implements \OCP\IUserBackend { private $cache = array(); /** @@ -260,4 +260,12 @@ class OC_User_Database extends OC_User_Backend { return $result->fetchOne(); } + /** + * Backend name to be shown in user management + * @return string the name of the backend to be shown + */ + public function getBackendName(){ + return 'Database'; + } + } diff --git a/lib/private/user/dummy.php b/lib/private/user/dummy.php index fd0201734fa..322a4562ee6 100644 --- a/lib/private/user/dummy.php +++ b/lib/private/user/dummy.php @@ -24,7 +24,7 @@ /** * dummy user backend, does not keep state, only for testing use */ -class OC_User_Dummy extends OC_User_Backend { +class OC_User_Dummy extends OC_User_Backend implements \OCP\IUserBackend { private $users = array(); private $displayNames = array(); @@ -156,4 +156,12 @@ class OC_User_Dummy extends OC_User_Backend { public function getDisplayName($uid) { return isset($this->displayNames[$uid])? $this->displayNames[$uid]: $uid; } + + /** + * Backend name to be shown in user management + * @return string the name of the backend to be shown + */ + public function getBackendName(){ + return 'Dummy'; + } } diff --git a/lib/private/user/http.php b/lib/private/user/http.php index 617e8adb3f2..8375c4e1e22 100644 --- a/lib/private/user/http.php +++ b/lib/private/user/http.php @@ -24,7 +24,7 @@ /** * user backend using http auth requests */ -class OC_User_HTTP extends OC_User_Backend { +class OC_User_HTTP extends OC_User_Backend implements \OCP\IUserBackend { /** * split http://user@host/path into a user and url part * @param string $url @@ -109,4 +109,12 @@ class OC_User_HTTP extends OC_User_Backend { return false; } } + + /** + * Backend name to be shown in user management + * @return string the name of the backend to be shown + */ + public function getBackendName(){ + return 'HTTP'; + } } diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php index 1bc3b51c2ef..1fc89f8c2c2 100644 --- a/lib/private/user/manager.php +++ b/lib/private/user/manager.php @@ -151,6 +151,9 @@ class Manager extends PublicEmitter implements IUserManager { * @return mixed the User object on success, false otherwise */ public function checkPassword($loginname, $password) { + $loginname = str_replace("\0", '', $loginname); + $password = str_replace("\0", '', $password); + foreach ($this->backends as $backend) { if ($backend->implementsActions(\OC_User_Backend::CHECK_PASSWORD)) { $uid = $backend->checkPassword($loginname, $password); @@ -276,10 +279,15 @@ class Manager extends PublicEmitter implements IUserManager { if ($backend->implementsActions(\OC_User_Backend::COUNT_USERS)) { $backendusers = $backend->countUsers(); if($backendusers !== false) { - if(isset($userCountStatistics[get_class($backend)])) { - $userCountStatistics[get_class($backend)] += $backendusers; + if($backend instanceof \OCP\IUserBackend) { + $name = $backend->getBackendName(); } else { - $userCountStatistics[get_class($backend)] = $backendusers; + $name = get_class($backend); + } + if(isset($userCountStatistics[$name])) { + $userCountStatistics[$name] += $backendusers; + } else { + $userCountStatistics[$name] = $backendusers; } } } diff --git a/lib/private/user/user.php b/lib/private/user/user.php index 062081d51d4..0b4f9a24276 100644 --- a/lib/private/user/user.php +++ b/lib/private/user/user.php @@ -225,6 +225,9 @@ class User implements IUser { * @return string */ public function getBackendClassName() { + if($this->backend instanceof \OCP\IUserBackend) { + return $this->backend->getBackendName(); + } return get_class($this->backend); } diff --git a/lib/private/util.php b/lib/private/util.php index 6ccb9dba087..b97c0684629 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -333,9 +333,9 @@ class OC_Util { /** * generates a path for JS/CSS files. If no application is provided it will create the path for core. * - * @param $application application to get the files from - * @param $directory directory withing this application (css, js, vendor, etc) - * @param $file the file inside of the above folder + * @param string $application application to get the files from + * @param string $directory directory withing this application (css, js, vendor, etc) + * @param string $file the file inside of the above folder * @return string the path */ private static function generatePath($application, $directory, $file) { @@ -358,7 +358,10 @@ class OC_Util { * @return void */ public static function addScript($application, $file = null) { - self::$scripts[] = OC_Util::generatePath($application, 'js', $file); + $path = OC_Util::generatePath($application, 'js', $file); + if (!in_array($path, self::$scripts)) { + self::$scripts[] = $path; + } } /** @@ -369,7 +372,10 @@ class OC_Util { * @return void */ public static function addVendorScript($application, $file = null) { - self::$scripts[] = OC_Util::generatePath($application, 'vendor', $file); + $path = OC_Util::generatePath($application, 'vendor', $file); + if (!in_array($path, self::$scripts)) { + self::$scripts[] = $path; + } } /** @@ -384,9 +390,12 @@ class OC_Util { $languageCode = $l->getLanguageCode($application); } if (!empty($application)) { - self::$scripts[] = "$application/l10n/$languageCode"; + $path = "$application/l10n/$languageCode"; } else { - self::$scripts[] = "l10n/$languageCode"; + $path = "l10n/$languageCode"; + } + if (!in_array($path, self::$scripts)) { + self::$scripts[] = $path; } } @@ -398,7 +407,10 @@ class OC_Util { * @return void */ public static function addStyle($application, $file = null) { - self::$styles[] = OC_Util::generatePath($application, 'css', $file); + $path = OC_Util::generatePath($application, 'css', $file); + if (!in_array($path, self::$styles)) { + self::$styles[] = $path; + } } /** @@ -409,7 +421,10 @@ class OC_Util { * @return void */ public static function addVendorStyle($application, $file = null) { - self::$styles[] = OC_Util::generatePath($application, 'vendor', $file); + $path = OC_Util::generatePath($application, 'vendor', $file); + if (!in_array($path, self::$styles)) { + self::$styles[] = $path; + } } /** @@ -1344,4 +1359,5 @@ class OC_Util { public static function isPhpCharSetUtf8() { return ini_get('default_charset') === 'UTF-8'; } + } |