diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php index ef22fe9218..1922bc4fcd 100644 --- a/apps/files/appinfo/remote.php +++ b/apps/files/appinfo/remote.php @@ -34,12 +34,8 @@ $authBackend = new OC_Connector_Sabre_Auth(); $lockBackend = new OC_Connector_Sabre_Locks(); $requestBackend = new OC_Connector_Sabre_Request(); -// Create ownCloud Dir -$rootDir = new OC_Connector_Sabre_Directory(''); -$objectTree = new \OC\Connector\Sabre\ObjectTree($rootDir); - // Fire up server -$server = new OC_Connector_Sabre_Server($objectTree); +$server = new OC_Connector_Sabre_Server(); $server->httpRequest = $requestBackend; $server->setBaseUri($baseuri); @@ -49,10 +45,22 @@ $server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, $defaults->getName()) $server->addPlugin(new Sabre_DAV_Locks_Plugin($lockBackend)); $server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload $server->addPlugin(new OC_Connector_Sabre_FilesPlugin()); -$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin()); -$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin()); $server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin()); $server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav')); +// wait with registering these until auth is handled and the filesystem is setup +$server->subscribeEvent('beforeMethod', function () use ($server) { + $view = \OC\Files\Filesystem::getView(); + $rootInfo = $view->getFileInfo(''); + + // Create ownCloud Dir + $rootDir = new OC_Connector_Sabre_Directory($view, $rootInfo); + $objectTree = new \OC\Connector\Sabre\ObjectTree($rootDir, $view); + $server->setObjectTree($objectTree); + + $server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin($view)); + $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view)); +}, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request + // And off we go! $server->exec(); diff --git a/lib/private/connector/sabre/aborteduploaddetectionplugin.php b/lib/private/connector/sabre/aborteduploaddetectionplugin.php index ad759d1d84..1a092a59a8 100644 --- a/lib/private/connector/sabre/aborteduploaddetectionplugin.php +++ b/lib/private/connector/sabre/aborteduploaddetectionplugin.php @@ -22,11 +22,16 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl private $server; /** - * is kept public to allow overwrite for unit testing - * * @var \OC\Files\View */ - public $fileView; + private $fileView; + + /** + * @param \OC\Files\View $view + */ + public function __construct($view) { + $this->fileView = $view; + } /** * This initializes the plugin. @@ -55,7 +60,7 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl // we should only react on PUT which is used for upload // e.g. with LOCK this will not work, but LOCK uses createFile() as well - if ($this->server->httpRequest->getMethod() !== 'PUT' ) { + if ($this->server->httpRequest->getMethod() !== 'PUT') { return; } @@ -70,9 +75,9 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl if (!$expected) { return; } - $actual = $this->getFileView()->filesize($filePath); + $actual = $this->fileView->filesize($filePath); if ($actual != $expected) { - $this->getFileView()->unlink($filePath); + $this->fileView->unlink($filePath); throw new Sabre_DAV_Exception_BadRequest('expected filesize ' . $expected . ' got ' . $actual); } @@ -81,8 +86,7 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl /** * @return string */ - public function getLength() - { + public function getLength() { $req = $this->server->httpRequest; $length = $req->getHeader('X-Expected-Entity-Length'); if (!$length) { @@ -91,17 +95,4 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl return $length; } - - /** - * @return \OC\Files\View - */ - public function getFileView() - { - if (is_null($this->fileView)) { - // initialize fileView - $this->fileView = \OC\Files\Filesystem::getView(); - } - - return $this->fileView; - } } diff --git a/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php index 02d1a9f4ba..619aec21ea 100644 --- a/lib/private/connector/sabre/directory.php +++ b/lib/private/connector/sabre/directory.php @@ -60,20 +60,22 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa // exit if we can't create a new file and we don't updatable existing file $info = OC_FileChunking::decodeName($name); - if (!\OC\Files\Filesystem::isCreatable($this->path) && - !\OC\Files\Filesystem::isUpdatable($this->path . '/' . $info['name'])) { + if (!$this->fileView->isCreatable($this->path) && + !$this->fileView->isUpdatable($this->path . '/' . $info['name'])) { throw new \Sabre_DAV_Exception_Forbidden(); } } else { // For non-chunked upload it is enough to check if we can create a new file - if (!\OC\Files\Filesystem::isCreatable($this->path)) { + if (!$this->fileView->isCreatable($this->path)) { throw new \Sabre_DAV_Exception_Forbidden(); } } $path = $this->path . '/' . $name; - $node = new OC_Connector_Sabre_File($path); + // 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()); + $node = new OC_Connector_Sabre_File($this->fileView, $info); return $node->put($data); } @@ -90,12 +92,12 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa throw new \Sabre_DAV_Exception_Forbidden(); } - if (!\OC\Files\Filesystem::isCreatable($this->path)) { + if (!$this->fileView->isCreatable($this->path)) { throw new \Sabre_DAV_Exception_Forbidden(); } $newPath = $this->path . '/' . $name; - if(!\OC\Files\Filesystem::mkdir($newPath)) { + if(!$this->fileView->mkdir($newPath)) { throw new Sabre_DAV_Exception_Forbidden('Could not create directory '.$newPath); } @@ -105,6 +107,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa * Returns a specific child node, referenced by its name * * @param string $name + * @param \OCP\Files\FileInfo $info * @throws Sabre_DAV_Exception_FileNotFound * @return Sabre_DAV_INode */ @@ -112,7 +115,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa $path = $this->path . '/' . $name; if (is_null($info)) { - $info = \OC\Files\Filesystem::getFileInfo($path); + $info = $this->fileView->getFileInfo($path); } if (!$info) { @@ -120,12 +123,10 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa } if ($info['mimetype'] == 'httpd/unix-directory') { - $node = new OC_Connector_Sabre_Directory($path); + $node = new OC_Connector_Sabre_Directory($this->fileView, $info); } else { - $node = new OC_Connector_Sabre_File($path); + $node = new OC_Connector_Sabre_File($this->fileView, $info); } - - $node->setFileinfoCache($info); return $node; } @@ -136,7 +137,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa */ public function getChildren() { - $folder_content = \OC\Files\Filesystem::getDirectoryContent($this->path); + $folder_content = $this->fileView->getDirectoryContent($this->path); $paths = array(); foreach($folder_content as $info) { $paths[] = $this->path.'/'.$info['name']; @@ -167,7 +168,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa $nodes = array(); foreach($folder_content as $info) { - $node = $this->getChild($info['name'], $info); + $node = $this->getChild($info->getName(), $info); $node->setPropertyCache($properties[$this->path.'/'.$info['name']]); $nodes[] = $node; } @@ -183,7 +184,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa public function childExists($name) { $path = $this->path . '/' . $name; - return \OC\Files\Filesystem::file_exists($path); + return $this->fileView->file_exists($path); } @@ -199,11 +200,11 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa throw new \Sabre_DAV_Exception_Forbidden(); } - if (!\OC\Files\Filesystem::isDeletable($this->path)) { + if (!$this->info->isDeletable()) { throw new \Sabre_DAV_Exception_Forbidden(); } - \OC\Files\Filesystem::rmdir($this->path); + $this->fileView->rmdir($this->path); } @@ -235,7 +236,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa public function getProperties($properties) { $props = parent::getProperties($properties); if (in_array(self::GETETAG_PROPERTYNAME, $properties) && !isset($props[self::GETETAG_PROPERTYNAME])) { - $props[self::GETETAG_PROPERTYNAME] = $this->getETagPropertyForPath($this->path); + $props[self::GETETAG_PROPERTYNAME] = $this->info->getEtag(); } return $props; } diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index ef6caaf22a..cbecd90b7d 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -45,11 +45,8 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return string|null */ public function put($data) { - - $fs = $this->getFS(); - - if ($fs->file_exists($this->path) && - !$fs->isUpdatable($this->path)) { + if ($this->info && $this->fileView->file_exists($this->path) && + !$this->info->isUpdateable()) { throw new \Sabre_DAV_Exception_Forbidden(); } @@ -79,10 +76,10 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D } try { - $putOkay = $fs->file_put_contents($partpath, $data); + $putOkay = $this->fileView->file_put_contents($partpath, $data); if ($putOkay === false) { \OC_Log::write('webdav', '\OC\Files\Filesystem::file_put_contents() failed', \OC_Log::ERROR); - $fs->unlink($partpath); + $this->fileView->unlink($partpath); // because we have no clue about the cause we can only throw back a 500/Internal Server Error throw new Sabre_DAV_Exception('Could not write file contents'); } @@ -105,29 +102,30 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D } // rename to correct path - $renameOkay = $fs->rename($partpath, $this->path); - $fileExists = $fs->file_exists($this->path); + $renameOkay = $this->fileView->rename($partpath, $this->path); + $fileExists = $this->fileView->file_exists($this->path); if ($renameOkay === false || $fileExists === false) { \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); - $fs->unlink($partpath); + $this->fileView->unlink($partpath); throw new Sabre_DAV_Exception('Could not rename part file to final file'); } // allow sync clients to send the mtime along in a header $mtime = OC_Request::hasModificationTime(); if ($mtime !== false) { - if($fs->touch($this->path, $mtime)) { + if($this->fileView->touch($this->path, $mtime)) { header('X-OC-MTime: accepted'); } } + $this->refreshInfo(); - return $this->getETagPropertyForPath($this->path); + return '"' . $this->info->getEtag() . '"'; } /** * Returns the data * - * @return string + * @return string | resource */ public function get() { @@ -135,7 +133,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D if (\OC_Util::encryptedFiles()) { throw new \Sabre_DAV_Exception_ServiceUnavailable(); } else { - return \OC\Files\Filesystem::fopen($this->path, 'rb'); + return $this->fileView->fopen($this->path, 'rb'); } } @@ -147,16 +145,14 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @throws Sabre_DAV_Exception_Forbidden */ public function delete() { - $fs = $this->getFS(); - if ($this->path === 'Shared') { throw new \Sabre_DAV_Exception_Forbidden(); } - if (!$fs->isDeletable($this->path)) { + if (!$this->info->isDeletable()) { throw new \Sabre_DAV_Exception_Forbidden(); } - $fs->unlink($this->path); + $this->fileView->unlink($this->path); // remove properties $this->removeProperties(); @@ -169,12 +165,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return int */ public function getSize() { - $this->getFileinfoCache(); - if ($this->fileinfo_cache['size'] > -1) { - return $this->fileinfo_cache['size']; - } else { - return null; - } + return $this->info->getSize(); } /** @@ -189,11 +180,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return mixed */ public function getETag() { - $properties = $this->getProperties(array(self::GETETAG_PROPERTYNAME)); - if (isset($properties[self::GETETAG_PROPERTYNAME])) { - return $properties[self::GETETAG_PROPERTYNAME]; - } - return null; + return $this->info->getEtag(); } /** @@ -204,12 +191,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return mixed */ public function getContentType() { - if (isset($this->fileinfo_cache['mimetype'])) { - return $this->fileinfo_cache['mimetype']; - } - - return \OC\Files\Filesystem::getMimeType($this->path); - + return $this->info->getMimetype(); } /** @@ -245,15 +227,14 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D $chunk_handler->file_assemble($partFile); // here is the final atomic rename - $fs = $this->getFS(); $targetPath = $path . '/' . $info['name']; - $renameOkay = $fs->rename($partFile, $targetPath); - $fileExists = $fs->file_exists($targetPath); + $renameOkay = $this->fileView->rename($partFile, $targetPath); + $fileExists = $this->fileView->file_exists($targetPath); if ($renameOkay === false || $fileExists === false) { \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); // only delete if an error occurred and the target file was already created if ($fileExists) { - $fs->unlink($targetPath); + $this->fileView->unlink($targetPath); } throw new Sabre_DAV_Exception('Could not rename part file assembled from chunks'); } @@ -261,12 +242,13 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D // allow sync clients to send the mtime along in a header $mtime = OC_Request::hasModificationTime(); if ($mtime !== false) { - if($fs->touch($targetPath, $mtime)) { + if($this->fileView->touch($targetPath, $mtime)) { header('X-OC-MTime: accepted'); } } - return OC_Connector_Sabre_Node::getETagPropertyForPath($targetPath); + $info = $this->fileView->getFileInfo($targetPath); + return $info->getEtag(); } return null; diff --git a/lib/private/connector/sabre/node.php b/lib/private/connector/sabre/node.php index 5807c5c7f7..3a5c721dda 100644 --- a/lib/private/connector/sabre/node.php +++ b/lib/private/connector/sabre/node.php @@ -20,7 +20,6 @@ * License along with this library. If not, see . * */ - abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IProperties { const GETETAG_PROPERTYNAME = '{DAV:}getetag'; const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; @@ -29,15 +28,13 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * Allow configuring the method used to generate Etags * * @var array(class_name, function_name) - */ + */ public static $ETagFunction = null; /** - * is kept public to allow overwrite for unit testing - * * @var \OC\Files\View */ - public $fileView; + protected $fileView; /** * The path to the current node @@ -46,53 +43,53 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr */ protected $path; - /** - * node fileinfo cache - * @var array - */ - protected $fileinfo_cache; /** * node properties cache + * * @var array */ protected $property_cache = null; /** - * @brief Sets up the node, expects a full path name - * @param string $path - * @return void + * @var \OCP\Files\FileInfo */ - public function __construct($path) { - $this->path = $path; + protected $info; + + /** + * @brief Sets up the node, expects a full path name + * @param \OC\Files\View $view + * @param \OCP\Files\FileInfo $info + */ + public function __construct($view, $info) { + $this->fileView = $view; + $this->path = $this->fileView->getRelativePath($info->getPath()); + $this->info = $info; } - + protected function refreshInfo() { + $this->info = $this->fileView->getFileInfo($this->path); + } /** * @brief Returns the name of the node * @return string */ public function getName() { - - list(, $name) = Sabre_DAV_URLUtil::splitPath($this->path); - return $name; - + return $this->info->getName(); } /** * @brief Renames the node * @param string $name The new name - * @return void */ public function setName($name) { - $fs = $this->getFS(); // rename is only allowed if the update privilege is granted - if (!$fs->isUpdatable($this->path)) { + if (!$this->info->isUpdateable()) { throw new \Sabre_DAV_Exception_Forbidden(); } - list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path); + list($parentPath,) = Sabre_DAV_URLUtil::splitPath($this->path); list(, $newName) = Sabre_DAV_URLUtil::splitPath($name); if (!\OCP\Util::isValidFileName($newName)) { @@ -102,38 +99,17 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr $newPath = $parentPath . '/' . $newName; $oldPath = $this->path; - $fs->rename($this->path, $newPath); + $this->fileView->rename($this->path, $newPath); $this->path = $newPath; - $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' - .' WHERE `userid` = ? AND `propertypath` = ?' ); - $query->execute( array( $newPath, OC_User::getUser(), $oldPath )); - + $query = OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?' + . ' WHERE `userid` = ? AND `propertypath` = ?'); + $query->execute(array($newPath, OC_User::getUser(), $oldPath)); + $this->refreshInfo(); } - public function setFileinfoCache($fileinfo_cache) - { - $this->fileinfo_cache = $fileinfo_cache; - } - - /** - * @brief Ensure that the fileinfo cache is filled - * @note Uses OC_FileCache or a direct stat - */ - protected function getFileinfoCache() { - if (!isset($this->fileinfo_cache)) { - if ($fileinfo_cache = \OC\Files\Filesystem::getFileInfo($this->path)) { - } else { - $fileinfo_cache = \OC\Files\Filesystem::stat($this->path); - } - - $this->fileinfo_cache = $fileinfo_cache; - } - } - - public function setPropertyCache($property_cache) - { + public function setPropertyCache($property_cache) { $this->property_cache = $property_cache; } @@ -142,8 +118,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * @return int */ public function getLastModified() { - $this->getFileinfoCache(); - return $this->fileinfo_cache['mtime']; + return $this->info->getMtime(); } @@ -153,7 +128,8 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * Even if the modification time is set to a custom value the access time is set to now. */ public function touch($mtime) { - \OC\Files\Filesystem::touch($this->path, $mtime); + $this->fileView->touch($this->path, $mtime); + $this->refreshInfo(); } /** @@ -163,29 +139,28 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr */ public function updateProperties($properties) { $existing = $this->getProperties(array()); - foreach($properties as $propertyName => $propertyValue) { + foreach ($properties as $propertyName => $propertyValue) { // If it was null, we need to delete the property if (is_null($propertyValue)) { - if(array_key_exists( $propertyName, $existing )) { - $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*properties`' - .' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' ); - $query->execute( array( OC_User::getUser(), $this->path, $propertyName )); + if (array_key_exists($propertyName, $existing)) { + $query = OC_DB::prepare('DELETE FROM `*PREFIX*properties`' + . ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'); + $query->execute(array(OC_User::getUser(), $this->path, $propertyName)); } - } - else { - if( strcmp( $propertyName, self::GETETAG_PROPERTYNAME) === 0 ) { - \OC\Files\Filesystem::putFileInfo($this->path, array('etag'=> $propertyValue)); - } elseif( strcmp( $propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0 ) { + } else { + if (strcmp($propertyName, self::GETETAG_PROPERTYNAME) === 0) { + \OC\Files\Filesystem::putFileInfo($this->path, array('etag' => $propertyValue)); + } elseif (strcmp($propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0) { $this->touch($propertyValue); } else { - if(!array_key_exists( $propertyName, $existing )) { - $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*properties`' - .' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)' ); - $query->execute( array( OC_User::getUser(), $this->path, $propertyName,$propertyValue )); + if (!array_key_exists($propertyName, $existing)) { + $query = OC_DB::prepare('INSERT INTO `*PREFIX*properties`' + . ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)'); + $query->execute(array(OC_User::getUser(), $this->path, $propertyName, $propertyValue)); } else { - $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' - .' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' ); - $query->execute( array( $propertyValue,OC_User::getUser(), $this->path, $propertyName )); + $query = OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' + . ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'); + $query->execute(array($propertyValue, OC_User::getUser(), $this->path, $propertyName)); } } } @@ -199,9 +174,9 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * removes all properties for this node and user */ public function removeProperties() { - $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*properties`' - .' WHERE `userid` = ? AND `propertypath` = ?' ); - $query->execute( array( OC_User::getUser(), $this->path)); + $query = OC_DB::prepare('DELETE FROM `*PREFIX*properties`' + . ' WHERE `userid` = ? AND `propertypath` = ?'); + $query->execute(array(OC_User::getUser(), $this->path)); $this->setPropertyCache(null); } @@ -219,29 +194,23 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr if (is_null($this->property_cache)) { $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?'; - $result = OC_DB::executeAudited( $sql, array( OC_User::getUser(), $this->path ) ); + $result = OC_DB::executeAudited($sql, array(OC_User::getUser(), $this->path)); $this->property_cache = array(); - while( $row = $result->fetchRow()) { + while ($row = $result->fetchRow()) { $this->property_cache[$row['propertyname']] = $row['propertyvalue']; } - // Don't call the static getETagPropertyForPath, its result is not cached - $this->getFileinfoCache(); - if ($this->fileinfo_cache['etag']) { - $this->property_cache[self::GETETAG_PROPERTYNAME] = '"'.$this->fileinfo_cache['etag'].'"'; - } else { - $this->property_cache[self::GETETAG_PROPERTYNAME] = null; - } + $this->property_cache[self::GETETAG_PROPERTYNAME] = '"' . $this->info->getEtag() . '"'; } // if the array was empty, we need to return everything - if(count($properties) == 0) { + if (count($properties) == 0) { return $this->property_cache; } $props = array(); - foreach($properties as $property) { + foreach ($properties as $property) { if (isset($this->property_cache[$property])) { $props[$property] = $this->property_cache[$property]; } @@ -250,36 +219,13 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr return $props; } - /** - * Returns the ETag surrounded by double-quotes for this path. - * @param string $path Path of the file - * @return string|null Returns null if the ETag can not effectively be determined - */ - protected function getETagPropertyForPath($path) { - $data = $this->getFS()->getFileInfo($path); - if (isset($data['etag'])) { - return '"'.$data['etag'].'"'; - } - return null; - } - - protected function getFS() { - if (is_null($this->fileView)) { - $this->fileView = \OC\Files\Filesystem::getView(); - } - return $this->fileView; - } - /** * @return string|null */ - public function getFileId() - { - $this->getFileinfoCache(); - - if (isset($this->fileinfo_cache['fileid'])) { + public function getFileId() { + if ($this->info->getId()) { $instanceId = OC_Util::getInstanceId(); - $id = sprintf('%08d', $this->fileinfo_cache['fileid']); + $id = sprintf('%08d', $this->info->getId()); return $id . $instanceId; } diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index d2fa425b22..d176d3333f 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -8,16 +8,28 @@ namespace OC\Connector\Sabre; +use OC\Files\FileInfo; use OC\Files\Filesystem; class ObjectTree extends \Sabre_DAV_ObjectTree { /** - * keep this public to allow mock injection during unit test - * * @var \OC\Files\View */ - public $fileView; + protected $fileView; + + /** + * Creates the object + * + * This method expects the rootObject to be passed as a parameter + * + * @param \Sabre_DAV_ICollection $rootNode + * @param \OC\Files\View $view + */ + public function __construct(\Sabre_DAV_ICollection $rootNode, $view) { + parent::__construct($rootNode); + $this->fileView = $view; + } /** * Returns the INode object for the requested path @@ -40,31 +52,34 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { if (pathinfo($path, PATHINFO_EXTENSION) === 'part') { // read from storage - $absPath = $this->getFileView()->getAbsolutePath($path); + $absPath = $this->fileView->getAbsolutePath($path); list($storage, $internalPath) = Filesystem::resolvePath('/' . $absPath); if ($storage) { + /** + * @var \OC\Files\Storage\Storage $storage + */ $scanner = $storage->getScanner($internalPath); // get data directly - $info = $scanner->getData($internalPath); + $data = $scanner->getData($internalPath); + $info = new FileInfo($absPath, $storage, $internalPath, $data); + } else { + $info = null; } - } - else { + } else { // read from cache - $info = $this->getFileView()->getFileInfo($path); + $info = $this->fileView->getFileInfo($path); } if (!$info) { throw new \Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); } - if ($info['mimetype'] === 'httpd/unix-directory') { - $node = new \OC_Connector_Sabre_Directory($path); + if ($info->getType() === 'dir') { + $node = new \OC_Connector_Sabre_Directory($this->fileView, $info); } else { - $node = new \OC_Connector_Sabre_File($path); + $node = new \OC_Connector_Sabre_File($this->fileView, $info); } - $node->setFileinfoCache($info); - $this->cache[$path] = $node; return $node; @@ -88,19 +103,18 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destinationPath); // check update privileges - $fs = $this->getFileView(); - if (!$fs->isUpdatable($sourcePath)) { + if (!$this->fileView->isUpdatable($sourcePath)) { throw new \Sabre_DAV_Exception_Forbidden(); } if ($sourceDir !== $destinationDir) { // for a full move we need update privileges on sourcePath and sourceDir as well as destinationDir - if (!$fs->isUpdatable($sourceDir)) { + if (!$this->fileView->isUpdatable($sourceDir)) { throw new \Sabre_DAV_Exception_Forbidden(); } - if (!$fs->isUpdatable($destinationDir)) { + if (!$this->fileView->isUpdatable($destinationDir)) { throw new \Sabre_DAV_Exception_Forbidden(); } - if (!$fs->isDeletable($sourcePath)) { + if (!$this->fileView->isDeletable($sourcePath)) { throw new \Sabre_DAV_Exception_Forbidden(); } } @@ -110,15 +124,15 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { throw new \Sabre_DAV_Exception_BadRequest(); } - $renameOkay = $fs->rename($sourcePath, $destinationPath); + $renameOkay = $this->fileView->rename($sourcePath, $destinationPath); if (!$renameOkay) { throw new \Sabre_DAV_Exception_Forbidden(''); } // update properties - $query = \OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' - .' WHERE `userid` = ? AND `propertypath` = ?' ); - $query->execute( array( $destinationPath, \OC_User::getUser(), $sourcePath )); + $query = \OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?' + . ' WHERE `userid` = ? AND `propertypath` = ?'); + $query->execute(array($destinationPath, \OC_User::getUser(), $sourcePath)); $this->markDirty($sourceDir); $this->markDirty($destinationDir); @@ -137,12 +151,12 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { */ public function copy($source, $destination) { - if (Filesystem::is_file($source)) { - Filesystem::copy($source, $destination); + if ($this->fileView->is_file($source)) { + $this->fileView->copy($source, $destination); } else { - Filesystem::mkdir($destination); - $dh = Filesystem::opendir($source); - if(is_resource($dh)) { + $this->fileView->mkdir($destination); + $dh = $this->fileView->opendir($source); + if (is_resource($dh)) { while (($subnode = readdir($dh)) !== false) { if ($subnode == '.' || $subnode == '..') continue; @@ -155,14 +169,4 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destination); $this->markDirty($destinationDir); } - - /** - * @return \OC\Files\View - */ - public function getFileView() { - if (is_null($this->fileView)) { - $this->fileView = \OC\Files\Filesystem::getView(); - } - return $this->fileView; - } } diff --git a/lib/private/connector/sabre/quotaplugin.php b/lib/private/connector/sabre/quotaplugin.php index 8099794f67..13fb187eed 100644 --- a/lib/private/connector/sabre/quotaplugin.php +++ b/lib/private/connector/sabre/quotaplugin.php @@ -9,6 +9,11 @@ */ class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin { + /** + * @var \OC\Files\View + */ + private $view; + /** * Reference to main server object * @@ -17,11 +22,11 @@ class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin { private $server; /** - * is kept public to allow overwrite for unit testing - * - * @var \OC\Files\View + * @param \OC\Files\View $view */ - public $fileView; + public function __construct($view) { + $this->view = $view; + } /** * This initializes the plugin. @@ -52,8 +57,8 @@ class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin { public function checkQuota($uri, $data = null) { $length = $this->getLength(); if ($length) { - if (substr($uri, 0, 1)!=='/') { - $uri='/'.$uri; + if (substr($uri, 0, 1) !== '/') { + $uri = '/' . $uri; } list($parentUri, $newName) = Sabre_DAV_URLUtil::splitPath($uri); $freeSpace = $this->getFreeSpace($parentUri); @@ -64,8 +69,7 @@ class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin { return true; } - public function getLength() - { + public function getLength() { $req = $this->server->httpRequest; $length = $req->getHeader('X-Expected-Entity-Length'); if (!$length) { @@ -84,14 +88,8 @@ class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin { * @param $parentUri * @return mixed */ - public function getFreeSpace($parentUri) - { - if (is_null($this->fileView)) { - // initialize fileView - $this->fileView = \OC\Files\Filesystem::getView(); - } - - $freeSpace = $this->fileView->free_space($parentUri); + public function getFreeSpace($parentUri) { + $freeSpace = $this->view->free_space($parentUri); return $freeSpace; } } diff --git a/lib/private/connector/sabre/server.php b/lib/private/connector/sabre/server.php index 2660b043f4..bb7a7171d1 100644 --- a/lib/private/connector/sabre/server.php +++ b/lib/private/connector/sabre/server.php @@ -27,6 +27,22 @@ * @see Sabre_DAV_Server */ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { + /** + * Sets up the server + * + * Unlike Sabre_DAV_Server's constructor this does not take an INode or ObjectTree as argument, + * the object tree needs to be set later with setObjectTree + */ + public function __construct() { + $this->httpResponse = new Sabre_HTTP_Response(); + $this->httpRequest = new Sabre_HTTP_Request(); + + } + + public function setObjectTree($tree) { + $this->tree = $tree; + } + /** * @see Sabre_DAV_Server @@ -40,22 +56,22 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { // The only two options for the depth of a propfind is 0 or 1 // if ($depth!=0) $depth = 1; - $newProperties = $this->getPropertiesForPath($uri,$requestedProperties,$depth); + $newProperties = $this->getPropertiesForPath($uri, $requestedProperties, $depth); // This is a multi-status response $this->httpResponse->sendStatus(207); - $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); - $this->httpResponse->setHeader('Vary','Brief,Prefer'); + $this->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8'); + $this->httpResponse->setHeader('Vary', 'Brief,Prefer'); // Normally this header is only needed for OPTIONS responses, however.. // iCal seems to also depend on these being set for PROPFIND. Since // this is not harmful, we'll add it. - $features = array('1','3', 'extended-mkcol'); - foreach($this->plugins as $plugin) { - $features = array_merge($features,$plugin->getFeatures()); + $features = array('1', '3', 'extended-mkcol'); + foreach ($this->plugins as $plugin) { + $features = array_merge($features, $plugin->getFeatures()); } - $this->httpResponse->setHeader('DAV',implode(', ',$features)); + $this->httpResponse->setHeader('DAV', implode(', ', $features)); $prefer = $this->getHTTPPrefer(); $minimal = $prefer['return-minimal']; @@ -67,10 +83,11 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { /** * Small helper to support PROPFIND with DEPTH_INFINITY. + * * @param string $path */ private function addPathNodesRecursively(&$nodes, $path) { - foreach($this->tree->getChildren($path) as $childNode) { + foreach ($this->tree->getChildren($path) as $childNode) { $nodes[$path . '/' . $childNode->getName()] = $childNode; if ($childNode instanceof Sabre_DAV_ICollection) $this->addPathNodesRecursively($nodes, $path . '/' . $childNode->getName()); @@ -81,7 +98,7 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { // if ($depth!=0) $depth = 1; - $path = rtrim($path,'/'); + $path = rtrim($path, '/'); $returnPropertyList = array(); @@ -89,9 +106,10 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { $nodes = array( $path => $parentNode ); - if ($depth==1 && $parentNode instanceof Sabre_DAV_ICollection) { - foreach($this->tree->getChildren($path) as $childNode) + if ($depth == 1 && $parentNode instanceof Sabre_DAV_ICollection) { + foreach ($this->tree->getChildren($path) as $childNode) { $nodes[$path . '/' . $childNode->getName()] = $childNode; + } } else if ($depth == self::DEPTH_INFINITY && $parentNode instanceof Sabre_DAV_ICollection) { $this->addPathNodesRecursively($nodes, $path); } @@ -99,9 +117,9 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { // If the propertyNames array is empty, it means all properties are requested. // We shouldn't actually return everything we know though, and only return a // sensible list. - $allProperties = count($propertyNames)==0; + $allProperties = count($propertyNames) == 0; - foreach($nodes as $myPath=>$node) { + foreach ($nodes as $myPath => $node) { $currentPropertyNames = $propertyNames; @@ -128,15 +146,15 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { // to make certain decisions about the entry. // WebDAV dictates we should add a / and the end of href's for collections $removeRT = false; - if (!in_array('{DAV:}resourcetype',$currentPropertyNames)) { + if (!in_array('{DAV:}resourcetype', $currentPropertyNames)) { $currentPropertyNames[] = '{DAV:}resourcetype'; $removeRT = true; } - $result = $this->broadcastEvent('beforeGetProperties',array($myPath, $node, &$currentPropertyNames, &$newProperties)); + $result = $this->broadcastEvent('beforeGetProperties', array($myPath, $node, &$currentPropertyNames, &$newProperties)); // If this method explicitly returned false, we must ignore this // node as it is inaccessible. - if ($result===false) continue; + if ($result === false) continue; if (count($currentPropertyNames) > 0) { @@ -149,7 +167,7 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { // So as we loop through this list, we will only take the // properties that were actually requested and discard the // rest. - foreach($currentPropertyNames as $k=>$currentPropertyName) { + foreach ($currentPropertyNames as $k => $currentPropertyName) { if (isset($nodeProperties[$currentPropertyName])) { unset($currentPropertyNames[$k]); $newProperties[200][$currentPropertyName] = $nodeProperties[$currentPropertyName]; @@ -160,12 +178,14 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { } - foreach($currentPropertyNames as $prop) { + foreach ($currentPropertyNames as $prop) { if (isset($newProperties[200][$prop])) continue; - switch($prop) { - case '{DAV:}getlastmodified' : if ($node->getLastModified()) $newProperties[200][$prop] = new Sabre_DAV_Property_GetLastModified($node->getLastModified()); break; + switch ($prop) { + case '{DAV:}getlastmodified' : + if ($node->getLastModified()) $newProperties[200][$prop] = new Sabre_DAV_Property_GetLastModified($node->getLastModified()); + break; case '{DAV:}getcontentlength' : if ($node instanceof Sabre_DAV_IFile) { $size = $node->getSize(); @@ -186,18 +206,22 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { $newProperties[200][$prop] = $quotaInfo[1]; } break; - case '{DAV:}getetag' : if ($node instanceof Sabre_DAV_IFile && $etag = $node->getETag()) $newProperties[200][$prop] = $etag; break; - case '{DAV:}getcontenttype' : if ($node instanceof Sabre_DAV_IFile && $ct = $node->getContentType()) $newProperties[200][$prop] = $ct; break; + case '{DAV:}getetag' : + if ($node instanceof Sabre_DAV_IFile && $etag = $node->getETag()) $newProperties[200][$prop] = $etag; + break; + case '{DAV:}getcontenttype' : + if ($node instanceof Sabre_DAV_IFile && $ct = $node->getContentType()) $newProperties[200][$prop] = $ct; + break; case '{DAV:}supported-report-set' : $reports = array(); - foreach($this->plugins as $plugin) { + foreach ($this->plugins as $plugin) { $reports = array_merge($reports, $plugin->getSupportedReportSet($myPath)); } $newProperties[200][$prop] = new Sabre_DAV_Property_SupportedReportSet($reports); break; case '{DAV:}resourcetype' : $newProperties[200]['{DAV:}resourcetype'] = new Sabre_DAV_Property_ResourceType(); - foreach($this->resourceTypeMapping as $className => $resourceType) { + foreach ($this->resourceTypeMapping as $className => $resourceType) { if ($node instanceof $className) $newProperties[200]['{DAV:}resourcetype']->add($resourceType); } break; @@ -209,16 +233,16 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { } - $this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties, $node)); + $this->broadcastEvent('afterGetProperties', array(trim($myPath, '/'), &$newProperties, $node)); - $newProperties['href'] = trim($myPath,'/'); + $newProperties['href'] = trim($myPath, '/'); // Its is a WebDAV recommendation to add a trailing slash to collectionnames. // Apple's iCal also requires a trailing slash for principals (rfc 3744), though this is non-standard. - if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype'])) { + if ($myPath != '' && isset($newProperties[200]['{DAV:}resourcetype'])) { $rt = $newProperties[200]['{DAV:}resourcetype']; if ($rt->is('{DAV:}collection') || $rt->is('{DAV:}principal')) { - $newProperties['href'] .='/'; + $newProperties['href'] .= '/'; } }