- unlink/mkdir/rmdir methods

- caching the information for dir_open vfs_sql::ls() to use it in url_stat, to not read it again from the db
- implemented a static touch method, which is not (yet) part of the stream-wrapper interface
This commit is contained in:
Ralf Becker 2008-01-30 06:47:53 +00:00
parent fbc8aa7be7
commit 399e087f2c
3 changed files with 388 additions and 131 deletions

View File

@ -18,25 +18,6 @@ if (isset($_SERVER['HTTP_HOST'])) // security precaution: forbit calling ls as w
die('<h1>'.basename(__FILE__).' must NOT be called as web-page --> exiting !!!</h1>');
}
/*
// this is kind of a hack, as the autocreate_session_callback can not change the type of the loaded account-class
// so we need to make sure the right one is loaded by setting the domain before the header gets included.
$arg0s = explode(',',@$arguments[0]);
@list(,$_GET['domain']) = explode('@',$arg0s[0]);
if (is_dir('/tmp')) ini_set('session.save_path','/tmp'); // regular users may have no rights to apache's session dir
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => 'admin',
'noheader' => true,
'autocreate_session_callback' => 'user_pass_from_argv',
)
);
include('../header.inc.php');
*/
/**
* callback if the session-check fails, redirects via xajax to login.php
*
@ -64,14 +45,19 @@ function user_pass_from_argv(&$account)
function usage($action=null,$ret=0)
{
$cmd = basename(__FILE__);
echo "Usage: $cmd URL\n";
echo "\t$cmd --cat URL\n";
echo "Usage:\t$cmd URL [URL2 ...]\n";
echo "\t$cmd --cat URL [URL2 ...]\n";
echo "\t$cmd --cp URL-from URL-to\n";
echo "\t$cmd --cp URL-from1 [URL-from2 ...] URL-to-directory\n";
echo "\t$cmd --cp URL-from [URL-from2 ...] URL-to-directory\n";
echo "\t$cmd --rm URL [URL2 ...]\n";
echo "\t$cmd --mkdir [-p|--parents] URL [URL2 ...]\n";
echo "\t$cmd --rmdir URL [URL2 ...]\n";
echo "\t$cmd --touch [-d|--date time] URL [URL2 ...]\n";
echo "URL: oldvfs://user:password@domain/home/user/file, /dir/file, ...\n";
exit;
}
$long = $numeric = false;
$long = $numeric = $recursive = false;
$argv = $_SERVER['argv'];
$cmd = basename(array_shift($argv),'.php');
@ -97,9 +83,24 @@ foreach($argv as $key => $option)
$numeric = true;
continue 2; // switch is counting too!
case '-r': case '--recursive':
case '-p': case '--parents':
$recursive = true;
continue 2; // switch is counting too!
case '-d': case '--date':
$time = strtotime($argv[$key+1]);
unset($argv[$key+1]);
break;
case '--cat': // cat files (!) to stdout
case '--cp': // cp files
case '--rm': // rm files
case '--cp': // copy files
case '--rm': // remove files
case '--ls': // list files
case '--rmdir': // remove dirs
case '--mkdir': // make directories
case '--rename':// rename
case '--touch': // touch
$cmd = substr($option,2);
continue 2; // switch is counting too!
}
@ -113,49 +114,90 @@ switch($cmd)
do_cp($argv);
break;
case 'rename':
if (count($argv) != 2) usage(null,3);
load_wrapper($argv[0]);
load_wrapper($argv[1]);
rename($argv[0],$argv[1]);
break;
default:
while($url = array_shift($argv))
{
load_wrapper($url);
//echo "$cmd $url (long=".(int)$long.", numeric=".(int)$numeric.")\n";
if ($cmd == 'rm')
switch($cmd)
{
unlink($url);
}
elseif (is_dir($url) && ($dir = opendir($url)))
{
if ($argc)
{
echo "\n".basename(parse_url($url,PHP_URL_PATH)).":\n";
}
while(($file = readdir($dir)) !== false)
{
do_stat($url.'/'.$file,$long,$numeric);
}
closedir($dir);
}
elseif ($cmd == 'cat')
{
if (!($f = fopen($url,'r')))
{
echo "File $url not found !!!\n\n";
}
else
{
if ($argc)
case 'rm':
unlink($url);
break;
case 'rmdir':
rmdir($url);
break;
case 'mkdir':
mkdir($url,null,$recursive);
break;
case 'touch':
if (($scheme = parse_url($url,PHP_URL_SCHEME)))
{
echo "\n".basename(parse_url($url,PHP_URL_PATH)).":\n";
load_wrapper($url);
if (class_exists($class = $scheme.'_stream_wrapper') && method_exists($class,'touch'))
{
call_user_func(array($scheme.'_stream_wrapper','touch'),$url,$time);
}
else
{
die("Can't touch for scheme $scheme!\n");
}
}
fpassthru($f);
fclose($f);
}
else
{
touch($url,$time);
}
break;
case 'cat':
case 'ls':
default:
if (is_dir($url) && ($dir = opendir($url)))
{
if ($argc)
{
echo "\n".basename(parse_url($url,PHP_URL_PATH)).":\n";
}
while(($file = readdir($dir)) !== false)
{
do_stat($url.'/'.$file,$long,$numeric);
}
closedir($dir);
}
elseif ($cmd == 'cat')
{
if (!($f = fopen($url,'r')))
{
echo "File $url not found !!!\n\n";
}
else
{
if ($argc)
{
echo "\n".basename(parse_url($url,PHP_URL_PATH)).":\n";
}
fpassthru($f);
fclose($f);
}
}
else
{
do_stat($url,$long,$numeric);
}
if (!$long && $cmd == 'ls') echo "\n";
break;
}
else
{
do_stat($url,$long,$numeric);
}
if (!$long && $cmd == 'ls') echo "\n";
}
}
@ -166,12 +208,13 @@ switch($cmd)
*/
function load_wrapper($url)
{
switch(parse_url($url,PHP_URL_SCHEME))
switch($scheme = parse_url($url,PHP_URL_SCHEME))
{
case 'webdav':
require_once('HTTP/WebDAV/Client.php');
break;
case 'oldvfs':
case 'vfs':
if (!isset($GLOBALS['egw_info']))
{
$_GET['domain'] = parse_url($url,PHP_URL_HOST);
@ -193,13 +236,16 @@ function load_wrapper($url)
include('../header.inc.php');
}
require_once(EGW_API_INC.'/class.oldvfs_stream_wrapper.inc.php');
require_once(EGW_API_INC.'/class.'.$scheme.'_stream_wrapper.inc.php');
break;
case '':
case 'ftp':
case '': // default scheme is file and alsways available
break;
default:
die("Unknown scheme in $url !!!\n\n");
if (!in_array($scheme,stream_get_wrappers()))
{
die("Unknown scheme '$scheme' in $url !!!\n\n");
}
break;
}
}
@ -215,9 +261,8 @@ function do_stat($url,$long=false,$numeric=false)
//echo "do_stat($url,$long,$numeric)\n";
$bname = basename(parse_url($url,PHP_URL_PATH));
if ($long)
if ($long && ($stat = stat($url)))
{
$stat = stat($url);
//print_r($stat);
$perms = verbosePerms($stat['mode']);
@ -233,13 +278,13 @@ function do_stat($url,$long=false,$numeric=false)
$uid = isset($GLOBALS['egw']) ? $GLOBALS['egw']->accounts->id2name($stat['uid']) : posix_getpwuid($stat['uid']);
if (is_array($uid)) $uid = $uid['name'];
}
if (!isset($uid)) $uid = 'none';
if (!isset($uid)) $uid = 'root';
if ($stat['gid'])
{
$gid = isset($GLOBALS['egw']) ? $GLOBALS['egw']->accounts->id2name($stat['gid']) : posix_getgrgid($stat['gid']);
if (is_array($gid)) $gid = $gid['name'];
}
if (!isset($gid)) $gid = 'none';
if (!isset($gid)) $gid = 'root';
}
$size = hsize($stat['size']);
$mtime = date('Y-m-d H:i:s',$stat['mtime']);
@ -322,7 +367,7 @@ function do_cp($argv)
if (count($argv) > 1 && !is_dir($to))
{
die ("Usage: cp from-file to-file | cp file1 [file2 ...] dir\n\n");
usage(null,4);
}
if (count($argv) > 1)
{
@ -337,7 +382,7 @@ function do_cp($argv)
if (!($from_fp = fopen($from,'r')))
{
die("File $from not found!");
die("File $from not found!\n");
}
if (is_dir($to))
{
@ -346,7 +391,7 @@ function do_cp($argv)
}
if (!($to_fp = fopen($to,'w')))
{
die("Can't open $to from writing!");
die("Can't open $to for writing!\n");
}
$count = stream_copy_to_stream($from_fp,$to_fp);

View File

@ -14,7 +14,7 @@
*
* The interface is according to the docu on php.net
*
* @link http://de.php.net/manual/de/function.stream-wrapper-register.php
* @link http://www.php.net/manual/en/function.stream-wrapper-register.php
*/
interface iface_stream_wrapper
{
@ -149,11 +149,13 @@ interface iface_stream_wrapper
* It should attempt to rename the item specified by path_from to the specification given by path_to.
* In order for the appropriate error message to be returned, do not define this method if your wrapper does not support renaming.
*
* The regular filesystem stream-wrapper returns an error, if $url_from and $url_to are not either both files or both dirs!
*
* @param string $path_from
* @param string $path_to
* @return boolean TRUE on success or FALSE on failure
*/
function rename ( $path_from, $path_to );
static function rename ( $path_from, $path_to );
/**
* This method is called in response to mkdir() calls on URL paths associated with the wrapper.
@ -166,7 +168,7 @@ interface iface_stream_wrapper
* @param int $options Posible values include STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE
* @return boolean TRUE on success or FALSE on failure
*/
function mkdir ( $path, $mode, $options );
static function mkdir ( $path, $mode, $options );
/**
* This method is called in response to rmdir() calls on URL paths associated with the wrapper.
@ -178,7 +180,7 @@ interface iface_stream_wrapper
* @param int $options Possible values include STREAM_REPORT_ERRORS.
* @return boolean TRUE on success or FALSE on failure.
*/
function rmdir ( $path, $options );
static function rmdir ( $path, $options );
/**
* This method is called immediately when your stream object is created for examining directory contents with opendir().
@ -211,9 +213,10 @@ interface iface_stream_wrapper
* This flag is set in response to calls to lstat(), is_link(), or filetype().
* - STREAM_URL_STAT_QUIET If this flag is set, your wrapper should not raise any errors. If this flag is not set,
* you are responsible for reporting errors using the trigger_error() function during stating of the path.
* stat triggers it's own warning anyway, so it makes no sense to trigger one by our stream-wrapper!
* @return array
*/
function url_stat ( $path, $flags );
static function url_stat ( $path, $flags );
/**
* This method is called in response to readdir().

View File

@ -7,7 +7,7 @@
* @package api
* @subpackage vfs
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
*/
@ -30,12 +30,17 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
*
*/
const USE_FILESYSTEM_DIRECT = true;
/**
* Mime type of directories, the old vfs uses 'Directory', while eg. WebDAV uses 'httpd/unix-directory'
*
*/
const DIR_MIME_TYPE = 'Directory';
/**
* How much should be logged to the apache error-log
*
* 0 = Nothing
* 1 = only errors
* 2 = all function calls and errors
* 2 = all function calls and errors (contains passwords too!)
*/
const LOG_LEVEL = 1;
@ -78,20 +83,22 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
*/
protected $opened_pos;
/**
* Global vfs::ls() cache
* Directory vfs::ls() of dir opened with dir_opendir()
*
* This static var gets overwritten by each new dir_opendir, it helps to not read the entries twice.
*
* @var array $path => info-array pairs
*/
static private $stat_cache;
/**
* Array with filenames of dir opened with dir_opendir
*
* @var array
*/
static protected $cache=array();
/**
* Directory vfs::ls() of path opened with dir_opendir()
*
* @var string
*/
protected $opened_dir;
/**
* Constructor
* Constructor, only called for the non-static stream_* methods!
*
* @return oldvfs_stream_wrapper
*/
@ -138,7 +145,12 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
'operation' => EGW_ACL_ADD,
)))
{
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file does not exist or can not be created!");
if (!($options & STREAM_URL_STAT_QUIET))
{
trigger_error(__METHOD__."($url,$mode,$options) file does not exist or can not be created!",E_USER_WARNING);
}
$this->opened_data = $this->opened_path = $this->opened_mode = null;
return false;
}
@ -152,7 +164,12 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
'operation' => EGW_ACL_EDIT,
)))
{
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file can not be edited!");
if (!($options & STREAM_URL_STAT_QUIET))
{
trigger_error(__METHOD__."($url,$mode,$options) file can not be edited!",E_USER_WARNING);
}
$this->opened_data = $this->opened_path = $this->opened_mode = null;
return false;
}
@ -311,8 +328,10 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
$len = bytes($this->opened_data);
$eof = $this->opened_pos >= $len;
}
if (self::LOG_LEVEL > 1) error_log(__METHOD__."() pos=$this->opened_pos >= $len=len --> ".($eof ? 'true' : 'false'));
if (self::LOG_LEVEL > 1)
{
error_log(__METHOD__."() pos=$this->opened_pos >= $len=len --> ".($eof ? 'true' : 'false'));
}
return $eof;
}
@ -385,6 +404,7 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
{
return fflush($this->opened_data);
}
// we cant flush, as the old vfs can only write the whole data as once
return true;
}
@ -415,13 +435,15 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
* It should attempt to delete the item specified by path.
* In order for the appropriate error message to be returned, do not define this method if your wrapper does not support unlinking!
*
* @param string $path
* @param string $url
* @return boolean TRUE on success or FALSE on failure
*/
static function unlink ( $path )
static function unlink ( $url )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($path)");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url)");
$path = parse_url($url,PHP_URL_PATH);
if (!is_object(self::$old_vfs))
{
self::$old_vfs =& new vfs_home();
@ -431,12 +453,16 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
);
if (!self::$old_vfs->acl_check($data+array(
'operation' => EGW_ACL_DELETE
)) /*|| ($type = self::$old_vfs->file_type($data)) === 'Directory'*/)
'operation' => EGW_ACL_DELETE,
'must_exist' => true,
)) || ($type = self::$old_vfs->file_type($data)) === self::DIR_MIME_TYPE)
{
if (self::LOG_LEVEL) error_log(__METHOD__."($path) (type=$type) permission denied!");
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url) (type=$type) permission denied!");
return false; // no permission or file does not exist
}
unset(self::$stat_cache[$path]);
return self::$old_vfs->rm($data);
}
@ -445,15 +471,67 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
*
* It should attempt to rename the item specified by path_from to the specification given by path_to.
* In order for the appropriate error message to be returned, do not define this method if your wrapper does not support renaming.
*
* The regular filesystem stream-wrapper returns an error, if $url_from and $url_to are not either both files or both dirs!
*
* @param string $path_from
* @param string $path_to
* @param string $url_from
* @param string $url_to
* @return boolean TRUE on success or FALSE on failure
*/
function rename ( $path_from, $path_to )
static function rename ( $url_from, $url_to )
{
error_log(__METHOD__."($path_from, $path_to) not yet implemented!");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url_from,$url_to)");
$path_from = parse_url($url_from,PHP_URL_PATH);
$path_to = parse_url($url_to,PHP_URL_PATH);
if (!is_object(self::$old_vfs))
{
self::$old_vfs =& new vfs_home();
}
$data_from = array(
'string' => $path_from,
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
);
if (!self::$old_vfs->acl_check($data_from+array(
'operation' => EGW_ACL_DELETE,
'must_exist'=> true,
)))
{
if (self::LOG_LEVEL) error_log(__METHOD__."($url_from,$url_to): $path_from permission denied!");
return false; // no permission or file does not exist
}
$data_to = array(
'string' => $path_to,
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
);
if (!self::$old_vfs->acl_check($data_to+array(
'operation' => EGW_ACL_ADD,
)))
{
self::remove_password($url_from);
self::remove_password($url_to);
if (self::LOG_LEVEL) error_log(__METHOD__."($url_from,$url_to): $path_to permission denied!");
return false; // no permission or file does not exist
}
// the filesystem stream-wrapper does NOT allow to rename files to directories, as this makes problems
// for our vfs too, we give abort here with an error, like the filesystem one does
if (($type_to = self::$old_vfs->file_type($data_to)) &&
($type_to === self::DIR_MIME_TYPE) !== (self::$old_vfs->file_type($data_from) === self::DIR_MIME_TYPE))
{
$is_dir = $type_to === self::DIR_MIME_TYPE ? 'a' : 'no';
self::remove_password($url_from);
self::remove_password($url_to);
if (self::LOG_LEVEL) error_log(__METHOD__."($url_to,$url_from) $path_to is $is_dir directory!");
return false; // no permission or file does not exist
}
unset(self::$stat_cache[$path_from]);
return self::$old_vfs->mv(array(
'from' => $path_from,
'to' => $path_to,
'relatives' => array(RELATIVE_ROOT,RELATIVE_ROOT),
));
}
/**
@ -462,15 +540,51 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
* It should attempt to create the directory specified by path.
* In order for the appropriate error message to be returned, do not define this method if your wrapper does not support creating directories.
*
* @param string $path
* @param string $url
* @param int $mode
* @param int $options Posible values include STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE
* @return boolean TRUE on success or FALSE on failure
*/
function mkdir ( $path, $mode, $options )
static function mkdir ( $url, $mode, $options )
{
error_log(__METHOD__."($path, $mode, $options) not yet implemented!");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)");
$path = parse_url($url,PHP_URL_PATH);
if (!is_object(self::$old_vfs))
{
self::$old_vfs =& new vfs_home();
}
// 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 (($options & STREAM_MKDIR_RECURSIVE) && $path != '/' && !self::$old_vfs->file_exists(array(
'string' => dirname($path),
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
)))
{
if (!self::mkdir(dirname($path),$mode,$options))
{
return false;
}
}
$data=array(
'string' => $path,
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
);
if (!self::$old_vfs->acl_check($data+array(
'operation' => EGW_ACL_ADD,
'must_exist' => false,
)))
{
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url) permission denied!");
if (!($options & STREAM_URL_STAT_QUIET))
{
trigger_error(__METHOD__."('$url',$mode,$options) permission denied!",E_USER_WARNING);
}
return false; // no permission or file does not exist
}
return self::$old_vfs->mkdir($data);
}
/**
@ -479,16 +593,80 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
* It should attempt to remove the directory specified by path.
* In order for the appropriate error message to be returned, do not define this method if your wrapper does not support removing directories.
*
* @param string $path
* @param string $url
* @param int $options Possible values include STREAM_REPORT_ERRORS.
* @return boolean TRUE on success or FALSE on failure.
*/
function rmdir ( $path, $options )
static function rmdir ( $url, $options )
{
error_log(__METHOD__."($path, $options) not yet implemented!");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url)");
$path = parse_url($url,PHP_URL_PATH);
if (!is_object(self::$old_vfs))
{
self::$old_vfs =& new vfs_home();
}
$data=array(
'string' => $path,
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
);
if (!self::$old_vfs->acl_check($data+array(
'operation' => EGW_ACL_DELETE,
'must_exist' => true,
)) || ($type = self::$old_vfs->file_type($data)) !== self::DIR_MIME_TYPE)
{
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$options) (type=$type) permission denied!");
if (!($options & STREAM_URL_STAT_QUIET))
{
trigger_error(__METHOD__."('$url',$options) (type=$type) permission denied!",E_USER_WARNING);
}
return false; // no permission or file does not exist
}
// abort with an error, if the dir is not empty
// our vfs deletes recursive, while the stream-wrapper interface does not!
if (($files = self::$old_vfs->ls($data)))
{
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$options) dir is not empty!");
if (!($options & STREAM_URL_STAT_QUIET))
{
trigger_error(__METHOD__."('$url',$options) dir is not empty!",E_USER_WARNING);
}
return false;
}
unset(self::$stat_cache[$path]);
return self::$old_vfs->rm($data);
}
/**
* This is not (yet) a stream-wrapper function, but it's necessary and can be used static
*
* @param string $url
* @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!
*/
static function touch($url,$time=null,$atime=null)
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url)");
$path = parse_url($url,PHP_URL_PATH);
if (!is_object(self::$old_vfs))
{
self::$old_vfs =& new vfs_home();
}
$data=array(
'string' => $path,
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
);
if (!is_null($time)) $data['time'] = $time;
return self::$old_vfs->touch($data);
}
/**
* This method is called immediately when your stream object is created for examining directory contents with opendir().
*
@ -499,6 +677,8 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
function dir_opendir ( $url, $options )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$options)");
$this->opened_dir = null;
if (!is_object(self::$old_vfs))
{
@ -506,22 +686,30 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
}
$path = parse_url($url,PHP_URL_PATH);
$this->opened_dir = self::$old_vfs->ls(array(
$files = self::$old_vfs->ls(array(
'string' => $path,
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
'checksubdirs' => false,
'nofiles' => false,
//'orderby' => '',
'orderby' => 'name',
//'mime_type' => '',
));
if (!is_array($this->opened_dir) ||
if (!is_array($files) ||
// we also need to return false, if $url is not a directory!
count($this->opened_dir) == 1 && $path == $this->opened_dir[0]['directory'].'/'.$this->opened_dir[0]['name'] &&
$this->opened_dir[0]['mime_type'] != 'Directory')
count($files) == 1 && $path == $files[0]['directory'].'/'.$files[0]['name'] &&
$files[0]['mime_type'] != self::DIR_MIME_TYPE)
{
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$options) $url is not directory!");
$this->opened_dir = null;
return false;
}
self::$stat_cache = $this->opened_dir = array();
foreach($files as $file)
{
$this->opened_dir[] = $file['name'];
self::$stat_cache[$file['directory'].'/'.$file['name']] = $file;
}
//print_r($this->opened_dir);
reset($this->opened_dir);
@ -551,39 +739,42 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
* This flag is set in response to calls to lstat(), is_link(), or filetype().
* - STREAM_URL_STAT_QUIET If this flag is set, your wrapper should not raise any errors. If this flag is not set,
* you are responsible for reporting errors using the trigger_error() function during stating of the path.
* stat triggers it's own warning anyway, so it makes no sense to trigger one by our stream-wrapper!
* @return array
*/
function url_stat ( $url, $flags )
static function url_stat ( $url, $flags )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$flags)");
/*return array(
'mode' => 0100666,
'name' => basename(parse_url($path,PHP_URL_PATH)),
'size' => strlen(basename(parse_url($path,PHP_URL_PATH))),
'nlink' => 1,
'uid' => 1000,
'gid' => 100,
'mtime' => time(),
);*/
$path = parse_url($url,PHP_URL_PATH);
// check if we already have the info from the last dir_open call, as the old vfs reads it anyway from the db
if (self::$stat_cache && isset(self::$stat_cache[$path]))
{
return self::_vfsinfo2stat(self::$stat_cache[$path]);
}
if (!is_object(self::$old_vfs))
{
self::$old_vfs =& new vfs_home();
}
$path = parse_url($url,PHP_URL_PATH);
list($info) = self::$old_vfs->ls(array(
'string' => $path,
'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root
'checksubdirs' => false,
'nofiles' => true,
//'orderby' => '',
//'orderby' => 'name',
//'mime_type' => '',
));
//print_r($info);
if (!$info)
{
self::remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$flags) file or directory not found!");
return false;
}
return $info ? $this->vfsinfo2stat($info) : false;
return self::_vfsinfo2stat($info);
}
/**
@ -595,13 +786,13 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
*/
function dir_readdir ( )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($this->opened_dir_path)");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."( )");
if (!is_array($this->opened_dir)) return false;
$file = current($this->opened_dir); next($this->opened_dir);
return $file ? $file['name'] : false;
return $file ? $file : false;
}
/**
@ -614,7 +805,7 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
*/
function dir_rewinddir ( )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($this->opened_dir_path)");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."( )");
if (!is_array($this->opened_dir)) return false;
@ -632,11 +823,11 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
*/
function dir_closedir ( )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($this->opened_dir_path)");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."( )");
if (!is_array($this->opened_dir)) return false;
$this->opened_dir = $this->opened_dir_path = null;
$this->opened_dir = null;
return true;
}
@ -647,18 +838,20 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
* @param array $info
* @return array
*/
function vfsinfo2stat($info)
static private function _vfsinfo2stat($info)
{
$stat = array(
'ino' => $info['file_id'],
'name' => $info['name'],
'mode' => $info['mime_type'] == 'Directory' ? 040700 : 0100600,
'mode' => $info['owner_id'] > 0 ?
($info['mime_type'] == self::DIR_MIME_TYPE ? 040700 : 0100600) :
($info['mime_type'] == self::DIR_MIME_TYPE ? 040070 : 0100060),
'size' => $info['size'],
'uid' => $info['owner_id'] > 0 ? $info['owner_id'] : 0,
'gid' => $info['owner_id'] < 0 ? $info['owner_id'] : 0,
'mtime' => strtotime($info['modified'] ? $info['modified'] : $info['created']),
'ctime' => strtotime($info['created']),
'nlink' => $info['mime_type'] == 'Directory' ? 2 : 1,
'nlink' => $info['mime_type'] == self::DIR_MIME_TYPE ? 2 : 1,
);
//print_r($stat);
return $stat;
@ -680,6 +873,22 @@ class oldvfs_stream_wrapper implements iface_stream_wrapper
return $func_overload & 2 ? mb_substr($str,$start,$length,'ascii') : substr($str,$start,$length);
}
/**
* Replace the password of an url with '...' for error messages
*
* @param string &$url
*/
static private function remove_password(&$url)
{
$parts = parse_url($url);
if ($parts['pass'] || $parts['scheme'])
{
$url = $parts['scheme'].'://'.($parts['user'] ? $parts['user'].($parts['pass']?':...':'').'@' : '').
$parts['host'].$parts['path'];
}
}
}
stream_register_wrapper('oldvfs','oldvfs_stream_wrapper');