Page MenuHomePhorge

No OneTemporary

diff --git a/lib/Kolab/DAV/Collection.php b/lib/Kolab/DAV/Collection.php
index b148ece..bec17a3 100644
--- a/lib/Kolab/DAV/Collection.php
+++ b/lib/Kolab/DAV/Collection.php
@@ -1,227 +1,229 @@
<?php
/**
* SabreDAV File Backend implementation for Kolab.
*
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Kolab\DAV;
use \Exception;
/**
* Collection class
*/
-class Collection extends \Kolab\DAV\Node implements \Sabre\DAV\ICollection
+class Collection extends Node implements \Sabre\DAV\ICollection
{
const ROOT_DIRECTORY = 'files';
public $children;
function getChildren()
{
// @TODO: maybe children array is too big to keep it in memory?
if (is_array($this->children)) {
return $this->children;
}
$path_len = strlen($this->path);
$this->children = array();
try {
// @TODO: This should be cached too (out of this class)
$folders = $this->backend->folder_list();
$folders = $folders['list'];
}
catch (Exception $e) {
+ $this->throw_exception($e);
}
-
// get subfolders
foreach ($folders as $folder) {
// need root-folders or subfolders of specified folder
if (!$path_len || strpos($folder, $this->path . '/') === 0) {
$virtual = false;
// remove path suffix, the list might contain folders (roots) that
// do not exist e.g.:
// Files
// Files/Sub
// Other Users/machniak/Files
// Other Users/machniak/Files/Sub
// the list is sorted so we can do this in such a way
if ($pos = strpos($folder, '/', $path_len + 1)) {
$folder = substr($folder, 0, $pos);
$virtual = true;
}
$path = Collection::ROOT_DIRECTORY . '/' . $folder;
if ($path_len) {
$folder = substr($folder, $path_len + 1);
}
if (!array_key_exists($folder, $this->children)) {
$this->children[$folder] = new Collection($path, $this, array('virtual' => $virtual));
}
}
}
// non-root existing folder, get files list
if ($path_len && empty($this->data['virtual'])) {
try {
$files = $this->backend->file_list($this->path);
}
catch (Exception $e) {
}
foreach ($files as $filename => $file) {
$path = Collection::ROOT_DIRECTORY . '/' . $filename;
// remove path prefix
$filename = substr($filename, $path_len + 1);
$this->children[$filename] = new File($path, $this, $file);
}
}
return $this->children;
}
/**
* Returns a child object, by its name.
*
* This method makes use of the getChildren method to grab all the child
* nodes, and compares the name.
* Generally its wise to override this, as this can usually be optimized
*
* This method must throw Sabre\DAV\Exception\NotFound if the node does not
* exist.
*
* @param string $name
- * @throws Sabre\DAV\Exception\NotFound
+ * @throws Sabre\DAV\Exception
* @return INode
*/
public function getChild($name)
{
// no support for hidden system files
if ($name[0] == '.') {
throw new \Sabre\DAV\Exception\NotFound('File not found: ' . $name);
}
$children = $this->getChildren();
if (array_key_exists($name, $children)) {
return $children[$name];
}
throw new \Sabre\DAV\Exception\NotFound('File not found: ' . $name);
}
/**
* Checks if a child-node exists.
*
* It is generally a good idea to try and override this. Usually it can be optimized.
*
* @param string $name
* @return bool
*/
public function childExists($name)
{
try {
$this->getChild($name);
return true;
}
catch (\Sabre\DAV\Exception\NotFound $e) {
return false;
}
}
/**
* Creates a new file in the directory
*
* Data will either be supplied as a stream resource, or in certain cases
* as a string. Keep in mind that you may have to support either.
*
* After succesful creation of the file, you may choose to return the ETag
* of the new file here.
*
* The returned ETag must be surrounded by double-quotes (The quotes should
* be part of the actual string).
*
* If you cannot accurately determine the ETag, you should not return it.
* If you don't store the file exactly as-is (you're transforming it
* somehow) you should also not return an ETag.
*
* This means that if a subsequent GET to this new file does not exactly
* return the same contents of what was submitted here, you are strongly
* recommended to omit the ETag.
*
* @param string $name Name of the file
* @param resource|string $data Initial payload
+ *
+ * @throws Sabre\DAV\Exception
* @return null|string
*/
public function createFile($name, $data = null)
{
// no support for hidden system files
if ($name[0] == '.') {
throw new \Sabre\DAV\Exception\Forbidden('Hidden files are not accepted');
}
$filename = $this->path . '/' . $name;
$filedata = $this->fileData($name, $data);
try {
$this->backend->file_create($filename, $filedata);
}
catch (Exception $e) {
-// throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
+ $this->throw_exception($e);
}
// reset cache
$this->children = null;
}
/**
* Creates a new subdirectory
*
* @param string $name
- * @throws Exception\Forbidden
+ * @throws Sabre\DAV\Exception
* @return void
*/
public function createDirectory($name)
{
// no support for hidden system files
if ($name[0] == '.') {
throw new \Sabre\DAV\Exception\Forbidden('Hidden files are not accepted');
}
$folder = $this->path . '/' . $name;
try {
$this->backend->folder_create($folder);
}
catch (Exception $e) {
- throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
+ $this->throw_exception($e);
}
// reset cache
$this->children = null;
}
}
diff --git a/lib/Kolab/DAV/File.php b/lib/Kolab/DAV/File.php
index 8e402c4..b7e0b20 100644
--- a/lib/Kolab/DAV/File.php
+++ b/lib/Kolab/DAV/File.php
@@ -1,221 +1,224 @@
<?php
/**
* SabreDAV File Backend implementation for Kolab.
*
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Kolab\DAV;
-use \rcube;
use \Exception;
use \DateTime;
/**
* File class
*/
class File extends Node implements \Sabre\DAV\IFile, \Sabre\DAV\IProperties
{
/**
* Updates the data
*
* The data argument is a readable stream resource.
*
* After a succesful put operation, you may choose to return an ETag. The
* etag must always be surrounded by double-quotes. These quotes must
* appear in the actual string you're returning.
*
* Clients may use the ETag from a PUT request to later on make sure that
* when they update the file, the contents haven't changed in the mean
* time.
*
* If you don't plan to store the file byte-by-byte, and you return a
* different object on a subsequent GET you are strongly recommended to not
* return an ETag, and just return null.
*
* @param resource $data
+ * @throws Sabre\DAV\Exception
* @return string|null
*/
public function put($data)
{
$filedata = $this->fileData($this->path, $data);
try {
$this->backend->file_update($this->path, $filedata);
}
catch (Exception $e) {
-// throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
+ $this->throw_exception($e);
}
try {
$this->data = $this->backend->file_info($this->path);
}
catch (Exception $e) {
+ $this->throw_exception($e);
}
return $this->getETag();
}
/**
* Returns the file content
*
* This method may either return a string or a readable stream resource
*
+ * @throws Sabre\DAV\Exception
* @return mixed
*/
public function get()
{
try {
$fp = fopen('php://temp', 'bw+');
$this->backend->file_get($this->path, array(), $fp);
rewind($fp);
}
catch (Exception $e) {
-// throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
+ $this->throw_exception($e);
}
return $fp;
}
/**
* Delete the current file
*
+ * @throws Sabre\DAV\Exception
* @return void
*/
public function delete()
{
try {
$this->backend->file_delete($this->path);
}
catch (Exception $e) {
-// throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
+ $this->throw_exception($e);
}
// reset cache
if ($this->parent) {
$this->parent->children = null;
}
}
/**
* Returns the size of the node, in bytes
*
* @return int
*/
public function getSize()
{
return $this->data['size'];
}
/**
* Returns the ETag for a file
*
* An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
* The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
*
* Return null if the ETag can not effectively be determined
*
* @return mixed
*/
public function getETag()
{
return sprintf('"%s-%d"', substr(md5($this->path . ':' . $this->data['size']), 0, 16), $this->data['modified']);
}
/**
* Returns the mime-type for a file
*
* If null is returned, we'll assume application/octet-stream
*
* @return mixed
*/
public function getContentType()
{
return $this->data['type'];
}
/**
* Updates properties on this node,
*
* The properties array uses the propertyName in clark-notation as key,
* and the array value for the property value. In the case a property
* should be deleted, the property value will be null.
*
* This method must be atomic. If one property cannot be changed, the
* entire operation must fail.
*
* If the operation was successful, true can be returned.
* If the operation failed, false can be returned.
*
* Deletion of a non-existent property is always successful.
*
* Lastly, it is optional to return detailed information about any
* failures. In this case an array should be returned with the following
* structure:
*
* array(
* 403 => array(
* '{DAV:}displayname' => null,
* ),
* 424 => array(
* '{DAV:}owner' => null,
* )
* )
*
* In this example it was forbidden to update {DAV:}displayname.
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
* (424 Failed Dependency) because the request needs to be atomic.
*
* @param array $mutations
* @return bool|array
*/
function updateProperties($mutations)
{
// not supported
return false;
}
/**
* Returns a list of properties for this node.
*
* The properties list is a list of propertynames the client requested,
* encoded in clark-notation {xmlnamespace}tagname
*
* If the array is empty, it means 'all properties' were requested.
*
* Note that it's fine to liberally give properties back, instead of
* conforming to the list of requested properties.
* The Server class will filter out the extra.
*
* @param array $properties
* @return void
*/
function getProperties($properties)
{
$result = array();
if ($this->data['created']) {
$result['{DAV:}creationdate'] = \Sabre\HTTP\Util::toHTTPDate(new DateTime('@'.$this->data['created']));
}
return $result;
}
}
diff --git a/lib/Kolab/DAV/Node.php b/lib/Kolab/DAV/Node.php
index beba2a9..9e72f8f 100644
--- a/lib/Kolab/DAV/Node.php
+++ b/lib/Kolab/DAV/Node.php
@@ -1,196 +1,215 @@
<?php
/**
* SabreDAV File Backend implementation for Kolab.
*
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Kolab\DAV;
-use \rcube;
-use \rcube_mime;
use \Exception;
/**
* Node class
*/
class Node implements \Sabre\DAV\INode
{
/**
* The path to the current node
*
* @var string
*/
protected $path;
/**
* The file API backend class
*
* @var Kolab\DAV\Backend
*/
protected $backend;
/**
* Internal node data (e.g. file parameters)
*
* @var array
*/
protected $data;
/**
* Parent node
*
* @var Kolab\DAV\Node
*/
protected $parent;
/**
* @brief Sets up the node, expects a full path name
* @param string $path Node name with path
* @param Kolab\DAV\Node $parent Parent node
* @param array $data Node data
*
* @return void
*/
public function __construct($path, $parent = null, $data = array())
{
$this->data = $data;
$this->path = $path;
$this->parent = $parent;
$this->backend = Backend::get_instance();
if ($this->path == Collection::ROOT_DIRECTORY) {
$this->path = '';
}
else if (strpos($this->path, Collection::ROOT_DIRECTORY . '/') === 0) {
$this->path = substr($this->path, strlen(Collection::ROOT_DIRECTORY . '/'));
}
}
/**
* Returns the last modification time
*
* In this case, it will simply return the current time
*
* @return int
*/
public function getLastModified()
{
return $this->data['modified'] ? $this->data['modified'] : null;
}
/**
* Deletes the current node (folder)
*
- * @throws Sabre\DAV\Exception\Forbidden
+ * @throws Sabre\DAV\Exception
* @return void
*/
public function delete()
{
try {
$this->backend->folder_delete($this->path);
}
catch (Exception $e) {
- throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
+ $this->throw_exception($e);
}
// reset cache
if ($this->parent) {
$this->parent->children = null;
}
}
/**
* Renames the node
*
- * @throws Sabre\DAV\Exception\Forbidden
+ * @throws Sabre\DAV\Exception
* @param string $name The new name
* @return void
*/
public function setName($name)
{
$path = explode('/', $this->path);
array_pop($path);
$newname = implode('/', $path) . '/' . $name;
$method = (is_a($this, 'Kolab\\DAV\\File') ? 'file' : 'folder') . '_move';
try {
$this->backend->$method($this->path, $newname);
}
catch (Exception $e) {
- throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
+ $this->throw_exception($e);
}
// reset cache
if ($this->parent) {
$this->parent->children = null;
}
}
/**
* @brief Returns the name of the node
* @return string
*/
public function getName()
{
if ($this->path === '') {
return Collection::ROOT_DIRECTORY;
}
return array_pop(explode('/', $this->path));
}
/**
* Build file data array to pass into backend
*/
protected function fileData($name, $data = null)
{
if ($this->data && $this->data['type']) {
$type = $this->data['type'];
}
else {
$type = 'application/octet-stream';
}
// $data can be a resource or a string
if (is_resource($data)) {
rewind($data);
// $data can be php://input or php://temp
// php://input is not seekable, we need to "convert"
// it to seekable resource, fstat/rewind later will work
$meta = stream_get_meta_data($data);
if (!$meta['seekable']) {
$new_data = fopen('php://temp','r+');
stream_copy_to_stream($data, $new_data);
rewind($new_data);
$data = $new_data;
}
}
$filedata = array(
'content' => $data,
'type' => $type,
);
return $filedata;
}
+
+ /**
+ * Convert Chwala exceptions to Sabre exceptions
+ *
+ * @param Exception Chwala exception
+ * @throws Sabre\DAV\Exception
+ */
+ protected function throw_exception($e)
+ {
+ $error = $e->getCode();
+ $msg = $e->getMessage();
+
+ if ($error == \file_storage::ERROR_UNAVAILABLE) {
+ throw new \Sabre\DAV\Exception\ServiceUnavailable($msg);
+ }
+ else if ($error == \kolab_storage::ERROR_FORBIDDEN) {
+ throw new \Sabre\DAV\Exception\Forbidden($msg);
+ }
+
+ throw new \Sabre\DAV\Exception($msg);
+ }
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jun 8, 11:32 AM (7 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
196686
Default Alt Text
(20 KB)

Event Timeline