mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 23:00:56 +01:00
locking for eGW's WebDAV (and later on CalDAV).
no recursive (depth infinit) locks atm.
This commit is contained in:
parent
2e0882c868
commit
f6a883713f
@ -72,6 +72,10 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
* Excecutable bit, here only use to check if user is allowed to search dirs
|
* Excecutable bit, here only use to check if user is allowed to search dirs
|
||||||
*/
|
*/
|
||||||
const EXECUTABLE = 1;
|
const EXECUTABLE = 1;
|
||||||
|
/**
|
||||||
|
* Name of the lock table
|
||||||
|
*/
|
||||||
|
const LOCK_TABLE = 'egw_locks';
|
||||||
/**
|
/**
|
||||||
* Current user has root rights, no access checks performed!
|
* Current user has root rights, no access checks performed!
|
||||||
*
|
*
|
||||||
@ -96,6 +100,12 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
static $find_total;
|
static $find_total;
|
||||||
|
/**
|
||||||
|
* Reference to the global db object
|
||||||
|
*
|
||||||
|
* @var egw_db
|
||||||
|
*/
|
||||||
|
static $db;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fopen working on just the eGW VFS
|
* fopen working on just the eGW VFS
|
||||||
@ -947,6 +957,158 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
return '/filemanager/webdav.php'.$path;
|
return '/filemanager/webdav.php'.$path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We cache locks within a request, as HTTP_WebDAV_Server generates so many, that it can be a bottleneck
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static protected $lock_cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lock a ressource/path
|
||||||
|
*
|
||||||
|
* @param string $path path or url
|
||||||
|
* @param string $token
|
||||||
|
* @param int &$timeout
|
||||||
|
* @param string &$owner
|
||||||
|
* @param string &$scope
|
||||||
|
* @param string &$type
|
||||||
|
* @param boolean $update=false
|
||||||
|
* @param boolean $check_writable=true should we check if the ressource is writable, before granting locks, default yes
|
||||||
|
* @return boolean true on success
|
||||||
|
*/
|
||||||
|
function lock($path,$token,&$timeout,&$owner,&$scope,&$type,$update=false,$check_writable=true)
|
||||||
|
{
|
||||||
|
// we require write rights to lock/unlock a resource
|
||||||
|
if (!$path || $update && !$token || $check_writable && !egw_vfs::is_writable($path))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// remove the lock info evtl. set in the cache
|
||||||
|
unset(self::$lock_cache[$path]);
|
||||||
|
|
||||||
|
if ($update) // Lock Update
|
||||||
|
{
|
||||||
|
if (($ret = (boolean)($row = self::$db->select(self::LOCK_TABLE,array('lock_owner','lock_exclusive','lock_write'),array(
|
||||||
|
'lock_path' => $path,
|
||||||
|
'lock_token' => $token,
|
||||||
|
)))))
|
||||||
|
{
|
||||||
|
$owner = $row['lock_owner'];
|
||||||
|
$scope = egw_db::from_bool($row['lock_exclusive']) ? 'exclusive' : 'shared';
|
||||||
|
$type = egw_db::from_bool($row['lock_write']) ? 'write' : 'read';
|
||||||
|
|
||||||
|
self::$db->update(self::LOCK_TABLE,array(
|
||||||
|
'lock_expires' => $timeout,
|
||||||
|
'lock_modified' => time(),
|
||||||
|
),array(
|
||||||
|
'path' => $path,
|
||||||
|
'token' => $token,
|
||||||
|
),__LINE__,__FILE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// HTTP_WebDAV_Server does this check before calling LOCK, but we want to be complete and usable outside WebDAV
|
||||||
|
elseif(($lock = self::checkLock($path)) && ($lock['scope'] == 'exclusive' || $scope == 'exclusive'))
|
||||||
|
{
|
||||||
|
$ret = false; // there's alread a lock
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// HTTP_WebDAV_Server sets owner and token, but we want to be complete and usable outside WebDAV
|
||||||
|
if (!$owner || $owner == 'unknown')
|
||||||
|
{
|
||||||
|
$owner = 'mailto:'.$GLOBALS['egw_info']['user']['account_email'];
|
||||||
|
}
|
||||||
|
if (!$token)
|
||||||
|
{
|
||||||
|
$token = HTTP_WebDAV_Server::_new_locktoken();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
self::$db->insert(self::LOCK_TABLE,array(
|
||||||
|
'lock_token' => $token,
|
||||||
|
'lock_path' => $path,
|
||||||
|
'lock_created' => time(),
|
||||||
|
'lock_modified' => time(),
|
||||||
|
'lock_owner' => $owner,
|
||||||
|
'lock_expires' => $timeout,
|
||||||
|
'lock_exclusive' => $scope == 'exclusive',
|
||||||
|
'lock_write' => $type == 'write',
|
||||||
|
),false,__LINE__,__FILE__);
|
||||||
|
$ret = true;
|
||||||
|
}
|
||||||
|
catch(egw_exception_db $e) {
|
||||||
|
$ret = false; // there's already a lock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error_log(__METHOD__."($path,$token,$timeout,$owner,$scope,$type,$update,$check_writable) returns ".($ret ? 'true' : 'false'));
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unlock a ressource/path
|
||||||
|
*
|
||||||
|
* @param string $path path to unlock
|
||||||
|
* @param string $token locktoken
|
||||||
|
* @param boolean $check_writable=true should we check if the ressource is writable, before granting locks, default yes
|
||||||
|
* @return boolean true on success
|
||||||
|
*/
|
||||||
|
function unlock($path,$token,$check_writable=true)
|
||||||
|
{
|
||||||
|
// we require write rights to lock/unlock a resource
|
||||||
|
if ($check_writable && !egw_vfs::is_writable($path))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (($ret = self::$db->delete(self::LOCK_TABLE,array(
|
||||||
|
'lock_path' => $path,
|
||||||
|
'lock_token' => $token,
|
||||||
|
),__LINE__,__FILE__) && self::$db->affected_rows()))
|
||||||
|
{
|
||||||
|
// remove the lock from the cache too
|
||||||
|
unset(self::$lock_cache[$path]);
|
||||||
|
}
|
||||||
|
error_log(__METHOD__."($path,$token,$check_writable) returns ".($ret ? 'true' : 'false'));
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkLock() helper
|
||||||
|
*
|
||||||
|
* @param string resource path to check for locks
|
||||||
|
* @return array|boolean false if there's no lock, else array with lock info
|
||||||
|
*/
|
||||||
|
function checkLock($path)
|
||||||
|
{
|
||||||
|
if (isset(self::$lock_cache[$path]))
|
||||||
|
{
|
||||||
|
error_log(__METHOD__."($path) returns from CACHE ".str_replace(array("\n",' '),'',print_r(self::$lock_cache[$path],true)));
|
||||||
|
return self::$lock_cache[$path];
|
||||||
|
}
|
||||||
|
$where = 'lock_path='.self::$db->quote($path);
|
||||||
|
// ToDo: additional check parent dirs for locks and children of the requested directory
|
||||||
|
//$where .= ' OR '.self::$db->quote($path).' LIKE '.self::$db->concat('lock_path',"'%'").' OR lock_path LIKE '.self::$db->quote($path.'%');
|
||||||
|
// ToDo: shared locks can return multiple rows
|
||||||
|
if (($result = self::$db->select(self::LOCK_TABLE,'*',$where,__LINE__,__FILE__)->fetch()))
|
||||||
|
{
|
||||||
|
$result = egw_db::strip_array_keys($result,'lock_');
|
||||||
|
$result['type'] = egw_db::from_bool($result['write']) ? 'write' : 'read';
|
||||||
|
$result['scope'] = egw_db::from_bool($result['exclusive']) ? 'exclusive' : 'shared';
|
||||||
|
$result['depth'] = egw_db::from_bool($result['recursive']) ? 'infinite' : 0;
|
||||||
|
}
|
||||||
|
if ($result && $result['expires'] < time()) // lock is expired --> remove it
|
||||||
|
{
|
||||||
|
self::$db->delete(self::LOCK_TABLE,array(
|
||||||
|
'lock_path' => $result['path'],
|
||||||
|
'lock_token' => $result['token'],
|
||||||
|
),__LINE__,__FILE__);
|
||||||
|
|
||||||
|
error_log(__METHOD__."($path) lock is expired at ".date('Y-m-d H:i:s',$result['expires'])." --> removed");
|
||||||
|
$result = false;
|
||||||
|
}
|
||||||
|
error_log(__METHOD__."($path) returns ".($result?str_replace(array("\n",' '),'',print_r($result,true)):'false'));
|
||||||
|
return self::$lock_cache[$path] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise our static vars
|
* Initialise our static vars
|
||||||
*/
|
*/
|
||||||
@ -954,6 +1116,8 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
{
|
{
|
||||||
self::$user = (int) $GLOBALS['egw_info']['user']['account_id'];
|
self::$user = (int) $GLOBALS['egw_info']['user']['account_id'];
|
||||||
self::$is_admin = isset($GLOBALS['egw_info']['user']['apps']['admin']);
|
self::$is_admin = isset($GLOBALS['egw_info']['user']['apps']['admin']);
|
||||||
|
self::$db = isset($GLOBALS['egw_setup']->db) ? $GLOBALS['egw_setup']->db : $GLOBALS['egw']->db;
|
||||||
|
self::$lock_cache = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,10 +60,10 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
|||||||
{
|
{
|
||||||
foreach (apache_request_headers() as $key => $value)
|
foreach (apache_request_headers() as $key => $value)
|
||||||
{
|
{
|
||||||
if (stristr($key, "litmus"))
|
if (stristr($key, 'litmus'))
|
||||||
{
|
{
|
||||||
error_log("Litmus test $value");
|
error_log("Litmus test $value");
|
||||||
header("X-Litmus-reply: ".$value);
|
header('X-Litmus-reply: '.$value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,114 +71,110 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
|||||||
HTTP_WebDAV_Server::ServeRequest();
|
HTTP_WebDAV_Server::ServeRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DELETE method handler
|
* DELETE method handler
|
||||||
*
|
*
|
||||||
* @param array general parameter passing array
|
* @param array general parameter passing array
|
||||||
* @return bool true on success
|
* @return bool true on success
|
||||||
*/
|
*/
|
||||||
function DELETE($options)
|
function DELETE($options)
|
||||||
{
|
{
|
||||||
$path = $this->base . "/" .$options["path"];
|
$path = $this->base . $options['path'];
|
||||||
|
|
||||||
if (!file_exists($path))
|
if (!file_exists($path))
|
||||||
{
|
{
|
||||||
return "404 Not found";
|
return '404 Not found';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_dir($path))
|
if (is_dir($path))
|
||||||
{
|
{
|
||||||
/*$query = "DELETE FROM {$this->db_prefix}properties
|
|
||||||
WHERE path LIKE '".$this->_slashify($options["path"])."%'";
|
|
||||||
mysql_query($query); */
|
|
||||||
// recursive delete the directory
|
|
||||||
if ($dir = egw_vfs::dir_opendir($options["path"]))
|
|
||||||
{
|
|
||||||
while(($file = readdir($dir)))
|
|
||||||
{
|
|
||||||
if ($file == '.' || $file == '..') continue;
|
|
||||||
|
|
||||||
if (is_dir($path.'/'.$file))
|
/*$query = "DELETE FROM {$this->db_prefix}properties
|
||||||
{
|
WHERE path LIKE '".$this->_slashify($options["path"])."%'";
|
||||||
// recursivly call ourself with the dir
|
mysql_query($query); */
|
||||||
$opts = $options;
|
|
||||||
$opts['path'] .= '/'.$file;
|
|
||||||
$this->DELETE($opts);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unlink($path.'/'.$file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir($dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unlink($path);
|
|
||||||
}
|
|
||||||
/*$query = "DELETE FROM {$this->db_prefix}properties
|
|
||||||
WHERE path = '$options[path]'";
|
|
||||||
mysql_query($query);*/
|
|
||||||
|
|
||||||
return "204 No Content";
|
// recursive delete the directory
|
||||||
}
|
egw_vfs::remove($options['path']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unlink($path);
|
||||||
|
}
|
||||||
|
/*$query = "DELETE FROM {$this->db_prefix}properties
|
||||||
|
WHERE path = '$options[path]'";
|
||||||
|
mysql_query($query);*/
|
||||||
|
|
||||||
/**
|
return '204 No Content';
|
||||||
* Get properties for a single file/resource
|
}
|
||||||
*
|
|
||||||
* @param string resource path
|
|
||||||
* @return array resource properties
|
|
||||||
*/
|
|
||||||
function fileinfo($path)
|
|
||||||
{
|
|
||||||
error_log(__METHOD__."($path)");
|
|
||||||
// map URI path to filesystem path
|
|
||||||
$fspath = $this->base . $path;
|
|
||||||
|
|
||||||
// create result array
|
/**
|
||||||
$info = array();
|
* Get properties for a single file/resource
|
||||||
// TODO remove slash append code when base clase is able to do it itself
|
*
|
||||||
$info["path"] = is_dir($fspath) ? $this->_slashify($path) : $path;
|
* @param string resource path
|
||||||
$info["props"] = array();
|
* @return array resource properties
|
||||||
|
*/
|
||||||
|
function fileinfo($path)
|
||||||
|
{
|
||||||
|
//error_log(__METHOD__."($path)");
|
||||||
|
// map URI path to filesystem path
|
||||||
|
$fspath = $this->base . $path;
|
||||||
|
|
||||||
// no special beautified displayname here ...
|
// create result array
|
||||||
$info["props"][] = $this->mkprop("displayname", strtoupper($path));
|
$info = array();
|
||||||
|
// TODO remove slash append code when base class is able to do it itself
|
||||||
|
$info['path'] = is_dir($fspath) ? $this->_slashify($path) : $path;
|
||||||
|
$info['props'] = array();
|
||||||
|
|
||||||
// creation and modification time
|
// no special beautified displayname here ...
|
||||||
$info["props"][] = $this->mkprop("creationdate", filectime($fspath));
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('displayname', strtoupper($path));
|
||||||
$info["props"][] = $this->mkprop("getlastmodified", filemtime($fspath));
|
|
||||||
|
|
||||||
// type and size (caller already made sure that path exists)
|
// creation and modification time
|
||||||
if (is_dir($fspath)) {
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('creationdate', filectime($fspath));
|
||||||
// directory (WebDAV collection)
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getlastmodified', filemtime($fspath));
|
||||||
$info["props"][] = $this->mkprop("resourcetype", "collection");
|
|
||||||
$info["props"][] = $this->mkprop("getcontenttype", "httpd/unix-directory");
|
// type and size (caller already made sure that path exists)
|
||||||
} else {
|
if (is_dir($fspath)) {
|
||||||
// plain file (WebDAV resource)
|
// directory (WebDAV collection)
|
||||||
$info["props"][] = $this->mkprop("resourcetype", "");
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', 'collection');
|
||||||
if (egw_vfs::is_readable($path)) {
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', 'httpd/unix-directory');
|
||||||
$info["props"][] = $this->mkprop("getcontenttype", egw_vfs::mime_content_type($path));
|
} else {
|
||||||
} else {
|
// plain file (WebDAV resource)
|
||||||
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', '');
|
||||||
|
if (egw_vfs::is_readable($path)) {
|
||||||
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', egw_vfs::mime_content_type($path));
|
||||||
|
} else {
|
||||||
error_log(__METHOD__."($path) $fspath is not readable!");
|
error_log(__METHOD__."($path) $fspath is not readable!");
|
||||||
$info["props"][] = $this->mkprop("getcontenttype", "application/x-non-readable");
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', 'application/x-non-readable');
|
||||||
}
|
}
|
||||||
$info["props"][] = $this->mkprop("getcontentlength", filesize($fspath));
|
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontentlength', filesize($fspath));
|
||||||
}
|
}
|
||||||
|
// supportedlock property
|
||||||
|
$info['props'][] = HTTP_WebDAV_Server::mkprop('supportedlock','
|
||||||
|
<D:lockentry>
|
||||||
|
<D:lockscope><D:exclusive/></D:lockscope>
|
||||||
|
<D:locktype><D:write/></D:lockscope>
|
||||||
|
</D:lockentry>
|
||||||
|
<D:lockentry>
|
||||||
|
<D:lockscope><D:shared/></D:lockscope>
|
||||||
|
<D:locktype><D:write/></D:lockscope>
|
||||||
|
</D:lockentry>');
|
||||||
|
|
||||||
|
// ToDo: etag from inode and modification time
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// get additional properties from database
|
// get additional properties from database
|
||||||
$query = "SELECT ns, name, value
|
$query = "SELECT ns, name, value
|
||||||
FROM {$this->db_prefix}properties
|
FROM {$this->db_prefix}properties
|
||||||
WHERE path = '$path'";
|
WHERE path = '$path'";
|
||||||
$res = mysql_query($query);
|
$res = mysql_query($query);
|
||||||
while ($row = mysql_fetch_assoc($res)) {
|
while ($row = mysql_fetch_assoc($res)) {
|
||||||
$info["props"][] = $this->mkprop($row["ns"], $row["name"], $row["value"]);
|
$info["props"][] = HTTP_WebDAV_Server::mkprop ($row["ns"], $row["name"], $row["value"]);
|
||||||
}
|
}
|
||||||
mysql_free_result($res);
|
mysql_free_result($res);
|
||||||
*/
|
*/
|
||||||
//error_log(__METHOD__."($path) info=".print_r($info,true));
|
//error_log(__METHOD__."($path) info=".print_r($info,true));
|
||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used eg. by get
|
* Used eg. by get
|
||||||
@ -207,7 +203,7 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
|||||||
{
|
{
|
||||||
$path = $GLOBALS['egw']->translation->convert($options['path'],'utf-8');
|
$path = $GLOBALS['egw']->translation->convert($options['path'],'utf-8');
|
||||||
|
|
||||||
foreach ($options["props"] as $key => $prop) {
|
foreach ($options['props'] as $key => $prop) {
|
||||||
$attributes = array();
|
$attributes = array();
|
||||||
switch($prop['ns'])
|
switch($prop['ns'])
|
||||||
{
|
{
|
||||||
@ -235,12 +231,12 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
|||||||
break;
|
break;
|
||||||
// not sure why, the filesystem example of the WebDAV class does it ...
|
// not sure why, the filesystem example of the WebDAV class does it ...
|
||||||
default:
|
default:
|
||||||
$options["props"][$key]['status'] = "403 Forbidden";
|
$options['props'][$key]['status'] = '403 Forbidden';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ($this->debug) $props[] = '('.$prop["ns"].')'.$prop['name'].'='.$prop['val'];
|
if ($this->debug) $props[] = '('.$prop['ns'].')'.$prop['name'].'='.$prop['val'];
|
||||||
}
|
}
|
||||||
if ($this->debug)
|
if ($this->debug)
|
||||||
{
|
{
|
||||||
@ -248,137 +244,55 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
|||||||
if ($attributes) error_log(__METHOD__.": path=$options[path], set attributes=".str_replace("\n",' ',print_r($attributes,true)));
|
if ($attributes) error_log(__METHOD__.": path=$options[path], set attributes=".str_replace("\n",' ',print_r($attributes,true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""; // this is as the filesystem example handler does it, no true or false ...
|
return ''; // this is as the filesystem example handler does it, no true or false ...
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LOCK method handler
|
* LOCK method handler
|
||||||
*
|
*
|
||||||
* @param array general parameter passing array
|
* @param array general parameter passing array
|
||||||
* @return bool true on success
|
* @return bool true on success
|
||||||
*/
|
*/
|
||||||
function LOCK(&$options)
|
function LOCK(&$options)
|
||||||
{
|
{
|
||||||
// behaving like LOCK is not implemented
|
error_log(__METHOD__.'('.str_replace(array("\n",' '),'',print_r($options,true)).')');
|
||||||
return "412 Precondition failed";
|
|
||||||
/*
|
|
||||||
// get absolute fs path to requested resource
|
|
||||||
$fspath = $this->base . $options["path"];
|
|
||||||
|
|
||||||
// TODO recursive locks on directories not supported yet
|
// TODO recursive locks on directories not supported yet
|
||||||
if (is_dir($fspath) && !empty($options["depth"])) {
|
if (is_dir($this->base . $options['path']) && !empty($options['depth']))
|
||||||
return "409 Conflict";
|
{
|
||||||
|
return '409 Conflict';
|
||||||
}
|
}
|
||||||
|
$options['timeout'] = time()+300; // 5min. hardcoded
|
||||||
|
|
||||||
$options["timeout"] = time()+300; // 5min. hardcoded
|
// dont know why, but HTTP_WebDAV_Server passes the owner in D:href tags, which get's passed unchanged to checkLock/PROPFIND
|
||||||
|
// that's wrong according to the standard and cadaver does not show it on discover --> strip_tags removes eventual tags
|
||||||
|
if (($ret = egw_vfs::lock($options['path'],$options['locktoken'],$options['timeout'],strip_tags($options['owner']),
|
||||||
|
$options['scope'],$options['type'],isset($options['update']))) && !isset($options['update']))
|
||||||
|
{
|
||||||
|
return $ret ? '200 OK' : '409 Conflict';
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($options["update"])) { // Lock Update
|
/**
|
||||||
$where = "WHERE path = '$options[path]' AND token = '$options[update]'";
|
* UNLOCK method handler
|
||||||
|
*
|
||||||
|
* @param array general parameter passing array
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
function UNLOCK(&$options)
|
||||||
|
{
|
||||||
|
error_log(__METHOD__.'('.str_replace(array("\n",' '),'',print_r($options,true)).')');
|
||||||
|
return egw_vfs::unlock($options['path'],$options['token']) ? '204 No Content' : '409 Conflict';
|
||||||
|
}
|
||||||
|
|
||||||
$query = "SELECT owner, exclusivelock FROM {$this->db_prefix}locks $where";
|
/**
|
||||||
$res = mysql_query($query);
|
* checkLock() helper
|
||||||
$row = mysql_fetch_assoc($res);
|
*
|
||||||
mysql_free_result($res);
|
* @param string resource path to check for locks
|
||||||
|
* @return bool true on success
|
||||||
if (is_array($row)) {
|
*/
|
||||||
$query = "UPDATE {$this->db_prefix}locks
|
function checkLock($path)
|
||||||
SET expires = '$options[timeout]'
|
{
|
||||||
, modified = ".time()."
|
return egw_vfs::checkLock($path);
|
||||||
$where";
|
}
|
||||||
mysql_query($query);
|
|
||||||
|
|
||||||
$options['owner'] = $row['owner'];
|
|
||||||
$options['scope'] = $row["exclusivelock"] ? "exclusive" : "shared";
|
|
||||||
$options['type'] = $row["exclusivelock"] ? "write" : "read";
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = "INSERT INTO {$this->db_prefix}locks
|
|
||||||
SET token = '$options[locktoken]'
|
|
||||||
, path = '$options[path]'
|
|
||||||
, created = ".time()."
|
|
||||||
, modified = ".time()."
|
|
||||||
, owner = '$options[owner]'
|
|
||||||
, expires = '$options[timeout]'
|
|
||||||
, exclusivelock = " .($options['scope'] === "exclusive" ? "1" : "0")
|
|
||||||
;
|
|
||||||
mysql_query($query);
|
|
||||||
|
|
||||||
return mysql_affected_rows() ? "200 OK" : "409 Conflict";*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UNLOCK method handler
|
|
||||||
*
|
|
||||||
* @param array general parameter passing array
|
|
||||||
* @return bool true on success
|
|
||||||
*/
|
|
||||||
function UNLOCK(&$options)
|
|
||||||
{
|
|
||||||
// behaving like LOCK is not implemented
|
|
||||||
return "405 Method not allowed";
|
|
||||||
/*
|
|
||||||
$query = "DELETE FROM {$this->db_prefix}locks
|
|
||||||
WHERE path = '$options[path]'
|
|
||||||
AND token = '$options[token]'";
|
|
||||||
mysql_query($query);
|
|
||||||
|
|
||||||
return mysql_affected_rows() ? "204 No Content" : "409 Conflict";*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* checkLock() helper
|
|
||||||
*
|
|
||||||
* @param string resource path to check for locks
|
|
||||||
* @return bool true on success
|
|
||||||
*/
|
|
||||||
function checkLock($path)
|
|
||||||
{
|
|
||||||
// behave like checkLock is not implemented
|
|
||||||
return false;
|
|
||||||
/*
|
|
||||||
$result = false;
|
|
||||||
|
|
||||||
$query = "SELECT owner, token, created, modified, expires, exclusivelock
|
|
||||||
FROM {$this->db_prefix}locks
|
|
||||||
WHERE path = '$path'
|
|
||||||
";
|
|
||||||
$res = mysql_query($query);
|
|
||||||
|
|
||||||
if ($res) {
|
|
||||||
$row = mysql_fetch_array($res);
|
|
||||||
mysql_free_result($res);
|
|
||||||
|
|
||||||
if ($row) {
|
|
||||||
$result = array( "type" => "write",
|
|
||||||
"scope" => $row["exclusivelock"] ? "exclusive" : "shared",
|
|
||||||
"depth" => 0,
|
|
||||||
"owner" => $row['owner'],
|
|
||||||
"token" => $row['token'],
|
|
||||||
"created" => $row['created'],
|
|
||||||
"modified" => $row['modified'],
|
|
||||||
"expires" => $row['expires']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove not (yet) implemented LOCK methods, so we can use the mostly unchanged HTTP_WebDAV_Server_Filesystem class
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
function _allow()
|
|
||||||
{
|
|
||||||
$allow = parent::_allow();
|
|
||||||
unset($allow['LOCK']);
|
|
||||||
unset($allow['UNLOCK']);
|
|
||||||
return $allow;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -12,7 +12,7 @@
|
|||||||
/* Basic information about this app */
|
/* Basic information about this app */
|
||||||
$setup_info['phpgwapi']['name'] = 'phpgwapi';
|
$setup_info['phpgwapi']['name'] = 'phpgwapi';
|
||||||
$setup_info['phpgwapi']['title'] = 'eGroupWare API';
|
$setup_info['phpgwapi']['title'] = 'eGroupWare API';
|
||||||
$setup_info['phpgwapi']['version'] = '1.5.009';
|
$setup_info['phpgwapi']['version'] = '1.5.010';
|
||||||
$setup_info['phpgwapi']['versions']['current_header'] = '1.28';
|
$setup_info['phpgwapi']['versions']['current_header'] = '1.28';
|
||||||
$setup_info['phpgwapi']['enable'] = 3;
|
$setup_info['phpgwapi']['enable'] = 3;
|
||||||
$setup_info['phpgwapi']['app_order'] = 1;
|
$setup_info['phpgwapi']['app_order'] = 1;
|
||||||
@ -47,6 +47,7 @@ $setup_info['phpgwapi']['tables'][] = 'egw_sqlfs';
|
|||||||
$setup_info['phpgwapi']['tables'][] = 'egw_index_keywords';
|
$setup_info['phpgwapi']['tables'][] = 'egw_index_keywords';
|
||||||
$setup_info['phpgwapi']['tables'][] = 'egw_index';
|
$setup_info['phpgwapi']['tables'][] = 'egw_index';
|
||||||
$setup_info['phpgwapi']['tables'][] = 'egw_cat2entry';
|
$setup_info['phpgwapi']['tables'][] = 'egw_cat2entry';
|
||||||
|
$setup_info['phpgwapi']['tables'][] = 'egw_locks';
|
||||||
|
|
||||||
// hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS
|
// hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS
|
||||||
$setup_info['phpgwapi']['hooks']['addaccount'] = 'phpgwapi.vfs_home_hooks.addAccount';
|
$setup_info['phpgwapi']['hooks']['addaccount'] = 'phpgwapi.vfs_home_hooks.addAccount';
|
||||||
@ -65,3 +66,5 @@ $setup_info['notifywindow']['app_order'] = 1;
|
|||||||
$setup_info['notifywindow']['tables'] = '';
|
$setup_info['notifywindow']['tables'] = '';
|
||||||
$setup_info['notifywindow']['hooks'][] = 'home';
|
$setup_info['notifywindow']['hooks'][] = 'home';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -486,5 +486,22 @@ $phpgw_baseline = array(
|
|||||||
'fk' => array(),
|
'fk' => array(),
|
||||||
'ix' => array('cat_id'),
|
'ix' => array('cat_id'),
|
||||||
'uc' => array()
|
'uc' => array()
|
||||||
|
),
|
||||||
|
'egw_locks' => array(
|
||||||
|
'fd' => array(
|
||||||
|
'lock_token' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||||
|
'lock_path' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||||
|
'lock_expires' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||||
|
'lock_owner' => array('type' => 'varchar','precision' => '255'),
|
||||||
|
'lock_recursive' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||||
|
'lock_write' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||||
|
'lock_exclusive' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||||
|
'lock_created' => array('type' => 'int','precision' => '8','default' => '0'),
|
||||||
|
'lock_modified' => array('type' => 'int','precision' => '8','default' => '0')
|
||||||
|
),
|
||||||
|
'pk' => array('lock_token'),
|
||||||
|
'fk' => array(),
|
||||||
|
'ix' => array('lock_path','lock_expires'),
|
||||||
|
'uc' => array()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -389,3 +389,27 @@ function phpgwapi_upgrade1_5_008()
|
|||||||
|
|
||||||
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.009';
|
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.009';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$test[] = '1.5.009';
|
||||||
|
function phpgwapi_upgrade1_5_009()
|
||||||
|
{
|
||||||
|
$GLOBALS['egw_setup']->oProc->CreateTable('egw_locks',array(
|
||||||
|
'fd' => array(
|
||||||
|
'lock_token' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||||
|
'lock_path' => array('type' => 'varchar','precision' => '255','nullable' => False),
|
||||||
|
'lock_expires' => array('type' => 'int','precision' => '8','nullable' => False),
|
||||||
|
'lock_owner' => array('type' => 'varchar','precision' => '255'),
|
||||||
|
'lock_recursive' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||||
|
'lock_write' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||||
|
'lock_exclusive' => array('type' => 'bool','nullable' => False,'default' => '0'),
|
||||||
|
'lock_created' => array('type' => 'int','precision' => '8','default' => '0'),
|
||||||
|
'lock_modified' => array('type' => 'int','precision' => '8','default' => '0')
|
||||||
|
),
|
||||||
|
'pk' => array('lock_token'),
|
||||||
|
'fk' => array(),
|
||||||
|
'ix' => array('lock_path','lock_expires'),
|
||||||
|
'uc' => array()
|
||||||
|
));
|
||||||
|
|
||||||
|
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.010';
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user