From 80367bb9433cca52ebd07c9fff01bc080b5c53e9 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Apr 2008 17:38:39 +0000 Subject: [PATCH] removed not longer used old vfs classes and the first stream_wrapper (oldvfs://), I have not yet droped the vfs table, to give the update script more testing with the change to restore --- .../inc/class.oldvfs_stream_wrapper.inc.php | 871 ----- .../inc/class.oldvfs_webdav_server.inc.php | 459 --- phpgwapi/inc/class.vfs.inc.php | 1417 -------- phpgwapi/inc/class.vfs_dav.inc.php | 2938 ----------------- phpgwapi/inc/class.vfs_home.inc.php | 204 -- phpgwapi/inc/class.vfs_sql.inc.php | 2650 --------------- 6 files changed, 8539 deletions(-) delete mode 100644 phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php delete mode 100644 phpgwapi/inc/class.oldvfs_webdav_server.inc.php delete mode 100644 phpgwapi/inc/class.vfs.inc.php delete mode 100644 phpgwapi/inc/class.vfs_dav.inc.php delete mode 100644 phpgwapi/inc/class.vfs_home.inc.php delete mode 100644 phpgwapi/inc/class.vfs_sql.inc.php diff --git a/phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php b/phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php deleted file mode 100644 index 433e81b370..0000000000 --- a/phpgwapi/inc/class.oldvfs_stream_wrapper.inc.php +++ /dev/null @@ -1,871 +0,0 @@ - - * @copyright (c) 2007-8 by Ralf Becker - * @version $Id$ - */ - -/** - * eGroupWare API: VFS - old (until eGW 1.4 inclusive) VFS stream wrapper - * - * This class uses eGW's vfs_home class to access the vfs. - * - * The interface is according to the docu on php.net - * - * @link http://de.php.net/manual/de/function.stream-wrapper-register.php - */ -class oldvfs_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' - */ - const DIR_MIME_TYPE = 'Directory'; - /** - * Scheme / protocoll used for this stream-wrapper - */ - const SCHEME = 'oldvfs'; - /** - * Does url_stat returns a mime type, or has it to be determined otherwise (string with attribute name) - */ - const STAT_RETURN_MIME_TYPE = 'mime'; - /** - * How much should be logged to the apache error-log - * - * 0 = Nothing - * 1 = only errors - * 2 = all function calls and errors (contains passwords too!) - */ - const LOG_LEVEL = 1; - - /** - * optional context param when opening the stream, null if no context passed - * - * @var mixed - */ - var $context; - - /** - * Instance of the old vfs class - * - * @var vfs_home - */ - static protected $old_vfs; - - /** - * Path off the file opened by stream_open - * - * @var string - */ - protected $opened_path; - /** - * Mode of the file opened by stream_open - * - * @var int - */ - protected $opened_mode; - /** - * Content of the opened file, as the old vfs can only read/write the whole file - * - * @var string - */ - protected $opened_data; - /** - * Position in the opened file - * - * @var int - */ - protected $opened_pos; - /** - * 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 - */ - protected $opened_dir; - - /** - * This method is called immediately after your stream object is created. - * - * @param string $url URL that was passed to fopen() and that this object is expected to retrieve - * @param string $mode mode used to open the file, as detailed for fopen() - * @param int $options additional flags set by the streams API (or'ed together): - * - STREAM_USE_PATH If path is relative, search for the resource using the include_path. - * - STREAM_REPORT_ERRORS If this flag is set, you are responsible for raising errors using trigger_error() during opening of the stream. - * If this flag is not set, you should not raise any errors. - * @param string $opened_path full path of the file/resource, if the open was successfull and STREAM_USE_PATH was set - * @return boolean true if the ressource was opened successful, otherwise false - */ - function stream_open ( $url, $mode, $options, &$opened_path ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)"); - - $path = parse_url($url,PHP_URL_PATH); - - $this->opened_path = $path; - $this->opened_mode = $mode; - $this->opened_data = null; - - if (!self::$old_vfs->file_exists($data = array( // file does not exists - 'string' => $path, - 'relatives' => array(RELATIVE_ROOT), - )) || $mode[0] == 'x') // or file should NOT exist - { - if ($mode[0] == 'r' || // does $mode require the file to exist (r,r+) - $mode[0] == 'x' || // or file should not exist, but does - !self::$old_vfs->acl_check($data+array( // or we are not allowed to create it - '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; - } - // new file - $this->opened_data = ''; - $this->opened_pos = 0; - } - else - { - if ($mode != 'r' && !self::$old_vfs->acl_check($data+array( // we are not allowed to edit it - '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; - } - if ($mode[0] == 'w') // w or w+ truncates the file to 0 size - { - $this->opened_data = ''; - $this->opened_pos = 0; - } - } - // can we operate directly on a filesystem stream? - if (self::$old_vfs->file_actions && self::USE_FILESYSTEM_DIRECT) - { - $p = self::$old_vfs->path_parts($data); - - if (!($this->opened_data = fopen($p->real_full_path,$mode,false))) - { - if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file $p->real_full_path can not be opened!"); - return false; - } - } - if ($mode[0] == 'a') // append modes: a, a+ - { - $this->stream_seek(0,SEEK_END); - } - return true; - } - - /** - * This method is called when the stream is closed, using fclose(). - * - * You must release any resources that were locked or allocated by the stream. - */ - function stream_close ( ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."()"); - - if (is_null($this->opened_path)) return false; - - $ret = true; - if (is_resource($this->opened_data)) - { - $ret = fclose($this->opened_data); - - if ($this->opened_mode != 'r') - { - // touch creates file (if necessary) and sets the modification or creation time and owner - self::$old_vfs->touch($data = array( - 'string' => $this->opened_path, - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - )); - // we read the size from the filesystem and write it to our db-based metadata - $p = self::$old_vfs->path_parts($data); - $data['attributes'] = array( - 'size' => filesize($p->real_full_path), - ); - self::$old_vfs->set_attributes($data); - } - } - elseif ($this->opened_mode != 'r') - { - // store the changes - self::$old_vfs->write($this->opened_data); - } - $this->opened_data = $this->opened_path = $this->opened_mode = null; - - return $ret; - } - - /** - * This method is called in response to fread() and fgets() calls on the stream. - * - * You must return up-to count bytes of data from the current read/write position as a string. - * If there are less than count bytes available, return as many as are available. - * If no more data is available, return either FALSE or an empty string. - * You must also update the read/write position of the stream by the number of bytes that were successfully read. - * - * @param int $count - * @return string/false up to count bytes read or false on EOF - */ - function stream_read ( $count ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($count) pos=$this->opened_pos"); - - if (is_resource($this->opened_data)) - { - return fread($this->opened_data,$count); - } - if (is_null($this->opened_data)) - { - if (($this->opened_data = self::$old_vfs->read(array( - 'string' => $this->opened_path, - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - ))) === false) - { - return false; - } - $this->opened_pos = 0; - } - if ($this->stream_eof()) return false; // nothing more to read - - $start = $this->opened_pos; - $this->opened_pos += $count; - - // multibyte save substr! - return self::substr($this->opened_data,$start,$count); - } - - /** - * This method is called in response to fwrite() calls on the stream. - * - * You should store data into the underlying storage used by your stream. - * If there is not enough room, try to store as many bytes as possible. - * You should return the number of bytes that were successfully stored in the stream, or 0 if none could be stored. - * You must also update the read/write position of the stream by the number of bytes that were successfully written. - * - * @param string $data - * @return integer - */ - function stream_write ( $data ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($data)"); - - if (is_resource($this->opened_data)) - { - return fwrite($this->opened_data,$data); - } - $len = bytes($data); - // multibyte save substr! - self::substr($this->opened_data,$this->opened_pos); - - $this->opened_pos += $len; - - return $len; - } - - /** - * This method is called in response to feof() calls on the stream. - * - * Important: PHP 5.0 introduced a bug that wasn't fixed until 5.1: the return value has to be the oposite! - * - * if(version_compare(PHP_VERSION,'5.0','>=') && version_compare(PHP_VERSION,'5.1','<')) - * { - * $eof = !$eof; - * } - * - * @return boolean true if the read/write position is at the end of the stream and no more data availible, false otherwise - */ - function stream_eof ( ) - { - if (is_resource($this->opened_data)) - { - return feof($this->opened_data); - } - if (!is_null($this->opened_data)) - { - $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')); - } - return $eof; - } - - /** - * This method is called in response to ftell() calls on the stream. - * - * @return integer current read/write position of the stream - */ - function stream_tell ( ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."()"); - - if (is_resource($this->opened_data)) - { - return ftell($this->opened_data); - } - return $this->opened_pos; - } - - /** - * This method is called in response to fseek() calls on the stream. - * - * You should update the read/write position of the stream according to offset and whence. - * See fseek() for more information about these parameters. - * - * @param integer $offset - * @param integer $whence SEEK_SET - Set position equal to offset bytes - * SEEK_CUR - Set position to current location plus offset. - * SEEK_END - Set position to end-of-file plus offset. (To move to a position before the end-of-file, you need to pass a negative value in offset.) - * @return boolean TRUE if the position was updated, FALSE otherwise. - */ - function stream_seek ( $offset, $whence ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($offset,$whence)"); - - if (is_resource($this->opened_data)) - { - return fseek($this->opened_data,$offset,$whence); - } - if (is_null($this->opened_path)) return false; - - switch($whence) - { - default: - case SEEK_SET: - $this->opened_pos = $offset; - break; - case SEEK_END: - $this->opened_pos = bytes($this->opened_data); - // fall through - case SEEK_CUR: - $this->opened_pos += $offset; - break; - } - return true; - } - - /** - * This method is called in response to fflush() calls on the stream. - * - * If you have cached data in your stream but not yet stored it into the underlying storage, you should do so now. - * - * @return booelan TRUE if the cached data was successfully stored (or if there was no data to store), or FALSE if the data could not be stored. - */ - function stream_flush ( ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."()"); - - if (is_resource($this->opened_data)) - { - return fflush($this->opened_data); - } - // we cant flush, as the old vfs can only write the whole data as once - return true; - } - - /** - * This method is called in response to fstat() calls on the stream. - * - * If you plan to use your wrapper in a require_once you need to define stream_stat(). - * If you plan to allow any other tests like is_file()/is_dir(), you have to define url_stat(). - * stream_stat() must define the size of the file, or it will never be included. - * url_stat() must define mode, or is_file()/is_dir()/is_executable(), and any of those functions affected by clearstatcache() simply won't work. - * It's not documented, but directories must be a mode like 040777 (octal), and files a mode like 0100666. - * If you wish the file to be executable, use 7s instead of 6s. - * The last 3 digits are exactly the same thing as what you pass to chmod. - * 040000 defines a directory, and 0100000 defines a file. - * - * @return array containing the same values as appropriate for the stream. - */ - function stream_stat ( ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($this->opened_path)"); - - return $this->url_stat($this->opened_path,0); - } - - /** - * This method is called in response to unlink() calls on URL paths associated with the 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 $url - * @return boolean TRUE on success or FALSE on failure - */ - static function unlink ( $url ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url)"); - - $path = parse_url($url,PHP_URL_PATH); - - $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) (type=$type) permission denied!"); - return false; // no permission or file does not exist - } - unset(self::$stat_cache[$path]); - - return self::$old_vfs->rm($data); - } - - /** - * This method is called in response to rename() calls on URL paths associated with the 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 $url_from - * @param string $url_to - * @return boolean TRUE on success or FALSE on failure - */ - static function rename ( $url_from, $url_to ) - { - 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); - - $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), - )); - } - - /** - * This method is called in response to mkdir() calls on URL paths associated with the 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 $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 - */ - static function mkdir ( $url, $mode, $options ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)"); - - $path = parse_url($url,PHP_URL_PATH); - - // 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); - } - - /** - * This method is called in response to rmdir() calls on URL paths associated with the 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 $url - * @param int $options Possible values include STREAM_REPORT_ERRORS. - * @return boolean TRUE on success or FALSE on failure. - */ - static function rmdir ( $url, $options ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url)"); - - $path = parse_url($url,PHP_URL_PATH); - - $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); - - $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(). - * - * @param string $path URL that was passed to opendir() and that this object is expected to explore. - * @param $options - * @return booelan - */ - function dir_opendir ( $url, $options ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$options)"); - - $this->opened_dir = null; - - $path = parse_url($url,PHP_URL_PATH); - - $files = self::$old_vfs->ls(array( - 'string' => $path, - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - 'checksubdirs' => false, - 'nofiles' => false, - 'orderby' => 'name', - //'mime_type' => '', - )); - if (!is_array($files) || - // we also need to return false, if $url is not a directory! - count($files) == 1 && $path == egw_vfs::concat($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[egw_vfs::concat($file['directory'],$file['name'])] = $file; - } - //print_r($this->opened_dir); - reset($this->opened_dir); - - return true; - } - - /** - * This method is called in response to stat() calls on the URL paths associated with the wrapper. - * - * It should return as many elements in common with the system function as possible. - * Unknown or unavailable values should be set to a rational value (usually 0). - * - * If you plan to use your wrapper in a require_once you need to define stream_stat(). - * If you plan to allow any other tests like is_file()/is_dir(), you have to define url_stat(). - * stream_stat() must define the size of the file, or it will never be included. - * url_stat() must define mode, or is_file()/is_dir()/is_executable(), and any of those functions affected by clearstatcache() simply won't work. - * It's not documented, but directories must be a mode like 040777 (octal), and files a mode like 0100666. - * If you wish the file to be executable, use 7s instead of 6s. - * The last 3 digits are exactly the same thing as what you pass to chmod. - * 040000 defines a directory, and 0100000 defines a file. - * - * @param string $path - * @param int $flags holds additional flags set by the streams API. It can hold one or more of the following values OR'd together: - * - STREAM_URL_STAT_LINK For resources with the ability to link to other resource (such as an HTTP Location: forward, - * or a filesystem symlink). This flag specified that only information about the link itself should be returned, - * not the resource pointed to by the link. - * 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 - */ - static function url_stat ( $url, $flags ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$flags)"); - - $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]); - } - - 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' => '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 self::_vfsinfo2stat($info); - } - - /** - * This method is called in response to readdir(). - * - * It should return a string representing the next filename in the location opened by dir_opendir(). - * - * @return string - */ - function dir_readdir ( ) - { - 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 : false; - } - - /** - * This method is called in response to rewinddir(). - * - * It should reset the output generated by dir_readdir(). i.e.: - * The next call to dir_readdir() should return the first entry in the location returned by dir_opendir(). - * - * @return boolean - */ - function dir_rewinddir ( ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."( )"); - - if (!is_array($this->opened_dir)) return false; - - reset($this->opened_dir); - - return true; - } - - /** - * This method is called in response to closedir(). - * - * You should release any resources which were locked or allocated during the opening and use of the directory stream. - * - * @return boolean - */ - function dir_closedir ( ) - { - if (self::LOG_LEVEL > 1) error_log(__METHOD__."( )"); - - if (!is_array($this->opened_dir)) return false; - - $this->opened_dir = null; - - return true; - } - - /** - * Convert a vfs-file-info into a stat array - * - * @param array $info - * @return array - */ - static private function _vfsinfo2stat($info) - { - $stat = array( - 'ino' => $info['file_id'], - 'name' => $info['name'], - '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'] == self::DIR_MIME_TYPE ? 2 : 1, - // eGW addition to return the mime type - 'mime' => $info['mime_type'], - ); - //error_log(__METHOD__."($info[name]) = ".print_r($stat,true)); - return $stat; - } - - /** - * Multibyte save substr - * - * @param string $str - * @param int $start - * @param int $length=null - * @return string - */ - static function substr($str,$start,$length=null) - { - static $func_overload; - - if (is_null($func_overload)) $func_overload = extension_loaded('mbstring') ? ini_get('mbstring.func_overload') : 0; - - 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']; - } - } - - /** - * Initialise our static vars - * - */ - function init_static() - { - stream_register_wrapper(self::SCHEME ,__CLASS__); - - if (!is_object(self::$old_vfs)) - { - self::$old_vfs =& new vfs_home(); - self::$old_vfs->override_acl =& egw_vfs::$is_root; - } - } -} - -oldvfs_stream_wrapper::init_static(); diff --git a/phpgwapi/inc/class.oldvfs_webdav_server.inc.php b/phpgwapi/inc/class.oldvfs_webdav_server.inc.php deleted file mode 100644 index 87e1c96f17..0000000000 --- a/phpgwapi/inc/class.oldvfs_webdav_server.inc.php +++ /dev/null @@ -1,459 +0,0 @@ - - * @copyright (c) 2006 by Ralf Becker - * @version $Id$ - */ - -require_once('HTTP/WebDAV/Server.php'); -require_once(EGW_API_INC.'/class.vfs_home.inc.php'); - -/** - * FileManger - WebDAV access - * - * Using the PEAR HTTP/WebDAV/Server class (which need to be installed!) - */ -class oldvfs_webdav_server extends HTTP_WebDAV_Server -{ - /** - * instance of the vfs class - * - * @var vfs_home - */ - var $vfs; - - var $dav_powered_by = 'eGroupWare WebDAV server'; - - /** - * Debug level: 0 = nothing, 1 = function calls, 2 = more info, eg. complete $_SERVER array - * - * The debug messages are send to the apache error_log - * - * @var integer - */ - var $debug = 0; - - function __construct() - { - if ($this->debug === 2) foreach($_SERVER as $name => $val) error_log("vfs_webdav_server: \$_SERVER[$name]='$val'"); - - parent::HTTP_WebDAV_Server(); - - $this->vfs =& new vfs_home; - } - - /** - * PROPFIND method handler - * - * @param array general parameter passing array - * @param array return array for file properties - * @return bool true on success - */ - function PROPFIND(&$options, &$files) - { - $vfs_data = array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - // at first only list the given path itself - 'checksubdirs' => False, - 'nofiles' => True - ); - if (!($vfs_files = $this->vfs->ls($vfs_data))) // path not found - { - // check if the users home-dir is just not yet created (should be done by the vfs-class!) - // ToDo: group-dirs - if ($vfs_data['string'] == '/home/'.$GLOBALS['egw_info']['user']['account_lid']) - { - $this->vfs->override_acl = true; // user has no right to create dir in /home - $created = $this->vfs->mkdir(array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - )); - $this->vfs->override_acl = false; - - if (!$created) - { - if ($this->debug) error_log("vfs_webdav_server::PROPFIND(path='$options[path]',depth=$options[depth]) could not create home dir"); - } - $vfs_files = $this->vfs->ls($vfs_data); - } - if (!$vfs_files) - { - if ($this->debug) error_log("vfs_webdav_server::PROPFIND(path='$options[path]',depth=$options[depth]) return false (path not found)"); - return false; // path not found - } - } - // if depth > 0 and path is a directory => show it's contents - if (!empty($options['depth']) && $vfs_files[0]['mime_type'] == 'Directory') - { - $vfs_data['checksubdirs'] = (int) $options['depth'] != 1; - $vfs_data['nofiles'] = false; - - if ($vfs_files[0]['directory'] == '/') // sub-dirs of the root? - { - $vfs_files = array(); // dont return the directory, it shows up double in konq - } - else // return the dir itself with a trailing slash, otherwise empty dirs are reported as non-existent - { - $vfs_files[0]['name'] .= '/'; - } - $vfs_files = array_merge($vfs_files,$this->vfs->ls($vfs_data)); - } - if ($this->debug) error_log("vfs_webdav_server::PROPFIND(path='$options[path]',depth=$options[depth]) ".count($vfs_files).' files'); - - $files['files'] = array(); - $egw_charset = $GLOBALS['egw']->translation->charset(); - foreach($vfs_files as $fileinfo) - { - if ($this->debug) error_log('dir="'.$fileinfo['directory'].'", name="'.$fileinfo['name'].'": '.$fileinfo['mime_type']); - foreach(array('modified','created') as $date) - { - // our vfs has no modified set, if never modified, use created - list($y,$m,$d,$h,$i,$s) = split("[- :]",$fileinfo[$date] ? $fileinfo[$date] : $fileinfo['created']); - $fileinfo[$date] = mktime((int)$h,(int)$i,(int)$s,(int)$m,(int)$d,(int)$y); - } - $info = array( - 'path' => $GLOBALS['egw']->translation->convert($fileinfo['directory'].'/'.$fileinfo['name'],$egw_charset,'utf-8'), - 'props' => array( - $this->mkprop('displayname',$GLOBALS['egw']->translation->convert($fileinfo['name'],$egw_charset,'utf-8')), - $this->mkprop('creationdate',$fileinfo['created']), - $this->mkprop('getlastmodified',$fileinfo['modified']), - ), - ); - if ($fileinfo['mime_type'] == 'Directory') - { - $info['props'][] = $this->mkprop('resourcetype', 'collection'); - $info['props'][] = $this->mkprop('getcontenttype', 'httpd/unix-directory'); - } - else - { - $info['props'][] = $this->mkprop('resourcetype', ''); - $info['props'][] = $this->mkprop('getcontenttype', $fileinfo['mime_type']); - $info['props'][] = $this->mkprop('getcontentlength', $fileinfo['size']); - } - $files['files'][] = $info; - } - if ($this->debug == 2) foreach($files['files'] as $info) error_log(print_r($info,true)); - // ok, all done - return true; - } - - /** - * GET method handler - * - * @param array parameter passing array - * @return bool true on success - */ - function GET(&$options) - { - if ($this->debug) error_log('vfs_webdav_server::GET('.print_r($options,true).')'); - - $vfs_data = array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - 'checksubdirs' => False, - 'nofiles' => True - ); - // sanity check - if (!($vfs_file = $this->vfs->ls($vfs_data))) - { - return false; - } - $options['mimetype'] = $vfs_file[0]['mime_type']; - $options['size'] = $vfs_file[0]['size']; - - if (($options['data'] = $this->vfs->read($vfs_data)) === false) - { - return '403 Forbidden'; // not sure if this is the right code for access denied - } - return true; - } - - /** - * PUT method handler - * - * @param array parameter passing array - * @return bool true on success - */ - function PUT(&$options) - { - if ($this->debug) error_log('vfs_webdav_server::PUT('.print_r($options,true).')'); - - $vfs_data = array( - 'string' => dirname($GLOBALS['egw']->translation->convert($options['path'],'utf-8')), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - 'checksubdirs' => False, - 'nofiles' => True - ); - if (!($vfs_file = $this->vfs->ls($vfs_data)) || $vfs_file[0]['mime_type'] != 'Directory') - { - return '409 Conflict'; - } - $vfs_data = array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - ); - $options['new'] = !$this->vfs->file_exists($vfs_data); - - $vfs_data['content'] = ''; - while(!feof($options['stream'])) - { - $vfs_data['content'] .= fread($options['stream'],8192); - } - return $this->vfs->write($vfs_data); - } - - /** - * MKCOL method handler - * - * @param array general parameter passing array - * @return bool true on success - */ - function MKCOL($options) - { - if ($this->debug) error_log('vfs_webdav_server::MKCOL('.print_r($options,true).')'); - - $vfs_data = array( - 'string' => dirname($GLOBALS['egw']->translation->convert($options['path'],'utf-8')), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - 'checksubdirs' => False, - 'nofiles' => True - ); - if (!($vfs_file = $this->vfs->ls($vfs_data))) - { - return '409 Conflict'; - } - if ($this->debug) error_log(print_r($vfs_file,true)); - - if ($vfs_file[0]['mime_type'] != 'Directory') - { - return '403 Forbidden'; - } - - $vfs_data = array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - ); - if ($this->vfs->file_exists($vfs_data) ) - { - return '405 Method not allowed'; - } - - if (!empty($_SERVER['CONTENT_LENGTH'])) // no body parsing yet - { - return '415 Unsupported media type'; - } - - if (!$this->vfs->mkdir($vfs_data)) - { - return '403 Forbidden'; - } - - return '201 Created'; - } - - /** - * DELETE method handler - * - * @param array general parameter passing array - * @return bool true on success - */ - function DELETE($options) - { - if ($this->debug) error_log('vfs_webdav_server::DELETE('.print_r($options,true).')'); - - $vfs_data = array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - ); - if (!$this->vfs->file_exists($vfs_data)) - { - return '404 Not found'; - } - if (!$this->vfs->rm($vfs_data)) - { - return '403 Forbidden'; - } - return '204 No Content'; - } - - /** - * MOVE method handler - * - * @param array general parameter passing array - * @return bool true on success - */ - function MOVE($options) - { - return $this->COPY($options, true); - } - - /** - * COPY method handler - * - * @param array general parameter passing array - * @return bool true on success - */ - function COPY($options, $del=false) - { - if ($this->debug) error_log('vfs_webdav_server::'.($del ? 'MOVE' : 'COPY').'('.print_r($options,true).')'); - - // TODO Property updates still broken (Litmus should detect this?) - - if (!empty($_SERVER['CONTENT_LENGTH'])) // no body parsing yet - { - return '415 Unsupported media type'; - } - - // no copying to different WebDAV Servers yet - if (isset($options['dest_url'])) - { - return '502 bad gateway'; - } - - $source = array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - ); - if (!$this->vfs->file_exists($source)) - { - return '404 Not found'; - } - - $dest = array( - 'string' => $options['dest'], - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - ); - $new = !$this->vfs->file_exists($dest); - $existing_col = false; - - if (!$new) - { - if ($del && $this->vfs->file_type($dest) == 'Directory') - { - if (!$options['overwrite']) - { - return '412 precondition failed'; - } - $dest['string'] .= basename($GLOBALS['egw']->translation->convert($options['path'],'utf-8')); - if ($this->vfs->file_exists($dest)) - { - $options['dest'] .= basename($GLOBALS['egw']->translation->convert($options['path'],'utf-8')); - } - else - { - $new = true; - $existing_col = true; - } - } - } - - if (!$new) - { - if ($options['overwrite']) - { - $stat = $this->DELETE(array('path' => $options['dest'])); - if (($stat{0} != '2') && (substr($stat, 0, 3) != '404')) - { - return $stat; - } - } - else - { - return '412 precondition failed'; - } - } - - if ($this->vfs->file_type($source) == 'Directory' && ($options['depth'] != 'infinity')) - { - // RFC 2518 Section 9.2, last paragraph - return '400 Bad request'; - } - - $op = $del ? 'mv' : 'cp'; - $vfs_data = array( - 'from' => $source['string'], - 'to' => $dest['string'], - 'relatives' => array(RELATIVE_ROOT,RELATIVE_ROOT) - ); - if (!$this->vfs->$op($vfs_data)) - { - return '500 Internal server error'; - } - return ($new && !$existing_col) ? '201 Created' : '204 No Content'; - } - - /** - * PROPPATCH method handler - * - * The current version only allows Webdrive to set creation and modificaton dates. - * They are not stored as (arbitrary) WebDAV properties with their own namespace and name, - * but in the regular vfs attributes. - * - * @todo Store a properties in the DB and retrieve them in PROPFIND again. - * @param array general parameter passing array - * @return bool true on success - */ - function PROPPATCH(&$options) - { - foreach ($options["props"] as $key => $prop) { - $attributes = array(); - switch($prop['ns']) - { - // allow Webdrive to set creation and modification time - case 'http://www.southrivertech.com/': - switch($prop['name']) - { - case 'srt_modifiedtime': - case 'getlastmodified': - $attributes['modified'] = strtotime($prop['val']); - break; - case 'srt_creationtime': - $attributes['created'] = strtotime($prop['val']); - break; - } - break; - - case 'DAV:': - switch($prop['name']) - { - // allow netdrive to change the modification time - case 'getlastmodified': - $attributes['modified'] = strtotime($prop['val']); - break; - // not sure why, the filesystem example of the WebDAV class does it ... - default: - $options["props"][$key]['status'] = "403 Forbidden"; - break; - } - break; - } - if ($this->debug) $props[] = '('.$prop["ns"].')'.$prop['name'].'='.$prop['val']; - } - if ($attributes) - { - $vfs_data = array( - 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), - 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root - 'attributes'=> $attributes, - ); - $this->vfs->set_attributes($vfs_data); - } - if ($this->debug) - { - error_log(__CLASS__.'::'.__METHOD__.": path=$options[path], props=".implode(', ',$props)); - if ($attributes) error_log(__CLASS__.'::'.__METHOD__.": path=$options[path], set attributes=".str_replace("\n",' ',print_r($attributes,true))); - } - - - return ""; // this is as the filesystem example handler does it, no true or false ... - } -} \ No newline at end of file diff --git a/phpgwapi/inc/class.vfs.inc.php b/phpgwapi/inc/class.vfs.inc.php deleted file mode 100644 index 3a51bdb7e3..0000000000 --- a/phpgwapi/inc/class.vfs.inc.php +++ /dev/null @@ -1,1417 +0,0 @@ - * - * This class handles file/dir access for eGroupWare * - * Copyright (C) 2001 Jason Wies * - * -------------------------------------------------------------------------* - * This library is part of the eGroupWare API * - * http://www.egroupware.org/api * - * ------------------------------------------------------------------------ * - * This library is free software; you can redistribute it and/or modify it * - * under the terms of the GNU Lesser General Public License as published by * - * the Free Software Foundation; either version 2.1 of the License, * - * or any later version. * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License * - * along with this library; if not, write to the Free Software Foundation, * - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - \**************************************************************************/ - - /* $Id$ */ - - if (empty ($GLOBALS['egw_info']['server']['file_repository'])) - { - $GLOBALS['egw_info']['server']['file_repository'] = 'sql'; - } - - /* Relative defines. Used mainly by getabsolutepath () */ - define ('RELATIVE_ROOT', 1); - define ('RELATIVE_USER', 2); - define ('RELATIVE_CURR_USER', 4); - define ('RELATIVE_USER_APP', 8); - define ('RELATIVE_PATH', 16); - define ('RELATIVE_NONE', 32); - define ('RELATIVE_CURRENT', 64); - define ('VFS_REAL', 1024); - define ('RELATIVE_ALL', RELATIVE_PATH); - - /* These are used in calls to add_journal (), and allow journal messages to be more standard */ - define ('VFS_OPERATION_CREATED', 1); - define ('VFS_OPERATION_EDITED', 2); - define ('VFS_OPERATION_EDITED_COMMENT', 4); - define ('VFS_OPERATION_COPIED', 8); - define ('VFS_OPERATION_MOVED', 16); - define ('VFS_OPERATION_DELETED', 32); - - /** - * * helper class for path_parts - * * - */ - class path_class - { - var $mask; - var $outside; - var $fake_full_path; - var $fake_leading_dirs; - var $fake_extra_path; - var $fake_name; - var $real_full_path; - var $real_leading_dirs; - var $real_extra_path; - var $real_name; - var $fake_full_path_clean; - var $fake_leading_dirs_clean; - var $fake_extra_path_clean; - var $fake_name_clean; - var $real_full_path_clean; - var $real_leading_dirs_clean; - var $real_extra_path_clean; - var $real_name_clean; - } - - /** - * * Base class for Virtual File System classes - * * - * * @author Zone - */ - class vfs_shared - { - /* - * All VFS classes must have some form of 'linked directories'. - * Linked directories allow an otherwise disparate "real" directory - * to be linked into the "virtual" filesystem. See make_link(). - */ - var $linked_dirs = array (); - - /* - * All VFS classes need to support the access control in some form - * (see acl_check()). There are times when applications will need - * to explictly disable access checking, for example when creating a - * user's home directory for the first time or when the admin is - * performing maintanence. When override_acl is set, any access - * checks must return True. - */ - var $override_acl = 0; - - /* - * The current relativity. See set_relative() and get_relative(). - */ - var $relative; - - /* - * Implementation dependant 'base real directory'. It is not required - * that derived classes use $basedir, but some of the shared functions - * below rely on it, so those functions will need to be overload if - * basedir isn't appropriate for a particular backend. - */ - var $basedir; - - /* - * Fake base directory. Only the administrator should change this. - */ - var $fakebase = '/home'; - - /* - * All derived classes must store certain information about each - * location. The attributes in the 'attributes' array represent - * the minimum attributes that must be stored. Derived classes - * should add to this array any custom attributes. - * - * Not all of the attributes below are appropriate for all backends. - * Those that don't apply can be replaced by dummy values, ie. '' or 0. - */ - var $attributes = array( - 'file_id', /* Integer. Unique to each location */ - 'owner_id', /* phpGW account_id of owner */ - 'createdby_id', /* phpGW account_id of creator */ - 'modifiedby_id',/* phpGW account_id of who last modified */ - 'created', /* Datetime created, in SQL format */ - 'modified', /* Datetime last modified, in SQL format */ - 'size', /* Size in bytes */ - 'mime_type', /* Mime type. 'Directory' for directories */ - 'comment', /* User-supplied comment. Can be empty */ - 'app', /* Name of phpGW application responsible for location */ - 'directory', /* Directory location is in */ - 'name', /* Name of file/directory */ - 'link_directory', /* Directory location is linked to, if any */ - 'link_name', /* Name location is linked to, if any */ - 'version', /* Version of file. May be 0 */ - ); - - /** - * * constructor - * * - * * All derived classes should call this function in their - * constructor ($this->vfs_shared()) - */ - function vfs_shared () - { - } - - /* - * Definitions for functions that every derived - * class must have, and suggestions for private functions - * to completement the public ones. The prototypes for - * the public functions need to be uniform for all - * classes. Of course, each derived class should overload these - * functions with their own version. - */ - - /* - * Journal functions. - * - * See also: VFS_OPERATION_* defines - * - * Overview: - * Each action performed on a location - * should be recorded, in both machine and human - * readable format. - * - * PRIVATE functions (suggested examples only, not mandatory): - * - * add_journal - Add journal entry - * flush_journal - Clear all journal entries for a location - * - * PUBLIC functions (mandatory): - * - * get_journal - Get journal entries for a location - */ - - /* Private, suggestions only */ - function add_journal ($data) {} - function flush_journal ($data) {} - - /** - * * Get journal entries for a location - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * type [0|1|2] - * 0 = any journal entries - * 1 = current journal entries - * 2 = deleted journal entries - * * @return Array of arrays of journal entries - * The keys will vary depending on the implementation, - * with most attributes in this->attributes being valid, - * and these keys being mandatory: - * created - Datetime in SQL format that journal entry - * was entered - * comment - Human readable comment describing the action - * version - May be 0 if the derived class does not support - * versioning - */ - function get_journal ($data) { return array(array()); } - - /* - * Access checking functions. - * - * Overview: - * Each derived class should have some kind of - * user and group access control. This will - * usually be based directly on the ACL class. - * - * If $this->override_acl is set, acl_check() - * must always return True. - * - * PUBLIC functions (mandatory): - * - * acl_check() - Check access for a user to a given - */ - - /** - * * Check access for a user to a given location - * * - * * If $this->override_acl is set, always return True - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * operation Operation to check access for. Any combination - * of the EGW_ACL_* defines, for example: - * EGW_ACL_READ - * EGW_ACL_READ|EGW_ACL_WRITE - * * owner_id phpGW ID to check access for. - * * Default: $GLOBALS['egw_info']['user']['account_id'] - * * must_exist If set, string must exist, and acl_check() must - * return False if it doesn't. If must_exist isn't - * passed, and string doesn't exist, check the owner_id's - * access to the parent directory, if it exists. - * * @return Boolean. True if access is ok, False otherwise. - */ - function acl_check ($data) { return True; } - - /* - * Operations functions. - * - * Overview: - * These functions perform basic file operations. - * - * PUBLIC functions (mandatory): - * - * read - Retreive file contents - * - * write - Store file contents - * - * touch - Create a file if it doesn't exist. - * Optionally, update the modified time and - * modified user if the file exists. - * - * cp - Copy location - * - * mv - Move location - * - * rm - Delete location - * - * mkdir - Create directory - */ - - /** - * * Retreive file contents - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * @return String. Contents of 'string', or False on error. - */ - function read ($data) { return False; } - - /** - * Views the specified file (does not return!) - * - * @param string filename - * @param relatives Relativity array - * @return None (doesnt return) - * By default this function just reads the file and - * outputs it too the browser, after setting the content-type header - * appropriately. For some other VFS implementations though, there - * may be some more sensible way of viewing the file. - */ - function view($data) - { - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $GLOBALS['egw_info']['flags']['noheader'] = true; - $GLOBALS['egw_info']['flags']['nonavbar'] = true; - $GLOBALS['egw_info']['flags']['noappheader'] = true; - $GLOBALS['egw_info']['flags']['noappfooter'] = true; - $ls_array = $this->ls (array ( - 'string' => $data['string'], - 'relatives' => $data['relatives'], - 'checksubdirs' => False, - 'nofiles' => True - ) - ); - - if ($ls_array[0]['mime_type']) - { - $mime_type = $ls_array[0]['mime_type']; - } - elseif ($GLOBALS['settings']['viewtextplain']) - { - $mime_type = 'text/plain'; - } - - header('Content-type: ' . $mime_type); - echo $this->read (array ( - 'string' => $data['string'], - 'relatives' => $data['relatives'], - ) - ); - exit(); - } - - /** - * * Store file contents - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function write ($data) { return False; } - - /** - * * Create a file if it doesn't exist. - * * - * Optionally, update the modified time and - * modified user if the file exists. - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function touch ($data) { return False; } - - /** - * * Copy location - * * - * * from Path to location to copy from - * * to Path to location to copy to - * * relatives Relativity array (default: RELATIVE_CURRENT, RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function cp ($data) { return False; } - - /** - * * Move location - * * - * * from Path to location to move from - * * to Path to location to move to - * * relatives Relativity array (default: RELATIVE_CURRENT, RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function mv ($data) { return False; } - - /** - * * Delete location - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function rm ($data) { return False; } - - /** - * * Create directory - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function mkdir ($data) { return False; } - - /* - * Information functions. - * - * Overview: - * These functions set or return information about locations. - * - * PUBLIC functions (mandatory): - * - * set_attributes - Set attributes for a location - * - * file_exists - Check if a location (file or directory) exists - * - * get_size - Determine size of location - * - * ls - Return detailed information for location(s) - */ - - /** - * * Set attributes for a location - * * - * * Valid attributes are listed in vfs->attributes, - * which may be extended by each derived class - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * attributes Keyed array of attributes. Key is attribute - * name, value is attribute value. - * * @return Boolean. True on success, False otherwise. - */ - function set_attributes ($data) { return False; } - - /** - * * Check if a location (file or directory) exists - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * @return Boolean. True if file exists, False otherwise. - */ - function file_exists ($data) { return False; } - - /** - * * Determine size of location - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * checksubdirs Boolean. If set, include the size of - * all subdirectories recursively. - * * @return Integer. Size of location in bytes. - */ - function get_size ($data) { return 0; } - - /** - * * Return detailed information for location(s) - * * - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * checksubdirs Boolean. If set, return information for all - * subdirectories recursively. - * * mime String. Only return information for locations with MIME type - * specified. VFS classes must recogize these special types: - * "Directory" - Location is a directory - * " " - Location doesn't not have a MIME type - * * nofiles Boolean. If set and 'string' is a directory, return - * information about the directory, not the files in it. - * * @return Array of arrays of file information. - * Keys may vary depending on the implementation, but must include - * at least those attributes listed in $this->attributes. - */ - function ls ($data) { return array(array()); } - - /* - * Linked directory functions. - * - * Overview: - * One 'special' feature that VFS classes must support - * is linking an otherwise unrelated 'real' directory into - * the virtual filesystem. For a traditional filesystem, this - * might mean linking /var/specialdir in the real filesystem to - * /home/user/specialdir in the VFS. For networked filesystems, - * this might mean linking 'another.host.com/dir' to - * 'this.host.com/home/user/somedir'. - * - * This is a feature that will be used mostly be administrators, - * in order to present a consistent view to users. Each VFS class - * will almost certainly need a new interface for the administrator - * to use to make links, but the concept is the same across all the - * VFS backends. - * - * Note that by using $this->linked_dirs in conjunction with - * $this->path_parts(), you can keep the implementation of linked - * directories very isolated in your code. - * - * PUBLIC functions (mandatory): - * - * make_link - Create a real to virtual directory link - */ - - /** - * * Create a real to virtual directory link - * * - * * rdir Real directory to make link from/to - * * vdir Virtual directory to make link to/from - * * relatives Relativity array (default: RELATIVE_CURRENT, RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function make_link ($data) { return False; } - - /* - * Miscellaneous functions. - * - * PUBLIC functions (mandatory): - * - * update_real - Ensure that information about a location is - * up-to-date - * - * compress - Archives a file or set of files in a compressed file - * - * extract - Dearchives a file or set of files of a compressed file - */ - - /** - * * Ensure that information about a location is up-to-date - * * - * * Some VFS backends store information about locations - * in a secondary location, for example in a database - * or in a cache file. update_real() can be called to - * ensure that the information in the secondary location - * is up-to-date. - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * @return Boolean. True on success, False otherwise. - */ - function update_real ($data) { return False; } - - /** - * * Creates an archive from a file or a set of files - * * - * * files File names to be stored in archive (array) - * * name Name of archive - * * type The type of compression, can be 'zip'(default)or 'gz' - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * Note: the last item is the relativity of the dest archive - * * @return Boolean. True on success, False otherwise. - */ - - function compress ($data) { return False; } - - /** - * * Extracts a file (or files) from archive - * * - * * name Name of archive - * * dest The destination path of files to be extracted - * * type The type of compression, can be 'zip' or 'gz'. If - * * not specified, uses according to the extension - * * files Files to be extracted from archive - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * Note: the first item is the relativity of the archive, the last of - * * the dest dir - * * @return Boolean. True on success, False otherwise. - */ - - function extract ($data) { return False; } - - - - /* - * SHARED FUNCTIONS - * - * The rest of the functions in this file are shared between - * all derived VFS classes. - * - * Derived classes can overload any of these functions if they - * see it fit to do so, as long as the prototypes and return - * values are the same for public functions, and the function - * accomplishes the same goal. - * - * PRIVATE functions: - * - * securitycheck - Check if location string is ok to use in VFS functions - * - * sanitize - Remove any possible security problems from a location - * string (i.e. remove leading '..') - * - * clean_string - Clean location string. This function is used if - * any special characters need to be escaped or removed - * before accessing a database, network protocol, etc. - * The default is to escape characters before doing an SQL - * query. - * - * getabsolutepath - Translate a location string depending on the - * relativity. This is the only function that is - * directly concerned with relativity. - * - * get_ext_mime_type - Return MIME type based on file extension - * - * PUBLIC functions (mandatory): - * - * set_relative - Sets the current relativity, the relativity used - * when RELATIVE_CURRENT is passed to a function - * - * get_relative - Return the current relativity - * - * path_parts - Return information about the component parts of a location string - * - * cd - Change current directory. This function is used to store the - * current directory in a standard way, so that it may be accessed - * throughout phpGroupWare to provide a consistent view for the user. - * - * pwd - Return current directory - * - * copy - Alias for cp - * - * move - Alias for mv - * - * delete - Alias for rm - * - * dir - Alias for ls - * - * command_line - Process and run a Unix-sytle command line - * - * compress - Archives a file or set of files in a compressed file - * - * extract - Dearchives a file or set of files of a compressed file - */ - - /* PRIVATE functions */ - - /** - * * Check if location string is ok to use in VFS functions - * * - * * Checks for basic violations such as .. - * If securitycheck () fails, run your string through $this->sanitize () - * * string Path to location - * * @return Boolean. True if string is ok, False otherwise. - */ - function securitycheck ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - if (substr ($data['string'], 0, 1) == '\\' || strpos($data['string'], '..') !== false || - strpos($data['string'], '\\..') !== false || strpos($data['string'], '.\\.') !== false) - { - return False; - } - else - { - return True; - } - } - - /** - * * Remove any possible security problems from a location - * * - * string (i.e. remove leading '..') - * * You should not pass all filenames through sanitize () - * unless you plan on rejecting .files. Instead, pass - * the name through securitycheck () first, and if it fails, - * pass it through sanitize. - * * string Path to location - * * @return String. 'string' with any security problems fixed. - */ - function sanitize ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - /* We use path_parts () just to parse the string, not translate paths */ - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array (RELATIVE_NONE) - ) - ); - - return (ereg_replace ("^\.+", '', $p->fake_name)); - } - - /** - * * Clean location string. This function is used if - * * - * any special characters need to be escaped or removed - * before accessing a database, network protocol, etc. - * The default is to escape characters before doing an SQL - * query. - * * string Location string to clean - * * @return String. Cleaned version of 'string'. - */ - function clean_string ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $string = $GLOBALS['egw']->db->db_addslashes ($data['string']); - - return $string; - } - - /** - * * Translate a location string depending on the - * * - * relativity. This is the only function that is - * directly concerned with relativity. - * * string Path to location, relative to mask[0]. - * * Defaults to empty string. - * * mask Relativity array (default: RELATIVE_CURRENT) - * * fake Boolean. If set, returns the 'fake' path, - * i.e. /home/user/dir/file. This is not always - * possible, use path_parts() instead. - * * @return String. Full fake or real path, or False on error. - */ - function getabsolutepath ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'string' => False, - 'mask' => array (RELATIVE_CURRENT), - 'fake' => True - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $currentdir = $this->pwd (False); - - /* If they supply just VFS_REAL, we assume they want current relativity */ - if ($data['mask'][0] == VFS_REAL) - { - $data['mask'][0] |= RELATIVE_CURRENT; - } - - if (!$this->securitycheck (array( - 'string' => $data['string'] - )) - ) - { - return False; - } - - if ($data['mask'][0] & RELATIVE_NONE) - { - return $data['string']; - } - - if ($data['fake']) - { - $sep = '/'; - } - else - { - $sep = SEP; - } - - /* if RELATIVE_CURRENT, retrieve the current mask */ - if ($data['mask'][0] & RELATIVE_CURRENT) - { - $mask = $data['mask'][0]; - /* Respect any additional masks by re-adding them after retrieving the current mask*/ - $data['mask'][0] = $this->get_relative () + ($mask - RELATIVE_CURRENT); - } - - if ($data['fake']) - { - $basedir = "/"; - } - else - { - $basedir = $this->basedir . $sep; - - /* This allows all requests to use /'s */ - $data['string'] = preg_replace ("|/|", $sep, $data['string']); - } - - if (($data['mask'][0] & RELATIVE_PATH) && $currentdir) - { - $basedir = $basedir . $currentdir . $sep; - } - elseif (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP)) - { - $basedir = $basedir . $this->fakebase . $sep; - } - - if ($data['mask'][0] & RELATIVE_CURR_USER) - { - $basedir = $basedir . $this->working_lid . $sep; - } - - if (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP)) - { - $basedir = $basedir . $GLOBALS['egw_info']['user']['account_lid'] . $sep; - } - - if ($data['mask'][0] & RELATIVE_USER_APP) - { - $basedir = $basedir . "." . $GLOBALS['egw_info']['flags']['currentapp'] . $sep; - } - - /* Don't add string if it's a /, just for aesthetics */ - if ($data['string'] && $data['string'] != $sep) - { - $basedir = $basedir . $data['string']; - } - - /* Let's not return // */ - while (ereg ($sep . $sep, $basedir)) - { - $basedir = ereg_replace ($sep . $sep, $sep, $basedir); - } - - // remove trailing slash - if ($basedir != '/' && substr($basedir,-1) == '/') $basedir = substr($basedir,0,-1); - - return $basedir; - } - - /** - * * Return MIME type based on file extension - * * - * * Internal use only. Applications should call vfs->file_type () - * * @author skeeter - * * string Real path to file, with or without leading paths - * * @return String. MIME type based on file extension. - */ - function get_ext_mime_type ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $file=basename($data['string']); - $mimefile=EGW_API_INC.'/phpgw_mime.types'; - $fp=fopen($mimefile,'r'); - $contents = explode("\n",fread($fp,filesize($mimefile))); - fclose($fp); - - $parts=explode('.',strtolower($file)); - $ext=$parts[(sizeof($parts)-1)]; - - for($i=0;$i= 2) - { - for($j=1;$jrelative); - } - else - { - $this->relative = $data['mask']; - } - } - - /** - * * Return the current relativity - * * - * * Returns relativity bitmask, or the default - * of "completely relative" if unset - * * @return Integer. One of the RELATIVE_* defines. - */ - function get_relative () - { - if (isset ($this->relative) && $this->relative) - { - return $this->relative; - } - else - { - return RELATIVE_ALL; - } - } - - /** - * * Return information about the component parts of a location string - * * - * * Most VFS functions call path_parts() with their 'string' and - * 'relatives' arguments before doing their work, in order to - * determine the file/directory to work on. - * * string Path to location - * * relatives Relativity array (default: RELATIVE_CURRENT) - * * object If set, return an object instead of an array - * * nolinks Don't check for linked directories (made with - * make_link()). Used internally to prevent recursion. - * * @return Array or object. Contains the fake and real component parts of the path. - * * Returned values are: - * mask - * outside - * fake_full_path - * fake_leading_dirs - * fake_extra_path BROKEN - * fake_name - * real_full_path - * real_leading_dirs - * real_extra_path BROKEN - * real_name - * fake_full_path_clean - * fake_leading_dirs_clean - * fake_extra_path_clean BROKEN - * fake_name_clean - * real_full_path_clean - * real_leading_dirs_clean - * real_extra_path_clean BROKEN - * real_name_clean - * "clean" values are run through vfs->clean_string () and - * are safe for use in SQL queries that use key='value' - * They should be used ONLY for SQL queries, so are used - * mostly internally - * mask is either RELATIVE_NONE or RELATIVE_NONE|VFS_REAL, - * and is used internally - * outside is boolean, True if 'relatives' contains VFS_REAL - */ - function path_parts ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'object' => True, - 'nolinks' => False - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $sep = SEP; - - $rarray['mask'] = RELATIVE_NONE; - - if (!($data['relatives'][0] & VFS_REAL)) - { - $rarray['outside'] = False; - $fake = True; - } - else - { - $rarray['outside'] = True; - $rarray['mask'] |= VFS_REAL; - } - - $string = $this->getabsolutepath (array( - 'string' => $data['string'], - 'mask' => array ($data['relatives'][0]), - 'fake' => $fake - ) - ); - - if ($fake) - { - $base_sep = '/'; - $base = '/'; - - $opp_base = $this->basedir . $sep; - - $rarray['fake_full_path'] = $string; - } - else - { - $base_sep = $sep; - if (substr($string,0,strlen($this->basedir)+1) == $this->basedir . $sep) - { - $base = $this->basedir . $sep; - } - else - { - $base = $sep; - } - - $opp_base = '/'; - - $rarray['real_full_path'] = $string; - } - - /* This is needed because of substr's handling of negative lengths */ - $baselen = strlen ($base); - $lastslashpos = @strrpos ($string, $base_sep); - $length = $lastslashpos < $baselen ? 0 : $lastslashpos - $baselen; - - $extra_path = $rarray['fake_extra_path'] = $rarray['real_extra_path'] = substr ($string, strlen ($base), $length); - if($string[1] != ':') - { - $name = $rarray['fake_name'] = $rarray['real_name'] = substr ($string, @strrpos ($string, $base_sep) + 1); - } - else - { - $name = $rarray['fake_name'] = $rarray['real_name'] = $string; - } - - if ($fake) - { - $rarray['real_extra_path'] ? $dispsep = $sep : $dispsep = ''; - $rarray['real_full_path'] = $opp_base . $rarray['real_extra_path'] . $dispsep . $rarray['real_name']; - if ($extra_path) - { - $rarray['fake_leading_dirs'] = $base . $extra_path; - $rarray['real_leading_dirs'] = $opp_base . $extra_path; - } - elseif (@strrpos ($rarray['fake_full_path'], $sep) == 0) - { - /* If there is only one $sep in the path, we don't want to strip it off */ - $rarray['fake_leading_dirs'] = $sep; - $rarray['real_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1); - } - else - { - /* These strip the ending / */ - $rarray['fake_leading_dirs'] = substr ($base, 0, strlen ($base) - 1); - $rarray['real_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1); - } - } - else - { - if($rarray['fake_name'][1] != ':') - { - $rarray['fake_full_path'] = $opp_base . $rarray['fake_extra_path'] . '/' . $rarray['fake_name']; - } - else - { - $rarray['fake_full_path'] = $rarray['fake_name']; - } - if ($extra_path) - { - $rarray['fake_leading_dirs'] = $opp_base . $extra_path; - $rarray['real_leading_dirs'] = $base . $extra_path; - } - else - { - $rarray['fake_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1); - $rarray['real_leading_dirs'] = substr ($base, 0, strlen ($base) - 1); - } - } - - /* We check for linked dirs made with make_link (). This could be better, but it works */ - if (!$data['nolinks']) - { - reset ($this->linked_dirs); - while (list ($num, $link_info) = each ($this->linked_dirs)) - { - if (ereg ("^$link_info[directory]/$link_info[name](/|$)", $rarray['fake_full_path'])) - { - $rarray['real_full_path'] = ereg_replace ("^$this->basedir", '', $rarray['real_full_path']); - $rarray['real_full_path'] = ereg_replace ("^$link_info[directory]" . SEP . "$link_info[name]", $link_info['link_directory'] . SEP . $link_info['link_name'], $rarray['real_full_path']); - - $p = $this->path_parts (array( - 'string' => $rarray['real_full_path'], - 'relatives' => array (RELATIVE_NONE|VFS_REAL), - 'nolinks' => True - ) - ); - - $rarray['real_leading_dirs'] = $p->real_leading_dirs; - $rarray['real_extra_path'] = $p->real_extra_path; - $rarray['real_name'] = $p->real_name; - } - } - } - - /* - We have to count it before because new keys will be added, - which would create an endless loop - */ - $count = count ($rarray); - reset ($rarray); - for ($i = 0; (list ($key, $value) = each ($rarray)) && $i != $count; $i++) - { - $rarray[$key . '_clean'] = $this->clean_string (array ('string' => $value)); - } - - if ($data['object']) - { - $robject =& new path_class; - - reset ($rarray); - while (list ($key, $value) = each ($rarray)) - { - $robject->$key = $value; - } - } - - /* - echo "
fake_full_path: $rarray[fake_full_path] -
fake_leading_dirs: $rarray[fake_leading_dirs] -
fake_extra_path: $rarray[fake_extra_path] -
fake_name: $rarray[fake_name] -
real_full_path: $rarray[real_full_path] -
real_leading_dirs: $rarray[real_leading_dirs] -
real_extra_path: $rarray[real_extra_path] -
real_name: $rarray[real_name]"; - */ - - if ($data['object']) - { - return ($robject); - } - else - { - return ($rarray); - } - } - - /** - * * Change current directory. This function is used to store the - * * - * current directory in a standard way, so that it may be accessed - * throughout phpGroupWare to provide a consistent view for the user. - * * To cd to the root '/', use: - * cd (array( - * 'string' => '/', - * 'relative' => False, - * 'relatives' => array (RELATIVE_NONE) - * )); - * * string Directory location to cd into. Default is '/'. - * * relative If set, add target to current path. - * Else, pass 'relative' as mask to getabsolutepath() - * Default is True. - * * relatives Relativity array (default: RELATIVE_CURRENT) - */ - function cd ($data = '') - { - if (!is_array ($data)) - { - $noargs = 1; - $data = array (); - } - - $default_values = array - ( - 'string' => '/', - 'relative' => True, - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - if ($data['relatives'][0] & VFS_REAL) - { - $sep = SEP; - } - else - { - $sep = '/'; - } - - if ($data['relative'] == 'relative' || $data['relative'] == True) - { - /* if 'string' is "/" and 'relative' is set, we cd to the user/group home dir */ - if ($data['string'] == '/') - { - $data['relatives'][0] = RELATIVE_USER; - $basedir = $this->getabsolutepath (array( - 'string' => False, - 'mask' => array ($data['relatives'][0]), - 'fake' => True - ) - ); - } - else - { - $currentdir = $GLOBALS['egw']->session->appsession('vfs',''); - $basedir = $this->getabsolutepath (array( - 'string' => $currentdir . $sep . $data['string'], - 'mask' => array ($data['relatives'][0]), - 'fake' => True - ) - ); - } - } - else - { - $basedir = $this->getabsolutepath (array( - 'string' => $data['string'], - 'mask' => array ($data['relatives'][0]) - ) - ); - } - - $GLOBALS['egw']->session->appsession('vfs','',$basedir); - - return True; - } - - /** - * * Return current directory - * * - * * full If set, return full fake path, else just - * the extra dirs (False strips the leading /). - * Default is True. - * * @return String. The current directory. - */ - function pwd ($data = '') - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'full' => True - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $currentdir = $GLOBALS['egw']->session->appsession('vfs',''); - - if (!$data['full']) - { - $currentdir = ereg_replace ("^/", '', $currentdir); - } - - if ($currentdir == '' && $data['full']) - { - $currentdir = '/'; - } - - $currentdir = trim ($currentdir); - - return $currentdir; - } - - /** - * * shortcut to cp - * * - */ - function copy ($data) - { - return $this->cp ($data); - } - - /** - * * shortcut to mv - * * - */ - function move ($data) - { - return $this->mv ($data); - } - - /** - * * shortcut to rm - * * - */ - function delete ($data) - { - return $this->rm ($data); - } - - /** - * * shortcut to ls - * * - */ - function dir ($data) - { - return $this->ls ($data); - } - - /** - * * Process and run a Unix-sytle command line - * * - * * EXPERIMENTAL. DANGEROUS. DO NOT USE THIS UNLESS YOU - * KNOW WHAT YOU'RE DOING! - * * This is mostly working, but the command parser needs - * to be improved to take files with spaces into - * consideration (those should be in ""). - * * command_line Unix-style command line with one of the - * commands in the $args array - * * @return The return value of the actual VFS call - */ - function command_line ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $args = array - ( - array ('name' => 'mv', 'params' => 2), - array ('name' => 'cp', 'params' => 2), - array ('name' => 'rm', 'params' => 1), - array ('name' => 'ls', 'params' => -1), - array ('name' => 'du', 'params' => 1, 'func' => get_size), - array ('name' => 'cd', 'params' => 1), - array ('name' => 'pwd', 'params' => 0), - array ('name' => 'cat', 'params' => 1, 'func' => read), - array ('name' => 'file', 'params' => 1, 'func' => file_type), - array ('name' => 'mkdir', 'params' => 1), - array ('name' => 'touch', 'params' => 1) - ); - - if (!$first_space = strpos ($data['command_line'], ' ')) - { - $first_space = strlen ($data['command_line']); - } - if ((!$last_space = strrpos ($data['command_line'], ' ')) || ($last_space == $first_space)) - { - $last_space = strlen ($data['command_line']) + 1; - } - $argv[0] = substr ($data['command_line'], 0, $first_space); - if (strlen ($argv[0]) != strlen ($data['command_line'])) - { - $argv[1] = substr ($data['command_line'], $first_space + 1, $last_space - ($first_space + 1)); - if ((strlen ($argv[0]) + 1 + strlen ($argv[1])) != strlen ($data['command_line'])) - { - $argv[2] = substr ($data['command_line'], $last_space + 1); - } - } - $argc = count ($argv); - - reset ($args); - while (list (,$arg_info) = each ($args)) - { - if ($arg_info['name'] == $argv[0]) - { - $command_ok = 1; - if (($argc == ($arg_info['params'] + 1)) || ($arg_info['params'] == -1)) - { - $param_count_ok = 1; - } - break; - } - } - - if (!$command_ok) - { -// return E_VFS_BAD_COMMAND; - return False; - } - if (!$param_count_ok) - { -// return E_VFS_BAD_PARAM_COUNT; - return False; - } - - for ($i = 1; $i != ($arg_info['params'] + 1); $i++) - { - if (substr ($argv[$i], 0, 1) == "/") - { - $relatives[] = RELATIVE_NONE; - } - else - { - $relatives[] = RELATIVE_ALL; - } - } - - $func = $arg_info['func'] ? $arg_info['func'] : $arg_info['name']; - - if (!$argv[2]) - { - $rv = $this->$func (array( - 'string' => $argv[1], - 'relatives' => $relatives - ) - ); - } - else - { - $rv = $this->$func (array( - 'from' => $argv[1], - 'to' => $argv[2], - 'relatives' => $relatives - ) - ); - } - - return ($rv); - } - - /* Helper functions, not public */ - - function default_values ($data, $default_values) - { - for ($i = 0; list ($key, $value) = each ($default_values); $i++) - { - if (!isset ($data[$key])) - { - $data[$key] = $value; - } - } - - return $data; - } - - } - - include (EGW_API_INC . '/class.vfs_' . $GLOBALS['egw_info']['server']['file_repository'] . '.inc.php'); diff --git a/phpgwapi/inc/class.vfs_dav.inc.php b/phpgwapi/inc/class.vfs_dav.inc.php deleted file mode 100644 index e87213cbf6..0000000000 --- a/phpgwapi/inc/class.vfs_dav.inc.php +++ /dev/null @@ -1,2938 +0,0 @@ - * - * This class handles file/dir access for eGroupWare * - * Copyright (C) 2001-2003 Jason Wies, Jonathon Sim * - * -------------------------------------------------------------------------* - * This library is part of the eGroupWare API * - * http://www.egroupware.org/api * - * ------------------------------------------------------------------------ * - * This library is free software; you can redistribute it and/or modify it * - * under the terms of the GNU Lesser General Public License as published by * - * the Free Software Foundation; either version 2.1 of the License, * - * or any later version. * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License * - * along with this library; if not, write to the Free Software Foundation, * - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - \**************************************************************************/ - - - /*Different aspects of debugging. DEBUG enables debug output for this class - DEBUG_SQL enables some SQL debugging. DEBUG_DAV enables (LOTS) of debugging inside - the HTTP class - */ - define ('DEBUG', 0); - define ('TRACE', 0);//This generates a whole lotta output - define ('DEBUG_SQL', 0); - define ('DEBUG_DAV', 0); - - class vfs - { - var $basedir; - var $fakebase; - var $relative; - var $working_id; - var $working_lid; - var $attributes; - var $override_acl; - var $linked_dirs = array(); - var $meta_types; - var $now; - var $override_locks; - var $vfs_table = 'egw_vfs'; - - //These are DAV-native properties that have different names in VFS - var $vfs_property_map = array( - 'creationdate' => 'created', - 'getlastmodified' => 'modified', - 'getcontentlength' => 'size', - 'getcontenttype' => 'mime_type', - 'description' => 'comment', - 'creator_id' => 'createdby_id', - 'contributor_id' => 'modifiedby_id', - 'publisher_id' => 'owner_id' - ); - - /** - * constructor, sets up variables - * - */ - - function vfs () - { - $this->basedir = $GLOBALS['egw_info']['server']['files_dir']; - $this->fakebase = '/home'; - $this->working_id = $GLOBALS['egw_info']['user']['account_id']; - $this->working_lid = $GLOBALS['egw']->accounts->id2name($this->working_id); - $this->now = date ('Y-m-d'); - $this->override_acl = 0; - /* - File/dir attributes, each corresponding to a database field. Useful for use in loops - If an attribute was added to the table, add it here and possibly add it to - set_attributes () - - set_attributes now uses this array(). 07-Dec-01 skeeter - */ - - $this->attributes = array( - 'file_id', - 'owner_id', - 'createdby_id', - 'modifiedby_id', - 'created', - 'modified', - 'size', - 'mime_type', - 'deleteable', - 'comment', - 'app', - 'directory', - 'name', - 'link_directory', - 'link_name', - 'version' - ); - - /* - These are stored in the MIME-type field and should normally be ignored. - Adding a type here will ensure it is normally ignored, but you will have to - explicitly add it to acl_check (), and to any other SELECT's in this file - */ - - $this->meta_types = array ('journal', 'journal-deleted'); - - /* We store the linked directories in an array now, so we don't have to make the SQL call again */ -/* I dont think this is needed for WebDAV -- RalfBecker 2006/03/27 - switch ($GLOBALS['egw']->db->Type) - { - case 'mssql': - case 'sybase': - $where = array( - "CONVERT(varchar,vfs_link_directory) != ''", - "CONVERT(varchar,vfs_link_name) != ''", - ); - break; - default: - $where = array( - "(vfs_link_directory IS NOT NULL OR vfs_link_directory != '')", - "(vfs_link_name IS NOT NULL OR vfs_link_name != '')", - ); - break; - } - $where[] = $this->extra_sql(array('query_type' => VFS_SQL_SELECT)); - $GLOBALS['egw']->db->select($this->vfs_table,'vfs_directory,vfs_name,vfs_link_directory,vfs_link_name',$where,__LINE__,__FILE__); - - $this->linked_dirs = array (); - while ($GLOBALS['egw']->db->next_record ()) - { - $this->linked_dirs[] = array( - 'directory' => $GLOBALS['egw']->db->Record['vfs_directory'], - 'name' => $GLOBALS['egw']->db->Record['vfs_name'], - 'link_directory' => $GLOBALS['egw']->db->Record['vfs_link_directory'], - 'link_name' => $GLOBALS['egw']->db->Record['vfs_link_name'], - ); - } -*/ - $this->repository = $GLOBALS['egw_info']['server']['files_dir']; - $this->dav_user=$GLOBALS['egw_info']['user']['userid']; - $this->dav_pwd=$GLOBALS['egw_info']['user']['passwd']; - $parsed_url = parse_url($this->repository); - $this->dav_host=$parsed_url['host']; - $this->dav_port=@isset($parsed_url['port']) ? $parsed_url['port'] : ($parsed_url['scheme'] == 'https' ? 443 : 80); - - $this->dav_client =& CreateObject('phpgwapi.http_dav_client'); - $this->dav_client->set_credentials($this->dav_user,$this->dav_pwd); - $this->dav_client->set_attributes($this->attributes,$this->vfs_property_map); - $result = $this->dav_client->connect($this->dav_host,$this->dav_port); - if (DEBUG_DAV) - { - echo 'DAV client debugging enabled!'; - $this->dav_client->set_debug(DBGTRACE|DBGINDATA|DBGOUTDATA|DBGSOCK|DBGLOW); - } - if (!$result) - { - echo '

Cannot connect to the file repository server!

'; - die($this->dav_client->get_body()); - } - //determine the supported DAV features -/* $features = $this->dav_client->dav_features('http://'.$this->dav_host); - if (!$features || ! in_array( '1', $features) ) - { - die("Error :: The specified file repository: $this->dav_host doesn't appear to support WebDAV! "); - - } -*/ - //Reload the overriden_locks - $app = $GLOBALS['egw_info']['flags']['currentapp']; - $session_data = base64_decode($GLOBALS['egw']->session->appsession ('vfs_dav',$app)); - $this->override_locks = array(); - if ($session_data) - { - $locks = explode('\n', $session_data); - foreach ($locks as $lock) - { - $lockdata = explode(';', $lock); - $name = $lockdata[0]; - $token = $lockdata[1]; - $this->override_locks[$name] = $token; - } - } - - register_shutdown_function(array(&$this, 'vfs_umount')); - $this->debug('Constructed with debug enabled'); - - } - - //TODO: Get rid of this - //A quick, temporary debug output function - function debug($info) { - if (DEBUG) - { - echo ' vfs_sql_dav debug: '; - if (is_array($info)) - { - print_r($info); - } - else - { - echo $info; - } - echo '
'; - } - } - - /** - * Apaches mod_dav in particular requires that the path sent in a dav request NOT be a URI - * - */ - function dav_path($uri) { - //$this->debug('DAV path'); - $parsed = parse_url($uri); - return $parsed['path']; - } - - /** - * glues a parsed url (ie parsed using PHP's parse_url) back - * - * together - * @param $url The parsed url (its an array) - */ - function glue_url ($url){ - if (!is_array($url)) - { - return false; - } - // scheme - $uri = (!empty($url['scheme'])) ? $url['scheme'].'://' : ''; - // user & pass - if (!empty($url['user'])) - { - $uri .= $url['user']; - if (!empty($url['pass'])) - { - $uri .=':'.$url['pass']; - } - $uri .='@'; - } - // host - $uri .= $url['host']; - // port - $port = (!empty($url['port'])) ? ':'.$url['port'] : ''; - $uri .= $port; - // path - $uri .= $url['path']; - // fragment or query - if (isset($url['fragment'])) - { - $uri .= '#'.$url['fragment']; - } elseif (isset($url['query'])) - { - $uri .= '?'.$url['query']; - } - return $uri; - } - - function dav_host($uri) { - //$this->debug('DAV path'); - $parsed = parse_url($uri); - $parsed['path'] = ''; - $host = $this->glue_url($parsed); - return $host; - } - - function vfs_umount() - { - $this->dav_client->disconnect(); - } - - - /** - * Set path relativity - * - * @param mask Relative bitmask (see RELATIVE_ defines) - */ - function set_relative ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - if (!$data['mask']) - { - unset ($this->relative); - } - else - { - $this->relative = $data['mask']; - } - } - - /** - * Return relativity bitmask - * - * Returns relativity bitmask, or the default of "completely relative" if unset - */ - function get_relative () - { - if (isset ($this->relative) && $this->relative) - { - return $this->relative; - } - else - { - return RELATIVE_ALL; - } - } - - /** - * Removes leading .'s from 'string' - * - * You should not pass all filenames through sanitize () unless you plan on rejecting - * * .files. Instead, pass the name through securitycheck () first, and if it fails, - * * pass it through sanitize - * @param string string to sanitize - * @return $string 'string' without it's leading .'s - */ - function sanitize ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - /* We use path_parts () just to parse the string, not translate paths */ - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array (RELATIVE_NONE) - ) - ); - - return (ereg_replace ('^\.+', '', $p->fake_name)); - } - - /** - * Security check function - * - * Checks for basic violations such as .. - * * If securitycheck () fails, run your string through vfs->sanitize () - * @param string string to check security of - * @return Boolean True/False. True means secure, False means insecure - */ - function securitycheck ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - if (substr ($data['string'], 0, 1) == "\\" || strstr ($data['string'], "..") || strstr ($data['string'], "\\..") || strstr ($data['string'], ".\\.")) - { - return False; - } - else - { - return True; - } - } - - /** - * Clean 'string' for use in database queries - * - * @param string String to clean - * @return Cleaned version of 'string' - */ - function db_clean ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $string = ereg_replace ("'", "\'", $data['string']); - - return $string; - } - - /** - * Return extra SQL code that should be appended to certain queries - * - * @param query_type The type of query to get extra SQL code for, in the form of a VFS_SQL define - * @return Extra SQL code - */ - function extra_sql ($data) - { //This is purely for SQL - return ''; - } - - /** - * Add a journal entry after (or before) completing an operation, - * - * * and increment the version number. This function should be used internally only - * Note that state_one and state_two are ignored for some VFS_OPERATION's, for others - * * they are required. They are ignored for any "custom" operation - * * The two operations that require state_two: - * * operation * state_two - * * VFS_OPERATION_COPIED fake_full_path of copied to - * * VFS_OPERATION_MOVED * fake_full_path of moved to - - * * If deleting, you must call add_journal () before you delete the entry from the database - * @param string File or directory to add entry for - * @param relatives Relativity array - * @param operation The operation that was performed. Either a VFS_OPERATION define or - * * a non-integer descriptive text string - * @param state_one The first "state" of the file or directory. Can be a file name, size, - * * location, whatever is appropriate for the specific operation - * @param state_two The second "state" of the file or directory - * @param incversion Boolean True/False. Increment the version for the file? Note that this is - * * handled automatically for the VFS_OPERATION defines. - * * i.e. VFS_OPERATION_EDITED would increment the version, VFS_OPERATION_COPIED - * * would not - * @return Boolean True/False - */ - function add_journal ($data) { - //The journalling dont work :( Ideally this will become "versioning" - return True; - } - - - /** - * Flush journal entries for $string. Used before adding $string - * - * flush_journal () is an internal function and should be called from add_journal () only - * @param string File/directory to flush journal entries of - * @param relatives Realtivity array - * @param deleteall Delete all types of journal entries, including the active Create entry. - * * Normally you only want to delete the Create entry when replacing the file - * * Note that this option does not effect $deleteonly - * @param deletedonly Only flush 'journal-deleted' entries (created when $string was deleted) - * @return Boolean True/False - */ - function flush_journal ($data) - { - return True; - } - - - /** - * Retrieve journal entries for $string - * - * @param string File/directory to retrieve journal entries of - * @param relatives Relativity array - * @param type 0/False = any, 1 = 'journal', 2 = 'journal-deleted' - * @return Array of arrays of journal entries - */ - function get_journal ($data) - { - return array(); - } - - /** - * take a real or fake pathname and return an array of its component parts - * - * @param string full real or fake path - * @param relatives Relativity array - * @param object True returns an object instead of an array - * @param nolinks Don't check for links (made with make_link ()). Used internally to prevent recursion - * @return $rarray/$robject Array or object containing the fake and real component parts of the path - * Returned values are: - * * mask - * * outside - * * fake_full_path - * * fake_leading_dirs - * * fake_extra_path * BROKEN - * * fake_name - * * real_full_path - * * real_leading_dirs - * * real_extra_path * BROKEN - * * real_name - * * fake_full_path_clean - * * fake_leading_dirs_clean - * * fake_extra_path_clean BROKEN - * * fake_name_clean - * * real_full_path_clean - * * real_leading_dirs_clean - * * real_extra_path_clean BROKEN - * * real_name_clean - * * real_uri - * "clean" values are run through vfs->db_clean () and - * are safe for use in SQL queries that use key='value' - * They should be used ONLY for SQL queries, so are used - * mostly internally - * mask is either RELATIVE_NONE or RELATIVE_NONE|VFS_REAL, - * and is used internally - * outside is boolean, True if 'relatives' contains VFS_REAL - */ - function path_parts ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'object' => True, - 'nolinks' => False - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $sep = SEP; - - $rarray['mask'] = RELATIVE_NONE; - - if (!($data['relatives'][0] & VFS_REAL)) - { - $rarray['outside'] = False; - $fake = True; - } - else - { - $rarray['outside'] = True; - $rarray['mask'] |= VFS_REAL; - } - - $string = $this->getabsolutepath (array( - 'string' => $data['string'], - 'mask' => array ($data['relatives'][0]), - 'fake' => $fake - ) - ); - - if ($fake) - { - $base_sep = '/'; - $base = '/'; - - $opp_base = $this->basedir . $sep; - - $rarray['fake_full_path'] = $string; - } - else - { - $base_sep = $sep; - if (ereg ("^$this->basedir" . $sep, $string)) - { - $base = $this->basedir . $sep; - } - else - { - $base = $sep; - } - - $opp_base = '/'; - $rarray['real_full_url'] = $string; - $rarray['real_full_path'] = $this->dav_path($string); - } - - /* This is needed because of substr's handling of negative lengths */ - $baselen = strlen ($base); - $lastslashpos = strrpos ($string, $base_sep); - $lastslashpos < $baselen ? $length = 0 : $length = $lastslashpos - $baselen; - - $extra_path = $rarray['fake_extra_path'] = $rarray['real_extra_path'] = substr ($string, strlen ($base), $length); - $name = $rarray['fake_name'] = $rarray['real_name'] = substr ($string, strrpos ($string, $base_sep) + 1); - - if ($fake) - { - $rarray['real_extra_path'] ? $dispsep = $sep : $dispsep = ''; - $rarray['real_full_url'] = $opp_base . $rarray['real_extra_path'] . $dispsep . $rarray['real_name']; - $rarray['real_full_path'] = $this->dav_path($rarray['real_full_url']); - if ($extra_path) - { - $rarray['fake_leading_dirs'] = $base . $extra_path; - $rarray['real_leading_dirs'] = $this->dav_path($opp_base . $extra_path); - } - elseif (strrpos ($rarray['fake_full_path'], $sep) == 0) - { - /* If there is only one $sep in the path, we don't want to strip it off */ - $rarray['fake_leading_dirs'] = $sep; - $rarray['real_leading_dirs'] = $this->dav_path( substr ($opp_base, 0, strlen ($opp_base) - 1)); - } - else - { - /* These strip the ending / */ - $rarray['fake_leading_dirs'] = substr ($base, 0, strlen ($base) - 1); - $rarray['real_leading_dirs'] = $this->dav_path( substr ($opp_base, 0, strlen ($opp_base) - 1)); - } - } - else - { - $rarray['fake_full_path'] = $opp_base . $rarray['fake_extra_path'] . '/' . $rarray['fake_name']; - if ($extra_path) - { - $rarray['fake_leading_dirs'] = $opp_base . $extra_path; - $rarray['real_leading_dirs'] = $this->dav_path($base . $extra_path); - } - else - { - $rarray['fake_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1); - $rarray['real_leading_dirs'] = $this->dav_path(substr ($base, 0, strlen ($base) - 1)); - } - } - - /* We check for linked dirs made with make_link (). This could be better, but it works */ - if (!$data['nolinks']) - { - reset ($this->linked_dirs); - while (list ($num, $link_info) = each ($this->linked_dirs)) - { - if (ereg ("^$link_info[directory]/$link_info[name](/|$)", $rarray['fake_full_path'])) - { - $rarray['real_full_path'] = ereg_replace ("^$this->basedir", '', $rarray['real_full_path']); - $rarray['real_full_path'] = ereg_replace ("^$link_info[directory]" . SEP . "$link_info[name]", $link_info['link_directory'] . SEP . $link_info['link_name'], $rarray['real_full_path']); - - $p = $this->path_parts (array( - 'string' => $rarray['real_full_path'], - 'relatives' => array (RELATIVE_NONE|VFS_REAL), - 'nolinks' => True - ) - ); - - $rarray['real_leading_dirs'] = $this->dav_path($p->real_leading_dirs); - $rarray['real_extra_path'] = $p->real_extra_path; - $rarray['real_name'] = $p->real_name; - } - } - } - - /* - Create the 'real_auth_url', which includes the user and - password (for the view method to redirect you there) - */ - - $parsed_url = parse_url($rarray['real_full_url']); - $parsed_url['user'] = $this->dav_user; -// $parsed_url['pass'] = $this->dav_pwd; - $rarray['real_full_auth_url'] = $this->glue_url($parsed_url); - - $parsed_url = parse_url($rarray['real_full_url']); - $parsed_url['scheme'] = 'https'; - $parsed_url['user'] = $this->dav_user; - $rarray['real_full_secure_url'] = $this->glue_url($parsed_url); - - - /* - We have to count it before because new keys will be added, - which would create an endless loop - */ - $count = count ($rarray); - reset ($rarray); - for ($i = 0; (list ($key, $value) = each ($rarray)) && $i != $count; $i++) - { - $rarray[$key . '_clean'] = $this->db_clean (array ('string' => $value)); - } - - if ($data['object']) - { - $robject =& new path_class; - - reset ($rarray); - while (list ($key, $value) = each ($rarray)) - { - $robject->$key = $value; - } - } - -/* - echo "
fake_full_path: $rarray[fake_full_path] -
fake_leading_dirs: $rarray[fake_leading_dirs] -
fake_extra_path: $rarray[fake_extra_path] -
fake_name: $rarray[fake_name] -
real_full_path: $rarray[real_full_path] -
real_full_url: $rarray[real_full_url] -
real_leading_dirs: $rarray[real_leading_dirs] -
real_extra_path: $rarray[real_extra_path] -
real_name: $rarray[real_name]"; -*/ - - if ($data['object']) - { - return ($robject); - } - else - { - return ($rarray); - } - } - - /** - * get the absolute path - * - * @param string defaults to False, directory/file to get path of, relative to relatives[0] - * @param mask Relativity bitmask (see RELATIVE_ defines). RELATIVE_CURRENT means use $this->relative - * @param fake Returns the "fake" path, ie /home/user/dir/file (not always possible. use path_parts () instead) - * @return $basedir Full fake or real path - */ - function getabsolutepath ($data) - { - $default_values = array - ( - 'string' => False, - 'mask' => array (RELATIVE_CURRENT), - 'fake' => True - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $currentdir = $this->pwd (False); - - /* If they supply just VFS_REAL, we assume they want current relativity */ - if ($data['mask'][0] == VFS_REAL) - { - $data['mask'][0] |= RELATIVE_CURRENT; - } - - if (!$this->securitycheck (array( - 'string' => $data['string'] - )) - ) - { - return False; - } - - if ($data['mask'][0] & RELATIVE_NONE) - { - return $data['string']; - } - - if ($data['fake']) - { - $sep = '/'; - } - else - { - $sep = SEP; - } - - /* if RELATIVE_CURRENT, retrieve the current mask */ - if ($data['mask'][0] & RELATIVE_CURRENT) - { - $mask = $data['mask'][0]; - /* Respect any additional masks by re-adding them after retrieving the current mask*/ - $data['mask'][0] = $this->get_relative () + ($mask - RELATIVE_CURRENT); - } - - if ($data['fake']) - { - $basedir = '/'; - } - else - { - $basedir = $this->basedir . $sep; - - /* This allows all requests to use /'s */ - $data['string'] = preg_replace ("|/|", $sep, $data['string']); - } - - if (($data['mask'][0] & RELATIVE_PATH) && $currentdir) - { - $basedir = $basedir . $currentdir . $sep; - } - elseif (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP)) - { - $basedir = $basedir . $this->fakebase . $sep; - } - - if ($data['mask'][0] & RELATIVE_CURR_USER) - { - $basedir = $basedir . $this->working_lid . $sep; - } - - if (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP)) - { - $basedir = $basedir . $GLOBALS['egw_info']['user']['account_lid'] . $sep; - } - - if ($data['mask'][0] & RELATIVE_USER_APP) - { - $basedir = $basedir . "." . $GLOBALS['egw_info']['flags']['currentapp'] . $sep; - } - - /* Don't add string if it's a /, just for aesthetics */ - if ($data['string'] && $data['string'] != $sep) - { - $basedir = $basedir . $data['string']; - } - - /* Let's not return // */ - while (ereg ($sep . $sep, $basedir)) - { - $basedir = ereg_replace ($sep . $sep, $sep, $basedir); - } - - $basedir = ereg_replace ($sep . '$', '', $basedir); - - return $basedir; - } - - /** - * Check ACL access to $file for $GLOBALS['egw_info']["user"]["account_id"]; - * - * @param string File to check access of - * To check the access for a file or directory, pass 'string'/'relatives'/'must_exist'. - * * To check the access to another user or group, pass 'owner_id'. - * * If 'owner_id' is present, we bypass checks on 'string'/'relatives'/'must_exist' - * @param relatives Standard relativity array - * @param operation Operation to check access to. In the form of a EGW_ACL defines bitmask. Default is read - * @param owner_id Owner id to check access of (see discussion above) - * @param must_exist Boolean. Set to True if 'string' must exist. Otherwise, we check the parent directory as well - * @return Boolean. True if access is ok, False otherwise - */ - function acl_check ($data) - { - return True; - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'operation' => EGW_ACL_READ, - 'must_exist' => False - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - /* Accommodate special situations */ - if ($this->override_acl || $data['relatives'][0] == RELATIVE_USER_APP) - { - return True; - } - - if (!$data['owner_id']) - { - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - /* Temporary, until we get symlink type files set up */ - if ($p->outside) - { - return True; - } - - /* Read access is always allowed here, but nothing else is */ - if ($data['string'] == '/' || $data['string'] == $this->fakebase) - { - if ($data['operation'] == EGW_ACL_READ) - { - return True; - } - else - { - return False; - } - } - - /* If the file doesn't exist, we get ownership from the parent directory */ - if (!$this->file_exists (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) - ) - { - if ($data['must_exist']) - { - return False; - } - - $data['string'] = $p->fake_leading_dirs; - $p2 = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($p->mask) - ) - ); - - if (!$this->file_exists (array( - 'string' => $data['string'], - 'relatives' => array ($p->mask) - )) - ) - { - return False; - } - } - else - { - $p2 = $p; - } - - $file_info = $this->ls($data); - $owner_id = $file_info['owner_id']; - } - else - { - $owner_id = $data['owner_id']; - } - - /* This is correct. The ACL currently doesn't handle undefined values correctly */ - if (!$owner_id) - { - $owner_id = 0; - } - - $user_id = $GLOBALS['egw_info']['user']['account_id']; - - /* They always have access to their own files */ - if ($owner_id == $user_id) - { - return True; - } - - /* Check if they're in the group */ - $memberships = $GLOBALS['egw']->accounts->membership ($user_id); - - if (is_array ($memberships)) - { - reset ($memberships); - while (list ($num, $group_array) = each ($memberships)) - { - if ($owner_id == $group_array['account_id']) - { - $group_ok = 1; - break; - } - } - } - - $acl =& CreateObject ('phpgwapi.acl', $owner_id); - $acl->account_id = $owner_id; - $acl->read_repository (); - - $rights = $acl->get_rights ($user_id); - - /* Add privileges from the groups this user belongs to */ - if (is_array ($memberships)) - { - reset ($memberships); - while (list ($num, $group_array) = each ($memberships)) - { - $rights |= $acl->get_rights ($group_array['account_id']); - } - } - - if ($rights & $data['operation']) - { - return True; - } - elseif (!$rights && $group_ok) - { - $conf =& CreateObject('phpgwapi.config', 'phpgwapi'); - $conf->read_repository(); - if ($conf->config_data['acl_default'] == 'grant') - { - return True; - } - else - { - return False; - } - } - else - { - return False; - } - } - - /** - * Change directory - * - * To cd to the files root '/', use cd ('/', False, array (RELATIVE_NONE)); - * @param string default '/'. directory to cd into. if "/" and $relative is True, uses "/home/"; - * @param relative default True/relative means add target to current path, else pass $relative as mask to getabsolutepath() - * @param relatives Relativity array - */ - function cd ($data = '') - { - if (!is_array ($data)) - { - $noargs = 1; - $data = array (); - } - - $default_values = array - ( - 'string' => '/', - 'relative' => True, - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - if ($data['relatives'][0] & VFS_REAL) - { - $sep = SEP; - } - else - { - $sep = '/'; - } - - if ($data['relative'] == 'relative' || $data['relative'] == True) - { - /* if 'string' is "/" and 'relative' is set, we cd to the user/group home dir */ - if ($data['string'] == '/') - { - $data['relatives'][0] = RELATIVE_USER; - $basedir = $this->getabsolutepath (array( - 'string' => False, - 'mask' => array ($data['relatives'][0]), - 'fake' => True - ) - ); - } - else - { - $currentdir = $GLOBALS['egw']->session->appsession('vfs',''); - $basedir = $this->getabsolutepath (array( - 'string' => $currentdir . $sep . $data['string'], - 'mask' => array ($data['relatives'][0]), - 'fake' => True - ) - ); - } - } - else - { - $basedir = $this->getabsolutepath (array( - 'string' => $data['string'], - 'mask' => array ($data['relatives'][0]) - ) - ); - } - - $GLOBALS['egw']->session->appsession('vfs','',$basedir); - - return True; - } - - /** - * current working dir - * - * @param full default True returns full fake path, else just the extra dirs (false strips the leading /) - * @return $currentdir currentdir - */ - function pwd ($data = '') - { - $default_values = array - ( - 'full' => True - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $currentdir = $GLOBALS['egw']->session->appsession('vfs',''); - - if (!$data['full']) - { - $currentdir = ereg_replace ("^/", '', $currentdir); - } - - if ($currentdir == '' && $data['full']) - { - $currentdir = '/'; - } - - $currentdir = trim ($currentdir); - - return $currentdir; - } - - /** - * return file contents - * - * @param string filename - * @param relatives Relativity array - * @return $contents Contents of $file, or False if file cannot be read - */ - function read ($data) - { - - /*If the user really wants to 'view' the file in the browser, it - is much smarter simply to redirect them to the files web-accessable - url */ -/* $app = $GLOBALS['egw_info']['flags']['currentapp']; - if ( ! $data['noview'] && ($app == 'phpwebhosting' || $app = 'filemanager' )) - { - $this->view($data); - } -*/ - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_READ - )) - ) - { - return False; - } - if ($p->outside) - { - - if (! $fp = fopen ($p->real_full_path, 'r')) - { - return False; - } - $size=filesize($p->real_full_path); - $buffer=fread($fp, $size); - fclose ($fp); - return $buffer; - } - else - { - $status=$this->dav_client->get($p->real_full_path); - $this->debug($this->dav_client->get_headers()); - - if($status != 200) return False; - $contents=$this->dav_client->get_body(); - $this->debug('Read:returning contents. Status:'.$status); - return $contents; - } - } - - /* - @function view - @abstract Redirect the users browser to the file - @param string filename - @param relatives Relativity array - @result None (doesnt return) - @discussion In the case of WebDAV, the file is web-accessible. So instead - of reading it into memory and then dumping it back out again when someone - views a file, it makes much more sense to simply redirect, which is what - this method does (its only called when reading from the file in the file manager, - when the variable "noview" isnt set to "true" - */ - function view($data) - { - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - $data = array_merge ($this->default_values ($data, $default_values), $data); - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - //Determine whether the repository supports SSL - $parsed_url = parse_url($this->repository); - if ($parsed_url['scheme']=='https') - { - header( 'Location: '.$p->real_full_secure_url, true ); - } - else - { - header( 'Location: '.$p->real_full_auth_url, true ); - } - exit(); - - } - - /* - @function lock - @abstract DAV (class 2) locking - sets an exclusive write lock - @param string filename - @param relatives Relativity array - @result True if successfull - */ - function lock ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'timeout' => 'infinity', - - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - return $this->dav_client->lock($p->real_full_url, $this->dav_user, 0, $data['timeout']); - - } - function lock_token ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'token' => '' - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $ls_array = $GLOBALS['egw']->vfs->ls (array ( - 'string' => $data['string'], - 'relatives' => $data['relatives'] - ) - ); - $lock = @end($ls_array[0]['locks']); - $token = @end($lock['lock_tokens']); - return $token['full_name']; - } - - - /* - @function add_lock_override - @abstract override a lock - @param string filename - @param relatives Relativity array - @param token (optional) a token for the lock we want to override - @result None - @discussion locks are no good unless you can write to a file you yourself locked: - to do this call add_lock_override with the lock token (or without it - it will - find it itself, so long as there is only one). lock_override info is stored in - the groupware session, so it will persist between page loads, but will be lost - when the browser is closed - */ - function add_lock_override($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'token' => '' - - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - if (!strlen($data['token'])) - { - $ls_array = $GLOBALS['egw']->vfs->ls (array ( - 'string' => $data['string'], - 'relatives' => $data['relatives'] - ) - ); - $lock = @end($ls_array[0]['locks']); - $token_array = @end($lock['lock_tokens']); - $token = $token_array['full_name']; - } - else - { - $token = $data['token']; - } - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - $this->override_locks[$p->real_full_path] = $token; - $this->save_session(); - } - - /* - @function remove_lock_override - @abstract stops overriding a lock - @param string filename - @param relatives Relativity array - @result None - */ - function remove_lock_override($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - if (!strlen($data['token'])) - { - $ls_array = $GLOBALS['egw']->vfs->ls (array ( - 'string' => $data['string'], - 'relatives' => $data['relatives'] - ) - ); - $lock = @end($ls_array[0]['locks']); - $token_array = @end($lock['lock_tokens']); - $token = $token_array['full_name']; - } - else - { - $token = $data['token']; - } - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - unset($this->override_locks[$p->real_full_path]); - $this->save_session(); - } - - /* - @function unlock - @abstract DAV (class 2) unlocking - unsets the specified lock - @param string filename - @param relatives Relativity array - @param tocken The token for the lock we wish to remove. - @result True if successfull - */ - function unlock ($data, $token) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'content' => '' - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - $this->remove_lock_override (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - return $this->dav_client->unlock($p->real_full_url, $token); - - - } - - /* - @function options - @abstract Allows querying for optional features - esp optional DAV features - like locking - @param option The option you want to test for. Options include 'LOCKING' - 'VIEW', 'VERSION-CONTROL (eventually) etc - @result true if the specified option is supported - @discussion This should really check the server. Unfortunately the overhead of doing this - in every VFS instance is unacceptable (it essentially doubles the time for any request). Ideally - we would store these features in the session perhaps? - */ - function options($option) - { - switch ($option) - { - case 'LOCKING': - return true; - case 'VIEW': - return true; - default: - return false; - } - } - - /** - * write to a file - * - * @param string file name - * @param relatives Relativity array - * @param content content - * @return Boolean True/False - */ - function write ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'content' => '' - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if ($this->file_exists (array ( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - )) - ) - { - $acl_operation = EGW_ACL_EDIT; - $journal_operation = VFS_OPERATION_EDITED; - } - else - { - $acl_operation = EGW_ACL_ADD; - } - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => $acl_operation - )) - ) - { - return False; - } - - //umask(000); - - /* - If 'string' doesn't exist, touch () creates both the file and the database entry - If 'string' does exist, touch () sets the modification time and modified by - */ - /*$this->touch (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - ) - );*/ - - $size=strlen($data['content']); - if ($p->outside) - { - if (! $fp = fopen ($p->real_full_path, 'w')) - { - return False; - } - $result = fwrite($fp, $data['content']); - fclose ($fp); - return $result; - } - else - { - $token = $this->override_locks[$p->real_full_path]; - $status=$this->dav_client->put($p->real_full_path,$data['content'],$token); -$this->debug('Put complete, status: '.$status); - if($status!=201 && $status!=204) - { - return False; - } - else - { - return True; - } - } - } - - /** - * Create blank file $file or set the modification time and modified by of $file to current time and user - * - * @param string File to touch or set modifies - * @param relatives Relativity array - * @return Boolean True/False - */ - function touch ($data) - { - $default_values = array( - 'relatives' => array (RELATIVE_CURRENT) - ); - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - $currentapp = $GLOBALS['egw_info']['flags']['currentapp']; - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - umask (000); - - /* - PHP's touch function will automatically decide whether to - create the file or set the modification time - */ - if($p->outside) - { - return @touch($p->real_full_path); - } - elseif ($this->file_exists (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) - ) - { - $result = $this->set_attributes (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => array( - 'modifiedby_id' => $account_id, - 'modified' => $this->now - ))); - } - else - { - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_ADD - )) - ) return False; - $result = $this->write (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]), - 'content' => '' - )); - $this->set_attributes(array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => array ( - 'createdby_id' => $account_id, - 'created' => $this->now, - 'app' => $currentapp - ))); - } - - return ($result); - } - - /** - * copy file - * - * @param from from file/directory - * @param to to file/directory - * @param relatives Relativity array - * @return boolean True/False - */ - function cp ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT, RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - - $f = $this->path_parts (array( - 'string' => $data['from'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - $t = $this->path_parts (array( - 'string' => $data['to'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => EGW_ACL_READ - )) - ) - { - return False; - } - - if ($this->file_exists (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - )) - ) - { - $remote_operation=EGW_ACL_EDIT; - } - else - { - $remote_operation=EGW_ACL_ADD; - - } - if (!$this->acl_check (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => $remote_operation - )) - ) - { - return False; - } - - umask(000); - - if ($this->file_type (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - )) != 'Directory' - ) - { - - if ($f->outside && $t->outside) - { - return copy($f->real_full_path, $t->real_full_url); - } - elseif ($f->outside || $t->outside) - { - $content = $this->read(array( - 'string' => $f->fake_full_path, - 'noview' => true, - 'relatives' => array ($f->mask) - ) - ); - $result = $this->write(array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'content' => $content - ) - ); - } - else - { - $status=$this->dav_client->copy($f->real_full_path, $t->real_full_url,True, 'Infinity', $this->override_locks[$p->real_full_path]); - $result = $status == 204 || $status==201; - if (!$result) - { - return False; - } - } - - $this->set_attributes(array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'attributes' => array ( - 'owner_id' => $this->working_id, - 'createdby_id' => $account_id, - ) - ) - ); - return $result; - - } - else if (!($f->outside || $t->outside)) - { - //if the files are both on server, its just a depth=infinity copy - $status=$this->dav_client->copy($f->real_full_path, $t->real_full_url,True, 'infinity', $this->override_locks[$p->real_full_path]); - if($status != 204 && $status!=201) - { - return False; - } - else - { - return True; - } - } - else /* It's a directory, and one of the files is local */ - { - /* First, make the initial directory */ - $this->mkdir (array( - 'string' => $data['to'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - /* Next, we create all the directories below the initial directory */ - $ls = $this->ls (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'checksubdirs' => True, - 'mime_type' => 'Directory' - ) - ); - - while (list ($num, $entry) = each ($ls)) - { - $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']); - $this->mkdir (array( - 'string' => $newdir.'/'.$entry['name'], - 'relatives' => array ($t->mask) - ) - ); - } - - /* Lastly, we copy the files over */ - $ls = $this->ls (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - ) - ); - - while (list ($num, $entry) = each ($ls)) - { - if ($entry['mime_type'] == 'Directory') - { - continue; - } - - $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']); - $this->cp (array( - 'from' => "$entry[directory]/$entry[name]", - 'to' => "$newdir/$entry[name]", - 'relatives' => array ($f->mask, $t->mask) - ) - ); - } - } - - return True; - } - - function copy ($data) - { - return $this->cp ($data); - } - - /** - * move file/directory - * - * @param from from file/directory - * @param to to file/directory - * @param relatives Relativity array - * @return boolean True/False - */ - function mv ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT, RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - - $f = $this->path_parts (array( - 'string' => $data['from'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - $t = $this->path_parts (array( - 'string' => $data['to'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => EGW_ACL_READ - )) - || !$this->acl_check (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => EGW_ACL_DELETE - )) - ) - { - return False; - } - - if (!$this->acl_check (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => EGW_ACL_ADD - )) - ) - { - return False; - } - - if ($this->file_exists (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - )) - ) - { - if (!$this->acl_check (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => EGW_ACL_EDIT - )) - ) - { - return False; - } - } - umask (000); - - /* We can't move directories into themselves */ - if (($this->file_type (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - ) == 'Directory')) - && ereg ("^$f->fake_full_path", $t->fake_full_path) - ) - { - if (($t->fake_full_path == $f->fake_full_path) || substr ($t->fake_full_path, strlen ($f->fake_full_path), 1) == '/') - { - return False; - } - } - - if ($this->file_exists (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - )) - ) - { - /* We get the listing now, because it will change after we update the database */ - $ls = $this->ls (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - ) - ); - - if ($this->file_exists (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - )) - ) - { - $this->rm (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ) - ); - } - - $this->correct_attributes (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ) - ); - - if ($f->outside && $t->outside) - { - echo 'local'; - $result = rename ($f->real_full_path, $t->real_full_path); - } - else if ($f->outside || $t->outside) //if either file is local, read then write - { - $content = $this->read(array( - 'string' => $f->fake_full_path, - 'noview' => true, - 'relatives' => array ($f->mask) - ) - ); - $result = $this->write(array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'content' => $content - ) - ); - if ($result) - { - $result = $this->rm(array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'content' => $content - ) - ); - } - } - else { //we can do a server-side copy if both files are on the server - $status=$this->dav_client->move($f->real_full_path, $t->real_full_url,True, 'infinity', $this->override_locks[$p->real_full_path]); - $result = ($status==201 || $status==204); - } - - if ($result) $this->set_attributes(array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'attributes' => array ( - 'modifiedby_id' => $account_id, - 'modified' => $this->now - ))); - return $result; - } - else - { - return False; - } - - $this->add_journal (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => VFS_OPERATION_MOVED, - 'state_one' => $f->fake_full_path, - 'state_two' => $t->fake_full_path - ) - ); - - return True; - } - - /** - * shortcut to mv - * - */ - function move ($data) - { - return $this->mv ($data); - } - - /** - * delete file/directory - * - * @param string file/directory to delete - * @param relatives Relativity array - * @return boolean True/False - */ - function rm ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - $this->debug("rm: $p->real_full_path"); - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_DELETE - )) - ) - { - return False; - } - -/*this would become apparent soon enough anyway? - if (!$this->file_exists (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - )) - ) return False; -*/ - if ($this->file_type (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - )) != 'Directory' - ) - { - if ($p->outside) - { - return unlink($p->real_full_path); - } - else - { - $rr=$this->dav_client->delete($p->real_full_path, 0, $this->override_locks[$p->real_full_path]); - return $rr == 204; - } - } - else - { - $ls = $this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - ) - ); - - while (list ($num, $entry) = each ($ls)) - { - $this->rm (array( - 'string' => "$entry[directory]/$entry[name]", - 'relatives' => array ($p->mask) - ) - ); - } - - /* If the directory is linked, we delete the placeholder directory */ - $ls_array = $this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'checksubdirs' => False, - 'mime_type' => False, - 'nofiles' => True - ) - ); - $link_info = $ls_array[0]; - - if ($link_info['link_directory'] && $link_info['link_name']) - { - $path = $this->path_parts (array( - 'string' => $link_info['directory'] . '/' . $link_info['name'], - 'relatives' => array ($p->mask), - 'nolinks' => True - ) - ); - $this->dav_client->delete($path->real_full_path,0, $this->override_locks[$p->real_full_path]); - } - - /* Last, we delete the directory itself */ - $this->add_journal (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operaton' => VFS_OPERATION_DELETED - ) - ); - -/* I dont think this is needed for WebDAV -- RalfBecker 2006/03/27 - $GLOBALS['egw']->db->delete($this->vfs_table,array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_DELETE)) - ), __LINE__, __FILE__); -*/ - //rmdir ($p->real_full_path); - $this->dav_client->delete($p->real_full_path.'/','Infinity', $this->override_locks[$p->real_full_path]); - - return True; - } - } - - /** - * shortcut to rm - * - */ - function delete ($data) - { - return $this->rm ($data); - } - - /** - * make a new directory - * - * @param string Directory name - * @param relatives Relativity array - * @return boolean True on success - */ - function mkdir ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - $currentapp = $GLOBALS['egw_info']['flags']['currentapp']; - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_ADD) - ) - ) - { - return False; - } - - /* We don't allow /'s in dir names, of course */ - if (ereg ('/', $p->fake_name)) - { - return False; - } - if ($p->outside) - { - if (!mkdir($p->real_full_path, 0777)) - { - return False; - } - } - else if($this->dav_client->mkcol($p->real_full_path, $this->override_locks[$p->real_full_path]) != 201) - { - return False; - } - - - if (!$this->file_exists (array( - 'string' => $p->fake_full_path.'/' - )) - ) - { - /*Now we need to set access control for this dir. Simply create an .htaccess - file limiting access to this user, if we are creating this dir in the user's home dir*/ - $homedir = $this->fakebase.'/'.$this->dav_user; - if ( substr($p->fake_leading_dirs, 0, strlen($homedir)) == $homedir) - { - $conf =& CreateObject('phpgwapi.config', 'phpgwapi'); - $conf->read_repository(); - if (!$conf->config_data['acl_default'] == 'grant') - { - $htaccess = 'require user '.$GLOBALS['egw_info']['user']['account_lid']; - if ( ! $this->write(array( - 'string' => $p->fake_full_path.'/.htaccess', - 'content' => $htaccess, - 'relatives' => array(RELATIVE_NONE) - ))) - { - echo '

Unable to write .htaccess file

'; - }; - } - } - return True; - } - else - { - return False; - } - } - - /** - * Make a link from virtual directory 'vdir' to real directory 'rdir' - * - * Making a link from 'vdir' to 'rdir' will cause path_parts () to substitute 'rdir' for the real - * * path variables when presented with 'vdir' - * @param vdir Virtual dir to make link from - * @param rdir Real dir to make link to - * @param relatives Relativity array - * @return Boolean True/False - */ - function make_link ($data) - { - return False; //This code certainly wont work anymore. Does anything use it? - /* - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT, RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - $currentapp = $GLOBALS['egw_info']['flags']['currentapp']; - - $vp = $this->path_parts (array( - 'string' => $data['vdir'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - $rp = $this->path_parts (array( - 'string' => $data['rdir'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask), - 'operation' => EGW_ACL_ADD - )) - ) return False; - - if ((!$this->file_exists (array( - 'string' => $rp->real_full_path, - 'relatives' => array ($rp->mask) - ))) - && !mkdir ($rp->real_full_path, 0770)) return False; - - if (!$this->mkdir (array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask) - )) - )return False; - - $size = $this->get_size (array( - 'string' => $rp->real_full_path, - 'relatives' => array ($rp->mask) - ) - ); - - $this->set_attributes(array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask), - 'attributes' => array ( - 'link_directory' => $rp->real_leading_dirs, - 'link_name' => $rp->real_name, - 'size' => $size - ) - ) - ); - - $this->correct_attributes (array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask) - ) - ); - - return True; - */ - } - - /** - * Update database entry for 'string' with the attributes in 'attributes' - * - * @param string file/directory to update - * @param relatives Relativity array - * @param attributes keyed array of attributes. key is attribute name, value is attribute value - * @return Boolean True/False - * Valid attributes are: - * * owner_id - * * createdby_id - * * modifiedby_id - * * created - * * modified - * * size - * * mime_type - * * deleteable - * * comment - * * app - * * link_directory - * * link_name - * * version - * * name - * * directory - */ - function set_attributes ($data,$operation=EGW_ACL_EDIT) - { - /*To get much benefit out of DAV properties we should use - some sensible XML namespace. We will use the Dublin Core - metadata specification (http://dublincore.org/) here where - we can*/ - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - )); - $dav_properties = array(); - $lid=''; $fname = ''; $lname=''; - if ($data['attributes']['comment']) - { - $dav_properties['dc:description'] = $data['attributes']['comment']; - } - if ($id=$data['attributes']['owner_id']) - { - $GLOBALS['egw']->accounts->get_account_name($id,&$lid,&$fname,&$lname); - $dav_properties['dc:publisher'] = $fname .' '. $lname; - $dav_properties['publisher_id'] = $id; - } - if ($id=$data['attributes']['createdby_id']) - { - $GLOBALS['egw']->accounts->get_account_name($id,&$lid,&$fname,&$lname); - $dav_properties['dc:creator'] = $fname .' '. $lname; - $dav_properties['creator_id'] = $id; - } - if ($id=$data['attributes']['modifiedby_id']) - { - $GLOBALS['egw']->accounts->get_account_name($id,&$lid,&$fname,&$lname); - $dav_properties['dc:contributor'] = $fname .' '. $lname; - $dav_properties['contributor_id'] = $id; - } - - $xmlns = 'xmlns:dc="http://purl.org/dc/elements/1.0/"'; - $this->dav_client->proppatch($p->real_full_path, $dav_properties, $xmlns, $this->override_locks[$p->real_full_path]); - return True; - } - - /** - * Set the correct attributes for 'string' (e.g. owner) - * - * @param string File/directory to correct attributes of - * @param relatives Relativity array - * @return Boolean True/False - */ - function correct_attributes ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); -$this->debug('correct_attributes: '.$data['string']); - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if ($p->fake_leading_dirs != $this->fakebase && $p->fake_leading_dirs != '/') - { - $ls_array = $this->ls (array( - 'string' => $p->fake_leading_dirs, - 'relatives' => array ($p->mask), - 'checksubdirs' => False, - 'nofiles' => True - ) - ); - $set_attributes_array = Array( - 'owner_id' => $ls_array[0]['owner_id'] - ); - } - elseif (preg_match ("+^$this->fakebase\/(.*)$+U", $p->fake_full_path, $matches)) - { - $set_attributes_array = Array( - 'owner_id' => $GLOBALS['egw']->accounts->name2id ($matches[1]) - ); - } - else - { - $set_attributes_array = Array( - 'owner_id' => 0 - ); - } - - $this->set_attributes (array( - 'string' => $p->fake_full_name, - 'relatives' => array ($p->mask), - 'attributes' => $set_attributes_array - ) - ); - - return True; - } - - /** - * return file/dir type (MIME or other) - * - * @param string File or directory path (/home/user/dir/dir2/dir3, /home/user/dir/dir2/file) - * @param relatives Relativity array - * @return MIME type, "Directory", or nothing if MIME type is not known - */ - function file_type ($data) - { -$this->debug('file_type'); - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_READ, - 'must_exist' => True - )) - ) return False; - - if ($p->outside) - { - if(is_dir($p->real_full_path)) return ('Directory'); - else return $this->get_ext_mime_type(array('string' => $p->real_full_path)); - - } - $tmp_prop=$this->dav_client->get_properties($p->real_full_path); -$this->debug('tmpprop: '.$p->real_full_path); -$this->debug($tmp_prop); - $mime_type=$tmp_prop[$p->real_full_path]['mime_type']; - if ($mime_type == 'httpd/unix-directory' || $tmp_prop[$p->real_full_path]['is_dir']== '1') - { - $mime_type='Directory'; - } -$this->debug('file_type: Mime type : '.$mime_type); - return $mime_type; - } - - /** - * return MIME type based on file extension - * - * Authors: skeeter - * * Internal use only. Applications should call vfs->file_type () - * @param string File name, with or without leading paths - * @return MIME type based on file extension - */ - function get_ext_mime_type ($data) - { - $file=basename($data['string']); - $mimefile=EGW_API_INC.'/phpgw_mime.types'; - $fp=fopen($mimefile,'r'); - $contents = explode("\n",fread($fp,filesize($mimefile))); - fclose($fp); - - $parts=explode('.',strtolower($file)); - $ext=$parts[(sizeof($parts)-1)]; - - for($i=0;$i= 2) - { - for($j=1;$j array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); -$this->debug('vfs->file_exists() data:'.$data['string']); -$this->debug('vfs->file_exists() full_path: '.$p->real_full_path); - if ($p->outside) - { - return file_exists($p->real_full_path); - } - - $path = $p->real_full_path; - - //Even though this does full XML parsing on the output, because - // it then caches the result this limits the amount of traffic to - //the dav server (which makes it faster even over a local connection) - $props = $this->dav_client->get_properties($path); - if ($props[$path]) - { - $this->debug('found'); - return True; - } - else - { - $this->debug('not found'); - return False; - } - } - - /** - * Return size of 'string' - * - * @param string file/directory to get size of - * @param relatives Relativity array - * @param checksubdirs Boolean, recursively add the size of all sub directories as well? - * @return Size of 'string' in bytes - */ - function get_size ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'checksubdirs' => True - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_READ, - 'must_exist' => True - )) - ) - { - return False; - } - - /* - WIP - this should run through all of the subfiles/directories in the directory and tally up - their sizes. Should modify ls () to be able to return a list for files outside the virtual root - */ - if ($p->outside){ - return filesize($p->real_full_path); - } - - $ls_array = $this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'checksubdirs' => $data['checksubdirs'], - 'nofiles' => !$data['checksubdirs'] - ) - ); - - while (list ($num, $file_array) = each ($ls_array)) - { - /* - Make sure the file is in the directory we want, and not - some deeper nested directory with a similar name - */ -/* - if (@!ereg ('^' . $file_array['directory'], $p->fake_full_path)) - { - continue; - } -*/ - - $size += $file_array['size']; -$this->debug('size:getting size from fs: '.$size); - } - - return $size; - } - - /** - * Check if $this->working_id has write access to create files in $dir - * - * Simple call to acl_check - * @param string Directory to check access of - * @param relatives Relativity array - * @return Boolean True/False - */ - function checkperms ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_ADD - )) - ) - { - return False; - } - else - { - return True; - } - } - - /** - * get directory listing or info about a single file - * - * Note: The entries are not guaranteed to be returned in any logical order - * * Note: The size for directories does not include subfiles/subdirectories. - * * If you need that, use $this->get_size () - * @param string File or Directory - * @param relatives Relativity array - * @param checksubdirs Boolean, recursively list all sub directories as well? - * @param mime_type Only return entries matching MIME-type 'mime_type'. Can be any MIME-type, "Directory" or "\ " for those without MIME types - * @param nofiles Boolean. True means you want to return just the information about the directory $dir. If $dir is a file, $nofiles is implied. This is the equivalent of 'ls -ld $dir' - * @param orderby How to order results. Note that this only works for directories inside the virtual root - * @return array of arrays. Subarrays contain full info for each file/dir. - */ - function ls ($data) - { - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'checksubdirs' => True, - 'mime_type' => False, - 'nofiles' => False, - 'orderby' => 'directory' - ); - $data = array_merge ($this->default_values ($data, $default_values), $data); - //Stupid "nofiles" fix" - if ($data['nofiles']) - { - $data['relatives'] = array (RELATIVE_NONE); - } - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if ($data['checksubdirs']==False && ereg('.*/$', $data['string']) && $data['nofiles'] ) - { -$this->debug('Returning empty for'.$data['string']); - return array(); - } - $dir = $p->fake_full_path; -$this->debug("ls'ing dir: $dir path: ".$p->real_full_path); - /* If they pass us a file or 'nofiles' is set, return the info for $dir only */ - if (((($type = $this->file_type (array( - 'string' => $dir, - 'relatives' => array ($p->mask) - )) != 'Directory')) - || ($data['nofiles'])) && !$p->outside - ) - { -$this->debug('ls branch 1'); - $prop=$this->dav_client->get_properties($p->real_full_path, 1); - //make the key the 'orderby' attribute - if (! ($data['orderby'] == 'directory')) - { - $tmp_prop = array(); - $id=0; - foreach ( $prop as $key=>$value) - { - $id++; - $new_key = substr($value[$data['orderby']].' ',0, 8); - $tmp_prop[strtolower($new_key).'_'.$id] = $value; - } - } - else - { - $tmp_prop = $prop; - } - ksort($tmp_prop); - $rarray = array (); - foreach($tmp_prop as $idx => $value) - { - if($value['mime_type']==$data['mime_type'] or $data['mime_type']=='') - { - $directory = $this->path_parts($value['directory']); - $value['directory'] = $directory->fake_full_path; - if($value['is_dir']) $value['mime_type']='Directory'; - $rarray[] = $value; - } - } -$this->debug('ls returning 1:'); - return $rarray; - } - - //WIP - this should recurse using the same options the virtual part of ls () does - /* If $dir is outside the virutal root, we have to check the file system manually */ - if ($p->outside) - { -$this->debug('ls branch 2 (outside)'); - if ($this->file_type (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) == 'Directory' - && !$data['nofiles'] - ) - { - $dir_handle = opendir ($p->real_full_path); - while ($filename = readdir ($dir_handle)) - { - if ($filename == '.' || $filename == '..') - { - continue; - } - - $rarray[] = $this->get_real_info (array( - 'string' => $p->real_full_path . SEP . $filename, - 'relatives' => array ($p->mask) - ) - ); - } - } - else - { - $rarray[] = $this->get_real_info (array( - 'string' => $p->real_full_path, - 'relatives' => array ($p->mask) - ) - ); - } -$this->debug('ls returning 2:'); - return $rarray; - } -$this->debug('ls branch 3'); - /* $dir's not a file, is inside the virtual root, and they want to check subdirs */ - $prop=$this->dav_client->get_properties($p->real_full_path,1); - unset($prop[$p->real_full_path]); - //make the key the 'orderby' attribute - - if (! ($data['orderby'] == 'directory')) - { - $tmp_prop = array(); - $id=0; - foreach ( $prop as $key=>$value) - { - $id++; - $new_key = substr($value[$data['orderby']].' ',0, 8); - $tmp_prop[strtolower($new_key).'_'.$id] = $value; - } - } - else - { - $tmp_prop = $prop; - } - - ksort($tmp_prop); - - unset($tmp_prop[ $p->real_full_path]); - $rarray = array (); - foreach($tmp_prop as $idx => $value) - { - if($data['mime_type']=='' || $value['mime_type']==$data['mime_type']) - { - //$directory = $this->path_parts($value['directory']); - $value['directory'] = $p->fake_full_path; - $rarray[] = $value; - } - } -$this->debug('ls:returning 3:'); - return $rarray; - } - - /** - * shortcut to ls - * - */ - function dir ($data) - { - return $this->ls ($data); - } - - /** - * Process and run a Unix-sytle command line - * - * EXPERIMENTAL. DANGEROUS. DO NOT USE THIS UNLESS YOU KNOW WHAT YOU'RE DOING! - * * This is mostly working, but the command parser needs to be improved to take - * * files with spaces into consideration (those should be in ""). - * @param command_line Unix-style command line with one of the commands in the $args array - * @return $result The return value of the actual VFS call - */ - function command_line ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $args = array - ( - array ('name' => 'mv', 'params' => 2), - array ('name' => 'cp', 'params' => 2), - array ('name' => 'rm', 'params' => 1), - array ('name' => 'ls', 'params' => -1), - array ('name' => 'du', 'params' => 1, 'func' => get_size), - array ('name' => 'cd', 'params' => 1), - array ('name' => 'pwd', 'params' => 0), - array ('name' => 'cat', 'params' => 1, 'func' => read), - array ('name' => 'file', 'params' => 1, 'func' => file_type), - array ('name' => 'mkdir', 'params' => 1), - array ('name' => 'touch', 'params' => 1) - ); - - if (!$first_space = strpos ($data['command_line'], ' ')) - { - $first_space = strlen ($data['command_line']); - } - if ((!$last_space = strrpos ($data['command_line'], ' ')) || ($last_space == $first_space)) - { - $last_space = strlen ($data['command_line']) + 1; - } - $argv[0] = substr ($data['command_line'], 0, $first_space); - if (strlen ($argv[0]) != strlen ($data['command_line'])) - { - $argv[1] = substr ($data['command_line'], $first_space + 1, $last_space - ($first_space + 1)); - if ((strlen ($argv[0]) + 1 + strlen ($argv[1])) != strlen ($data['command_line'])) - { - $argv[2] = substr ($data['command_line'], $last_space + 1); - } - } - $argc = count ($argv); - - reset ($args); - while (list (,$arg_info) = each ($args)) - { - if ($arg_info['name'] == $argv[0]) - { - $command_ok = 1; - if (($argc == ($arg_info['params'] + 1)) || ($arg_info['params'] == -1)) - { - $param_count_ok = 1; - } - break; - } - } - - if (!$command_ok) - { -// return E_VFS_BAD_COMMAND; - return False; - } - if (!$param_count_ok) - { -// return E_VFS_BAD_PARAM_COUNT; - return False; - } - - for ($i = 1; $i != ($arg_info['params'] + 1); $i++) - { - if (substr ($argv[$i], 0, 1) == '/') - { - $relatives[] = RELATIVE_NONE; - } - else - { - $relatives[] = RELATIVE_ALL; - } - } - - $func = $arg_info['func'] ? $arg_info['func'] : $arg_info['name']; - - if (!$argv[2]) - { - $rv = $this->$func (array( - 'string' => $argv[1], - 'relatives' => $relatives - ) - ); - } - else - { - $rv = $this->$func (array( - 'from' => $argv[1], - 'to' => $argv[2], - 'relatives' => $relatives - ) - ); - } - - return ($rv); - } - - /* Helper functions */ - - function default_values ($data, $default_values) - { - if(!is_array($data)) $data=array(); - for ($i = 0; list ($key, $value) = each ($default_values); $i++) - { - if (!isset ($data[$key])) - { - $data[$key] = $value; - } - } - - return $data; - } - - /* Since we are always dealing with real info, this just calls ls */ - function get_real_info ($data){ - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if ( $this->file_type(array('string' => $p->real_full_path, 'relatives' => array (RELATIVE_ROOT))) == 'Directory') - { - $mime_type = 'Directory'; - } - else - { - $mime_type = $this->get_ext_mime_type (array( - 'string' => $p->fake_name - ) - ); - - } - - $size = filesize ($p->real_full_path); - $rarray = array( - 'directory' => $p->fake_leading_dirs, - 'name' => $p->fake_name, - 'size' => $size, - 'mime_type' => $mime_type - ); - - return ($rarray); - } - - function update_real() - { //hmmm. things break without this, but it does nothing in this implementation - return True; - } - - function save_session() - { - //Save the overrided locks in the session - $app = $GLOBALS['egw_info']['flags']['currentapp']; - $a = array(); - foreach ($this->override_locks as $name => $token) - { - $a[] = $name.';'.$token; - } - $session_data = implode('\n', $a); - $this->session = $GLOBALS['egw']->session->appsession ('vfs_dav',$app, base64_encode($session_data)); - - } - } -?> diff --git a/phpgwapi/inc/class.vfs_home.inc.php b/phpgwapi/inc/class.vfs_home.inc.php deleted file mode 100644 index 62679a8f1e..0000000000 --- a/phpgwapi/inc/class.vfs_home.inc.php +++ /dev/null @@ -1,204 +0,0 @@ - - * @copyright (c) 2007 by Ralf Becker - * @version $Id$ - */ - -require_once(EGW_API_INC.'/class.vfs.inc.php'); - -/** - * eGroupWare API: VFS - Homedirectories - * - * This class implements some necessary stuff for user- and group-directories ontop the vfs class. - * - * Some of it is already implemented in the filemanager app, but it's also needed for the WebDAV access: - * - show only directories in /home, to which the user has at least read-access - * - * Stuff dealing with creation, renaming or deletion of users via some hooks from admin: - * - create the homedir if a new user gets created - * - rename the homedir if the user-name changes - * - delete the homedir or copy its content to an other users homedir, if a user gets deleted - * --> these hooks are registered via phpgwapi/setup/setup.inc.php and called by the admin app - */ -class vfs_home extends vfs -{ - /** - * List a directory, reimplemented to hide dirs the user has no rights to read - * - * @param array $data - * @param string $data['string'] path - * @param array $data['relatives'] Relativity array (default: RELATIVE_CURRENT) - * @param boolean $data['checksubdirs'] If true return information for all subdirectories recursively - * @param string $data['mime'] Only return information for locations with MIME type specified (eg. 'Directory') - * @param boolean $data['nofiles'] If set and $data['string'] is a directory, return information about the directory, not the files in it. - * @return array of arrays of file information. - */ - function ls($data) - { - //error_log("vfs_home(".print_r($data,true).")"); - $fileinfos = parent::ls($data); - - if (!$this->override_acl && !$data['nofiles'] && ($data['string'] == $this->fakebase || $data['string'].$this->fakebase.'/')) - { - //error_log("vfs_home() grants=".print_r($this->grants,true)); - - // remove directories the user has no rights to see, no grant from the owner - foreach($fileinfos as $key => $info) - { - //error_log("vfs_home() ".(!$this->grants[$info['owner_id']] ? 'hidding' : 'showing')." $info[directory]/$info[name] (owner=$info[owner_id])"); - - if (!$this->grants[$info['owner_id']]) - { - unset($fileinfos[$key]); - } - } - } - return $fileinfos; - } - - /** - * Hook called after new accounts have been added - * - * @param array $data - * @param int $data['account_id'] numerical id - * @param string $data['account_lid'] account-name - */ - function addAccount($data) - { - // create a user-dir - $save_id = $this->working_id; - $this->working_id = $data['account_id']; - $save_currentapp = $GLOBALS['egw_info']['flags']['currentapp']; - $GLOBALS['egw_info']['flags']['currentapp'] = 'filemanager'; - - $this->override_acl = true; - $this->mkdir(array( - 'string' => $this->fakebase.'/'.$data['account_lid'], - 'relatives' => array(RELATIVE_ROOT), - )); - $this->override_acl = false; - - $this->working_id = $save_id; - $GLOBALS['egw_info']['flags']['currentapp'] = $currentapp; - } - - /** - * Hook called after accounts has been modified - * - * @param array $data - * @param int $data['account_id'] numerical id - * @param string $data['account_lid'] new account-name - * @param string $data['old_loginid'] old account-name - */ - function editAccount($data) - { - if ($data['account_lid'] == $data['old_loginid']) return; // nothing to do here - - // rename the user-dir - $this->override_acl = true; - $this->mv(array( - 'from' => $this->fakebase.'/'.$data['old_loginid'], - 'to' => $this->fakebase.'/'.$data['account_lid'], - 'relatives' => array(RELATIVE_ROOT,RELATIVE_ROOT), - )); - $this->override_acl = false; - } - - /** - * Hook called before an account get deleted - * - * @param array $data - * @param int $data['account_id'] numerical id - * @param string $data['account_lid'] account-name - * @param int $data['new_owner'] account-id of new owner, or false if data should get deleted - */ - function deleteAccount($data) - { - if ($data['new_owner']) - { - // ToDo: copy content of user-dir to new owner's user-dir - - } - // delete the user-directory - $this->override_acl = true; - $this->delete(array( - 'string' => $this->fakebase.'/'.$data['account_lid'], - 'relatives' => array(RELATIVE_ROOT), - )); - $this->override_acl = false; - } - - /** - * Hook called after new groups have been added - * - * @param array $data - * @param int $data['account_id'] numerical id - * @param string $data['account_name'] group-name - */ - function addGroup($data) - { - // create a group-dir - $save_id = $this->working_id; - $this->working_id = $data['account_id']; - $save_currentapp = $GLOBALS['egw_info']['flags']['currentapp']; - $GLOBALS['egw_info']['flags']['currentapp'] = 'filemanager'; - - $this->override_acl = true; - $this->mkdir(array( - 'string' => $this->fakebase.'/'.$data['account_name'], - 'relatives' => array(RELATIVE_ROOT), - )); - $this->override_acl = false; - - $this->working_id = $save_id; - $GLOBALS['egw_info']['flags']['currentapp'] = $currentapp; - } - - /** - * Hook called after group has been modified - * - * @param array $data - * @param int $data['account_id'] numerical id - * @param string $data['account_name'] new group-name - * @param string $data['old_name'] old account-name - */ - function editGroup($data) - { - if ($data['account_name'] == $data['old_name']) return; // nothing to do here - - // rename the group-dir - $this->override_acl = true; - $this->mv(array( - 'from' => $this->fakebase.'/'.$data['old_name'], - 'to' => $this->fakebase.'/'.$data['account_name'], - 'relatives' => array(RELATIVE_ROOT,RELATIVE_ROOT), - )); - $this->override_acl = false; - } - - /** - * Hook called before a group get deleted - * - * @param array $data - * @param int $data['account_id'] numerical id - * @param string $data['account_name'] account-name - */ - function deleteGroup($data) - { - // delete the group-directory - $this->override_acl = true; - $this->delete(array( - 'string' => $this->fakebase.'/'.$data['account_name'], - 'relatives' => array(RELATIVE_ROOT), - )); - $this->override_acl = false; - } - -} \ No newline at end of file diff --git a/phpgwapi/inc/class.vfs_sql.inc.php b/phpgwapi/inc/class.vfs_sql.inc.php deleted file mode 100644 index 7caf9525e2..0000000000 --- a/phpgwapi/inc/class.vfs_sql.inc.php +++ /dev/null @@ -1,2650 +0,0 @@ - * - * This class handles file/dir access for eGroupWare * - * Copyright (C) 2001 Jason Wies * - * Database layer reworked 2005/09/20 by RalfBecker-AT-outdoor-training.de * - * -------------------------------------------------------------------------* - * This library is part of the eGroupWare API * - * ------------------------------------------------------------------------ * - * This library is free software; you can redistribute it and/or modify it * - * under the terms of the GNU Lesser General Public License as published by * - * the Free Software Foundation; either version 2.1 of the License, * - * or any later version. * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License * - * along with this library; if not, write to the Free Software Foundation, * - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - \**************************************************************************/ - - /* $Id$ */ - - /** - * Virtual File System with SQL backend - * - * Authors: Zone - */ - - /* These are used in calls to extra_sql () */ - define ('VFS_SQL_SELECT', 1); - define ('VFS_SQL_DELETE', 2); - define ('VFS_SQL_UPDATE', 4); - - class vfs extends vfs_shared - { - var $working_id; - var $working_lid; - var $meta_types; - var $now; - var $file_actions; // true if the content is stored in the file-system, false if it's stored in the DB too - var $vfs_table = 'egw_vfs'; - var $vfs_column_prefix = 'vfs_'; - - /** - * constructor, sets up variables - * - */ - function vfs () - { - $this->vfs_shared (); - $this->basedir = $GLOBALS['egw_info']['server']['files_dir']; - $this->working_id = $GLOBALS['egw_info']['user']['account_id']; - $this->working_lid = $GLOBALS['egw_info']['user']['account_lid']; - $this->now = date ('Y-m-d H:i:s'); - - /* - File/dir attributes, each corresponding to a database field. Useful for use in loops - If an attribute was added to the table, add it here and possibly add it to - set_attributes () - - set_attributes now uses this array(). 07-Dec-01 skeeter - */ - - $this->attributes[] = 'deleteable'; - $this->attributes[] = 'content'; - - // set up the keys as db-column-names - foreach($this->attributes as $n => $attr) - { - unset($this->attributes[$n]); - $this->attributes[$this->vfs_column_prefix.$attr] = $attr; - } - /* - Decide whether to use any actual filesystem calls (fopen(), fread(), - unlink(), rmdir(), touch(), etc.). If not, then we're working completely - in the database. - */ - $this->file_actions = $GLOBALS['egw_info']['server']['file_store_contents'] == 'filesystem' || - !$GLOBALS['egw_info']['server']['file_store_contents']; - - // test if the files-dir is inside the document-root, and refuse working if so - // - if ($this->file_actions && $this->in_docroot($this->basedir)) - { - $GLOBALS['egw']->common->egw_header(); - if ($GLOBALS['egw_info']['flags']['noheader']) - { - echo parse_navbar(); - } - echo '

'.lang('Path to user and group files HAS TO BE OUTSIDE of the webservers document-root!!!')."

\n"; - $GLOBALS['egw']->common->egw_exit(); - } - /* - These are stored in the MIME-type field and should normally be ignored. - Adding a type here will ensure it is normally ignored, but you will have to - explicitly add it to acl_check (), and to any other SELECT's in this file - */ - - $this->meta_types = array ('journal', 'journal-deleted'); - - $this->db = clone($GLOBALS['egw']->db); - $this->db->set_app('phpgwapi'); - - /* We store the linked directories in an array now, so we don't have to make the SQL call again */ - switch ($this->db->Type) - { - case 'mssql': - case 'sybase': - $where = array( - "CONVERT(varchar,vfs_link_directory) != ''", - "CONVERT(varchar,vfs_link_name) != ''", - ); - break; - default: - $where = array( - "(vfs_link_directory IS NOT NULL OR vfs_link_directory != '')", - "(vfs_link_name IS NOT NULL OR vfs_link_name != '')", - ); - break; - } - $where[] = $this->extra_sql(array('query_type' => VFS_SQL_SELECT)); - $this->db->select($this->vfs_table,'vfs_directory,vfs_name,vfs_link_directory,vfs_link_name',$where,__LINE__,__FILE__); - - $this->linked_dirs = array (); - while ($this->db->next_record ()) - { - $this->linked_dirs[] = array( - 'directory' => $this->db->Record['vfs_directory'], - 'name' => $this->db->Record['vfs_name'], - 'link_directory' => $this->db->Record['vfs_link_directory'], - 'link_name' => $this->db->Record['vfs_link_name'], - ); - } - // group grants in filemanage are used for group-directories, NOT as grants for each group-member!!! - $this->grants = $GLOBALS['egw']->acl->get_grants('filemanager',false); - } - - /** - * test if $path lies within the webservers document-root - * - */ - function in_docroot($path) - { - $docroots = array(EGW_SERVER_ROOT,$_SERVER['DOCUMENT_ROOT']); - - foreach ($docroots as $docroot) - { - $len = strlen($docroot); - - if ($docroot && $docroot == substr($path,0,$len)) - { - $rest = substr($path,$len); - - if (!strlen($rest) || $rest[0] == DIRECTORY_SEPARATOR) - { - return True; - } - } - } - return False; - } - - /** - * Return extra SQL code that should be appended (AND'ed) to certain queries - * - * @param query_type The type of query to get extra SQL code for, in the form of a VFS_SQL define - * @return Extra SQL code - */ - function extra_sql ($data) - { - if (!is_array ($data)) - { - $data = array ('query_type' => VFS_SQL_SELECT); - } - - if ($data['query_type'] == VFS_SQL_SELECT || $data['query_type'] == VFS_SQL_DELETE || $data['query_type'] == VFS_SQL_UPDATE) - { - return "((vfs_mime_type != '".implode("' AND vfs_mime_type != '",$this->meta_types)."') OR vfs_mime_type IS NULL)"; - } - return ''; - } - - /** - * Add a journal entry after (or before) completing an operation, - * - * * and increment the version number. This function should be used internally only - * Note that state_one and state_two are ignored for some VFS_OPERATION's, for others - * * they are required. They are ignored for any "custom" operation - * * The two operations that require state_two: - * * operation * state_two - * * VFS_OPERATION_COPIED fake_full_path of copied to - * * VFS_OPERATION_MOVED * fake_full_path of moved to - - * * If deleting, you must call add_journal () before you delete the entry from the database - * @param string File or directory to add entry for - * @param relatives Relativity array - * @param operation The operation that was performed. Either a VFS_OPERATION define or - * * a non-integer descriptive text string - * @param state_one The first "state" of the file or directory. Can be a file name, size, - * * location, whatever is appropriate for the specific operation - * @param state_two The second "state" of the file or directory - * @param incversion Boolean True/False. Increment the version for the file? Note that this is - * * handled automatically for the VFS_OPERATION defines. - * * i.e. VFS_OPERATION_EDITED would increment the version, VFS_OPERATION_COPIED - * * would not - * @return Boolean True/False - */ - function add_journal ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'state_one' => False, - 'state_two' => False, - 'incversion' => True - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - - $p = $this->path_parts (array ('string' => $data['string'], 'relatives' => array ($data['relatives'][0]))); - - /* We check that they have some sort of access to the file other than read */ - if (!$this->acl_check (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask), 'operation' => EGW_ACL_WRITE)) && - !$this->acl_check (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask), 'operation' => EGW_ACL_EDIT)) && - !$this->acl_check (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask), 'operation' => EGW_ACL_DELETE))) - { - return False; - } - - if (!$this->file_exists (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask)))) - { - return False; - } - - $ls_array = $this->ls (array ( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'checksubdirs' => False, - 'mime_type' => False, - 'nofiles' => True - ) - ); - $file_array = $ls_array[0]; - - $to_write = array(); - foreach ($file_array as $attribute => $value) - { - if ($attribute == 'file_id' || $attribute == 'content') - { - continue; - } - - if ($attribute == 'owner_id') - { - $value = $account_id; - } - - if ($attribute == 'created') - { - $value = $this->now; - } - - if ($attribute == 'modified' && !$data['modified']) - { - unset ($value); - } - - if ($attribute == 'mime_type') - { - $value = 'journal'; - } - - if ($attribute == 'comment') - { - switch ($data['operation']) - { - case VFS_OPERATION_CREATED: - $value = 'Created'; - $data['incversion'] = True; - break; - case VFS_OPERATION_EDITED: - $value = 'Edited'; - $data['incversion'] = True; - break; - case VFS_OPERATION_EDITED_COMMENT: - $value = 'Edited comment'; - $data['incversion'] = False; - break; - case VFS_OPERATION_COPIED: - if (!$data['state_one']) - { - $data['state_one'] = $p->fake_full_path; - } - if (!$data['state_two']) - { - return False; - } - $value = 'Copied '.$data['state_one'].' to '.$data['state_two']; - $data['incversion'] = False; - break; - case VFS_OPERATION_MOVED: - if (!$data['state_one']) - { - $data['state_one'] = $p->fake_full_path; - } - if (!$data['state_two']) - { - return False; - } - $value = 'Moved '.$data['state_one'].' to '.$data['state_two']; - $data['incversion'] = False; - break; - case VFS_OPERATION_DELETED: - $value = 'Deleted'; - $data['incversion'] = False; - break; - default: - $value = $data['operation']; - break; - } - } - - /* - Let's increment the version for the file itself. We keep the current - version when making the journal entry, because that was the version that - was operated on. The maximum numbers for each part in the version string: - none.99.9.9 - */ - if ($attribute == 'version' && $data['incversion']) - { - $version_parts = explode ('.', $value); - $newnumofparts = count ($version_parts); - - if ($version_parts[3] >= 9) - { - $version_parts[3] = 0; - $version_parts[2]++; - $version_parts_3_update = 1; - } - elseif (isset ($version_parts[3])) - { - $version_parts[3]++; - } - - if ($version_parts[2] >= 9 && $version_parts[3] == 0 && $version_parts_3_update) - { - $version_parts[2] = 0; - $version_parts[1]++; - } - - if ($version_parts[1] > 99) - { - $version_parts[1] = 0; - $version_parts[0]++; - } - - for ($i = 0; $i < $newnumofparts; $i++) - { - if (!isset ($version_parts[$i])) - { - break; - } - - if ($i) - { - $newversion .= '.'; - } - - $newversion .= $version_parts[$i]; - } - - $this->set_attributes (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => array( - 'version' => $newversion - ) - ) - ); - } - - if (isset ($value)) - { - $to_write[$this->vfs_column_prefix.$attribute] = $value; - } - } - /* - These are some special situations where we need to flush the journal entries - or move the 'journal' entries to 'journal-deleted'. Kind of hackish, but they - provide a consistent feel to the system - */ - if ($data['operation'] == VFS_OPERATION_CREATED) - { - $flush_path = $p->fake_full_path; - $deleteall = True; - } - - if ($data['operation'] == VFS_OPERATION_COPIED || $data['operation'] == VFS_OPERATION_MOVED) - { - $flush_path = $data['state_two']; - $deleteall = False; - } - - if ($flush_path) - { - $flush_path_parts = $this->path_parts (array( - 'string' => $flush_path, - 'relatives' => array (RELATIVE_NONE) - ) - ); - - $this->flush_journal (array( - 'string' => $flush_path_parts->fake_full_path, - 'relatives' => array ($flush_path_parts->mask), - 'deleteall' => $deleteall - ) - ); - } - - if ($data['operation'] == VFS_OPERATION_COPIED) - { - /* - We copy it going the other way as well, so both files show the operation. - The code is a bad hack to prevent recursion. Ideally it would use VFS_OPERATION_COPIED - */ - $this->add_journal (array( - 'string' => $data['state_two'], - 'relatives' => array (RELATIVE_NONE), - 'operation' => 'Copied '.$data['state_one'].' to '.$data['state_two'], - 'state_one' => NULL, - 'state_two' => NULL, - 'incversion' => False - ) - ); - } - - if ($data['operation'] == VFS_OPERATION_MOVED) - { - $state_one_path_parts = $this->path_parts (array( - 'string' => $data['state_one'], - 'relatives' => array (RELATIVE_NONE) - ) - ); - - $this->db->update($this->vfs_table,array('vfs_mime_type'=>'journal-deleted'),array( - 'vfs_directory' => $state_one_path_parts->fake_leading_dirs, - 'vfs_name' => $state_one_path_parts->fake_name, - 'vfs_mime_type' => 'journal', - ),__LINE__,__FILE__); - - /* - We create the file in addition to logging the MOVED operation. This is an - advantage because we can now search for 'Create' to see when a file was created - */ - $this->add_journal (array( - 'string' => $data['state_two'], - 'relatives' => array (RELATIVE_NONE), - 'operation' => VFS_OPERATION_CREATED - ) - ); - } - - /* This is the SQL query we made for THIS request, remember that one? */ - $this->db->insert($this->vfs_table,$to_write,false, __LINE__, __FILE__); - - /* - If we were to add an option of whether to keep journal entries for deleted files - or not, it would go in the if here - */ - if ($data['operation'] == VFS_OPERATION_DELETED) - { - $this->db->update($this->vfs_table,array( - 'vfs_mime_type' => 'journal-deleted' - ),array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - 'vfs_mime_type' => 'journal', - ),__LINE__,__FILE__); - } - - return True; - } - - /** - * Flush journal entries for $string. Used before adding $string - * - * flush_journal () is an internal function and should be called from add_journal () only - * @param string File/directory to flush journal entries of - * @param relatives Realtivity array - * @param deleteall Delete all types of journal entries, including the active Create entry. - * * Normally you only want to delete the Create entry when replacing the file - * * Note that this option does not effect $deleteonly - * @param deletedonly Only flush 'journal-deleted' entries (created when $string was deleted) - * @return Boolean True/False - */ - function flush_journal ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'deleteall' => False, - 'deletedonly' => False - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - $where = array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - ); - if (!$data['deleteall']) - { - $where[] = "(vfs_mime_type != 'journal' AND vfs_comment != 'Created')"; - } - - $where[] = "(vfs_mime_type='journal-deleted'".(!$data['deletedonly']?" OR vfs_mime_type='journal'":'').')'; - - return !!$this->db->delete($this->vfs_table,$where, __LINE__, __FILE__); - } - - /* - * See vfs_shared - */ - function get_journal ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'type' => False - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - ))) - { - return False; - } - - $where = array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - ); - - if ($data['type'] == 1) - { - $where[] = "vfs_mime_type='journal'"; - } - elseif ($data['type'] == 2) - { - $where[] = "vfs_mime_type='journal-deleted'"; - } - else - { - $where[] = "(vfs_mime_type='journal' OR vfs_mime_type='journal-deleted')"; - } - - $this->db->select($this->vfs_table,'*',$where, __LINE__, __FILE__); - - while (($row = $this->db->Row(true))) - { - $rarray[] = $this->remove_prefix($row); - } - - return $rarray; - } - - /* - * See vfs_shared - */ - function acl_check ($data) - { - //error_log(__METHOD__.'('.print_r($data,true).')'); - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'operation' => EGW_ACL_READ, - 'must_exist' => False - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - /* Accommodate special situations */ - if ($this->override_acl || $data['relatives'][0] == RELATIVE_USER_APP) - { - return True; - } - - if (!$data['owner_id']) - { - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - /* Temporary, until we get symlink type files set up */ - if ($p->outside) - { - return True; - } - - /* Read access is always allowed here, but nothing else is */ - if ($data['string'] == '/' || $data['string'] == $this->fakebase) - { - if ($data['operation'] == EGW_ACL_READ) - { - return True; - } - else - { - return False; - } - } - - /* If the file doesn't exist, we get ownership from the parent directory */ - if (!$this->file_exists (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) - ) - { - if ($data['must_exist']) - { - return False; - } - - $data['string'] = $p->fake_leading_dirs; - $p2 = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($p->mask) - ) - ); - - if (!$this->file_exists (array( - 'string' => $data['string'], - 'relatives' => array ($p->mask) - )) - ) - { - return False; - } - } - else - { - $p2 = $p; - //echo "using parent directory for acl-check, "; - } - - /* - We don't use ls () to get owner_id as we normally would, - because ls () calls acl_check (), which would create an infinite loop - */ - $this->db->select($this->vfs_table,'vfs_owner_id',array( - 'vfs_directory' => $p2->fake_leading_dirs, - 'vfs_name' => $p2->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - $this->db->next_record (); - - $owner_id = $this->db->Record['vfs_owner_id']; - } - else - { - $owner_id = $data['owner_id']; - } - //echo "owner=$owner_id, "; - - /* This is correct. The ACL currently doesn't handle undefined values correctly */ - if (!$owner_id) - { - $owner_id = 0; - } - - $user_id = $GLOBALS['egw_info']['user']['account_id']; - //echo "user=$user_id, "; - /* They always have access to their own files */ - /* Files with owner_id = 0 are created by apps, and need at least to be readable */ - if ($owner_id == $user_id || ($owner_id == 0 && $data['operation'] == EGW_ACL_READ)) - { - return True; - } - $rights = $this->grants[(string)$owner_id]; - //echo "rights=$rights, "; - if ($rights & $data['operation']) - { - return True; - } - elseif (!$rights) - { - return $GLOBALS['egw_info']['server']['acl_default'] == 'grant'; - } - else - { - return False; - } - } - - /* - * See vfs_shared - */ - function read ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_READ - )) - ) - { - return False; - } - - if ($this->file_actions || $p->outside) - { - if (($fp = fopen ($p->real_full_path, 'rb'))) - { - if (filesize($p->real_full_path) > 0) - { - $contents = fread ($fp, filesize($p->real_full_path)); - } - else - { - // files could also have no contents. In this case - // the second parameter should not be present! - $contents = fread ($fp); - } - - fclose ($fp); - } - else - { - $contents = False; - } - } - else - { - $ls_array = $this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - ) - ); - - $contents = $ls_array[0]['content']; - } - - return $contents; - } - - /* - * See vfs_shared - */ - function write ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'content' => '' - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if ($this->file_exists (array ( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) - ) - { - $acl_operation = EGW_ACL_EDIT; - $journal_operation = VFS_OPERATION_EDITED; - } - else - { - $acl_operation = EGW_ACL_ADD; - } - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => $acl_operation - )) - ) - { - return False; - } - - umask(0177); - - /* - If 'string' doesn't exist, touch () creates both the file and the database entry - If 'string' does exist, touch () sets the modification time and modified by - */ - $this->touch (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - ) - ); - - if ($this->file_actions) - { - if (($fp = fopen ($p->real_full_path, 'wb'))) - { - fwrite ($fp, $data['content']); - fclose ($fp); - $write_ok = 1; - } - } - - if ($write_ok || !$this->file_actions) - { - if ($this->file_actions) - { - $set_attributes_array = array( - 'size' => filesize ($p->real_full_path) - ); - } - else - { - $set_attributes_array = array ( - 'size' => strlen ($data['content']), - 'content' => $data['content'] - ); - } - - - $this->set_attributes (array - ( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => $set_attributes_array - ) - ); - - if ($journal_operation) - { - $this->add_journal (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => $journal_operation - ) - ); - } - - return True; - } - else - { - return False; - } - } - - /* - * See vfs_shared - */ - function touch ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'time' => $this->now, - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - $currentapp = $GLOBALS['egw_info']['flags']['currentapp']; - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - umask (0177); - - if ($this->file_actions) - { - /* - PHP's touch function will automatically decide whether to - create the file or set the modification time - */ - $rr = @touch ($p->real_full_path,$data['time']); - - if ($p->outside) - { - return $rr; - } - } - - /* We, however, have to decide this ourselves */ - if ($this->file_exists (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) - ) - { - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_EDIT - ))) - { - return False; - } - - $vr = $this->set_attributes (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => array( - 'modifiedby_id' => $account_id, - 'modified' => $data['time'], - ) - ) - ); - } - else - { - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_ADD - )) - ) - { - return False; - } - - $query = $this->db->insert($this->vfs_table,array( - 'vfs_owner_id' => $this->working_id, - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - ),false,__LINE__,__FILE__); - - $this->set_attributes(array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => array ( - 'createdby_id' => $account_id, - 'created' => $data['time'], - 'size' => 0, - 'deleteable' => 'Y', - 'app' => $currentapp - ) - ) - ); - $this->correct_attributes (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - ) - ); - - $this->add_journal (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => VFS_OPERATION_CREATED - ) - ); - } - - return $rr || $vr || $query; - } - - /* - * See vfs_shared - * If $data['symlink'] the file is symlinked instead of copied - */ - function cp ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT, RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - - $f = $this->path_parts (array( - 'string' => $data['from'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - $t = $this->path_parts (array( - 'string' => $data['to'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => EGW_ACL_READ - )) - ) - { - return False; - } - - if (($exists = $this->file_exists (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ))) - ) - { - if (!$this->acl_check (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => EGW_ACL_EDIT - )) - ) - { - return False; - } - } - else - { - if (!$this->acl_check (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => EGW_ACL_ADD - )) - ) - { - return False; - } - } - - umask(0177); - - if ($this->file_type (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - )) != 'Directory' - ) - { - if ($this->file_actions) - { - if (@$data['symlink']) - { - if ($exists) - { - @unlink($t->real_full_path); - } - if (!symlink($f->real_full_path, $t->real_full_path)) - { - return False; - } - } - elseif (!copy ($f->real_full_path, $t->real_full_path)) - { - return False; - } - - $size = filesize ($t->real_full_path); - } - else - { - $content = $this->read (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - ) - ); - - $size = strlen ($content); - } - - if ($t->outside) - { - return True; - } - - $ls_array = $this->ls (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'checksubdirs' => False, - 'mime_type' => False, - 'nofiles' => True - ) - ); - $record = $ls_array[0]; - - if ($this->file_exists (array( - 'string' => $data['to'], - 'relatives' => array ($data['relatives'][1]) - )) - ) - { - $set_attributes_array = array ( - 'createdby_id' => $account_id, - 'created' => $this->now, - 'size' => $size, - 'mime_type' => $record['mime_type'], - 'deleteable' => $record['deleteable'], - 'comment' => $record['comment'], - 'app' => $record['app'] - ); - - if (!$this->file_actions) - { - $set_attributes_array['content'] = $content; - } - - $this->set_attributes(array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'attributes' => $set_attributes_array - ) - ); - - $this->add_journal (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => VFS_OPERATION_EDITED - ) - ); - } - else - { - $this->touch (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ) - ); - - $set_attributes_array = array ( - 'createdby_id' => $account_id, - 'created' => $this->now, - 'size' => $size, - 'mime_type' => $record['mime_type'], - 'deleteable' => $record['deleteable'], - 'comment' => $record['comment'], - 'app' => $record['app'] - ); - - if (!$this->file_actions) - { - $set_attributes_array['content'] = $content; - } - - $this->set_attributes(array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'attributes' => $set_attributes_array - ) - ); - } - $this->correct_attributes (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ) - ); - } - else /* It's a directory */ - { - /* First, make the initial directory */ - $this->mkdir (array( - 'string' => $data['to'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - /* Next, we create all the directories below the initial directory */ - foreach($this->ls (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'checksubdirs' => True, - 'mime_type' => 'Directory' - )) as $entry) - { - $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']); - $this->mkdir (array( - 'string' => $newdir.'/'.$entry['name'], - 'relatives' => array ($t->mask) - ) - ); - } - - /* Lastly, we copy the files over */ - foreach($this->ls (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - )) as $entry) - { - if ($entry['mime_type'] == 'Directory') - { - continue; - } - - $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']); - $this->cp (array( - 'from' => "$entry[directory]/$entry[name]", - 'to' => "$newdir/$entry[name]", - 'relatives' => array ($f->mask, $t->mask) - ) - ); - } - } - - if (!$f->outside) - { - $this->add_journal (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => VFS_OPERATION_COPIED, - 'state_one' => NULL, - 'state_two' => $t->fake_full_path - ) - ); - } - - return True; - } - - /* - * See vfs_shared - */ - function mv ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT, RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - - $f = $this->path_parts (array( - 'string' => $data['from'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - $t = $this->path_parts (array( - 'string' => $data['to'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => EGW_ACL_READ - )) - || !$this->acl_check (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => EGW_ACL_DELETE - )) - ) - { - return False; - } - - if (!$this->acl_check (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => EGW_ACL_ADD - )) - ) - { - return False; - } - - if ($this->file_exists (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - )) - ) - { - if (!$this->acl_check (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => EGW_ACL_EDIT - )) - ) - { - return False; - } - } - - umask (0177); - - /* We can't move directories into themselves */ - if (($this->file_type (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - ) == 'Directory')) - && ereg ("^$f->fake_full_path", $t->fake_full_path) - ) - { - if (($t->fake_full_path == $f->fake_full_path) || substr ($t->fake_full_path, strlen ($f->fake_full_path), 1) == '/') - { - return False; - } - } - - if ($this->file_exists (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - )) - ) - { - /* We get the listing now, because it will change after we update the database */ - $ls = $this->ls (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask) - ) - ); - - if ($this->file_exists (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - )) - ) - { - $this->rm (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ) - ); - } - - /* - We add the journal entry now, before we delete. This way the mime_type - field will be updated to 'journal-deleted' when the file is actually deleted - */ - if (!$f->outside) - { - $this->add_journal (array( - 'string' => $f->fake_full_path, - 'relatives' => array ($f->mask), - 'operation' => VFS_OPERATION_MOVED, - 'state_one' => $f->fake_full_path, - 'state_two' => $t->fake_full_path - ) - ); - } - - /* - If the from file is outside, it won't have a database entry, - so we have to touch it and find the size - */ - if ($f->outside) - { - $size = filesize ($f->real_full_path); - - $this->touch (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ) - ); - $this->db->update($this->vfs_table,array('vfs_size'=>$size),array( - 'vfs_directory' => $t->fake_leading_dirs, - 'vfs_name' => $t->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_UPDATE)), - ), __LINE__, __FILE__); - } - elseif (!$t->outside) - { - $this->db->update($this->vfs_table,array( - 'vfs_directory' => $t->fake_leading_dirs, - 'vfs_name' => $t->fake_name, - ),array( - 'vfs_directory' => $f->fake_leading_dirs, - 'vfs_name' => $f->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_UPDATE)), - ), __LINE__, __FILE__); - } - - $this->set_attributes(array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'attributes' => array ( - 'modifiedby_id' => $account_id, - 'modified' => $this->now - ) - ) - ); - - $this->correct_attributes (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - ) - ); - - if ($this->file_actions) - { - rename ($f->real_full_path, $t->real_full_path); - } - - /* - This removes the original entry from the database - The actual file is already deleted because of the rename () above - */ - if ($t->outside) - { - $this->rm (array( - 'string' => $f->fake_full_path, - 'relatives' => $f->mask - ) - ); - } - } - else - { - return False; - } - - if ($this->file_type (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask) - )) == 'Directory' - ) - { - /* We got $ls from above, before we renamed the directory */ - foreach ($ls as $entry) - { - $newdir = ereg_replace ("^$f->fake_full_path", $t->fake_full_path, $entry['directory']); - - $this->db->update($this->vfs_table,array( - 'vfs_directory' => $newdir - ),array( - 'vfs_file_id' => $entry['file_id'], - $this->extra_sql(array ('query_type' => VFS_SQL_UPDATE)) - ), __LINE__, __FILE__); - - $this->correct_attributes (array( - 'string' => "$newdir/$entry[name]", - 'relatives' => array ($t->mask) - ) - ); - } - } - - $this->add_journal (array( - 'string' => $t->fake_full_path, - 'relatives' => array ($t->mask), - 'operation' => VFS_OPERATION_MOVED, - 'state_one' => $f->fake_full_path, - 'state_two' => $t->fake_full_path - ) - ); - - return True; - } - - /* - * See vfs_shared - */ - function rm ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_DELETE - )) - ) - { - return False; - } - - if (!$this->file_exists (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - )) - ) - { - if ($this->file_actions) - { - $rr = @unlink ($p->real_full_path); - } - else - { - $rr = True; - } - - if ($rr) - { - return True; - } - else - { - return False; - } - } - - if ($this->file_type (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - )) != 'Directory' - ) - { - $this->add_journal (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => VFS_OPERATION_DELETED - ) - ); - - $query = $this->db->delete($this->vfs_table,array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_DELETE)) - ), __LINE__, __FILE__); - - if ($this->file_actions) - { - $rr = unlink ($p->real_full_path); - } - else - { - $rr = True; - } - - return $query || $rr; - } - else - { - $ls = $this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - ) - ); - - /* First, we cycle through the entries and delete the files */ - foreach($ls as $entry) - { - if ($entry['mime_type'] == 'Directory') - { - continue; - } - - $this->rm (array( - 'string' => "$entry[directory]/$entry[name]", - 'relatives' => array ($p->mask) - ) - ); - } - - /* Now we cycle through again and delete the directories */ - foreach ($ls as $entry) - { - if ($entry['mime_type'] != 'Directory') - { - continue; - } - - /* Only the best in confusing recursion */ - $this->rm (array( - 'string' => "$entry[directory]/$entry[name]", - 'relatives' => array ($p->mask) - ) - ); - } - - /* If the directory is linked, we delete the placeholder directory */ - $ls_array = $this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'checksubdirs' => False, - 'mime_type' => False, - 'nofiles' => True - ) - ); - $link_info = $ls_array[0]; - - if ($link_info['link_directory'] && $link_info['link_name']) - { - $path = $this->path_parts (array( - 'string' => $link_info['directory'] . '/' . $link_info['name'], - 'relatives' => array ($p->mask), - 'nolinks' => True - ) - ); - - if ($this->file_actions) - { - rmdir ($path->real_full_path); - } - } - - /* Last, we delete the directory itself */ - $this->add_journal (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operaton' => VFS_OPERATION_DELETED - ) - ); - - $this->db->delete($this->vfs_table,array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_DELETE)) - ), __LINE__, __FILE__); - - if ($this->file_actions) - { - rmdir ($p->real_full_path); - } - - return True; - } - } - - /* - * See vfs_shared - */ - function mkdir ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $account_id = $GLOBALS['egw_info']['user']['account_id']; - $currentapp = $GLOBALS['egw_info']['flags']['currentapp']; - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_ADD) - ) - ) - {//echo "!acl_check('$p->fake_full_path',EGW_ACL_ADD)"; - return False; - } - - /* We don't allow /'s in dir names, of course */ - if (strpos ($p->fake_name,'/') !== false) - { - return False; - } - - umask (077); - - if ($this->file_actions) - { - if (!@is_dir($p->real_leading_dirs)) // eg. /home or /group does not exist - { - if (!@mkdir($p->real_leading_dirs,0770)) // ==> create it - {//echo "!mkdir('$p->real_leading_dirs')"; - return False; - } - } - if (@is_dir($p->real_full_path)) // directory already exists - { - $this->update_real($data,True); // update its contents - } - elseif (!@mkdir ($p->real_full_path, 0770)) - {//echo "!mkdir('$p->real_full_path')"; - return False; - } - } - - if (!$this->file_exists (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) - ) - { - $this->db->insert($this->vfs_table,array( - 'vfs_owner_id' => $this->working_id, - 'vfs_name' => $p->fake_name, - 'vfs_directory' => $p->fake_leading_dirs, - ),false,__LINE__,__FILE__); - - $this->set_attributes(array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => array ( - 'createdby_id' => $account_id, - 'size' => 4096, - 'mime_type' => 'Directory', - 'created' => $this->now, - 'deleteable' => 'Y', - 'app' => $currentapp - ) - ) - ); - - $this->correct_attributes (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - ) - ); - - $this->add_journal (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => VFS_OPERATION_CREATED - ) - ); - } - else - {//echo"!file_exists('$p->fake_full_path');"; - return False; - } - return True; - } - - /* - * See vfs_shared - */ - function make_link ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT, RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $vp = $this->path_parts (array( - 'string' => $data['vdir'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - $rp = $this->path_parts (array( - 'string' => $data['rdir'], - 'relatives' => array ($data['relatives'][1]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask), - 'operation' => EGW_ACL_ADD - )) - ) - { - return False; - } - - if ((!$this->file_exists (array( - 'string' => $rp->real_full_path, - 'relatives' => array ($rp->mask) - ))) - && !mkdir ($rp->real_full_path, 0770)) - { - return False; - } - - if (!$this->mkdir (array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask) - )) - ) - { - return False; - } - - $size = $this->get_size (array( - 'string' => $rp->real_full_path, - 'relatives' => array ($rp->mask) - ) - ); - - $this->set_attributes(array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask), - 'attributes' => array ( - 'link_directory' => $rp->real_leading_dirs, - 'link_name' => $rp->real_name, - 'size' => $size - ) - ) - ); - - $this->correct_attributes (array( - 'string' => $vp->fake_full_path, - 'relatives' => array ($vp->mask) - ) - ); - - return True; - } - - /* - * See vfs_shared - */ - function set_attributes ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'attributes' => array () - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - /* - This is kind of trivial, given that set_attributes () can change owner_id, - size, etc. - */ - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_EDIT - )) - ) - { - return False; - } - - if (!$this->file_exists (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - )) - ) - { - return False; - } - - /* - All this voodoo just decides which attributes to update - depending on if the attribute was supplied in the 'attributes' array - */ - - $ls_array = $this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'checksubdirs' => False, - 'nofiles' => True - ) - ); - $record = $ls_array[0]; - - $to_write = array(); - foreach ($this->attributes as $attribute) - { - if (isset ($data['attributes'][$attribute])) - { - /* - Indicate that the EDITED_COMMENT operation needs to be journaled, - but only if the comment changed - */ - if ($attribute == 'comment' && $data['attributes'][$attribute] != $record[$attribute]) - { - $edited_comment = 1; - } - $to_write[$this->vfs_column_prefix.$attribute] = $data['attributes'][$attribute]; - - if ($this->file_actions) - { - switch($attribute) - { - // if the modification time get's set, we also set it in the filesystem, as - // the next reload reset it again to the modification time of the filesystem - case 'modified': - // we only set it if the file already exists, as otherwise renames of directories fail - if (file_exists($p->real_full_path) && $data['attributes'][$attribute]) - { - touch($p->real_full_path,$data['attributes'][$attribute]); - } - break; - } - } - } - } - - if (!count($to_write)) - { - return True; // nothing to do - } - if (!$this->db->update($this->vfs_table,$to_write,array( - 'vfs_file_id' => $record['file_id'], - $this->extra_sql(array ('query_type' => VFS_SQL_UPDATE)), - ), __LINE__, __FILE__)) - { - return False; - } - if ($edited_comment) - { - $this->add_journal (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => VFS_OPERATION_EDITED_COMMENT - ) - ); - } - return True; - } - - /** - * Set the correct attributes for 'string' (e.g. owner) - * - * @param string File/directory to correct attributes of - * @param relatives Relativity array - * @return Boolean True/False - */ - function correct_attributes ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if ($p->fake_leading_dirs != $this->fakebase && $p->fake_leading_dirs != '/') - { - $ls_array = $this->ls (array( - 'string' => $p->fake_leading_dirs, - 'relatives' => array ($p->mask), - 'checksubdirs' => False, - 'nofiles' => True - ) - ); - $set_attributes_array = Array( - 'owner_id' => $ls_array[0]['owner_id'] - ); - } - elseif (preg_match ("+^$this->fakebase\/(.*)$+U", $p->fake_full_path, $matches)) - { - $set_attributes_array = Array( - 'owner_id' => $GLOBALS['egw']->accounts->name2id ($matches[1]) - ); - } - else - { - $set_attributes_array = Array( - 'owner_id' => 0 - ); - } - - $this->set_attributes (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'attributes' => $set_attributes_array - ) - ); - - return True; - } - - /* - * See vfs_shared - */ - function file_type ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_READ, - 'must_exist' => True - )) - ) - { - return False; - } - - if ($p->outside) - { - if (is_dir ($p->real_full_path)) - { - return ('Directory'); - } - - /* - We don't return an empty string here, because it may still match with a database query - because of linked directories - */ - } - - /* - We don't use ls () because it calls file_type () to determine if it has been - passed a directory - */ - $db2 = clone($this->db); - $db2->select($this->vfs_table,'vfs_mime_type',array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - $db2->next_record (); - $mime_type = $db2->Record['vfs_mime_type']; - if(!$mime_type && ($mime_type = $this->get_ext_mime_type (array ('string' => $data['string'])))) - { - $db2->update($this->vfs_table,array( - 'vfs_mime_type' => $mime_type - ),array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - } - return $mime_type; - } - - /* - * See vfs_shared - */ - function file_exists ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if ($p->outside) - { - $rr = file_exists ($p->real_full_path); - - return $rr; - } - - $db2 = clone($this->db); - $db2->select($this->vfs_table,'vfs_name',array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - - return $db2->next_record (); - } - - /* - * See vfs_shared - */ - function get_size ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'checksubdirs' => True - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (!$this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_READ, - 'must_exist' => True - )) - ) - { - return False; - } - - /* - WIP - this should run through all of the subfiles/directories in the directory and tally up - their sizes. Should modify ls () to be able to return a list for files outside the virtual root - */ - if ($p->outside) - { - $size = filesize ($p->real_full_path); - - return $size; - } - - foreach($this->ls (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'checksubdirs' => $data['checksubdirs'], - 'nofiles' => !$data['checksubdirs'] - )) as $file_array) - { - /* - Make sure the file is in the directory we want, and not - some deeper nested directory with a similar name - */ -/* - if (@!ereg ('^' . $file_array['directory'], $p->fake_full_path)) - { - continue; - } -*/ - - $size += $file_array['size']; - } - - if ($data['checksubdirs']) - { - $this->db->select($this->vfs_table,'vfs_size',array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - $this->db->next_record (); - $size += $this->db->Record[0]; - } - - return $size; - } - - /** - * Check if $this->working_id has write access to create files in $dir - * - * Simple call to acl_check - * @param string Directory to check access of - * @param relatives Relativity array - * @return Boolean True/False - */ - function checkperms ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - return $this->acl_check (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask), - 'operation' => EGW_ACL_ADD - )); - } - - /* - * See vfs_shared - * If $data['readlink'] then a readlink is tryed on the real file - * If $data['file_id'] then the file_id is used instead of a path - */ - function ls ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT), - 'checksubdirs' => True, - 'mime_type' => False, - 'nofiles' => False, - 'orderby' => 'directory' - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - $dir = $p->fake_full_path; - - /* If they pass us a file or 'nofiles' is set, return the info for $dir only */ - if (@$data['file_id'] || ($this->file_type (array( - 'string' => $dir, - 'relatives' => array ($p->mask) - )) != 'Directory' || $data['nofiles']) && !$p->outside) - { - /* SELECT all, the, attributes */ - if (@$data['file_id']) - { - $where = array('vfs_file_id' => $data['file_id']); - } - else - { - $where = array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ); - } - $this->db->select($this->vfs_table,array_keys($this->attributes),$where,__LINE__,__FILE__); - - if (!($record = $this->db->Row(true,$this->vfs_column_prefix))) return array(); - - /* We return an array of one array to maintain the standard */ - $rarray = array (); - foreach($this->attributes as $attribute) - { - if ($attribute == 'mime_type' && !$record[$attribute]) - { - $record[$attribute] = $this->get_ext_mime_type (array( - 'string' => $p->fake_name - ) - ); - - if($record[$attribute]) - { - $this->db->update($this->vfs_table,array( - 'vfs_mime_type' => $record[$attribute] - ),array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - } - } - - $rarray[0][$attribute] = $record[$attribute]; - } - if ($this->file_actions && @$data['readlink']) // test if file is a symlink and get it's target - { - $rarray[0]['symlink'] = @readlink($p->real_full_path); - } - - return $rarray; - } - - //WIP - this should recurse using the same options the virtual part of ls () does - /* If $dir is outside the virutal root, we have to check the file system manually */ - if ($p->outside) - { - if ($this->file_type (array( - 'string' => $p->fake_full_path, - 'relatives' => array ($p->mask) - )) == 'Directory' - && !$data['nofiles'] - ) - { - $dir_handle = opendir ($p->real_full_path); - while (($filename = readdir ($dir_handle))) - { - if ($filename == '.' || $filename == '..') - { - continue; - } - - $rarray[] = $this->get_real_info (array( - 'string' => $p->real_full_path . SEP . $filename, - 'relatives' => array ($p->mask) - ) - ); - } - } - else - { - $rarray[] = $this->get_real_info (array( - 'string' => $p->real_full_path, - 'relatives' => array ($p->mask) - ) - ); - } - - return $rarray; - } - - /* $dir's not a file, is inside the virtual root, and they want to check subdirs */ - /* SELECT all, the, attributes FROM $this->vfs_table WHERE file=$dir */ - $db2 = clone($this->db); - $where = array( - 'vfs_directory LIKE '.$this->db->quote($dir.'%'), - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)), - ); - if ($data['mime_type']) - { - $where['vfs_mime_type'] = $data['mime_type']; - } - $this->db->select($this->vfs_table,array_keys($this->attributes),$where, __LINE__, __FILE__,false, - isset($this->attributes[$this->vfs_column_prefix.$data['orderby']]) ? - 'ORDER BY '.$this->vfs_column_prefix.$data['orderby'] : ''); - - $rarray = array (); - for ($i = 0; ($record = $this->db->Row(true,$this->vfs_column_prefix)); $i++) - { - /* Further checking on the directory. This makes sure /home/user/test won't match /home/user/test22 */ - if (@!ereg ("^$dir(/|$)", $record['directory']) || $record['name'] === '') - { - continue; - } - - /* If they want only this directory, then $dir should end without a trailing / */ - if (!$data['checksubdirs'] && ereg ("^$dir/", $record['directory'])) - { - continue; - } - - foreach($this->attributes as $attribute) - { - if ($attribute == 'mime_type' && !$record[$attribute]) - { - $record[$attribute] = $this->get_ext_mime_type (array( - 'string' => $p->fake_name - ) - ); - - if($record[$attribute]) - { - $db2->update($this->vfs_table,array( - 'vfs_mime_type' => $record[$attribute] - ),array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - } - } - - $rarray[$i][$attribute] = $record[$attribute]; - } - } - - return $rarray; - } - - /* - * See vfs_shared - */ - function update_real ($data,$recursive = False) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (file_exists ($p->real_full_path)) - { - if (is_dir ($p->real_full_path)) - { - $dir_handle = opendir ($p->real_full_path); - while (($filename = readdir ($dir_handle))) - { - if ($filename == '.' || $filename == '..') - { - continue; - } - - $rarray[] = $this->get_real_info (array( - 'string' => $p->fake_full_path . '/' . $filename, - 'relatives' => array (RELATIVE_NONE) - ) - ); - } - } - else - { - $rarray[] = $this->get_real_info (array( - 'string' => $p->fake_full_path, - 'relatives' => array (RELATIVE_NONE) - ) - ); - } - - if (!is_array ($rarray)) - { - $rarray = array (); - } - - foreach($rarray as $file_array) - { - $p2 = $this->path_parts (array( - 'string' => $file_array['directory'] . '/' . $file_array['name'], - 'relatives' => array (RELATIVE_NONE) - ) - ); - - /* Note the mime_type. This can be "Directory", which is how we create directories */ - $set_attributes_array = Array( - 'size' => $file_array['size'], - 'mime_type' => $file_array['mime_type'] - ); - - if (!$this->file_exists (array( - 'string' => $p2->fake_full_path, - 'relatives' => array (RELATIVE_NONE) - )) - ) - { - $this->touch (array( - 'string' => $p2->fake_full_path, - 'relatives' => array (RELATIVE_NONE) - ) - ); - } - $this->set_attributes (array( - 'string' => $p2->fake_full_path, - 'relatives' => array (RELATIVE_NONE), - 'attributes' => $set_attributes_array - ) - ); - if ($recursive && $file_array['mime_type'] == 'Directory') - { - $dir_data = $data; - $dir_data['string'] = $file_array['directory'] . '/' . $file_array['name']; - $this->update_real($dir_data,$recursive); - } - } - } - } - - /* Helper functions */ - - /* This fetchs all available file system information for string (not using the database) */ - function get_real_info ($data) - { - if (!is_array ($data)) - { - $data = array (); - } - - $default_values = array - ( - 'relatives' => array (RELATIVE_CURRENT) - ); - - $data = array_merge ($this->default_values ($data, $default_values), $data); - - $p = $this->path_parts (array( - 'string' => $data['string'], - 'relatives' => array ($data['relatives'][0]) - ) - ); - - if (is_dir ($p->real_full_path)) - { - $mime_type = 'Directory'; - } - else - { - $mime_type = $this->get_ext_mime_type (array( - 'string' => $p->fake_name - ) - ); - if (!$mime_type) - { - $parts = explode('.',$p->fake_name); - $_ext = array_pop($parts); - $mime_type = ExecMethod('phpgwapi.mime_magic.ext2mime',$_ext); - } - if($mime_type) - { - $this->db->update($this->vfs_table,array( - 'vfs_mime_type' => $mime_type - ),array( - 'vfs_directory' => $p->fake_leading_dirs, - 'vfs_name' => $p->fake_name, - $this->extra_sql(array ('query_type' => VFS_SQL_SELECT)) - ), __LINE__, __FILE__); - } - } - - $size = filesize ($p->real_full_path); - $rarray = array( - 'directory' => $p->fake_leading_dirs, - 'name' => $p->fake_name, - 'size' => $size, - 'mime_type' => $mime_type - ); - - return $rarray; - } - } -?>