From d313eb2daf9a71ea62243f0782992a8644cfbbe9 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Mon, 9 Mar 2009 12:23:47 +0000 Subject: [PATCH] fixing various webdav problems, regarding pathbuilding --- egw-pear/HTTP/WebDAV/Server.php | 50 ++++++++++++------- phpgwapi/inc/class.egw_vfs.inc.php | 6 +-- .../inc/class.sqlfs_stream_wrapper.inc.php | 21 +++++++- phpgwapi/inc/class.vfs_stream_wrapper.inc.php | 14 ++++-- webdav.php | 11 ++++ 5 files changed, 76 insertions(+), 26 deletions(-) diff --git a/egw-pear/HTTP/WebDAV/Server.php b/egw-pear/HTTP/WebDAV/Server.php index e4ed9a0225..7a58379b6d 100644 --- a/egw-pear/HTTP/WebDAV/Server.php +++ b/egw-pear/HTTP/WebDAV/Server.php @@ -145,7 +145,8 @@ class HTTP_WebDAV_Server // default uri is the complete request uri $uri = (@$this->_SERVER["HTTPS"] === "on" ? "https:" : "http:"); // we cant use SCRIPT_NAME, because it fails, if there's any url rewriting - $uri.= '//'.$this->_SERVER['HTTP_HOST'].substr($this->_SERVER['REQUEST_URI'],0,-strlen($this->_SERVER["PATH_INFO"])); + //error_log("pathinfo:\n". $this->_urldecode($this->_SERVER['REQUEST_URI']).":\n".$this->_SERVER['PATH_INFO']); + $uri.= '//'.$this->_SERVER['HTTP_HOST'].substr($this->_urldecode($this->_SERVER['REQUEST_URI']),0,-strlen($this->_SERVER["PATH_INFO"])); $path_info = empty($this->_SERVER["PATH_INFO"]) ? "/" : $this->_SERVER["PATH_INFO"]; @@ -1975,7 +1976,8 @@ class HTTP_WebDAV_Server } // return generated response - return $activelocks; + //error_log(__METHOD__."\n".print_r($activelocks,true)); + return $activelocks; } /** @@ -2010,7 +2012,8 @@ class HTTP_WebDAV_Server */ function _urlencode($url) { - return strtr($url, array(" "=>"%20", + //error_log( __METHOD__."\n" .print_r($url,true)); + return strtr($url, array(" "=>"%20", "&"=>"%26", "<"=>"%3C", ">"=>"%3E", @@ -2039,14 +2042,19 @@ class HTTP_WebDAV_Server */ function _prop_encode($text) { - switch (strtolower($this->_prop_encoding)) { - case "utf-8": - return $text; - case "iso-8859-1": - case "iso-8859-15": - case "latin-1": - default: - return utf8_encode($text); + //error_log( __METHOD__."\n" .print_r($text,true)); + //error_log("prop-encode:" . print_r($this->_prop_encoding,true)); + + switch (strtolower($this->_prop_encoding)) { + case "utf-8": + //error_log( __METHOD__."allready encoded\n" .print_r($text,true)); + return $text; + case "iso-8859-1": + case "iso-8859-15": + case "latin-1": + default: + //error_log( __METHOD__."utf8 encode\n" .print_r(utf8_encode($text),true)); + return utf8_encode($text); } } @@ -2058,10 +2066,12 @@ class HTTP_WebDAV_Server */ function _slashify($path) { - if ($path[strlen($path)-1] != '/') { - $path = $path."/"; - } - return $path; + //error_log(__METHOD__." called with $path"); + if ($path[$this->bytes($path)-1] != '/') { + //error_log(__METHOD__." added slash at the end of path"); + $path = $path."/"; + } + return $path; } /** @@ -2072,8 +2082,10 @@ class HTTP_WebDAV_Server */ function _unslashify($path) { - if ($path[strlen($path)-1] == '/') { - $path = substr($path, 0, strlen($path) -1); + //error_log(__METHOD__." called with $path"); + if ($path[$this->bytes($path)-1] == '/') { + $path = substr($path, 0, -1); + //error_log(__METHOD__." removed slash at the end of path"); } return $path; } @@ -2087,7 +2099,9 @@ class HTTP_WebDAV_Server */ function _mergePathes($parent, $child) { - if ($child{0} == '/') { + //error_log("merge called :\n$parent \n$child\n" . function_backtrace()); + //error_log("merge :\n".print_r($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path)true)); + if ($child{0} == '/') { return $this->_unslashify($parent).$child; } else { return $this->_slashify($parent).$child; diff --git a/phpgwapi/inc/class.egw_vfs.inc.php b/phpgwapi/inc/class.egw_vfs.inc.php index 5e27d8b459..d32c9c3a7a 100644 --- a/phpgwapi/inc/class.egw_vfs.inc.php +++ b/phpgwapi/inc/class.egw_vfs.inc.php @@ -349,7 +349,7 @@ class egw_vfs extends vfs_stream_wrapper } if ($is_dir && (!isset($options['maxdepth']) || $options['maxdepth'] > 0) && ($dir = @opendir($path))) { - while($file = readdir($dir)) + while(($file = readdir($dir)) !== false) { if ($file == '.' || $file == '..') continue; // ignore current and parent dir! @@ -1125,7 +1125,7 @@ class egw_vfs extends vfs_stream_wrapper { if (isset(self::$lock_cache[$path])) { - error_log(__METHOD__."($path) returns from CACHE ".str_replace(array("\n",' '),'',print_r(self::$lock_cache[$path],true))); + //error_log(__METHOD__."($path) returns from CACHE ".str_replace(array("\n",' '),'',print_r(self::$lock_cache[$path],true))); return self::$lock_cache[$path]; } $where = 'lock_path='.self::$db->quote($path); @@ -1146,7 +1146,7 @@ class egw_vfs extends vfs_stream_wrapper 'lock_token' => $result['token'], ),__LINE__,__FILE__); - //error_log(__METHOD__."($path) lock is expired at ".date('Y-m-d H:i:s',$result['expires'])." --> removed"); + //error_log(__METHOD__."($path) lock is expired at ".date('Y-m-d H:i:s',$result['expires'])." --> removed"); $result = false; } //error_log(__METHOD__."($path) returns ".($result?array2string($result):'false')); diff --git a/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php b/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php index 81745c99ed..ad879e5d90 100644 --- a/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php +++ b/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php @@ -222,7 +222,9 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper // create the hash-dirs, if they not yet exist elseif(!file_exists($fs_dir=dirname(self::_fs_path($this->opened_fs_id)))) { - mkdir($fs_dir,0700,true); + $umaskbefore = umask(); + if (self::LOG_LEVEL) error_log(__METHOD__." about to call mkdir for $fs_dir # Present UMASK:".decoct($umaskbefore)." called from:".function_backtrace()); + self::mkdir_recursive($fs_dir,0700,true); } } else @@ -264,6 +266,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper // do we operate directly on the filesystem if ($this->operation == self::STORE2FS) { + if (self::LOG_LEVEL > 1) error_log(__METHOD__." fopen (may create a directory? mkdir) ($this->opened_fs_id,$mode,$options)"); $this->opened_stream = fopen(self::_fs_path($this->opened_fs_id),$mode); } if ($mode[0] == 'a') // append modes: a, a+ @@ -575,6 +578,18 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper )); } + /** + * due to problems with recursive directory creation, we have our own here + */ + function mkdir_recursive($pathname, $mode, $depth=0) + { + $maxdepth=10; + $depth2propagate = (int)$depth + 1; + if ($depth2propagate > $maxdepth) return is_dir($pathname); + is_dir(dirname($pathname)) || self::mkdir_recursive(dirname($pathname), $mode, $depth2propagate); + return is_dir($pathname) || @mkdir($pathname, $mode); + } + /** * This method is called in response to mkdir() calls on URL paths associated with the wrapper. * @@ -589,7 +604,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper static function mkdir ( $url, $mode, $options ) { if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)"); - + if (self::LOG_LEVEL > 1) error_log(__METHOD__." called from:".function_backtrace()); $path = parse_url($url,PHP_URL_PATH); if (self::url_stat($path,STREAM_URL_STAT_QUIET)) @@ -611,6 +626,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper // if yes call ourself recursive with the parent directory if (($options & STREAM_MKDIR_RECURSIVE) && $path != '/' && !$parent) { + if (self::LOG_LEVEL > 1) error_log(__METHOD__." creating parents: $parent_path, $mode"); if (!self::mkdir($parent_path,$mode,$options)) { return false; @@ -1291,6 +1307,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper { return false; // parent not found, should never happen ... } + if (self::LOG_LEVEL > 1) error_log(__METHOD__." trying foreach with:".print_r($rows,true)."#"); foreach($rows as $fs_id => $row) { $parent = $row['fs_dir'] > 1 ? $parents[$row['fs_dir']] : ''; diff --git a/phpgwapi/inc/class.vfs_stream_wrapper.inc.php b/phpgwapi/inc/class.vfs_stream_wrapper.inc.php index 9e16d327f7..b033fcfc13 100644 --- a/phpgwapi/inc/class.vfs_stream_wrapper.inc.php +++ b/phpgwapi/inc/class.vfs_stream_wrapper.inc.php @@ -587,6 +587,7 @@ class vfs_stream_wrapper implements iface_stream_wrapper */ function dir_opendir ( $path, $options ) { + //error_log(__METHOD__." called with ".$path); $this->opened_dir = $this->extra_dirs = null; $this->extra_dir_ptr = 0; @@ -596,16 +597,20 @@ class vfs_stream_wrapper implements iface_stream_wrapper } if (!($this->opened_dir = opendir($this->opened_dir_url))) { + //error_log(__METHOD__." dir failed: ".$this->opened_dir); return false; } $this->opened_dir_writable = egw_vfs::check_access($this->opened_dir_url,egw_vfs::WRITABLE); - + #error_log(__METHOD__." check for ".$this->opened_dir_url); // check our fstab if we need to add some of the mountpoints $basepath = parse_url($this->opened_dir_url,PHP_URL_PATH); + #error_log(__METHOD__." basepath here: ".print_r($basepath,true)); foreach(self::$fstab as $mounted => $nul) { - if (dirname($mounted) == $basepath && $mounted != '/') + #error_log(__METHOD__." dirname mounted: ".print_r(dirname($mounted),true)); + if ((dirname($mounted) == $basepath || dirname($mounted)."/" == $basepath) && $mounted != '/') { + #error_log(__METHOD__." mounted dir: ".print_r($mounted,true)); $this->extra_dirs[] = basename($mounted); } } @@ -685,13 +690,16 @@ class vfs_stream_wrapper implements iface_stream_wrapper */ function dir_readdir ( ) { + #error_log(__METHOD__." called."); if ($this->extra_dirs && count($this->extra_dirs) > $this->extra_dir_ptr) { return $this->extra_dirs[$this->extra_dir_ptr++]; } // only return children readable by the user, if dir is not writable do { + //error_log(__METHOD__." called with:".$this->opened_dir_url); $file = readdir($this->opened_dir); + //error_log(__METHOD__." got:".$file); } while($file !== false && (is_array($this->extra_dirs) && in_array($file,$this->extra_dirs) || // dont return mountpoints twice self::HIDE_UNREADABLES && !$this->opened_dir_writable && @@ -791,4 +799,4 @@ class vfs_stream_wrapper implements iface_stream_wrapper } } -vfs_stream_wrapper::init_static(); \ No newline at end of file +vfs_stream_wrapper::init_static(); diff --git a/webdav.php b/webdav.php index afaa56fbf9..516dcd1502 100644 --- a/webdav.php +++ b/webdav.php @@ -44,6 +44,16 @@ function check_access(&$account) // if we are called with a /apps/$app path, use that $app as currentapp, to not require filemanager rights for the links $parts = explode('/',$_SERVER['PATH_INFO']); +//error_log("webdav: explode".print_r($parts,true)); +if(count($parts)== 1){ + error_log(__METHOD__. "Malformed Url: missing slash:\n".$_SERVER['SERVER_NAME']."\n PATH_INFO:".$_SERVER['PATH_INFO']. + "\n REQUEST_URI".$_SERVER['REQUEST_URI']."\n ORIG_SCRIPT_NAME:".$_SERVER['ORIG_SCRIPT_NAME']. + "\n REMOTE_ADDR:".$_SERVER['REMOTE_ADDR']."\n PATH_INFO:".$_SERVER['PATH_INFO']."\n HTTP_USER_AGENT:".$_SERVER['HTTP_USER_AGENT']) ; + header("HTTP/1.1 501 Not implemented"); + header("X-WebDAV-Status: 501 Not implemented", true); + exit; +} + $app = count($parts) > 3 && $parts[1] == 'apps' ? $parts[2] : 'filemanager'; $GLOBALS['egw_info'] = array( @@ -63,3 +73,4 @@ $headertime = microtime(true); $webdav_server = new vfs_webdav_server(); $webdav_server->ServeRequest(); //error_log(sprintf("GroupDAV %s request took %5.3f s (header include took %5.3f s)",$_SERVER['REQUEST_METHOD'],microtime(true)-$starttime,$headertime-$starttime)); +