mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-22 16:03:47 +01:00
work-in-progress keeping vfs user in stream context to allow mounting shares
This commit is contained in:
parent
39b630d36e
commit
0cbcd7bde0
@ -7,7 +7,7 @@
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2008-19 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2008-20 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api;
|
||||
@ -865,11 +865,12 @@ class Vfs
|
||||
{
|
||||
throw new Exception\WrongParameter('path has to be string, use check_access($path,$check,$stat=null)!');
|
||||
}
|
||||
// query stat array, if not given
|
||||
// if we have no $stat, delegate whole check to vfs stream-wrapper to correctly deal with shares / effective user-ids
|
||||
if (is_null($stat))
|
||||
{
|
||||
if (!isset($vfs)) $vfs = new Vfs\StreamWrapper();
|
||||
$stat = $vfs->url_stat($path,0);
|
||||
//$stat = $vfs->url_stat($path,0);
|
||||
return $vfs->check_access($path, $check);
|
||||
}
|
||||
//error_log(__METHOD__."(path=$path||stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check)");
|
||||
|
||||
@ -898,8 +899,9 @@ class Vfs
|
||||
//error_log(__METHOD__."(path=$path||stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via other rights!");
|
||||
return true;
|
||||
}
|
||||
if (!isset($user)) $user = self::$user;
|
||||
// check if there's owner access and we are the owner
|
||||
if (($stat['mode'] & ($check << 6)) == ($check << 6) && $stat['uid'] && $stat['uid'] == self::$user)
|
||||
if (($stat['mode'] & ($check << 6)) == ($check << 6) && $stat['uid'] && $stat['uid'] == $user)
|
||||
{
|
||||
//error_log(__METHOD__."(path=$path||stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via owner rights!");
|
||||
return true;
|
||||
@ -907,7 +909,7 @@ class Vfs
|
||||
// check if there's a group access and we have the right membership
|
||||
if (($stat['mode'] & ($check << 3)) == ($check << 3) && $stat['gid'])
|
||||
{
|
||||
if (($memberships = $GLOBALS['egw']->accounts->memberships(self::$user, true)) && in_array(-abs($stat['gid']), $memberships))
|
||||
if (($memberships = $GLOBALS['egw']->accounts->memberships($user, true)) && in_array(-abs($stat['gid']), $memberships))
|
||||
{
|
||||
//error_log(__METHOD__."(path=$path||stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via group rights!");
|
||||
return true;
|
||||
@ -1038,7 +1040,7 @@ class Vfs
|
||||
*/
|
||||
static function proppatch($path,array $props)
|
||||
{
|
||||
return self::_call_on_backend('proppatch',array($path,$props));
|
||||
return self::_call_on_backend('proppatch', [$path,$props], false, 0, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1057,7 +1059,7 @@ class Vfs
|
||||
*/
|
||||
static function propfind($path,$ns=self::DEFAULT_PROP_NAMESPACE)
|
||||
{
|
||||
return self::_call_on_backend('propfind',array($path,$ns),true); // true = fail silent (no PHP Warning)
|
||||
return self::_call_on_backend('propfind', [$path, $ns],true, 0, true); // true = fail silent (no PHP Warning)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2286,9 +2288,10 @@ class Vfs
|
||||
* @param boolean $fail_silent =false should only false be returned if function is not supported by the backend,
|
||||
* or should an E_USER_WARNING error be triggered (default)
|
||||
* @param int $path_param_key =0 key in params containing the path, default 0
|
||||
* @param boolean $instanciate =false true: instanciate the class to call method $name, false: static call
|
||||
* @return mixed return value of backend or false if function does not exist on backend
|
||||
*/
|
||||
static protected function _call_on_backend($name,$params,$fail_silent=false,$path_param_key=0)
|
||||
protected static function _call_on_backend($name, array $params, $fail_silent=false, $path_param_key=0, $instanciate=false)
|
||||
{
|
||||
$pathes = $params[$path_param_key];
|
||||
|
||||
@ -2313,14 +2316,15 @@ class Vfs
|
||||
if (!$fail_silent) trigger_error("Can't $name for scheme $scheme!\n",E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
$callback = [$instanciate ? new $class($url) : $class, $name];
|
||||
if (!is_array($pathes))
|
||||
{
|
||||
$params[$path_param_key] = $url;
|
||||
|
||||
return call_user_func_array(array($class,$name),$params);
|
||||
return call_user_func_array($callback, $params);
|
||||
}
|
||||
$params[$path_param_key] = $urls;
|
||||
if (!is_array($r = call_user_func_array(array($class,$name),$params)))
|
||||
if (!is_array($r = call_user_func_array($callback, $params)))
|
||||
{
|
||||
return $r;
|
||||
}
|
||||
@ -2412,7 +2416,7 @@ class Vfs
|
||||
*/
|
||||
static function readlink($path)
|
||||
{
|
||||
$ret = self::_call_on_backend('readlink',array($path),true); // true = fail silent, if backend does not support readlink
|
||||
$ret = self::_call_on_backend('readlink', [$path],true, 0, true); // true = fail silent, if backend does not support readlink
|
||||
//error_log(__METHOD__."('$path') returning ".array2string($ret).' '.function_backtrace());
|
||||
return $ret;
|
||||
}
|
||||
@ -2428,7 +2432,7 @@ class Vfs
|
||||
*/
|
||||
static function symlink($target,$link)
|
||||
{
|
||||
if (($ret = self::_call_on_backend('symlink',array($target,$link),false,1))) // 1=path is in $link!
|
||||
if (($ret = self::_call_on_backend('symlink', [$target, $link],false,1, true))) // 1=path is in $link!
|
||||
{
|
||||
Vfs\StreamWrapper::symlinkCache_remove($link);
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare API: VFS - stream wrapper for linked files
|
||||
* EGroupware API: VFS - stream wrapper for linked files
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2008-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id: class.sqlfs_stream_wrapper.inc.php 24997 2008-03-02 21:44:15Z ralfbecker $
|
||||
* @copyright (c) 2008-20 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Vfs\Links;
|
||||
@ -76,7 +75,7 @@ class StreamWrapper extends LinksParent
|
||||
* @param int $check mode to check: one or more or'ed together of: 4 = read, 2 = write, 1 = executable
|
||||
* @return boolean
|
||||
*/
|
||||
static function check_extended_acl($url,$check)
|
||||
function check_extended_acl($url,$check)
|
||||
{
|
||||
if (Vfs::$is_root)
|
||||
{
|
||||
@ -159,7 +158,9 @@ class StreamWrapper extends LinksParent
|
||||
*/
|
||||
function url_stat ( $url, $flags )
|
||||
{
|
||||
$eacl_check=self::check_extended_acl($url,Vfs::READABLE);
|
||||
$this->check_set_context($url);
|
||||
|
||||
$eacl_check=$this->check_extended_acl($url,Vfs::READABLE);
|
||||
|
||||
// return vCard as /.entry
|
||||
if ( $eacl_check && substr($url,-7) == '/.entry' &&
|
||||
@ -264,7 +265,7 @@ class StreamWrapper extends LinksParent
|
||||
list(,$apps,$app,$id) = explode('/',$path);
|
||||
|
||||
$ret = false;
|
||||
if ($apps == 'apps' && $app && !$id || self::check_extended_acl($path,Vfs::WRITABLE)) // app directory itself is allways ok
|
||||
if ($apps == 'apps' && $app && !$id || $this->check_extended_acl($path,Vfs::WRITABLE)) // app directory itself is allways ok
|
||||
{
|
||||
$current_is_root = Vfs::$is_root; Vfs::$is_root = true;
|
||||
$current_user = Vfs::$user; Vfs::$user = 0;
|
||||
@ -335,7 +336,7 @@ class StreamWrapper extends LinksParent
|
||||
{
|
||||
$charset = 'utf-8';
|
||||
}
|
||||
if (!($vcard =& $ab_vcard->getVCard($id, $charset)))
|
||||
if (!($vcard = $ab_vcard->getVCard($id, $charset)))
|
||||
{
|
||||
error_log(__METHOD__."('$url', '$mode', $options) addressbook_vcal::getVCard($id) returned false!");
|
||||
return false;
|
||||
@ -348,7 +349,7 @@ class StreamWrapper extends LinksParent
|
||||
}
|
||||
// create not existing entry directories on the fly
|
||||
if ($mode[0] != 'r' && ($dir = Vfs::dirname($url)) &&
|
||||
!parent::url_stat($dir, 0) && self::check_extended_acl($dir, Vfs::WRITABLE))
|
||||
!parent::url_stat($dir, 0) && $this->check_extended_acl($dir, Vfs::WRITABLE))
|
||||
{
|
||||
$this->mkdir($dir,0,STREAM_MKDIR_RECURSIVE);
|
||||
}
|
||||
@ -431,14 +432,14 @@ class StreamWrapper extends LinksParent
|
||||
* @param string $link
|
||||
* @return boolean true on success false on error
|
||||
*/
|
||||
static function symlink($target,$link)
|
||||
function symlink($target,$link)
|
||||
{
|
||||
$parent = new \EGroupware\Api\Vfs\Links\LinksParent();
|
||||
if (!$parent->url_stat($dir = Vfs::dirname($link),0) && self::check_extended_acl($dir,Vfs::WRITABLE))
|
||||
$parent = new \EGroupware\Api\Vfs\Links\LinksParent($target);
|
||||
if (!$parent->url_stat($dir = Vfs::dirname($link),0) && $this->check_extended_acl($dir,Vfs::WRITABLE))
|
||||
{
|
||||
$parent->mkdir($dir,0,STREAM_MKDIR_RECURSIVE);
|
||||
}
|
||||
return parent::symlink($target,$link);
|
||||
return $parent->symlink($target,$link);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -446,7 +447,7 @@ class StreamWrapper extends LinksParent
|
||||
*/
|
||||
public static function register()
|
||||
{
|
||||
stream_register_wrapper(self::SCHEME, __CLASS__);
|
||||
stream_wrapper_register(self::SCHEME, __CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,7 @@
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2008-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
* @copyright (c) 2008-20 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Vfs\Sqlfs;
|
||||
@ -36,6 +35,8 @@ use EGroupware\Api;
|
||||
*/
|
||||
class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
{
|
||||
use Vfs\UserContext;
|
||||
|
||||
/**
|
||||
* Mime type of directories, the old vfs uses 'Directory', while eg. WebDAV uses 'httpd/unix-directory'
|
||||
*/
|
||||
@ -102,13 +103,6 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
*/
|
||||
protected $operation = self::DEFAULT_OPERATION;
|
||||
|
||||
/**
|
||||
* optional context param when opening the stream, null if no context passed
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
var $context;
|
||||
|
||||
/**
|
||||
* Path off the file opened by stream_open
|
||||
*
|
||||
@ -199,6 +193,8 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
$this->operation = self::url2operation($url);
|
||||
$dir = Vfs::dirname($url);
|
||||
|
||||
error_log(__METHOD__."('$url', $mode, $options) path=$path, context=".json_encode(stream_context_get_options($this->context)));
|
||||
|
||||
$this->opened_path = $opened_path = $path;
|
||||
$this->opened_mode = $mode = str_replace('b','',$mode); // we are always binary, like every Linux system
|
||||
$this->opened_stream = null;
|
||||
@ -210,7 +206,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
if (!$dir || $mode[0] == 'r' || // does $mode require the file to exist (r,r+)
|
||||
$mode[0] == 'x' && $stat || // or file should not exist, but does
|
||||
!($dir_stat=$this->url_stat($dir,STREAM_URL_STAT_QUIET)) || // or parent dir does not exist create it
|
||||
!Vfs::check_access($dir,Vfs::WRITABLE,$dir_stat)) // or we are not allowed to create it
|
||||
!Vfs::check_access($dir,Vfs::WRITABLE, $dir_stat, $this->user)) // or we are not allowed to create it
|
||||
{
|
||||
self::_remove_password($url);
|
||||
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file does not exist or can not be created!");
|
||||
@ -233,12 +229,12 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
// we use the mode of the dir, so files in group dirs stay accessible by all members
|
||||
'fs_mode' => $dir_stat['mode'] & 0666,
|
||||
// for the uid we use the uid of the dir if not 0=root or the current user otherwise
|
||||
'fs_uid' => $dir_stat['uid'] ? $dir_stat['uid'] : Vfs::$user,
|
||||
'fs_uid' => $dir_stat['uid'] ? $dir_stat['uid'] : $this->user,
|
||||
// we allways use the group of the dir
|
||||
'fs_gid' => $dir_stat['gid'],
|
||||
'fs_created' => self::_pdo_timestamp(time()),
|
||||
'fs_modified' => self::_pdo_timestamp(time()),
|
||||
'fs_creator' => Vfs::$user,
|
||||
'fs_creator' => Vfs::$user, // real user, not effective one / $this->user
|
||||
'fs_mime' => 'application/octet-stream', // required NOT NULL!
|
||||
'fs_size' => 0,
|
||||
'fs_active' => self::_pdo_boolean(true),
|
||||
@ -276,8 +272,8 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($mode == 'r' && !Vfs::check_access($url,Vfs::READABLE ,$stat) ||// we are not allowed to read
|
||||
$mode != 'r' && !Vfs::check_access($url,Vfs::WRITABLE,$stat)) // or edit it
|
||||
if ($mode == 'r' && !Vfs::check_access($url,Vfs::READABLE ,$stat, $this->user) ||// we are not allowed to read
|
||||
$mode != 'r' && !Vfs::check_access($url,Vfs::WRITABLE, $stat, $this->user)) // or edit it
|
||||
{
|
||||
self::_remove_password($url);
|
||||
$op = $mode == 'r' ? 'read' : 'edited';
|
||||
@ -355,7 +351,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
// todo: analyse the file for the mime-type
|
||||
'fs_mime' => Api\MimeMagic::filename2mime($this->opened_path),
|
||||
'fs_id' => $this->opened_fs_id,
|
||||
'fs_modifier' => Vfs::$user,
|
||||
'fs_modifier' => $this->user,
|
||||
'fs_modified' => self::_pdo_timestamp(time()),
|
||||
);
|
||||
|
||||
@ -534,6 +530,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
function stream_stat ( )
|
||||
{
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($this->opened_path)");
|
||||
error_log(__METHOD__."() opened_path=$this->opened_path, context=".json_encode(stream_context_get_options($this->context)));
|
||||
|
||||
return $this->url_stat($this->opened_path,0);
|
||||
}
|
||||
@ -558,7 +555,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
$this->url_stat($dir, STREAM_URL_STAT_LINK);
|
||||
|
||||
if (!$parent_stat || !($stat = $this->url_stat($path,STREAM_URL_STAT_LINK)) ||
|
||||
!$dir || !Vfs::check_access($dir, Vfs::WRITABLE, $parent_stat))
|
||||
!$dir || !Vfs::check_access($dir, Vfs::WRITABLE, $parent_stat, $this->user))
|
||||
{
|
||||
self::_remove_password($url);
|
||||
if (self::LOG_LEVEL) error_log(__METHOD__."($url) permission denied!");
|
||||
@ -610,14 +607,14 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
$to_dir = Vfs::dirname($path_to);
|
||||
|
||||
if (!($from_stat = $this->url_stat($path_from, 0)) || !$from_dir ||
|
||||
!Vfs::check_access($from_dir, Vfs::WRITABLE, $from_dir_stat = $this->url_stat($from_dir, 0)))
|
||||
!Vfs::check_access($from_dir, Vfs::WRITABLE, $from_dir_stat = $this->url_stat($from_dir, 0), $this->user))
|
||||
{
|
||||
self::_remove_password($url_from);
|
||||
self::_remove_password($url_to);
|
||||
if (self::LOG_LEVEL) error_log(__METHOD__."($url_from,$url_to): $path_from permission denied!");
|
||||
return false; // no permission or file does not exist
|
||||
}
|
||||
if (!$to_dir || !Vfs::check_access($to_dir, Vfs::WRITABLE, $to_dir_stat = $this->url_stat($to_dir, 0)))
|
||||
if (!$to_dir || !Vfs::check_access($to_dir, Vfs::WRITABLE, $to_dir_stat = $this->url_stat($to_dir, 0), $this->user))
|
||||
{
|
||||
self::_remove_password($url_from);
|
||||
self::_remove_password($url_to);
|
||||
@ -699,7 +696,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__." called from:".function_backtrace());
|
||||
$path = Vfs::parse_url($url,PHP_URL_PATH);
|
||||
|
||||
if ($this->url_stat($path,STREAM_URL_STAT_QUIET))
|
||||
if ($this->url_stat($url,STREAM_URL_STAT_QUIET))
|
||||
{
|
||||
self::_remove_password($url);
|
||||
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) already exist!");
|
||||
@ -733,7 +730,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
}
|
||||
$parent = $this->url_stat($parent_path,0);
|
||||
}
|
||||
if (!$parent || !Vfs::check_access($parent_path,Vfs::WRITABLE,$parent))
|
||||
if (!$parent || !Vfs::check_access($parent_path,Vfs::WRITABLE, $parent, $this->user))
|
||||
{
|
||||
self::_remove_password($url);
|
||||
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) permission denied!");
|
||||
@ -756,7 +753,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
'fs_mime' => self::DIR_MIME_TYPE,
|
||||
'fs_created' => self::_pdo_timestamp(time()),
|
||||
'fs_modified' => self::_pdo_timestamp(time()),
|
||||
'fs_creator' => Vfs::$user,
|
||||
'fs_creator' => $this->user,
|
||||
))))
|
||||
{
|
||||
// check if some other process created the directory parallel to us (sqlfs would gives SQL errors later!)
|
||||
@ -796,7 +793,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
|
||||
if (!($parent = Vfs::dirname($path)) ||
|
||||
!($stat = $this->url_stat($path, 0)) || $stat['mime'] != self::DIR_MIME_TYPE ||
|
||||
!Vfs::check_access($parent, Vfs::WRITABLE, $this->url_stat($parent,0)))
|
||||
!Vfs::check_access($parent, Vfs::WRITABLE, $this->url_stat($parent,0), $this->user))
|
||||
{
|
||||
self::_remove_password($url);
|
||||
$err_msg = __METHOD__."($url,$options) ".(!$stat ? 'not found!' :
|
||||
@ -911,7 +908,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
|
||||
return $stmt->execute(array(
|
||||
'fs_modified' => self::_pdo_timestamp($time ? $time : time()),
|
||||
'fs_modifier' => Vfs::$user,
|
||||
'fs_modifier' => $this->user,
|
||||
'fs_id' => $stat['ino'],
|
||||
));
|
||||
}
|
||||
@ -1082,7 +1079,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
|
||||
if (!($stat = $this->url_stat($url,0)) || // dir not found
|
||||
!($stat['mode'] & self::MODE_DIR) && $stat['mime'] != self::DIR_MIME_TYPE || // no dir
|
||||
!Vfs::check_access($url,Vfs::EXECUTABLE|Vfs::READABLE,$stat)) // no access
|
||||
!Vfs::check_access($url,Vfs::EXECUTABLE|Vfs::READABLE, $stat, $this->user)) // no access
|
||||
{
|
||||
self::_remove_password($url);
|
||||
$msg = !($stat['mode'] & self::MODE_DIR) && $stat['mime'] != self::DIR_MIME_TYPE ?
|
||||
@ -1152,6 +1149,12 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
|
||||
$path = Vfs::parse_url($url,PHP_URL_PATH);
|
||||
|
||||
if (!$this->context)
|
||||
{
|
||||
$this->check_set_context($url);
|
||||
}
|
||||
error_log(__METHOD__."('$url', $flags) path=$path, context=".json_encode(stream_context_get_options($this->context)));
|
||||
|
||||
// webdav adds a trailing slash to dirs, which causes url_stat to NOT find the file otherwise
|
||||
if ($path != '/' && substr($path,-1) == '/')
|
||||
{
|
||||
@ -1177,7 +1180,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
$parts = explode('/',$path);
|
||||
|
||||
// if we have extended acl access to the url, we dont need and can NOT include the sql for the readable check
|
||||
$eacl_access = static::check_extended_acl($path,Vfs::READABLE);
|
||||
$eacl_access = $this->check_extended_acl($path,Vfs::READABLE);
|
||||
|
||||
try {
|
||||
foreach($parts as $n => $name)
|
||||
@ -1208,13 +1211,13 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
// if we are not root AND have no extended acl access, we need to make sure the user has the right to tranverse all parent directories (read-rights)
|
||||
if (!Vfs::$is_root && !$eacl_access)
|
||||
{
|
||||
if (!Vfs::$user)
|
||||
if (!$this->user)
|
||||
{
|
||||
self::_remove_password($url);
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$flags) permission denied, no user-id and not root!");
|
||||
return false;
|
||||
}
|
||||
$query .= ' AND '.self::_sql_readable();
|
||||
$query .= ' AND '.$this->_sql_readable();
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1248,6 +1251,10 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) $GLOBALS['egw']->invalidate_session_cache();
|
||||
return $this->url_stat($url, $flags);
|
||||
}
|
||||
if (!isset($info['effectiv-uid']) && $this->context)
|
||||
{
|
||||
$info['effectiv-uid'] = stream_context_get_options($this->context)[Vfs::SCHEME]['user'];
|
||||
}
|
||||
self::$stat_cache[$path] = $info;
|
||||
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$flags)=".array2string($info));
|
||||
@ -1259,23 +1266,23 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function _sql_readable()
|
||||
protected function _sql_readable()
|
||||
{
|
||||
static $sql_read_acl=null;
|
||||
static $sql_read_acl=[];
|
||||
|
||||
if (is_null($sql_read_acl))
|
||||
if (!isset($sql_read_acl[$user = $this->user]))
|
||||
{
|
||||
foreach($GLOBALS['egw']->accounts->memberships(Vfs::$user,true) as $gid)
|
||||
foreach($GLOBALS['egw']->accounts->memberships($user, true) as $gid)
|
||||
{
|
||||
$memberships[] = abs($gid); // sqlfs stores the gid's positiv
|
||||
}
|
||||
// using octal numbers with mysql leads to funny results (select 384 & 0400 --> 384 not 256=0400)
|
||||
// 256 = 0400, 32 = 040
|
||||
$sql_read_acl = '((fs_mode & 4)=4 OR (fs_mode & 256)=256 AND fs_uid='.(int)Vfs::$user.
|
||||
$sql_read_acl[$user] = '((fs_mode & 4)=4 OR (fs_mode & 256)=256 AND fs_uid='.$user.
|
||||
($memberships ? ' OR (fs_mode & 32)=32 AND fs_gid IN('.implode(',',$memberships).')' : '').')';
|
||||
//error_log(__METHOD__."() Vfs::\$user=".array2string(Vfs::$user).' --> memberships='.array2string($memberships).' --> '.$sql_read_acl.($memberships?'':': '.function_backtrace()));
|
||||
error_log(__METHOD__."() user=".array2string($user).' --> memberships='.array2string($memberships).' --> '.$sql_read_acl.($memberships?'':': '.function_backtrace()));
|
||||
}
|
||||
return $sql_read_acl;
|
||||
return $sql_read_acl[$user];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1341,10 +1348,9 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
* @param string $path
|
||||
* @return string|boolean content of the symlink or false if $url is no symlink (or not found)
|
||||
*/
|
||||
static function readlink($path)
|
||||
function readlink($path)
|
||||
{
|
||||
$vfs = new self();
|
||||
$link = !($lstat = $vfs->url_stat($path,STREAM_URL_STAT_LINK)) || is_null($lstat['readlink']) ? false : $lstat['readlink'];
|
||||
$link = !($lstat = $this->url_stat($path,STREAM_URL_STAT_LINK)) || is_null($lstat['readlink']) ? false : $lstat['readlink'];
|
||||
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$path') = $link");
|
||||
|
||||
@ -1358,18 +1364,17 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
* @param string $link
|
||||
* @return boolean true on success false on error
|
||||
*/
|
||||
static function symlink($target,$link)
|
||||
function symlink($target, $link)
|
||||
{
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$target','$link')");
|
||||
|
||||
$inst = new static();
|
||||
if ($inst->url_stat($link,0))
|
||||
if ($this->url_stat($link,0))
|
||||
{
|
||||
if (self::LOG_LEVEL > 0) error_log(__METHOD__."('$target','$link') $link exists, returning false!");
|
||||
return false; // $link already exists
|
||||
}
|
||||
if (!($dir = Vfs::dirname($link)) ||
|
||||
!Vfs::check_access($dir,Vfs::WRITABLE,$dir_stat=$inst->url_stat($dir,0)))
|
||||
!Vfs::check_access($dir,Vfs::WRITABLE, $dir_stat=$this->url_stat($dir,0), $this->user))
|
||||
{
|
||||
if (self::LOG_LEVEL > 0) error_log(__METHOD__."('$target','$link') returning false! (!is_writable('$dir'), dir_stat=".array2string($dir_stat).")");
|
||||
return false; // parent dir does not exist or is not writable
|
||||
@ -1384,7 +1389,7 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
'fs_name' => self::limit_filename(Vfs::basename($link)),
|
||||
'fs_dir' => $dir_stat['ino'],
|
||||
'fs_mode' => ($dir_stat['mode'] & 0666),
|
||||
'fs_uid' => $dir_stat['uid'] ? $dir_stat['uid'] : Vfs::$user,
|
||||
'fs_uid' => $dir_stat['uid'] ? $dir_stat['uid'] : $this->user,
|
||||
'fs_gid' => $dir_stat['gid'],
|
||||
'fs_created' => self::_pdo_timestamp(time()),
|
||||
'fs_modified' => self::_pdo_timestamp(time()),
|
||||
@ -1407,13 +1412,13 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
* @param int $check mode to check: one or more or'ed together of: 4 = read, 2 = write, 1 = executable
|
||||
* @return boolean
|
||||
*/
|
||||
static function check_extended_acl($url,$check)
|
||||
function check_extended_acl($url,$check)
|
||||
{
|
||||
$url_path = Vfs::parse_url($url,PHP_URL_PATH);
|
||||
|
||||
if (is_null(self::$extended_acl))
|
||||
{
|
||||
self::_read_extended_acl();
|
||||
$this->_read_extended_acl();
|
||||
}
|
||||
$access = false;
|
||||
foreach(self::$extended_acl as $path => $rights)
|
||||
@ -1432,14 +1437,14 @@ class StreamWrapper extends Api\Db\Pdo implements Vfs\StreamWrapperIface
|
||||
* Read the extended acl via acl::get_grants('sqlfs')
|
||||
*
|
||||
*/
|
||||
static protected function _read_extended_acl()
|
||||
protected function _read_extended_acl()
|
||||
{
|
||||
if ((self::$extended_acl = Api\Cache::getSession(self::EACL_APPNAME, 'extended_acl')))
|
||||
{
|
||||
return; // ext. ACL read from session.
|
||||
}
|
||||
self::$extended_acl = array();
|
||||
if (($rights = $GLOBALS['egw']->acl->get_all_location_rights(Vfs::$user,self::EACL_APPNAME)))
|
||||
if (($rights = $GLOBALS['egw']->acl->get_all_location_rights($this->user, self::EACL_APPNAME)))
|
||||
{
|
||||
$pathes = self::id2path(array_keys($rights));
|
||||
}
|
||||
@ -1732,6 +1737,7 @@ GROUP BY A.fs_id';
|
||||
// eGW addition to return some extra values
|
||||
'mime' => $info['fs_mime'],
|
||||
'readlink' => $info['fs_link'],
|
||||
'effectiv-uid' => $info['effectiv-uid'],
|
||||
);
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($info[name]) = ".array2string($stat));
|
||||
return $stat;
|
||||
@ -1843,14 +1849,12 @@ GROUP BY A.fs_id';
|
||||
* @param array $props array of array with values for keys 'name', 'ns', 'val' (null to delete the prop)
|
||||
* @return boolean true if props are updated, false otherwise (eg. ressource not found)
|
||||
*/
|
||||
static function proppatch($path,array $props)
|
||||
function proppatch($path,array $props)
|
||||
{
|
||||
static $inst = null;
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."(".array2string($path).','.array2string($props));
|
||||
if (!is_numeric($path))
|
||||
{
|
||||
if (!isset($inst)) $inst = new self();
|
||||
if (!($stat = $inst->url_stat($path,0)))
|
||||
if (!($stat = $this->url_stat($path,0)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1910,17 +1914,14 @@ GROUP BY A.fs_id';
|
||||
* @return array|boolean false on error ($path_ids does not exist), array with props (values for keys 'name', 'ns', 'value'), or
|
||||
* fs_id/path => array of props for $depth==1 or is_array($path_ids)
|
||||
*/
|
||||
static function propfind($path_ids,$ns=Vfs::DEFAULT_PROP_NAMESPACE)
|
||||
function propfind($path_ids,$ns=Vfs::DEFAULT_PROP_NAMESPACE)
|
||||
{
|
||||
static $inst = null;
|
||||
|
||||
$ids = is_array($path_ids) ? $path_ids : array($path_ids);
|
||||
foreach($ids as &$id)
|
||||
{
|
||||
if (!is_numeric($id))
|
||||
{
|
||||
if (!isset($inst)) $inst = new self();
|
||||
if (!($stat = $inst->url_stat($id,0)))
|
||||
if (!($stat = $this->url_stat($id,0)))
|
||||
{
|
||||
if (self::LOG_LEVEL) error_log(__METHOD__."(".array2string($path_ids).",$ns) path '$id' not found!");
|
||||
return false;
|
||||
@ -1974,7 +1975,7 @@ GROUP BY A.fs_id';
|
||||
*/
|
||||
public static function register()
|
||||
{
|
||||
stream_register_wrapper(self::SCHEME, __CLASS__);
|
||||
stream_wrapper_register(self::SCHEME, __CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,7 @@
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2008-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
* @copyright (c) 2008-20 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Vfs;
|
||||
@ -26,6 +25,8 @@ use EGroupware\Api;
|
||||
*/
|
||||
class StreamWrapper implements StreamWrapperIface
|
||||
{
|
||||
use UserContext;
|
||||
|
||||
/**
|
||||
* Scheme / protocol used for this stream-wrapper
|
||||
*/
|
||||
@ -39,12 +40,6 @@ class StreamWrapper implements StreamWrapperIface
|
||||
*/
|
||||
const HIDE_UNREADABLES = true;
|
||||
|
||||
/**
|
||||
* optional context param when opening the stream, null if no context passed
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
var $context;
|
||||
/**
|
||||
* mode-bits, which have to be set for links
|
||||
*/
|
||||
@ -174,7 +169,12 @@ class StreamWrapper implements StreamWrapperIface
|
||||
// if the url resolves to a symlink to the vfs, resolve this vfs:// url direct
|
||||
if ($url && Vfs::parse_url($url,PHP_URL_SCHEME) == self::SCHEME)
|
||||
{
|
||||
$user = Vfs::parse_url($url,PHP_URL_USER);
|
||||
$url = self::resolve_url(Vfs::parse_url($url,PHP_URL_PATH));
|
||||
if (!empty($user) && empty(parse_url($url, PHP_URL_USER)))
|
||||
{
|
||||
$url = str_replace('://', '://'.$user.'@', $url);
|
||||
}
|
||||
}
|
||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($path,file_exists=$file_exists,resolve_last_symlink=$resolve_last_symlink) = '$url'$log");
|
||||
return $url;
|
||||
@ -304,6 +304,8 @@ class StreamWrapper implements StreamWrapperIface
|
||||
unset($options,$opened_path); // not used but required by function signature
|
||||
$this->opened_stream = null;
|
||||
|
||||
error_log(__METHOD__."('$path', $mode, $options) context=".json_encode(stream_context_get_options($this->context)));
|
||||
|
||||
$stat = null;
|
||||
if (!($url = $this->resolve_url_symlinks($path,$mode[0]=='r',true,$stat)))
|
||||
{
|
||||
@ -313,8 +315,10 @@ class StreamWrapper implements StreamWrapperIface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!($this->opened_stream = $this->context ?
|
||||
fopen($url, $mode, false, $this->context) : fopen($url, $mode, false)))
|
||||
$this->check_set_context($url, true);
|
||||
|
||||
if (!($this->opened_stream = $context ?
|
||||
fopen($url, $mode, false, $context) : fopen($url, $mode, false)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -325,7 +329,7 @@ class StreamWrapper implements StreamWrapperIface
|
||||
|
||||
// are we requested to treat the opened file as new file (only for files opened NOT for reading)
|
||||
if ($mode[0] != 'r' && !$this->opened_stream_is_new && $this->context &&
|
||||
($opts = stream_context_get_params($this->context)) &&
|
||||
($opts = stream_context_get_options($this->context)) &&
|
||||
$opts['options'][self::SCHEME]['treat_as_new'])
|
||||
{
|
||||
$this->opened_stream_is_new = true;
|
||||
@ -538,10 +542,12 @@ class StreamWrapper implements StreamWrapperIface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// set user-context
|
||||
$this->check_set_context($url, true);
|
||||
$stat = $this->url_stat($path, STREAM_URL_STAT_LINK);
|
||||
|
||||
self::symlinkCache_remove($path);
|
||||
$ok = unlink($url);
|
||||
$ok = unlink($url, $this->context);
|
||||
|
||||
// call "vfs_unlink" hook only after successful unlink, with data from (not longer possible) stat call
|
||||
if ($ok && !class_exists('setup_process', false))
|
||||
@ -585,13 +591,16 @@ class StreamWrapper implements StreamWrapperIface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// set user-context
|
||||
$this->check_set_context($url_from);
|
||||
|
||||
// if file is moved from one filesystem / wrapper to an other --> copy it (rename fails cross wrappers)
|
||||
if (Vfs::parse_url($url_from,PHP_URL_SCHEME) == Vfs::parse_url($url_to,PHP_URL_SCHEME))
|
||||
{
|
||||
self::symlinkCache_remove($path_from);
|
||||
$ret = rename($url_from,$url_to);
|
||||
$ret = rename($url_from, $url_to, $this->context);
|
||||
}
|
||||
elseif (($from = fopen($url_from,'r')) && ($to = fopen($url_to,'w')))
|
||||
elseif (($from = fopen($url_from,'r', false, $this->context)) && ($to = fopen($url_to,'w')))
|
||||
{
|
||||
$ret = stream_copy_to_stream($from,$to) !== false;
|
||||
fclose($from);
|
||||
@ -642,6 +651,11 @@ class StreamWrapper implements StreamWrapperIface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// set user context
|
||||
if (Vfs::parse_url($url, PHP_URL_USER))
|
||||
{
|
||||
$this->check_set_context($url, true);
|
||||
}
|
||||
// check if recursive option is set and needed
|
||||
if (($options & STREAM_MKDIR_RECURSIVE) &&
|
||||
($parent_url = Vfs::dirname($url)) &&
|
||||
@ -660,7 +674,7 @@ class StreamWrapper implements StreamWrapperIface
|
||||
$options &= ~STREAM_MKDIR_RECURSIVE;
|
||||
}
|
||||
|
||||
$ret = mkdir($url,$mode,$options);
|
||||
$ret = mkdir($url, $mode, $options, $this->context);
|
||||
|
||||
// call "vfs_mkdir" hook
|
||||
if ($ret && !class_exists('setup_process', false))
|
||||
@ -702,8 +716,13 @@ class StreamWrapper implements StreamWrapperIface
|
||||
}
|
||||
$stat = $this->url_stat($path, STREAM_URL_STAT_LINK);
|
||||
|
||||
// set user context
|
||||
if (Vfs::parse_url($url, PHP_URL_USER))
|
||||
{
|
||||
$this->check_set_context($url, true);
|
||||
}
|
||||
self::symlinkCache_remove($path);
|
||||
$ok = rmdir($url);
|
||||
$ok = rmdir($url, $this->context);
|
||||
|
||||
// call "vfs_rmdir" hook, only after successful rmdir
|
||||
if ($ok && !class_exists('setup_process', false))
|
||||
@ -735,6 +754,9 @@ class StreamWrapper implements StreamWrapperIface
|
||||
if (self::LOG_LEVEL > 0) error_log(__METHOD__."( $path,$options) resolve_url_symlinks() failed!");
|
||||
return false;
|
||||
}
|
||||
// need to set user-context from resolved url
|
||||
$this->check_set_context($this->opened_dir_url, true);
|
||||
|
||||
if (!($this->opened_dir = $this->context ?
|
||||
opendir($this->opened_dir_url, $this->context) : opendir($this->opened_dir_url)))
|
||||
{
|
||||
@ -790,13 +812,22 @@ class StreamWrapper implements StreamWrapperIface
|
||||
*/
|
||||
function url_stat ( $path, $flags, $try_create_home=false, $check_symlink_components=true, $check_symlink_depth=self::MAX_SYMLINK_DEPTH, $try_reconnect=true )
|
||||
{
|
||||
// we have no context, but $path is a URL with a valid user --> set it
|
||||
$this->check_set_context($path);
|
||||
|
||||
if (!($url = self::resolve_url($path,!($flags & STREAM_URL_STAT_LINK), $check_symlink_components)))
|
||||
{
|
||||
if (self::LOG_LEVEL > 0) error_log(__METHOD__."('$path',$flags) can NOT resolve path!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty(parse_url($url, PHP_URL_USER)))
|
||||
{
|
||||
$url = str_replace('://', '://'.Api\Accounts::id2name($this->context ? stream_context_get_options($this->context)[self::SCHEME]['user'] : Vfs::$user).'@', $url);
|
||||
}
|
||||
|
||||
try {
|
||||
clearstatcache(); // testwise, NOT good for performance
|
||||
if ($flags & STREAM_URL_STAT_LINK)
|
||||
{
|
||||
$stat = @lstat($url); // suppressed the stat failed warnings
|
||||
@ -853,6 +884,7 @@ class StreamWrapper implements StreamWrapperIface
|
||||
// if numer of tries is exceeded, re-throw exception
|
||||
throw $e;
|
||||
}
|
||||
clearstatcache(); // testwise, NOT good for performance
|
||||
// check if a failed url_stat was for a home dir, in that case silently create it
|
||||
if (!$stat && $try_create_home && Vfs::dirname(Vfs::parse_url($path,PHP_URL_PATH)) == '/home' &&
|
||||
($id = $GLOBALS['egw']->accounts->name2id(Vfs::basename($path))) &&
|
||||
@ -901,6 +933,38 @@ class StreamWrapper implements StreamWrapperIface
|
||||
return $stat;*/
|
||||
}
|
||||
|
||||
/**
|
||||
* The stream_wrapper interface checks is_{readable|writable|executable} against the webservers uid,
|
||||
* which is wrong in case of our vfs, as we use the current users id and memberships
|
||||
*
|
||||
* @param string $path path
|
||||
* @param int $check mode to check: one or more or'ed together of: 4 = self::READABLE,
|
||||
* 2 = self::WRITABLE, 1 = self::EXECUTABLE
|
||||
* @return boolean
|
||||
*/
|
||||
function check_access($path, $check)
|
||||
{
|
||||
if (!($stat = $this->url_stat($path, 0)))
|
||||
{
|
||||
$ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (($account_lid = Vfs::parse_url($stat['url'], PHP_URL_USER)) &&
|
||||
($account_id = Api\Accounts::getInstance()->name2id($account_lid)))
|
||||
{
|
||||
$user = $account_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$user = $this->user ?: Vfs::$user;
|
||||
}
|
||||
$ret = Vfs::check_access($path, $check, $stat, $user);
|
||||
}
|
||||
error_log(__METHOD__."('$path', $check) user=".Api\Accounts::id2name($user).", effective user=$user=".Api\Accounts::id2name($user).", mode=".decoct($stat['mode'] & 0777).", uid=".($stat['uid']?Api\Accounts::id2name($stat['uid']):0).", uid=".($stat['gid']?Api\Accounts::id2name(-$stat['gid']):0)." returning ".array2string($ret));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if path (which fails the stat call) contains symlinks in path-components other then the last one
|
||||
*
|
||||
@ -1156,6 +1220,10 @@ class StreamWrapper implements StreamWrapperIface
|
||||
*/
|
||||
static function scheme2class($scheme)
|
||||
{
|
||||
if ($scheme === self::SCHEME)
|
||||
{
|
||||
return __CLASS__;
|
||||
}
|
||||
list($app, $app_scheme) = explode('.', $scheme);
|
||||
foreach(array(
|
||||
empty($app_scheme) ? 'EGroupware\\Api\\Vfs\\'.ucfirst($scheme).'\\StreamWrapper' : // streamwrapper in Api\Vfs
|
||||
@ -1329,12 +1397,19 @@ class StreamWrapper implements StreamWrapperIface
|
||||
if (in_array(self::SCHEME, stream_get_wrappers())) {
|
||||
stream_wrapper_unregister(self::SCHEME);
|
||||
}
|
||||
stream_register_wrapper(self::SCHEME,__CLASS__);
|
||||
stream_wrapper_register(self::SCHEME,__CLASS__);
|
||||
|
||||
if (($fstab = $GLOBALS['egw_info']['server']['vfs_fstab']) && is_array($fstab) && count($fstab))
|
||||
{
|
||||
self::$fstab = $fstab;
|
||||
}
|
||||
|
||||
// set default context for our schema ('vfs') with current user
|
||||
if (!($context = stream_context_get_options(stream_context_get_default())) || empty($context[self::SCHEME]['user']))
|
||||
{
|
||||
$context[self::SCHEME]['user'] = (int)$GLOBALS['egw_info']['user']['account_id'];
|
||||
stream_context_set_default($context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
119
api/src/Vfs/UserContext.php
Normal file
119
api/src/Vfs/UserContext.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware API: VFS - Trait to store user / account_id in stream context
|
||||
*
|
||||
* @link https://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2020 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Vfs;
|
||||
|
||||
use EGroupware\Api\Vfs;
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* Trait to store user / account_id in stream context
|
||||
*
|
||||
* Used by Vfs and SqlFS stream-wrapper.
|
||||
*
|
||||
* @property int $user user / account_id stored in context
|
||||
*/
|
||||
trait UserContext
|
||||
{
|
||||
/**
|
||||
* optional context param when opening the stream, null if no context passed
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
public $context;
|
||||
|
||||
/**
|
||||
* Contructor to set context/user incl. from user in url or passed in context
|
||||
*
|
||||
* @param resource|string|null $url_or_context url with user or context to set
|
||||
*/
|
||||
public function __construct($url_or_context=null)
|
||||
{
|
||||
if (is_resource($url_or_context))
|
||||
{
|
||||
$this->context = $url_or_context;
|
||||
}
|
||||
elseif(is_string($url_or_context))
|
||||
{
|
||||
$this->check_set_context($url_or_context, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have no user-context, but an url with a user --> set it as context
|
||||
*
|
||||
* @param $url
|
||||
* @param bool $always_set false (default): only set if we have not context or user in context, true: always set
|
||||
*/
|
||||
protected function check_set_context($url, $always_set=false)
|
||||
{
|
||||
if (($always_set || !$this->context || empty(stream_context_get_options($this->context)[Vfs::SCHEME]['user'])) &&
|
||||
$url[0] !== '/' && ($account_lid = Vfs::parse_url($url, PHP_URL_USER)))
|
||||
{
|
||||
$this->user = $account_lid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
switch($name)
|
||||
{
|
||||
case 'user':
|
||||
return $this->context ? stream_context_get_options($this->context)[Vfs::SCHEME]['user'] : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
switch($name)
|
||||
{
|
||||
case 'user':
|
||||
if (!is_int($value) && is_string($value) && !is_numeric($value))
|
||||
{
|
||||
$value = Api\Accounts::getInstance()->name2id($value);
|
||||
}
|
||||
if ($value)
|
||||
{
|
||||
$options = [
|
||||
Vfs::SCHEME => ['user' => (int)$value]
|
||||
];
|
||||
if ($this->context)
|
||||
{
|
||||
stream_context_set_option($this->context, $options);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->context = stream_context_create($options);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->__get($name) !== null;
|
||||
}
|
||||
}
|
43
vfs-context.php
Normal file
43
vfs-context.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use EGroupware\Api\Vfs;
|
||||
|
||||
$GLOBALS['egw_info'] = [
|
||||
'flags' => [
|
||||
'currentapp' => 'login',
|
||||
],
|
||||
];
|
||||
require_once __DIR__.'/header-default.inc.php';
|
||||
|
||||
$GLOBALS['egw_info']['user'] = [
|
||||
'account_id' => 5,
|
||||
'account_lid' => 'ralf',
|
||||
];
|
||||
|
||||
var_dump(Vfs\StreamWrapper::mount());
|
||||
|
||||
var_dump(file_put_contents('vfs://default/home/ralf/test.txt', "Just a test ;)\n"));
|
||||
|
||||
var_dump($f=fopen('vfs://default/home/ralf/test.txt', 'r'), fread($f, 100), fclose($f));
|
||||
|
||||
Vfs::$is_root = true;
|
||||
var_dump(file_put_contents('vfs://default/home/birgit/test.txt', "Just a test ;)\n"));
|
||||
var_dump(Vfs\StreamWrapper::mount('vfs://birgit@default/home/birgit', '/home/ralf/birgit'));
|
||||
Vfs::$is_root = false;
|
||||
|
||||
var_dump(Vfs\StreamWrapper::mount());
|
||||
|
||||
var_dump("Vfs::resolve_url('/home/ralf/birgit/test.txt')=".Vfs::resolve_url('/home/ralf/birgit/test.txt'));
|
||||
var_dump("Vfs::url_stat('/home/ralf/birgit/test.txt')=".json_encode(Vfs::stat('/home/ralf/birgit/test.txt'), JSON_UNESCAPED_SLASHES));
|
||||
var_dump("Vfs::is_readable('/home/ralf/birgit/test.txt')=".json_encode(Vfs::is_readable('/home/ralf/birgit/test.txt')));
|
||||
var_dump("fopen('vfs://default/home/ralf/birgit/test.txt', 'r')", $f=fopen('vfs://default/home/ralf/birgit/test.txt', 'r'), fread($f, 100), fclose($f));
|
||||
|
||||
var_dump("Vfs::url_stat('/home/ralf/birgit/test.txt')=".json_encode(Vfs::stat('/home/ralf/birgit/test-dir')));
|
||||
var_dump("Vfs::mkdir('/home/ralf/birgit/test-dir')=".json_encode(Vfs::mkdir('/home/ralf/birgit/test-dir')));
|
||||
var_dump("Vfs::url_stat('/home/ralf/birgit/test.txt')=".json_encode(Vfs::stat('/home/ralf/birgit/test-dir'), JSON_UNESCAPED_SLASHES));
|
||||
var_dump("Vfs::rmdir('/home/ralf/birgit/test-dir')=".json_encode(Vfs::rmdir('/home/ralf/birgit/test-dir')));
|
||||
var_dump("Vfs::url_stat('/home/ralf/birgit/test.txt')=".json_encode(Vfs::stat('/home/ralf/birgit/test-dir')));
|
||||
|
||||
var_dump("Vfs::scandir('/home/ralf/birgit')=".json_encode(Vfs::scandir('/home/ralf/birgit'), JSON_UNESCAPED_SLASHES));
|
||||
var_dump("Vfs::remove('/home/ralf/birgit/test.txt')=".json_encode(Vfs::remove('/home/ralf/birgit/test.txt')));
|
||||
var_dump("Vfs::scandir('/home/ralf/birgit')=".json_encode(Vfs::scandir('/home/ralf/birgit'), JSON_UNESCAPED_SLASHES));
|
Loading…
Reference in New Issue
Block a user