Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F256603
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
20 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R5 irony
Attached
Detach File
Event Timeline
Log In to Comment