mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-22 07:53:39 +01:00
More improvments of the sqlfs code and the command line interface:
- read rights are not checks in each traversed directory (via sql in a single query to locate the path) - diropen additionally checks for execute rights - fopen checks for read or write depending on the mode - chmod, chgrp, chown methods in sqlfs and egw_vfs/vfs plus an egw_vfs::$is_root var used to grant root rights (no access controll and chown or chgrp without being the owner of a file) - find method (some more params to come) to recursivly search and optionaly execute some callback - egw_vfs::remove doing a "rm -r" / recursive remove or dirs and files - new files or dirs inherit the perms and ownership from the parent directory (no umask) - files/dirs the user has no read rights, in a directory where he has no write rights, get hidden (eg. not showing all the other users / groups home dirs - many new cli commands (chmod, chgrp, chown, find), recursive option for most commands and the ability to use it with root rights, see the usage message if called without options - "cp -r -p" to copy a whole tree incl. ownership and perms, eg. backing up /home to /backup
This commit is contained in:
parent
d81d9bce03
commit
8afe9094b7
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
chdir(dirname(__FILE__)); // to enable our relative pathes to work
|
chdir(dirname(__FILE__)); // to enable our relative pathes to work
|
||||||
|
|
||||||
|
error_reporting(error_reporting() & ~E_NOTICE);
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_HOST'])) // security precaution: forbit calling ls as web-page
|
if (isset($_SERVER['HTTP_HOST'])) // security precaution: forbit calling ls as web-page
|
||||||
{
|
{
|
||||||
die('<h1>'.basename(__FILE__).' must NOT be called as web-page --> exiting !!!</h1>');
|
die('<h1>'.basename(__FILE__).' must NOT be called as web-page --> exiting !!!</h1>');
|
||||||
@ -30,7 +32,7 @@ function user_pass_from_argv(&$account)
|
|||||||
//print_r($account);
|
//print_r($account);
|
||||||
if (!($sessionid = $GLOBALS['egw']->session->create($account)))
|
if (!($sessionid = $GLOBALS['egw']->session->create($account)))
|
||||||
{
|
{
|
||||||
echo "Wrong admin-account or -password !!!\n\n";
|
echo "Wrong user-account or -password !!!\n\n";
|
||||||
usage('',1);
|
usage('',1);
|
||||||
}
|
}
|
||||||
return $sessionid;
|
return $sessionid;
|
||||||
@ -45,19 +47,26 @@ function user_pass_from_argv(&$account)
|
|||||||
function usage($action=null,$ret=0)
|
function usage($action=null,$ret=0)
|
||||||
{
|
{
|
||||||
$cmd = basename(__FILE__);
|
$cmd = basename(__FILE__);
|
||||||
echo "Usage:\t$cmd URL [URL2 ...]\n";
|
echo "Usage:\t$cmd [-r|--recursive] URL [URL2 ...]\n";
|
||||||
echo "\t$cmd --cat URL [URL2 ...]\n";
|
echo "\t$cmd --cat URL [URL2 ...]\n";
|
||||||
echo "\t$cmd --cp URL-from URL-to\n";
|
echo "\t$cmd --cp [-r|--recursive] [-p|--perms] URL-from URL-to\n";
|
||||||
echo "\t$cmd --cp URL-from [URL-from2 ...] URL-to-directory\n";
|
echo "\t$cmd --cp [-r|--recursive] [-p|--perms] URL-from [URL-from2 ...] URL-to-directory\n";
|
||||||
echo "\t$cmd --rm URL [URL2 ...]\n";
|
echo "\t$cmd --rm [-r|--recursive] URL [URL2 ...]\n";
|
||||||
echo "\t$cmd --mkdir [-p|--parents] URL [URL2 ...]\n";
|
echo "\t$cmd --mkdir [-p|--parents] URL [URL2 ...]\n";
|
||||||
echo "\t$cmd --rmdir URL [URL2 ...]\n";
|
echo "\t$cmd --rmdir URL [URL2 ...]\n";
|
||||||
echo "\t$cmd --touch [-d|--date time] URL [URL2 ...]\n";
|
echo "\t$cmd --touch [-r|--recursive] [-d|--date time] URL [URL2 ...]\n";
|
||||||
echo "URL: oldvfs://user:password@domain/home/user/file, /dir/file, ...\n";
|
echo "\t$cmd --chmod [-r|--recursive] mode=[ugoa]*[+-=][rwx]+,... URL [URL2 ...]\n";
|
||||||
|
echo "\t$cmd --chown [-r|--recursive] user URL [URL2 ...]\n";
|
||||||
|
echo "\t$cmd --chgrp [-r|--recursive] group URL [URL2 ...]\n";
|
||||||
|
echo "\t$cmd --find URL [URL2 ...] [options to come]\n";
|
||||||
|
|
||||||
|
echo "\nURL: {vfs|sqlfs|oldvfs}://user:password@domain/home/user/file, /dir/file, ...\n";
|
||||||
|
|
||||||
|
echo "\nUse root_{header-admin|config-user} as user and according password for root access (no user specific access control and chown).\n\n";
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
$long = $numeric = $recursive = false;
|
$long = $numeric = $recursive = $perms = false;
|
||||||
$argv = $_SERVER['argv'];
|
$argv = $_SERVER['argv'];
|
||||||
$cmd = basename(array_shift($argv),'.php');
|
$cmd = basename(array_shift($argv),'.php');
|
||||||
|
|
||||||
@ -84,10 +93,20 @@ foreach($argv as $key => $option)
|
|||||||
continue 2; // switch is counting too!
|
continue 2; // switch is counting too!
|
||||||
|
|
||||||
case '-r': case '--recursive':
|
case '-r': case '--recursive':
|
||||||
case '-p': case '--parents':
|
|
||||||
$recursive = true;
|
$recursive = true;
|
||||||
continue 2; // switch is counting too!
|
continue 2; // switch is counting too!
|
||||||
|
|
||||||
|
case '-p': case '--parents': case '--perms':
|
||||||
|
if ($cmd == 'cp')
|
||||||
|
{
|
||||||
|
$perms = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$recursive = true;
|
||||||
|
}
|
||||||
|
continue 2; // switch is counting too!
|
||||||
|
|
||||||
case '-d': case '--date':
|
case '-d': case '--date':
|
||||||
$time = strtotime($argv[$key+1]);
|
$time = strtotime($argv[$key+1]);
|
||||||
unset($argv[$key+1]);
|
unset($argv[$key+1]);
|
||||||
@ -101,6 +120,10 @@ foreach($argv as $key => $option)
|
|||||||
case '--mkdir': // make directories
|
case '--mkdir': // make directories
|
||||||
case '--rename':// rename
|
case '--rename':// rename
|
||||||
case '--touch': // touch
|
case '--touch': // touch
|
||||||
|
case '--chmod': // chmod
|
||||||
|
case '--chown': // chown (requires root)
|
||||||
|
case '--chgrp': // chgrp
|
||||||
|
case '--find':
|
||||||
$cmd = substr($option,2);
|
$cmd = substr($option,2);
|
||||||
continue 2; // switch is counting too!
|
continue 2; // switch is counting too!
|
||||||
}
|
}
|
||||||
@ -110,8 +133,12 @@ $argc = count($argv);
|
|||||||
|
|
||||||
switch($cmd)
|
switch($cmd)
|
||||||
{
|
{
|
||||||
|
case 'find':
|
||||||
|
do_find($argv);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'cp':
|
case 'cp':
|
||||||
do_cp($argv);
|
do_cp($argv,$recursive,$perms);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'rename':
|
case 'rename':
|
||||||
@ -122,15 +149,26 @@ switch($cmd)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
while($url = array_shift($argv))
|
while($argv)
|
||||||
{
|
{
|
||||||
|
$url = array_shift($argv);
|
||||||
|
|
||||||
load_wrapper($url);
|
load_wrapper($url);
|
||||||
//echo "$cmd $url (long=".(int)$long.", numeric=".(int)$numeric.")\n";
|
//echo "$cmd $url (long=".(int)$long.", numeric=".(int)$numeric.")\n";
|
||||||
|
|
||||||
switch($cmd)
|
switch($cmd)
|
||||||
{
|
{
|
||||||
case 'rm':
|
case 'rm':
|
||||||
unlink($url);
|
if ($recursive && class_exists('egw_vfs'))
|
||||||
|
{
|
||||||
|
array_unshift($argv,$url);
|
||||||
|
egw_vfs::remove($argv);
|
||||||
|
$argv = array();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unlink($url);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'rmdir':
|
case 'rmdir':
|
||||||
@ -142,28 +180,106 @@ switch($cmd)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'touch':
|
case 'touch':
|
||||||
|
case 'chmod':
|
||||||
|
case 'chown':
|
||||||
|
case 'chgrp':
|
||||||
|
switch($cmd)
|
||||||
|
{
|
||||||
|
case 'touch':
|
||||||
|
$params = array($url,$time);
|
||||||
|
break;
|
||||||
|
case 'chmod':
|
||||||
|
if (!isset($mode))
|
||||||
|
{
|
||||||
|
$mode = $url; // first param is mode
|
||||||
|
$url = array_shift($argv);
|
||||||
|
}
|
||||||
|
if (parse_url($url,PHP_URL_SCHEME)) load_wrapper($url); // cant use stat or egw_vfs::mode2int otherwise!
|
||||||
|
|
||||||
|
if (strpos($mode,'+') !== false || strpos($mode,'-') !== false)
|
||||||
|
{
|
||||||
|
$stat = stat($url);
|
||||||
|
$set = $stat['mode'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$set = 0;
|
||||||
|
}
|
||||||
|
if (!class_exists('egw_vfs'))
|
||||||
|
{
|
||||||
|
die("chmod only implemented for eGW streams!"); // dont want to repeat the code here
|
||||||
|
}
|
||||||
|
$set = egw_vfs::mode2int($mode,$set);
|
||||||
|
$params = array($url,$set);
|
||||||
|
break;
|
||||||
|
case 'chown':
|
||||||
|
case 'chgrp':
|
||||||
|
$type = $cmd == 'chgrp' ? 'group' : 'user';
|
||||||
|
if (!isset($owner))
|
||||||
|
{
|
||||||
|
$owner = $url; // first param is owner/group
|
||||||
|
$url = array_shift($argv);
|
||||||
|
if (parse_url($url,PHP_URL_SCHEME)) load_wrapper($url); // we need the header loaded
|
||||||
|
if ($owner == 'root')
|
||||||
|
{
|
||||||
|
$owner = 0;
|
||||||
|
}
|
||||||
|
elseif (!is_numeric($owner))
|
||||||
|
{
|
||||||
|
if (!is_object($GLOBALS['egw']))
|
||||||
|
{
|
||||||
|
die("only numeric user/group-id's allowed for non eGW streams!");
|
||||||
|
}
|
||||||
|
if (!($owner = $GLOBALS['egw']->accounts->name2id($owner_was=$owner,'account_lid',$type[0])) ||
|
||||||
|
($owner < 0) != ($cmd == 'chgrp'))
|
||||||
|
{
|
||||||
|
die("Unknown $type '$owner_was'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif($owner && is_object($GLOBALS['egw']) && (!$GLOBALS['egw']->accounts->id2name($owner) ||
|
||||||
|
($owner < 0) != ($cmd == 'chgrp')))
|
||||||
|
{
|
||||||
|
die("Unknown $type '$owner_was'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$params = array($url,$owner);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (($scheme = parse_url($url,PHP_URL_SCHEME)))
|
if (($scheme = parse_url($url,PHP_URL_SCHEME)))
|
||||||
{
|
{
|
||||||
load_wrapper($url);
|
load_wrapper($url);
|
||||||
if (class_exists($class = $scheme.'_stream_wrapper') && method_exists($class,'touch'))
|
if (class_exists($class = $scheme.'_stream_wrapper') && method_exists($class,'touch'))
|
||||||
{
|
{
|
||||||
call_user_func(array($scheme.'_stream_wrapper','touch'),$url,$time);
|
$cmd = array($scheme.'_stream_wrapper',$cmd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
die("Can't touch for scheme $scheme!\n");
|
die("Can't $cmd for scheme $scheme!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
if ($recursive && class_exists('egw_vfs'))
|
||||||
{
|
{
|
||||||
touch($url,$time);
|
array_unshift($argv,$url);
|
||||||
|
$params = array($argv,null,$cmd,$params[1]);
|
||||||
|
$cmd = array('egw_vfs','find');
|
||||||
|
$argv = array(); // we processed all url's
|
||||||
}
|
}
|
||||||
|
//echo "calling cmd=".print_r($cmd,true).", params=".print_r($params,true)."\n";
|
||||||
|
call_user_func_array($cmd,$params);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'cat':
|
case 'cat':
|
||||||
case 'ls':
|
case 'ls':
|
||||||
default:
|
default:
|
||||||
if (is_dir($url) && ($dir = opendir($url)))
|
// recursive ls atm only for vfs://
|
||||||
|
if ($cmd != 'cat' && $recursive && class_exists('egw_vfs'))
|
||||||
|
{
|
||||||
|
load_wrapper($url);
|
||||||
|
array_unshift($argv,$url);
|
||||||
|
egw_vfs::find($argv,array('dirs_last'=>true),'do_stat',array($long,$numeric,true));
|
||||||
|
$argv = array();
|
||||||
|
}
|
||||||
|
elseif (is_dir($url) && ($dir = opendir($url)))
|
||||||
{
|
{
|
||||||
if ($argc)
|
if ($argc)
|
||||||
{
|
{
|
||||||
@ -235,7 +351,29 @@ function load_wrapper($url)
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
include('../header.inc.php');
|
if (substr($GLOBALS['egw_login_data']['login'],0,5) != 'root_')
|
||||||
|
{
|
||||||
|
include('../header.inc.php');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$GLOBALS['egw_info']['flags']['currentapp'] = 'login';
|
||||||
|
include('../header.inc.php');
|
||||||
|
|
||||||
|
if ($GLOBALS['egw_login_data']['login'] == 'root_'.$GLOBALS['egw_info']['server']['header_admin_user'] &&
|
||||||
|
_check_pw($GLOBALS['egw_info']['server']['header_admin_password'],$GLOBALS['egw_login_data']['passwd']) ||
|
||||||
|
$GLOBALS['egw_login_data']['login'] == 'root_'.$GLOBALS['egw_domain'][$_GET['domain']]['config_user'] &&
|
||||||
|
_check_pw($GLOBALS['egw_domain'][$_GET['domain']]['config_passwd'],$GLOBALS['egw_login_data']['passwd']))
|
||||||
|
{
|
||||||
|
echo "\nRoot access granted!\n";
|
||||||
|
egw_vfs::$is_root = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
die("Unknown user or password!\n");
|
||||||
|
}
|
||||||
|
set_exception_handler('cli_exception_handler'); // otherwise we get html!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
require_once(EGW_API_INC.'/class.'.$scheme.'_stream_wrapper.inc.php');
|
require_once(EGW_API_INC.'/class.'.$scheme.'_stream_wrapper.inc.php');
|
||||||
break;
|
break;
|
||||||
@ -250,6 +388,23 @@ function load_wrapper($url)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check password against a md5 hash or cleartext password
|
||||||
|
*
|
||||||
|
* @param string $hash_or_cleartext
|
||||||
|
* @param string $pw
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
function _check_pw($hash_or_cleartext,$pw)
|
||||||
|
{
|
||||||
|
//echo "_check_pw($hash_or_cleartext,$pw) md5=".md5($pw)."\n";
|
||||||
|
if (preg_match('/^[0-9a-f]{32}$/',$hash_or_cleartext))
|
||||||
|
{
|
||||||
|
return $hash_or_cleartext == md5($pw);
|
||||||
|
}
|
||||||
|
return $hash_or_cleartext == $pw;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Give the stats for one file
|
* Give the stats for one file
|
||||||
*
|
*
|
||||||
@ -257,16 +412,27 @@ function load_wrapper($url)
|
|||||||
* @param boolean $long=false true=long listing with owner,group,size,perms, default false only filename
|
* @param boolean $long=false true=long listing with owner,group,size,perms, default false only filename
|
||||||
* @param boolean $numeric=false true=give numeric uid&gid, else resolve the id to a name
|
* @param boolean $numeric=false true=give numeric uid&gid, else resolve the id to a name
|
||||||
*/
|
*/
|
||||||
function do_stat($url,$long=false,$numeric=false)
|
function do_stat($url,$long=false,$numeric=false,$full_path=false)
|
||||||
{
|
{
|
||||||
//echo "do_stat($url,$long,$numeric)\n";
|
//echo "do_stat($url,$long,$numeric,$full_path)\n";
|
||||||
$bname = basename(parse_url($url,PHP_URL_PATH));
|
$bname = parse_url($url,PHP_URL_PATH);
|
||||||
|
|
||||||
|
if (!$full_path)
|
||||||
|
{
|
||||||
|
$bname = basename($bname);
|
||||||
|
}
|
||||||
if ($long && ($stat = stat($url)))
|
if ($long && ($stat = stat($url)))
|
||||||
{
|
{
|
||||||
//print_r($stat);
|
//echo $url; print_r($stat);
|
||||||
|
|
||||||
$perms = verbosePerms($stat['mode']);
|
if (class_exists('egw_vfs'))
|
||||||
|
{
|
||||||
|
$perms = egw_vfs::int2mode($stat['mode']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$perms = int2mode($stat['mode']);
|
||||||
|
}
|
||||||
if ($numeric)
|
if ($numeric)
|
||||||
{
|
{
|
||||||
$uid = $stat['uid'];
|
$uid = $stat['uid'];
|
||||||
@ -276,14 +442,18 @@ function do_stat($url,$long=false,$numeric=false)
|
|||||||
{
|
{
|
||||||
if ($stat['uid'])
|
if ($stat['uid'])
|
||||||
{
|
{
|
||||||
$uid = isset($GLOBALS['egw']) ? $GLOBALS['egw']->accounts->id2name($stat['uid']) : posix_getpwuid($stat['uid']);
|
$uid = isset($GLOBALS['egw']) ? $GLOBALS['egw']->accounts->id2name($stat['uid']) :
|
||||||
|
(function_exists('posix_getpwuid') ? posix_getpwuid($stat['uid']) : $stat['uid']);
|
||||||
if (is_array($uid)) $uid = $uid['name'];
|
if (is_array($uid)) $uid = $uid['name'];
|
||||||
|
if (empty($uid)) $uid = $stat['uid'];
|
||||||
}
|
}
|
||||||
if (!isset($uid)) $uid = 'root';
|
if (!isset($uid)) $uid = 'root';
|
||||||
if ($stat['gid'])
|
if ($stat['gid'])
|
||||||
{
|
{
|
||||||
$gid = isset($GLOBALS['egw']) ? $GLOBALS['egw']->accounts->id2name(-abs($stat['gid'])) : posix_getgrgid($stat['gid']);
|
$gid = isset($GLOBALS['egw']) ? $GLOBALS['egw']->accounts->id2name(-abs($stat['gid'])) :
|
||||||
|
(function_exists('posix_getgrgid') ? posix_getgrgid($stat['gid']) : $stat['gid']);
|
||||||
if (is_array($gid)) $gid = $gid['name'];
|
if (is_array($gid)) $gid = $gid['name'];
|
||||||
|
if (empty($gid)) $gid = $stat['gid'];
|
||||||
}
|
}
|
||||||
if (!isset($gid)) $gid = 'root';
|
if (!isset($gid)) $gid = 'root';
|
||||||
}
|
}
|
||||||
@ -306,33 +476,147 @@ function hsize($size)
|
|||||||
return sprintf('%3.1lfM',(float)$size/(1024*1024));
|
return sprintf('%3.1lfM',(float)$size/(1024*1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
function verbosePerms( $in_Perms )
|
|
||||||
|
function do_cp($argv,$recursive=false,$perms=false)
|
||||||
{
|
{
|
||||||
if($in_Perms & 0x1000) // FIFO pipe
|
$to = array_pop($argv);
|
||||||
|
load_wrapper($to);
|
||||||
|
|
||||||
|
$to_exists = file_exists($to);
|
||||||
|
|
||||||
|
if (count($argv) > 1 && $to_exists && !is_dir($to))
|
||||||
|
{
|
||||||
|
usage(null,4);
|
||||||
|
}
|
||||||
|
foreach($argv as $from)
|
||||||
|
{
|
||||||
|
if (is_dir($from) && (!file_exists($to) || is_dir($to)) && $recursive && class_exists('egw_vfs'))
|
||||||
|
{
|
||||||
|
foreach(egw_vfs::find($from) as $f)
|
||||||
|
{
|
||||||
|
$t = $to.substr($f,strlen($from));
|
||||||
|
if (is_dir($f))
|
||||||
|
{
|
||||||
|
++$anz_dirs;
|
||||||
|
mkdir($t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++$anz_files;
|
||||||
|
_cp($f,$t);
|
||||||
|
}
|
||||||
|
if ($perms) _cp_perms($f,$t);
|
||||||
|
}
|
||||||
|
echo ($anz_dirs?"$anz_dirs dir(s) created and ":'')."$anz_files file(s) copied.\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_cp($from,$to,true);
|
||||||
|
if ($perms) _cp_perms($from,$to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _cp($from,$to,$verbose=false,$perms=false)
|
||||||
|
{
|
||||||
|
load_wrapper($from);
|
||||||
|
|
||||||
|
if (is_dir($to) || !file_exists($to) && is_dir($from) && $mkdir)
|
||||||
|
{
|
||||||
|
$path = parse_url($from,PHP_URL_PATH);
|
||||||
|
if (is_dir($to)) $to .= '/'.basename($path);
|
||||||
|
}
|
||||||
|
if (!($from_fp = fopen($from,'r')))
|
||||||
|
{
|
||||||
|
die("File $from not found!\n");
|
||||||
|
}
|
||||||
|
if (!($to_fp = fopen($to,'w')))
|
||||||
|
{
|
||||||
|
die("Can't open $to for writing!\n");
|
||||||
|
}
|
||||||
|
$count = stream_copy_to_stream($from_fp,$to_fp);
|
||||||
|
|
||||||
|
if ($verbose) echo hsize($count)." bytes written to $to\n";
|
||||||
|
|
||||||
|
fclose($from_fp);
|
||||||
|
|
||||||
|
if (!fclose($to_fp))
|
||||||
|
{
|
||||||
|
die("Error closing $to!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _cp_perms($from,$to)
|
||||||
|
{
|
||||||
|
if (($from_stat = stat($from)) && ($to_stat = stat($to)))
|
||||||
|
{
|
||||||
|
foreach(array(
|
||||||
|
'mode' => 'chmod',
|
||||||
|
'uid' => 'chown',
|
||||||
|
'gid' => 'chgrp',
|
||||||
|
) as $perm => $cmd)
|
||||||
|
{
|
||||||
|
if ($from_stat[$perm] != $to_stat[$perm])
|
||||||
|
{
|
||||||
|
//echo "egw_vfs::$cmd($to,{$from_stat[$perm]}\n";
|
||||||
|
call_user_func(array('egw_vfs',$cmd),$to,$from_stat[$perm]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_find($bases)
|
||||||
|
{
|
||||||
|
foreach($bases as $url)
|
||||||
|
{
|
||||||
|
load_wrapper($url);
|
||||||
|
}
|
||||||
|
foreach(egw_vfs::find($bases) as $path)
|
||||||
|
{
|
||||||
|
echo "$path\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cli_exception_handler(Exception $e)
|
||||||
|
{
|
||||||
|
echo $e->getMessage()."\n";
|
||||||
|
exit($e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a numerical mode to a symbolic mode-string
|
||||||
|
*
|
||||||
|
* @param int $mode
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function int2mode( $mode )
|
||||||
|
{
|
||||||
|
if($mode & 0x1000) // FIFO pipe
|
||||||
{
|
{
|
||||||
$sP = 'p';
|
$sP = 'p';
|
||||||
}
|
}
|
||||||
elseif($in_Perms & 0x2000) // Character special
|
elseif($mode & 0x2000) // Character special
|
||||||
{
|
{
|
||||||
$sP = 'c';
|
$sP = 'c';
|
||||||
}
|
}
|
||||||
elseif($in_Perms & 0x4000) // Directory
|
elseif($mode & 0x4000) // Directory
|
||||||
{
|
{
|
||||||
$sP = 'd';
|
$sP = 'd';
|
||||||
}
|
}
|
||||||
elseif($in_Perms & 0x6000) // Block special
|
elseif($mode & 0x6000) // Block special
|
||||||
{
|
{
|
||||||
$sP = 'b';
|
$sP = 'b';
|
||||||
}
|
}
|
||||||
elseif($in_Perms & 0x8000) // Regular
|
elseif($mode & 0x8000) // Regular
|
||||||
{
|
{
|
||||||
$sP = '-';
|
$sP = '-';
|
||||||
}
|
}
|
||||||
elseif($in_Perms & 0xA000) // Symbolic Link
|
elseif($mode & 0xA000) // Symbolic Link
|
||||||
{
|
{
|
||||||
$sP = 'l';
|
$sP = 'l';
|
||||||
}
|
}
|
||||||
elseif($in_Perms & 0xC000) // Socket
|
elseif($mode & 0xC000) // Socket
|
||||||
{
|
{
|
||||||
$sP = 's';
|
$sP = 's';
|
||||||
}
|
}
|
||||||
@ -342,66 +626,22 @@ function verbosePerms( $in_Perms )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// owner
|
// owner
|
||||||
$sP .= (($in_Perms & 0x0100) ? 'r' : '-') .
|
$sP .= (($mode & 0x0100) ? 'r' : '-') .
|
||||||
(($in_Perms & 0x0080) ? 'w' : '-') .
|
(($mode & 0x0080) ? 'w' : '-') .
|
||||||
(($in_Perms & 0x0040) ? (($in_Perms & 0x0800) ? 's' : 'x' ) :
|
(($mode & 0x0040) ? (($mode & 0x0800) ? 's' : 'x' ) :
|
||||||
(($in_Perms & 0x0800) ? 'S' : '-'));
|
(($mode & 0x0800) ? 'S' : '-'));
|
||||||
|
|
||||||
// group
|
// group
|
||||||
$sP .= (($in_Perms & 0x0020) ? 'r' : '-') .
|
$sP .= (($mode & 0x0020) ? 'r' : '-') .
|
||||||
(($in_Perms & 0x0010) ? 'w' : '-') .
|
(($mode & 0x0010) ? 'w' : '-') .
|
||||||
(($in_Perms & 0x0008) ? (($in_Perms & 0x0400) ? 's' : 'x' ) :
|
(($mode & 0x0008) ? (($mode & 0x0400) ? 's' : 'x' ) :
|
||||||
(($in_Perms & 0x0400) ? 'S' : '-'));
|
(($mode & 0x0400) ? 'S' : '-'));
|
||||||
|
|
||||||
// world
|
// world
|
||||||
$sP .= (($in_Perms & 0x0004) ? 'r' : '-') .
|
$sP .= (($mode & 0x0004) ? 'r' : '-') .
|
||||||
(($in_Perms & 0x0002) ? 'w' : '-') .
|
(($mode & 0x0002) ? 'w' : '-') .
|
||||||
(($in_Perms & 0x0001) ? (($in_Perms & 0x0200) ? 't' : 'x' ) :
|
(($mode & 0x0001) ? (($mode & 0x0200) ? 't' : 'x' ) :
|
||||||
(($in_Perms & 0x0200) ? 'T' : '-'));
|
(($mode & 0x0200) ? 'T' : '-'));
|
||||||
|
|
||||||
return $sP;
|
return $sP;
|
||||||
}
|
}
|
||||||
|
|
||||||
function do_cp($argv)
|
|
||||||
{
|
|
||||||
$to = array_pop($argv);
|
|
||||||
load_wrapper($to);
|
|
||||||
|
|
||||||
if (count($argv) > 1 && !is_dir($to))
|
|
||||||
{
|
|
||||||
usage(null,4);
|
|
||||||
}
|
|
||||||
if (count($argv) > 1)
|
|
||||||
{
|
|
||||||
foreach($argv as $from)
|
|
||||||
{
|
|
||||||
do_cp(array($from,$to));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$from = array_shift($argv);
|
|
||||||
load_wrapper($from);
|
|
||||||
|
|
||||||
if (!($from_fp = fopen($from,'r')))
|
|
||||||
{
|
|
||||||
die("File $from not found!\n");
|
|
||||||
}
|
|
||||||
if (is_dir($to))
|
|
||||||
{
|
|
||||||
$path = parse_url($from,PHP_URL_PATH);
|
|
||||||
$to .= '/'.basename($path);
|
|
||||||
}
|
|
||||||
if (!($to_fp = fopen($to,'w')))
|
|
||||||
{
|
|
||||||
die("Can't open $to for writing!\n");
|
|
||||||
}
|
|
||||||
$count = stream_copy_to_stream($from_fp,$to_fp);
|
|
||||||
|
|
||||||
echo hsize($count)." bytes written to $to\n";
|
|
||||||
|
|
||||||
fclose($from_fp);
|
|
||||||
|
|
||||||
if (!fclose($to_fp))
|
|
||||||
{
|
|
||||||
die("Error closing $to!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -59,9 +59,31 @@
|
|||||||
*/
|
*/
|
||||||
class egw_vfs extends vfs_stream_wrapper
|
class egw_vfs extends vfs_stream_wrapper
|
||||||
{
|
{
|
||||||
const EXECUTABLE = 4;
|
/**
|
||||||
const READABLE = 2;
|
* Readable bit, for dirs traversable
|
||||||
const WRITABLE = 1;
|
*/
|
||||||
|
const READABLE = 4;
|
||||||
|
/**
|
||||||
|
* Writable bit, for dirs delete or create files in that dir
|
||||||
|
*/
|
||||||
|
const WRITABLE = 2;
|
||||||
|
/**
|
||||||
|
* Excecutable bit, here only use to check if user is allowed to search dirs
|
||||||
|
*/
|
||||||
|
const EXECUTABLE = 1;
|
||||||
|
/**
|
||||||
|
* Current user has root rights, no access checks performed!
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
static $is_root = false;
|
||||||
|
/**
|
||||||
|
* Current user id, in case we ever change if away from $GLOBALS['egw_info']['user']['account_id']
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
static $user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fopen working on just the eGW VFS
|
* fopen working on just the eGW VFS
|
||||||
*
|
*
|
||||||
@ -188,6 +210,131 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find = recursive search over the filesystem
|
||||||
|
*
|
||||||
|
* @param string/array $base base of the search
|
||||||
|
* @param array $params=null
|
||||||
|
* @param string/array/true $exec=null function to call with each found file or dir as first param or
|
||||||
|
* true to return file => stat pairs
|
||||||
|
* @param array $exec_params=null further params for exec as array, path is always the first param!
|
||||||
|
* @return array of pathes if no $exec, otherwise path => stat pairs
|
||||||
|
*/
|
||||||
|
function find($base,$params=null,$exec=null,$exec_params=null)
|
||||||
|
{
|
||||||
|
//error_log(__METHOD__."(".print_r($base,true).",".print_r($params,true).",".print_r($exec,true).",".print_r($exec_params,true).")\n");
|
||||||
|
|
||||||
|
$type = $params['type']; // 'd' or 'f'
|
||||||
|
$dirs_last = $params['dirs_last']; // list dirs after the files they contain
|
||||||
|
|
||||||
|
if (!is_array($base))
|
||||||
|
{
|
||||||
|
$base = array($base);
|
||||||
|
}
|
||||||
|
foreach($base as $path)
|
||||||
|
{
|
||||||
|
// check our fstab if we need to add some of the mountpoints
|
||||||
|
$basepath = parse_url($path,PHP_URL_PATH);
|
||||||
|
foreach(self::$fstab as $mounted => $src_url)
|
||||||
|
{
|
||||||
|
if (dirname($mounted) == $basepath)
|
||||||
|
{
|
||||||
|
$base[] = $mounted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result = array();
|
||||||
|
foreach($base as $path)
|
||||||
|
{
|
||||||
|
/* if (($scheme = parse_url($path,PHP_URL_SCHEME)))
|
||||||
|
{
|
||||||
|
self::load_wrapper();
|
||||||
|
}*/
|
||||||
|
if (!$type || ($type[0]=='d') == is_dir($path))
|
||||||
|
{
|
||||||
|
if (!($stat = self::url_stat($path,0))) continue;
|
||||||
|
|
||||||
|
if (!$dirs_last || !is_dir($path))
|
||||||
|
{
|
||||||
|
$result[$path] = $stat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_dir($path) && ($dir = opendir($path)))
|
||||||
|
{
|
||||||
|
while($file = readdir($dir))
|
||||||
|
{
|
||||||
|
$file = $path.'/'.$file;
|
||||||
|
if (!$type || ($type[0]=='d') == is_dir($file))
|
||||||
|
{
|
||||||
|
if (!($stat = self::url_stat($file,0))) continue;
|
||||||
|
$result[$file] = $stat;
|
||||||
|
}
|
||||||
|
if (is_dir($file))
|
||||||
|
{
|
||||||
|
foreach(self::find($file,$params,true) as $p => $s)
|
||||||
|
{
|
||||||
|
unset($result[$p]);
|
||||||
|
$result[$p] = $s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir($dir);
|
||||||
|
|
||||||
|
if ($dirs_last)
|
||||||
|
{
|
||||||
|
$result[$path] = $stat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//_debug_array($result);
|
||||||
|
if ($exec !== true && is_callable($exec))
|
||||||
|
{
|
||||||
|
if (!is_array($exec_params))
|
||||||
|
{
|
||||||
|
$exec_params = is_null($exec_params) ? array() : array($exec_params);
|
||||||
|
}
|
||||||
|
foreach($result as $path => &$stat)
|
||||||
|
{
|
||||||
|
$params = $exec_params;
|
||||||
|
array_unshift($params,$path);
|
||||||
|
//echo "calling ".print_r($exec,true).print_r($params,true)."\n";
|
||||||
|
$stat = call_user_func_array($exec,$params);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
if ($exec !== true)
|
||||||
|
{
|
||||||
|
return array_keys($result);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursiv remove all given url's, including it's content if they are files
|
||||||
|
*
|
||||||
|
* @param string/array $urls url or array of url's
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
static function remove($urls)
|
||||||
|
{
|
||||||
|
return self::find($urls,array('dirs_last'=>true),array(__CLASS__,'_rm_rmdir'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for remove: either rmdir or unlink given url (depending if it's a dir or file)
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
static function _rm_rmdir($url)
|
||||||
|
{
|
||||||
|
if (is_dir($url))
|
||||||
|
{
|
||||||
|
return rmdir($url);
|
||||||
|
}
|
||||||
|
return unlink($url);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The stream_wrapper interface checks is_{readable|writable|executable} against the webservers uid,
|
* 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
|
* which is wrong in case of our vfs, as we use the current users id and memberships
|
||||||
@ -210,12 +357,17 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
* which is wrong in case of our vfs, as we use the current users id and memberships
|
* which is wrong in case of our vfs, as we use the current users id and memberships
|
||||||
*
|
*
|
||||||
* @param array $stat
|
* @param array $stat
|
||||||
* @param int $check mode to check: 4 = read, 2 = write, 1 = executable
|
* @param int $check mode to check: one or more or'ed together of: 4 = read, 2 = write, 1 = executable
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
static function check_access($stat,$check)
|
static function check_access($stat,$check)
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__."(stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check)");
|
//error_log(__METHOD__."(stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check)");
|
||||||
|
|
||||||
|
if (self::$is_root)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$stat)
|
if (!$stat)
|
||||||
{
|
{
|
||||||
@ -223,24 +375,24 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
return false; // file not found
|
return false; // file not found
|
||||||
}
|
}
|
||||||
// check if other rights grant access
|
// check if other rights grant access
|
||||||
if ($stat['mode'] & $check)
|
if (($stat['mode'] & $check) == $check)
|
||||||
{
|
{
|
||||||
error_log(__METHOD__."(stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via other rights!");
|
//error_log(__METHOD__."(stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via other rights!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// check if there's owner access and we are the owner
|
// check if there's owner access and we are the owner
|
||||||
if (($stat['mode'] & ($check << 6)) && $stat['uid'] && $stat['uid'] == $GLOBALS['egw_info']['user']['account_id'])
|
if (($stat['mode'] & ($check << 6)) == ($check << 6) && $stat['uid'] && $stat['uid'] == self::$user)
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__."(stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via owner rights!");
|
//error_log(__METHOD__."(stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via owner rights!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// check if there's a group access and we have the right membership
|
// check if there's a group access and we have the right membership
|
||||||
if (($stat['mode'] & ($check << 3)) && $stat['gid'])
|
if (($stat['mode'] & ($check << 3)) == ($check << 3) && $stat['gid'])
|
||||||
{
|
{
|
||||||
static $memberships;
|
static $memberships;
|
||||||
if (is_null($memberships))
|
if (is_null($memberships))
|
||||||
{
|
{
|
||||||
$memberships = $GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'],true);
|
$memberships = $GLOBALS['egw']->accounts->memberships(self::$user,true);
|
||||||
}
|
}
|
||||||
if (in_array(-abs($stat['gid']),$memberships))
|
if (in_array(-abs($stat['gid']),$memberships))
|
||||||
{
|
{
|
||||||
@ -285,4 +437,131 @@ class egw_vfs extends vfs_stream_wrapper
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a symbolic mode string or octal mode to an integer
|
||||||
|
*
|
||||||
|
* @param string/int $set comma separated mode string to set [ugo]+[+=-]+[rwx]+
|
||||||
|
* @param int $mode=0 current mode of the file, necessary for +/- operation
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
static function mode2int($set,$mode=0)
|
||||||
|
{
|
||||||
|
if (is_int($set)) // already an integer
|
||||||
|
{
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
if (is_numeric($set)) // octal string
|
||||||
|
{
|
||||||
|
//error_log(__METHOD__."($set,$mode) returning ".(int)base_convert($set,8,10));
|
||||||
|
return (int)base_convert($set,8,10); // convert octal to decimal
|
||||||
|
}
|
||||||
|
foreach(explode(',',$set) as $s)
|
||||||
|
{
|
||||||
|
if (!preg_match($use='/^([ugoa]*)([+=-]+)([rwx]+)$/',$s,$matches))
|
||||||
|
{
|
||||||
|
$use = str_replace(array('/','^','$','(',')'),'',$use);
|
||||||
|
throw new egw_exception_wrong_userinput("$s is not an allowed mode, use $use !");
|
||||||
|
}
|
||||||
|
$base = (strpos($matches[3],'r') !== false ? self::READABLE : 0) |
|
||||||
|
(strpos($matches[3],'w') !== false ? self::WRITABLE : 0) |
|
||||||
|
(strpos($matches[3],'x') !== false ? self::EXECUTABLE : 0);
|
||||||
|
|
||||||
|
for($n = $m = 0; $n < strlen($matches[1]); $n++)
|
||||||
|
{
|
||||||
|
switch($matches[1][$n])
|
||||||
|
{
|
||||||
|
case 'o':
|
||||||
|
$m |= $base;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
$m |= $base << 3;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
$m |= $base << 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case 'a':
|
||||||
|
$m = $base | ($base << 3) | ($base << 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch($matches[2])
|
||||||
|
{
|
||||||
|
case '+':
|
||||||
|
$mode |= $m;
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
$mode = $m;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
$mode &= ~$m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//error_log(__METHOD__."($set,) returning ".sprintf('%o',$mode));
|
||||||
|
return $mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a numerical mode to a symbolic mode-string
|
||||||
|
*
|
||||||
|
* @param int $mode
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function int2mode( $mode )
|
||||||
|
{
|
||||||
|
if($mode & 0x1000) // FIFO pipe
|
||||||
|
{
|
||||||
|
$sP = 'p';
|
||||||
|
}
|
||||||
|
elseif($mode & 0x2000) // Character special
|
||||||
|
{
|
||||||
|
$sP = 'c';
|
||||||
|
}
|
||||||
|
elseif($mode & 0x4000) // Directory
|
||||||
|
{
|
||||||
|
$sP = 'd';
|
||||||
|
}
|
||||||
|
elseif($mode & 0x6000) // Block special
|
||||||
|
{
|
||||||
|
$sP = 'b';
|
||||||
|
}
|
||||||
|
elseif($mode & 0x8000) // Regular
|
||||||
|
{
|
||||||
|
$sP = '-';
|
||||||
|
}
|
||||||
|
elseif($mode & 0xA000) // Symbolic Link
|
||||||
|
{
|
||||||
|
$sP = 'l';
|
||||||
|
}
|
||||||
|
elseif($mode & 0xC000) // Socket
|
||||||
|
{
|
||||||
|
$sP = 's';
|
||||||
|
}
|
||||||
|
else // UNKNOWN
|
||||||
|
{
|
||||||
|
$sP = 'u';
|
||||||
|
}
|
||||||
|
|
||||||
|
// owner
|
||||||
|
$sP .= (($mode & 0x0100) ? 'r' : '-') .
|
||||||
|
(($mode & 0x0080) ? 'w' : '-') .
|
||||||
|
(($mode & 0x0040) ? (($mode & 0x0800) ? 's' : 'x' ) :
|
||||||
|
(($mode & 0x0800) ? 'S' : '-'));
|
||||||
|
|
||||||
|
// group
|
||||||
|
$sP .= (($mode & 0x0020) ? 'r' : '-') .
|
||||||
|
(($mode & 0x0010) ? 'w' : '-') .
|
||||||
|
(($mode & 0x0008) ? (($mode & 0x0400) ? 's' : 'x' ) :
|
||||||
|
(($mode & 0x0400) ? 'S' : '-'));
|
||||||
|
|
||||||
|
// world
|
||||||
|
$sP .= (($mode & 0x0004) ? 'r' : '-') .
|
||||||
|
(($mode & 0x0002) ? 'w' : '-') .
|
||||||
|
(($mode & 0x0001) ? (($mode & 0x0200) ? 't' : 'x' ) :
|
||||||
|
(($mode & 0x0200) ? 'T' : '-'));
|
||||||
|
|
||||||
|
return $sP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
egw_vfs::$user = (int) $GLOBALS['egw_info']['user']['account_id'];
|
||||||
|
@ -31,10 +31,6 @@
|
|||||||
*/
|
*/
|
||||||
class sqlfs_stream_wrapper implements iface_stream_wrapper
|
class sqlfs_stream_wrapper implements iface_stream_wrapper
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* If this class should do the operations direct in the filesystem, instead of going through the vfs
|
|
||||||
*/
|
|
||||||
const USE_FILESYSTEM_DIRECT = true;
|
|
||||||
/**
|
/**
|
||||||
* Mime type of directories, the old vfs uses 'Directory', while eg. WebDAV uses 'httpd/unix-directory'
|
* Mime type of directories, the old vfs uses 'Directory', while eg. WebDAV uses 'httpd/unix-directory'
|
||||||
*/
|
*/
|
||||||
@ -193,12 +189,15 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
$values = array(
|
$values = array(
|
||||||
'fs_name' => basename($path),
|
'fs_name' => basename($path),
|
||||||
'fs_dir' => $dir_stat['ino'],
|
'fs_dir' => $dir_stat['ino'],
|
||||||
|
// we use the mode of the dir, so files in group dirs stay accessible by all members
|
||||||
'fs_mode' => $dir_stat['mode'] & 0666,
|
'fs_mode' => $dir_stat['mode'] & 0666,
|
||||||
'fs_uid' => $dir_stat['uid'],
|
// 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'] : egw_vfs::$user,
|
||||||
|
// we allways use the group of the dir
|
||||||
'fs_gid' => $dir_stat['gid'],
|
'fs_gid' => $dir_stat['gid'],
|
||||||
'fs_created' => self::_pdo_timestamp(time()),
|
'fs_created' => self::_pdo_timestamp(time()),
|
||||||
'fs_modified' => self::_pdo_timestamp(time()),
|
'fs_modified' => self::_pdo_timestamp(time()),
|
||||||
'fs_creator' => $GLOBALS['egw_info']['user']['account_id'],
|
'fs_creator' => egw_vfs::$user,
|
||||||
);
|
);
|
||||||
foreach($values as $name => &$val)
|
foreach($values as $name => &$val)
|
||||||
{
|
{
|
||||||
@ -529,8 +528,19 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)");
|
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)");
|
||||||
|
|
||||||
$path = parse_url($url,PHP_URL_PATH);
|
$path = parse_url($url,PHP_URL_PATH);
|
||||||
|
|
||||||
|
if (self::url_stat($path,STREAM_URL_STAT_QUIET))
|
||||||
|
{
|
||||||
|
self::_remove_password($url);
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) already exist!");
|
||||||
|
if (!($options & STREAM_URL_STAT_QUIET))
|
||||||
|
{
|
||||||
|
trigger_error(__METHOD__."('$url',$mode,$options) already exist!",E_USER_WARNING);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$parent = self::url_stat(dirname($path),0);
|
$parent = self::url_stat(dirname($path),STREAM_URL_STAT_QUIET);
|
||||||
|
|
||||||
// check if we should also create all non-existing path components and our parent does not exist,
|
// check if we should also create all non-existing path components and our parent does not exist,
|
||||||
// if yes call ourself recursive with the parent directory
|
// if yes call ourself recursive with the parent directory
|
||||||
@ -545,7 +555,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
if (!$parent || !egw_vfs::check_access($parent,egw_vfs::WRITABLE))
|
if (!$parent || !egw_vfs::check_access($parent,egw_vfs::WRITABLE))
|
||||||
{
|
{
|
||||||
self::_remove_password($url);
|
self::_remove_password($url);
|
||||||
if (self::LOG_LEVEL) error_log(__METHOD__."($url) permission denied!");
|
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) permission denied!");
|
||||||
if (!($options & STREAM_URL_STAT_QUIET))
|
if (!($options & STREAM_URL_STAT_QUIET))
|
||||||
{
|
{
|
||||||
trigger_error(__METHOD__."('$url',$mode,$options) permission denied!",E_USER_WARNING);
|
trigger_error(__METHOD__."('$url',$mode,$options) permission denied!",E_USER_WARNING);
|
||||||
@ -564,7 +574,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
':fs_mime' => self::DIR_MIME_TYPE,
|
':fs_mime' => self::DIR_MIME_TYPE,
|
||||||
':fs_created' => self::_pdo_timestamp(time()),
|
':fs_created' => self::_pdo_timestamp(time()),
|
||||||
':fs_modified' => self::_pdo_timestamp(time()),
|
':fs_modified' => self::_pdo_timestamp(time()),
|
||||||
':fs_creator' => $GLOBALS['egw_info']['user']['account_id'],
|
':fs_creator' => egw_vfs::$user,
|
||||||
))) && $operation == self::STORE2FS)
|
))) && $operation == self::STORE2FS)
|
||||||
{
|
{
|
||||||
mkdir(self::_fs_path($path));
|
mkdir(self::_fs_path($path));
|
||||||
@ -634,9 +644,20 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
|
|
||||||
$path = parse_url($url,PHP_URL_PATH);
|
$path = parse_url($url,PHP_URL_PATH);
|
||||||
|
|
||||||
if (!($stat = self::url_stat($path,0)))
|
if (!($stat = self::url_stat($path,STREAM_URL_STAT_QUIET)))
|
||||||
{
|
{
|
||||||
return false;
|
// file does not exist --> create an empty one
|
||||||
|
if (($f = fopen(self::SCHEME.'://default'.$path,'w')) && fclose($f))
|
||||||
|
{
|
||||||
|
if (!is_null($time))
|
||||||
|
{
|
||||||
|
$stat = self::url_stat($path,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_modified=:fs_modified WHERE fs_id=:fs_id');
|
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_modified=:fs_modified WHERE fs_id=:fs_id');
|
||||||
|
|
||||||
@ -645,10 +666,131 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
':fs_id' => $stat['ino'],
|
':fs_id' => $stat['ino'],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chown command, not yet a stream-wrapper function, but necessary
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param int $owner
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
static function chown($url,$owner)
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$owner)");
|
||||||
|
|
||||||
|
$path = parse_url($url,PHP_URL_PATH);
|
||||||
|
|
||||||
|
if (!($stat = self::url_stat($path,0)))
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) no such file or directory!");
|
||||||
|
trigger_error("No such file or directory $url !",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!egw_vfs::$is_root)
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) only root can do that!");
|
||||||
|
trigger_error("Only root can do that!",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($owner < 0 || !$GLOBALS['egw']->accounts->id2name($owner)) // not a user
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) unknown (numeric) user id!");
|
||||||
|
trigger_error("Unknown (numeric) user id!",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_uid=:fs_uid WHERE fs_id=:fs_id');
|
||||||
|
|
||||||
|
return $stmt->execute(array(
|
||||||
|
':fs_uid' => (int) $owner,
|
||||||
|
':fs_id' => $stat['ino'],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chgrp command, not yet a stream-wrapper function, but necessary
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param int $group
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
static function chgrp($url,$owner)
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$owner)");
|
||||||
|
|
||||||
|
$path = parse_url($url,PHP_URL_PATH);
|
||||||
|
|
||||||
|
if (!($stat = self::url_stat($path,0)))
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) no such file or directory!");
|
||||||
|
trigger_error("No such file or directory $url !",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!egw_vfs::$is_root && $stat['uid'] != egw_vfs::$user)
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) only owner or root can do that!");
|
||||||
|
trigger_error("Only owner or root can do that!",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($owner < 0) $owner = -$owner; // sqlfs uses a positiv group id's!
|
||||||
|
|
||||||
|
if ($owner && !$GLOBALS['egw']->accounts->id2name(-$owner)) // not a group
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) unknown (numeric) group id!");
|
||||||
|
trigger_error("Unknown (numeric) group id!",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_gid=:fs_gid WHERE fs_id=:fs_id');
|
||||||
|
|
||||||
|
return $stmt->execute(array(
|
||||||
|
':fs_gid' => $owner,
|
||||||
|
':fs_id' => $stat['ino'],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chmod command, not yet a stream-wrapper function, but necessary
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param int $mode
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
static function chmod($url,$mode)
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$owner)");
|
||||||
|
|
||||||
|
$path = parse_url($url,PHP_URL_PATH);
|
||||||
|
|
||||||
|
if (!($stat = self::url_stat($path,0)))
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) no such file or directory!");
|
||||||
|
trigger_error("No such file or directory $url !",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!egw_vfs::$is_root && $stat['uid'] != egw_vfs::$user)
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) only owner or root can do that!");
|
||||||
|
trigger_error("Only owner or root can do that!",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!is_numeric($mode)) // not a mode
|
||||||
|
{
|
||||||
|
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$owner) no (numeric) mode!");
|
||||||
|
trigger_error("No (numeric) mode!",E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_mode=:fs_mode WHERE fs_id=:fs_id');
|
||||||
|
|
||||||
|
return $stmt->execute(array(
|
||||||
|
':fs_mode' => ((int) $mode) & 0777, // we dont store the file and dir bits, give int overflow!
|
||||||
|
':fs_id' => $stat['ino'],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called immediately when your stream object is created for examining directory contents with opendir().
|
* This method is called immediately when your stream object is created for examining directory contents with opendir().
|
||||||
*
|
*
|
||||||
|
* @ToDo check all parent dirs for readable (fastest would be with sql query) !!!
|
||||||
* @param string $path URL that was passed to opendir() and that this object is expected to explore.
|
* @param string $path URL that was passed to opendir() and that this object is expected to explore.
|
||||||
* @param $options
|
* @param $options
|
||||||
* @return booelan
|
* @return booelan
|
||||||
@ -663,7 +805,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
|
|
||||||
if (!($stat = self::url_stat($url,0)) || // dir not found
|
if (!($stat = self::url_stat($url,0)) || // dir not found
|
||||||
$stat['mime'] != self::DIR_MIME_TYPE || // no dir
|
$stat['mime'] != self::DIR_MIME_TYPE || // no dir
|
||||||
!egw_vfs::check_access($stat,egw_vfs::EXECUTABLE)) // no access
|
!egw_vfs::check_access($stat,egw_vfs::EXECUTABLE|egw_vfs::READABLE)) // no access
|
||||||
{
|
{
|
||||||
self::_remove_password($url);
|
self::_remove_password($url);
|
||||||
$msg = $stat['mime'] != self::DIR_MIME_TYPE ? "$url is no directory" : 'permission denied';
|
$msg = $stat['mime'] != self::DIR_MIME_TYPE ? "$url is no directory" : 'permission denied';
|
||||||
@ -672,7 +814,13 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
self::$stat_cache = $this->opened_dir = array();
|
self::$stat_cache = $this->opened_dir = array();
|
||||||
$stmt = self::$pdo->prepare('SELECT fs_id,fs_name,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified FROM '.self::TABLE.' WHERE fs_dir=?');
|
$query = 'SELECT fs_id,fs_name,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified FROM '.self::TABLE.' WHERE fs_dir=?';
|
||||||
|
// only return readable files, if dir is not writable by user
|
||||||
|
if (!egw_vfs::check_access($stat,egw_vfs::WRITABLE))
|
||||||
|
{
|
||||||
|
$query .= ' AND '.self::_sql_readable();
|
||||||
|
}
|
||||||
|
$stmt = self::$pdo->prepare($query);
|
||||||
$stmt->setFetchMode(PDO::FETCH_ASSOC);
|
$stmt->setFetchMode(PDO::FETCH_ASSOC);
|
||||||
if ($stmt->execute(array($stat['ino'])))
|
if ($stmt->execute(array($stat['ino'])))
|
||||||
{
|
{
|
||||||
@ -741,11 +889,17 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
{
|
{
|
||||||
if ($n == 0)
|
if ($n == 0)
|
||||||
{
|
{
|
||||||
$query = 1; // / always has fs_id == 1, no need to query it
|
$query = (int) ($path != '/'); // / always has fs_id == 1, no need to query it ($path=='/' needs fs_dir=0!)
|
||||||
}
|
}
|
||||||
elseif ($n < count($parts)-1)
|
elseif ($n < count($parts)-1)
|
||||||
{
|
{
|
||||||
$query = 'SELECT fs_id FROM '.self::TABLE.' WHERE fs_dir=('.$query.') AND fs_name='.self::$pdo->quote($name);
|
$query = 'SELECT fs_id FROM '.self::TABLE.' WHERE fs_dir=('.$query.') AND fs_name='.self::$pdo->quote($name);
|
||||||
|
|
||||||
|
// if we are not root, we need to make sure the user has the right to tranverse all partent directories (read-rights)
|
||||||
|
if (!egw_vfs::$is_root)
|
||||||
|
{
|
||||||
|
$query .= ' AND '.$sql_read_acl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -757,7 +911,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
if (!($result = self::$pdo->query($query)) || !($info = $result->fetch(PDO::FETCH_ASSOC)))
|
if (!($result = self::$pdo->query($query)) || !($info = $result->fetch(PDO::FETCH_ASSOC)))
|
||||||
{
|
{
|
||||||
self::_remove_password($url);
|
self::_remove_password($url);
|
||||||
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$flags) file or directory not found!");
|
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$flags) file or directory not found!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
self::$stat_cache[$path] = $info;
|
self::$stat_cache[$path] = $info;
|
||||||
@ -765,6 +919,27 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
return self::_vfsinfo2stat($info);
|
return self::_vfsinfo2stat($info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return readable check as sql (to be AND'ed into the query), only use if !egw_vfs::$is_root
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function _sql_readable()
|
||||||
|
{
|
||||||
|
static $sql_read_acl;
|
||||||
|
|
||||||
|
if (is_null($sql_read_acl))
|
||||||
|
{
|
||||||
|
foreach($GLOBALS['egw']->accounts->memberships(egw_vfs::$user,true) as $gid)
|
||||||
|
{
|
||||||
|
$memberships[] = abs($gid); // sqlfs stores the gid's positiv
|
||||||
|
}
|
||||||
|
$sql_read_acl = '(fs_mode & 04 OR fs_mode & 0400 AND fs_uid='.(int)egw_vfs::$user.
|
||||||
|
' OR fs_mode & 040 AND fs_gid IN('.implode(',',$memberships).'))';
|
||||||
|
}
|
||||||
|
return $sql_read_acl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called in response to readdir().
|
* This method is called in response to readdir().
|
||||||
*
|
*
|
||||||
|
@ -63,6 +63,18 @@ class vfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
* @var ressource
|
* @var ressource
|
||||||
*/
|
*/
|
||||||
private $opened_dir;
|
private $opened_dir;
|
||||||
|
/**
|
||||||
|
* URL of the opened dir, used to build the complete URL of files in the dir
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $opened_dir_url;
|
||||||
|
/**
|
||||||
|
* Flag if opened dir is writable, in which case we return un-readable entries too
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private $opened_dir_writable;
|
||||||
/**
|
/**
|
||||||
* Extra dirs from our fstab in the current opened dir
|
* Extra dirs from our fstab in the current opened dir
|
||||||
*
|
*
|
||||||
@ -357,28 +369,93 @@ class vfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is not (yet) a stream-wrapper function, but it's necessary and can be used static
|
* Allow to call methods of the underlying stream wrapper: touch, chmod, chgrp, chown, ...
|
||||||
|
*
|
||||||
|
* We cant use a magic __call() method, as it does not work for static methods!
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $name
|
||||||
* @param int $time=null modification time (unix timestamp), default null = current time
|
* @param array $params first param has to be the path, otherwise we can not determine the correct wrapper
|
||||||
* @param int $atime=null access time (unix timestamp), default null = current time, not implemented in the vfs!
|
|
||||||
*/
|
*/
|
||||||
static function touch($path,$time=null,$atime=null)
|
static private function _call_on_backend($name,$params)
|
||||||
{
|
{
|
||||||
if (!($url = self::resolve_url($path)))
|
$path = $params[0];
|
||||||
|
|
||||||
|
if (!($url = self::resolve_url($params[0])))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (($scheme = parse_url($url,PHP_URL_SCHEME)))
|
if (($scheme = parse_url($url,PHP_URL_SCHEME)))
|
||||||
{
|
{
|
||||||
if (!class_exists($class = $scheme.'_stream_wrapper') || !method_exists($class,'touch'))
|
if (!class_exists($class = $scheme.'_stream_wrapper') || !method_exists($class,$name))
|
||||||
{
|
{
|
||||||
trigger_error("Can't touch for scheme $scheme!\n",E_USER_WARNING);
|
trigger_error("Can't $name for scheme $scheme!\n",E_USER_WARNING);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return call_user_func(array($scheme.'_stream_wrapper','touch'),$url,$time);
|
$params[0] = $url;
|
||||||
|
|
||||||
|
return call_user_func_array(array($scheme.'_stream_wrapper',$name),$params);
|
||||||
}
|
}
|
||||||
return touch($url,$time);
|
// call the filesystem specific function
|
||||||
|
if (!function_exists($name))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $name($url,$time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not (yet) a stream-wrapper function, but it's necessary and can be used static
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param int $time=null modification time (unix timestamp), default null = current time
|
||||||
|
* @param int $atime=null access time (unix timestamp), default null = current time, not implemented in the vfs!
|
||||||
|
* @return boolean true on success, false otherwise
|
||||||
|
*/
|
||||||
|
static function touch($path,$time=null,$atime=null)
|
||||||
|
{
|
||||||
|
return self::_call_on_backend('touch',array($path,$time,$atime));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not (yet) a stream-wrapper function, but it's necessary and can be used static
|
||||||
|
*
|
||||||
|
* Requires owner or root rights!
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param string $mode mode string see egw_vfs::mode2int
|
||||||
|
* @return boolean true on success, false otherwise
|
||||||
|
*/
|
||||||
|
static function chmod($path,$mode)
|
||||||
|
{
|
||||||
|
return self::_call_on_backend('chmod',array($path,$mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not (yet) a stream-wrapper function, but it's necessary and can be used static
|
||||||
|
*
|
||||||
|
* Requires root rights!
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param int $owner numeric user id
|
||||||
|
* @return boolean true on success, false otherwise
|
||||||
|
*/
|
||||||
|
static function chown($path,$owner)
|
||||||
|
{
|
||||||
|
return self::_call_on_backend('chown',array($path,$owner));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not (yet) a stream-wrapper function, but it's necessary and can be used static
|
||||||
|
*
|
||||||
|
* Requires owner or root rights!
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param int $group numeric group id
|
||||||
|
* @return boolean true on success, false otherwise
|
||||||
|
*/
|
||||||
|
static function chgrp($path,$group)
|
||||||
|
{
|
||||||
|
return self::_call_on_backend('chgrp',array($path,$group));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -434,7 +511,7 @@ class vfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
//error_log(__METHOD__."($path) mime=$mime");
|
//error_log(__METHOD__."($path) mime=$mime");
|
||||||
return $mime;
|
return $mime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called immediately when your stream object is created for examining directory contents with opendir().
|
* This method is called immediately when your stream object is created for examining directory contents with opendir().
|
||||||
*
|
*
|
||||||
@ -446,16 +523,18 @@ class vfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
$this->opened_dir = $this->extra_dirs = null;
|
$this->opened_dir = $this->extra_dirs = null;
|
||||||
$this->extra_dir_ptr = 0;
|
$this->extra_dir_ptr = 0;
|
||||||
|
|
||||||
if (!($url = self::resolve_url($path)))
|
if (!($this->opened_dir_url = self::resolve_url($path)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!($this->opened_dir = opendir($url)))
|
if (!($this->opened_dir = opendir($this->opened_dir_url)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$this->opened_dir_writable = ($stat = @stat($this->opened_dir_url)) && egw_vfs::check_access($stat,egw_vfs::WRITABLE);
|
||||||
|
|
||||||
// check our fstab if we need to add some of the mountpoints
|
// check our fstab if we need to add some of the mountpoints
|
||||||
$basepath = parse_url($url,PHP_URL_PATH);
|
$basepath = parse_url($this->opened_dir_url,PHP_URL_PATH);
|
||||||
foreach(self::$fstab as $mounted => $nul)
|
foreach(self::$fstab as $mounted => $nul)
|
||||||
{
|
{
|
||||||
if (dirname($mounted) == $basepath)
|
if (dirname($mounted) == $basepath)
|
||||||
@ -500,8 +579,8 @@ class vfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
error_log(__METHOD__."('$path',$flags) calling stat($url)");
|
//error_log(__METHOD__."('$path',$flags) calling stat($url)");
|
||||||
return stat($url);
|
return @stat($url); // suppressed the stat failed warnings
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -509,6 +588,9 @@ class vfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
*
|
*
|
||||||
* It should return a string representing the next filename in the location opened by dir_opendir().
|
* It should return a string representing the next filename in the location opened by dir_opendir().
|
||||||
*
|
*
|
||||||
|
* Unless other filesystem, we only return files readable by the user, if the dir is not writable for him.
|
||||||
|
* This is done to hide files and dirs not accessible by the user (eg. other peoples home-dirs in /home).
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function dir_readdir ( )
|
function dir_readdir ( )
|
||||||
@ -517,7 +599,18 @@ class vfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
{
|
{
|
||||||
return $this->extra_dirs[$this->extra_dir_ptr++];
|
return $this->extra_dirs[$this->extra_dir_ptr++];
|
||||||
}
|
}
|
||||||
return readdir($this->opened_dir);
|
// only return children readable by the user, if dir is not writable
|
||||||
|
do {
|
||||||
|
if (($file = readdir($this->opened_dir)) !== false && !$this->opened_dir_writable)
|
||||||
|
{
|
||||||
|
$stat = stat($this->opened_dir_url.'/'.$file);
|
||||||
|
}
|
||||||
|
//echo __METHOD__."() opened_dir_writable=$this->opened_dir_writable, file=$file, readable=".(int)egw_vfs::check_access($stat,egw_vfs::READABLE).", loop=".
|
||||||
|
// (int)($file !== false && $stat && !egw_vfs::check_access($stat,egw_vfs::READABLE))."\n";
|
||||||
|
}
|
||||||
|
while($file !== false && $stat && !egw_vfs::check_access($stat,egw_vfs::READABLE));
|
||||||
|
|
||||||
|
return $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user