diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base.php | 3 | ||||
-rw-r--r-- | lib/connector/sabre/directory.php | 6 | ||||
-rw-r--r-- | lib/filecache.php | 574 | ||||
-rw-r--r-- | lib/fileproxy.php | 2 | ||||
-rw-r--r-- | lib/fileproxy/quota.php | 4 | ||||
-rw-r--r-- | lib/files.php | 53 | ||||
-rw-r--r-- | lib/filestorage.php | 4 | ||||
-rw-r--r-- | lib/filestorage/local.php | 99 | ||||
-rw-r--r-- | lib/filestorage/remote.php | 350 | ||||
-rw-r--r-- | lib/filestoragecommon.php | 83 | ||||
-rw-r--r-- | lib/filesystem.php | 418 | ||||
-rw-r--r-- | lib/filesystemview.php | 318 | ||||
-rw-r--r-- | lib/search/provider/file.php | 11 | ||||
-rw-r--r-- | lib/util.php | 8 |
14 files changed, 1127 insertions, 806 deletions
diff --git a/lib/base.php b/lib/base.php index 4da17c70a57..5b8eeb746b1 100644 --- a/lib/base.php +++ b/lib/base.php @@ -216,9 +216,6 @@ class OC{ OC_User::useBackend( OC_Config::getValue( "userbackend", "database" )); OC_Group::setBackend( OC_Config::getValue( "groupbackend", "database" )); - // Was in required file ... put it here - OC_Filesystem::registerStorageType('local','OC_Filestorage_Local',array('datadir'=>'string')); - // Set up file system unless forbidden global $RUNTIME_NOSETUPFS; if(!$RUNTIME_NOSETUPFS ){ diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index 139c6b784b1..bb03851e39d 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -116,11 +116,11 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa * @return array */ public function getQuotaInfo() { - + $rootInfo=OC_FileCache::get(''); return array( - OC_Filesystem::filesize('/'), + $rootInfo['size'], OC_Filesystem::free_space() - ); + ); } diff --git a/lib/filecache.php b/lib/filecache.php new file mode 100644 index 00000000000..964099c7fcd --- /dev/null +++ b/lib/filecache.php @@ -0,0 +1,574 @@ +<?php + +/** +* @author Robin Appelman +* @copyright 2011 Robin Appelman icewind1991@gmail.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * provide caching for filesystem info in the database + * + * not used by OC_Filesystem for reading filesystem info, + * instread apps should use OC_FileCache::get where possible + * + * It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache + */ +class OC_FileCache{ + /** + * get the filesystem info from the cache + * @param string path + * @param string root (optional) + * @return array + * + * returns an assiciative array with the following keys: + * - size + * - mtime + * - ctime + * - mimetype + * - encrypted + * - versioned + */ + public static function get($path,$root=''){ + if(self::isUpdated($path,$root)){ + if(!$root){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); + }else{ + self::fileSystemWatcherWrite(array('path'=>$path),$root); + } + } + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$root.$path; + $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path=?'); + $result=$query->execute(array($path))->fetchRow(); + if(is_array($result)){ + return $result; + }else{ + OC_Log::write('file not found in cache ('.$path.')','core',OC_Log::DEBUG); + return false; + } + } + + /** + * put filesystem info in the cache + * @param string $path + * @param array data + * @param string root (optional) + * + * $data is an assiciative array in the same format as returned by get + */ + public static function put($path,$data,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$root.$path; + if($path=='/'){ + $parent=-1; + }else{ + $parent=self::getFileId(dirname($path)); + } + $id=self::getFileId($path); + if($id!=-1){ + self::update($id,$data); + return; + } + if(!isset($data['encrypted'])){ + $data['encrypted']=false; + } + if(!isset($data['versioned'])){ + $data['versioned']=false; + } + $mimePart=dirname($data['mimetype']); + $user=OC_User::getUser(); + $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, size, mtime, ctime, mimetype, mimepart,user,writable) VALUES(?,?,?,?,?,?,?,?,?,?)'); + $query->execute(array($parent,basename($path),$path,$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'])); + + } + + /** + * update filesystem info of a file + * @param int $id + * @param array $data + */ + private static function update($id,$data){ + $arguments=array(); + $queryParts=array(); + foreach(array('size','mtime','ctime','mimetype','encrypted','versioned','writable') as $attribute){ + if(isset($data[$attribute])){ + $arguments[]=$data[$attribute]; + $queryParts[]=$attribute.'=?'; + } + } + if(isset($data['mimetype'])){ + $arguments[]=dirname($data['mimetype']); + $queryParts[]='mimepart=?'; + } + $arguments[]=$id; + $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET '.implode(' , ',$queryParts).' WHERE id=?'); + $query->execute($arguments); + } + + /** + * register a file move in the cache + * @param string oldPath + * @param string newPath + * @param string root (optional) + */ + public static function move($oldPath,$newPath,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $oldPath=$root.$oldPath; + $newPath=$root.$newPath; + $newParent=self::getParentId($newPath); + $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET parent=? ,name=?, path=? WHERE path=?'); + $query->execute(array($newParent,basename($newPath),$newPath,$oldPath)); + } + + /** + * delete info from the cache + * @param string $path + * @param string root (optional) + */ + public static function delete($path,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$root.$path; + $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path=?'); + $query->execute(array($path)); + } + + /** + * return array of filenames matching the querty + * @param string $query + * @param boolean $returnData + * @param string root (optional) + * @return array of filepaths + */ + public static function search($search,$returnData=false,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $rootLen=strlen($root); + if(!$returnData){ + $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE name LIKE ? AND user=?'); + }else{ + $query=OC_DB::prepare('SELECT * FROM *PREFIX*fscache WHERE name LIKE ? AND user=?'); + } + $result=$query->execute(array("%$search%",OC_User::getUser())); + $names=array(); + while($row=$result->fetchRow()){ + if(!$returnData){ + $names[]=substr($row['path'],$rootLen); + }else{ + $row['path']=substr($row['path'],$rootLen); + $names[]=$row; + } + } + return $names; + } + + /** + * get all files and folders in a folder + * @param string path + * @param string root (optional) + * @return array + * + * returns an array of assiciative arrays with the following keys: + * - name + * - size + * - mtime + * - ctime + * - mimetype + * - encrypted + * - versioned + */ + public static function getFolderContent($path,$root=''){ + if(self::isUpdated($path,$root)){ + self::updateFolder($path,$root); + } + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$root.$path; + $parent=self::getFileId($path); + $query=OC_DB::prepare('SELECT name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=?'); + $result=$query->execute(array($parent))->fetchAll(); + if(is_array($result)){ + return $result; + }else{ + OC_Log::write('file not found in cache ('.$path.')','core',OC_Log::DEBUG); + return false; + } + } + + /** + * check if a file or folder is in the cache + * @param string $path + * @param string root (optional) + * @return bool + */ + public static function inCache($path,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$root.$path; + return self::getFileId($path)!=-1; + } + + /** + * get the file id as used in the cache + * @param string $path + * @return int + */ + private static function getFileId($path){ + $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path=?'); + $result=$query->execute(array($path))->fetchRow(); + if(is_array($result)){ + return $result['id']; + }else{ + OC_Log::write('file not found in cache ('.$path.')','core',OC_Log::DEBUG); + return -1; + } + } + + /** + * get the file id of the parent folder, taking into account '/' has no parent + * @param string $path + * @return int + */ + private static function getParentId($path){ + if($path=='/'){ + return -1; + }else{ + return self::getFileId(dirname($path)); + } + } + + /** + * called when changes are made to files + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherWrite($params,$root=''){ + if(!$root){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView(($root=='/')?'':$root); + } + $path=$params['path']; + $fullPath=$view->getRoot().$path; + $mimetype=$view->getMimeType($path); + //dont use self::get here, we don't want inifinte loops when a file has changed + $cachedSize=self::getCachedSize($path,$root); + $size=0; + if($mimetype=='httpd/unix-directory'){ + if(self::inCache($path,$root)){ + $parent=self::getFileId($fullPath); + $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE parent=?'); + $query->execute(array($parent)); + while($row=$query->fetch()){ + $size+=$row['size']; + } + $mtime=$view->filemtime($path); + $ctime=$view->filectime($path); + $writable=$view->is_writable($path); + self::put($path,array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype,'writable'=>$writable)); + }else{ + $count=0; + self::scan($path,null,$count,$root); + } + }else{ + $size=self::scanFile($path,$root); + } + self::increaseSize(dirname($fullPath),$size-$cachedSize); + } + + private static function getCachedSize($path,$root){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + }else{ + if($root=='/'){ + $root=''; + } + } + $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path=?'); + $query->execute(array($path)); + if($row=$query->fetch()){ + return $row['size']; + }else{//file not in cache + return 0; + } + } + + /** + * called when files are deleted + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherDelete($params,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$params['path']; + $fullPath=$root.$path; + if(self::getFileId($fullPath)==-1){ + return; + } + $size=self::getCachedSize($path,$root); + self::increaseSize(dirname($fullPath),-$size); + self::delete($path); + } + + /** + * called when files are deleted + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherRename($params,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $oldPath=$params['oldpath']; + $newPath=$params['newpath']; + $fullOldPath=$root.$oldPath; + $fullNewPath=$root.$newPath; + if(($id=self::getFileId($fullOldPath))!=-1){ + $oldInfo=self::get($fullOldPath); + $oldSize=$oldInfo['size']; + }else{ + return; + } + $size=OC_Filesystem::filesize($oldPath); + self::increaseSize(dirname($fullOldPath),-$oldSize); + self::increaseSize(dirname($fullNewPath),$oldSize); + self::move($oldPath,$newPath); + } + + /** + * adjust the size of the parent folders + * @param string $path + * @param int $sizeDiff + */ + private static function increaseSize($path,$sizeDiff){ + if($sizeDiff==0) return; + while(($id=self::getFileId($path))!=-1){//walk up the filetree increasing the size of all parent folders + $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET size=size+? WHERE id=?'); + $query->execute(array($sizeDiff,$id)); + $path=dirname($path); + } + } + + /** + * recursively scan the filesystem and fill the cache + * @param string $path + * @param OC_EventSource $enventSource (optional) + * @param int count (optional) + * @param string root (optionak) + */ + public static function scan($path,$eventSource=false,&$count=0,$root=''){ + if(!$root){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView(($root=='/')?'':$root); + } + self::scanFile($path,$root); + $dh=$view->opendir($path); + $totalSize=0; + if($dh){ + while (($filename = readdir($dh)) !== false) { + if($filename != '.' and $filename != '..'){ + $file=$path.'/'.$filename; + if($view->is_dir($file)){ + if($eventSource){ + $eventSource->send('scanning',array('file'=>$file,'count'=>$count)); + } + self::scan($file,$eventSource,$count,$root); + }else{ + $totalSize+=self::scanFile($file,$root); + $count++; + } + } + } + } + self::increaseSize($view->getRoot().$path,$totalSize); + } + + /** + * scan a single file + * @param string path + * @param string root (optional) + * @return int size of the scanned file + */ + public static function scanFile($path,$root=''){ + if(!$root){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView(($root=='/')?'':$root); + } + if(!$view->is_readable($path)) return; //cant read, nothing we can do + $stat=$view->stat($path); + $mimetype=$view->getMimeType($path); + $writable=$view->is_writable($path); + $stat['mimetype']=$mimetype; + $stat['writable']=$writable; + if($path=='/'){ + $path=''; + } + self::put($path,$stat,$root); + return $stat['size']; + } + + /** + * fine files by mimetype + * @param string $part1 + * @param string $part2 (optional) + * @return array of file paths + * + * $part1 and $part2 together form the complete mimetype. + * e.g. searchByMime('text','plain') + * + * seccond mimetype part can be ommited + * e.g. searchByMime('audio') + */ + public static function searchByMime($part1,$part2=''){ + if($part2){ + $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimepart=?'); + $result=$query->execute(array($part1)); + }else{ + $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimetype=?'); + $result=$query->execute(array($part1.'/'.$part2)); + } + $names=array(); + while($row=$result->fetchRow()){ + $names[]=$row['path']; + } + return $names; + } + + /** + * check if a file or folder is updated outside owncloud + * @param string path + * @param string root (optional) + * @return bool + */ + public static function isUpdated($path,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + $view=OC_Filesystem::getView(); + }else{ + if($root=='/'){ + $root=''; + } + $view=new OC_FilesystemView($root); + } + $mtime=$view->filemtime($path); + $isDir=$view->is_dir($path); + $path=$root.$path; + $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path=?'); + $query->execute(array($path)); + if($row=$query->fetch()){ + $cachedMTime=$row['mtime']; + return ($mtime>$cachedMTime); + }else{//file not in cache, so it has to be updated + return !($isDir);//new folders are handeled sperate + } + } + + /** + * update the cache according to changes in the folder + * @param string path + * @param string root (optional) + */ + private static function updateFolder($path,$root=''){ + if(!$root){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView(($root=='/')?'':$root); + } + $dh=$view->opendir($path); + if($dh){//check for changed/new files + while (($filename = readdir($dh)) !== false) { + if($filename != '.' and $filename != '..'){ + $file=$path.'/'.$filename; + if(self::isUpdated($file,$root)){ + if(!$root){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$file)); + }else{ + self::fileSystemWatcherWrite(array('path'=>$file),$root); + } + } + } + } + } + + //check for removed files, not using getFolderContent to prevent loops + $parent=self::getFileId($view->getRoot().$path); + $query=OC_DB::prepare('SELECT name FROM *PREFIX*fscache WHERE parent=?'); + $result=$query->execute(array($parent)); + while($row=$result->fetch()){ + $file=$path.'/'.$row['name']; + if(!$view->file_exists($file)){ + if(!$root){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_delete',array('path'=>$file)); + }else{ + self::fileSystemWatcherDelete(array('path'=>$file),$root); + } + } + } + //update the folder last, so we can calculate the size correctly + if(!$root){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); + }else{ + self::fileSystemWatcherWrite(array('path'=>$path),$root); + } + } +} + +//watch for changes and try to keep the cache up to date +OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache','fileSystemWatcherWrite'); +OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache','fileSystemWatcherDelete'); +OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache','fileSystemWatcherRename'); diff --git a/lib/fileproxy.php b/lib/fileproxy.php index 549b7015a6a..235fc8bf284 100644 --- a/lib/fileproxy.php +++ b/lib/fileproxy.php @@ -34,7 +34,7 @@ * A post-proxy recieves 2 arguments, the filepath and the result of the operation. * The return calue of the post-proxy will be used as the new result of the operation * The operations that have a post-proxy are - * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, is_writable, fileatime, filemtime, filectime, file_get_contents, getMimeType, hash, free_space and search + * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, is_writable, filemtime, filectime, file_get_contents, getMimeType, hash, free_space and search */ class OC_FileProxy{ diff --git a/lib/fileproxy/quota.php b/lib/fileproxy/quota.php index f770c9cb32b..94a49176ee6 100644 --- a/lib/fileproxy/quota.php +++ b/lib/fileproxy/quota.php @@ -27,8 +27,10 @@ class OC_FileProxy_Quota extends OC_FileProxy{ private function getFreeSpace(){ - $usedSpace=OC_Filesystem::filesize(''); + $rootInfo=OC_FileCache::get(''); + $usedSpace=$rootInfo['size']; $totalSpace=OC_Preferences::getValue(OC_User::getUser(),'files','quota',0); + $totalSpace=OC_Helper::computerFileSize($totalSpace); if($totalSpace==0){ return 0; } diff --git a/lib/files.php b/lib/files.php index 9ae5320ad1d..457c8ea38f2 100644 --- a/lib/files.php +++ b/lib/files.php @@ -36,44 +36,13 @@ class OC_Files { if(strpos($directory,OC::$CONFIG_DATADIRECTORY)===0){ $directory=substr($directory,strlen(OC::$CONFIG_DATADIRECTORY)); } - $filesfound=true; - $content=array(); - $dirs=array(); - $file=array(); - $files=array(); - if(OC_Filesystem::is_dir($directory)) { - if ($dh = OC_Filesystem::opendir($directory)) { - while (($filename = readdir($dh)) !== false) { - if($filename<>'.' and $filename<>'..' and substr($filename,0,1)!='.'){ - $file=array(); - $filesfound=true; - $file['name']=$filename; - $file['directory']=$directory; - $stat=OC_Filesystem::stat($directory.'/'.$filename); - $file=array_merge($file,$stat); - $file['size']=OC_Filesystem::filesize($directory.'/'.$filename); - $file['mime']=OC_Files::getMimeType($directory .'/'. $filename); - $file['readable']=OC_Filesystem::is_readable($directory .'/'. $filename); - $file['writeable']=OC_Filesystem::is_writeable($directory .'/'. $filename); - $file['type']=OC_Filesystem::filetype($directory .'/'. $filename); - if($file['type']=='dir'){ - $dirs[$file['name']]=$file; - }else{ - $files[$file['name']]=$file; - } - } - } - closedir($dh); - } - } - uksort($dirs, "strnatcasecmp"); - uksort($files, "strnatcasecmp"); - $content=array_merge($dirs,$files); - if($filesfound){ - return $content; - }else{ - return false; + $files=OC_FileCache::getFolderContent($directory); + foreach($files as &$file){ + $file['directory']=$directory; + $file['type']=($file['mimetype']=='httpd/unix-directory')?'dir':'file'; } + usort($files, "fileCmp");//TODO: remove this once ajax is merged + return $files; } @@ -321,3 +290,13 @@ class OC_Files { return $path; } } + +function fileCmp($a,$b){ + if($a['type']=='dir' and $b['type']!='dir'){ + return -1; + }elseif($a['type']!='dir' and $b['type']=='dir'){ + return 1; + }else{ + return strnatcasecmp($a['name'],$b['name']); + } +} diff --git a/lib/filestorage.php b/lib/filestorage.php index 34fa6457fd2..4523144f6f4 100644 --- a/lib/filestorage.php +++ b/lib/filestorage.php @@ -34,12 +34,11 @@ class OC_Filestorage{ public function filetype($path){} public function filesize($path){} public function is_readable($path){} - public function is_writeable($path){} + public function is_writable($path){} public function file_exists($path){} public function readfile($path){} public function filectime($path){} public function filemtime($path){} - public function fileatime($path){} public function file_get_contents($path){} public function file_put_contents($path,$data){} public function unlink($path){} @@ -48,7 +47,6 @@ class OC_Filestorage{ public function fopen($path,$mode){} public function toTmpFile($path){}//copy the file to a temporary file, used for cross-storage file actions public function fromTmpFile($tmpPath,$path){}//copy a file from a temporary file, used for cross-storage file actions - public function fromUploadedFile($tmpPath,$path){}//copy a file from a temporary file, used for cross-storage file actions public function getMimeType($path){} public function hash($type,$path,$raw){} public function free_space($path){} diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index e846aa420e4..2c1f650cb9f 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -13,13 +13,11 @@ class OC_Filestorage_Local extends OC_Filestorage{ } public function mkdir($path){ if($return=mkdir($this->datadir.$path)){ - $this->clearFolderSizeCache($path); } return $return; } public function rmdir($path){ if($return=rmdir($this->datadir.$path)){ - $this->clearFolderSizeCache($path); } return $return; } @@ -52,7 +50,7 @@ class OC_Filestorage_Local extends OC_Filestorage{ public function is_readable($path){ return is_readable($this->datadir.$path); } - public function is_writeable($path){ + public function is_writable($path){ return is_writable($this->datadir.$path); } public function file_exists($path){ @@ -67,20 +65,15 @@ class OC_Filestorage_Local extends OC_Filestorage{ public function filemtime($path){ return filemtime($this->datadir.$path); } - public function fileatime($path){ - return fileatime($this->datadir.$path); - } public function file_get_contents($path){ return file_get_contents($this->datadir.$path); } public function file_put_contents($path,$data){ if($return=file_put_contents($this->datadir.$path,$data)){ - $this->clearFolderSizeCache($path); } } public function unlink($path){ $return=$this->delTree($path); - $this->clearFolderSizeCache($path); return $return; } public function rename($path1,$path2){ @@ -90,8 +83,6 @@ class OC_Filestorage_Local extends OC_Filestorage{ } if($return=rename($this->datadir.$path1,$this->datadir.$path2)){ - $this->clearFolderSizeCache($path1); - $this->clearFolderSizeCache($path2); } return $return; } @@ -104,7 +95,6 @@ class OC_Filestorage_Local extends OC_Filestorage{ $path2.=$source; } if($return=copy($this->datadir.$path1,$this->datadir.$path2)){ - $this->clearFolderSizeCache($path2); } return $return; } @@ -117,12 +107,10 @@ class OC_Filestorage_Local extends OC_Filestorage{ case 'w+': case 'x+': case 'a+': - $this->clearFolderSizeCache($path); break; case 'w': case 'x': case 'a': - $this->clearFolderSizeCache($path); break; } } @@ -192,18 +180,6 @@ class OC_Filestorage_Local extends OC_Filestorage{ $fileStats = stat($tmpFile); if(rename($tmpFile,$this->datadir.$path)){ touch($this->datadir.$path, $fileStats['mtime'], $fileStats['atime']); - $this->clearFolderSizeCache($path); - return true; - }else{ - return false; - } - } - - public function fromUploadedFile($tmpFile,$path){ - $fileStats = stat($tmpFile); - if(move_uploaded_file($tmpFile,$this->datadir.$path)){ - touch($this->datadir.$path, $fileStats['mtime'], $fileStats['atime']); - $this->clearFolderSizeCache($path); return true; }else{ return false; @@ -219,7 +195,6 @@ class OC_Filestorage_Local extends OC_Filestorage{ if ($item == '.' || $item == '..') continue; if(is_file($dir.'/'.$item)){ if(unlink($dir.'/'.$item)){ - $this->clearFolderSizeCache($dir); } }elseif(is_dir($dir.'/'.$item)){ if (!$this->delTree($dirRelative. "/" . $item)){ @@ -228,7 +203,6 @@ class OC_Filestorage_Local extends OC_Filestorage{ } } if($return=rmdir($dir)){ - $this->clearFolderSizeCache($dir); } return $return; } @@ -268,75 +242,6 @@ class OC_Filestorage_Local extends OC_Filestorage{ * @return int size of folder and it's content */ public function getFolderSize($path){ - $path=str_replace('//','/',$path); - if($this->is_dir($path) and substr($path,-1)!='/'){ - $path.='/'; - } - $query=OC_DB::prepare("SELECT size FROM *PREFIX*foldersize WHERE path=?"); - $size=$query->execute(array($path))->fetchAll(); - if(count($size)>0){// we already the size, just return it - return $size[0]['size']; - }else{//the size of the folder isn't know, calulate it - return $this->calculateFolderSize($path); - } - } - - /** - * @brief calulate the size of folder and it's content and cache it - * @param string $path file path - * @return int size of folder and it's content - */ - public function calculateFolderSize($path){ - if($this->is_file($path)){ - $path=dirname($path); - } - $path=str_replace('//','/',$path); - if($this->is_dir($path) and substr($path,-1)!='/'){ - $path.='/'; - } - $size=0; - if ($dh = $this->opendir($path)) { - while (($filename = readdir($dh)) !== false) { - if($filename!='.' and $filename!='..'){ - $subFile=$path.'/'.$filename; - if($this->is_file($subFile)){ - $size+=$this->filesize($subFile); - }else{ - $size+=$this->getFolderSize($subFile); - } - } - } - if($size>0){ - $query=OC_DB::prepare("INSERT INTO *PREFIX*foldersize VALUES(?,?)"); - $result=$query->execute(array($path,$size)); - } - } - return $size; - } - - /** - * @brief clear the folder size cache of folders containing a file - * @param string $path - */ - public function clearFolderSizeCache($path){ - if($this->is_file($path)){ - $path=dirname($path); - } - $path=str_replace('//','/',$path); - if($this->is_dir($path) and substr($path,-1)!='/'){ - $path.='/'; - } - $query=OC_DB::prepare("DELETE FROM *PREFIX*foldersize WHERE path = ?"); - $result=$query->execute(array($path)); - if($path!='/' and $path!=''){ - $parts=explode('/',$path); - //pop empty part - $part=array_pop($parts); - if(empty($part)){ - array_pop($parts); - } - $parent=implode('/',$parts); - $this->clearFolderSizeCache($parent); - } + return 0;//depricated, use OC_FileCach instead } } diff --git a/lib/filestorage/remote.php b/lib/filestorage/remote.php deleted file mode 100644 index 88bdbca481c..00000000000 --- a/lib/filestorage/remote.php +++ /dev/null @@ -1,350 +0,0 @@ -<?php - -/** -* ownCloud -* -* @author Frank Karlitschek -* @copyright 2010 Frank Karlitschek karlitschek@kde.org -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 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 AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Affero General Public -* License along with this library. If not, see <http://www.gnu.org/licenses/>. -* -*/ - -class OC_Filestorage_Remote extends OC_Filestorage{ - private $url; - private $username; - private $password; - private $remote=false; - private $statCache; - private $statCacheDir=false; - private $changed=array(); - - private function cacheDir($dir){ - if($this->statCacheDir!=$dir or $this->statCacheDir===false){ - $this->statCache=$this->remote->getFiles($dir); - $keys=array_keys($this->statCache); - $this->statCacheDir=$dir; - } - } - - public function __construct($arguments){ - $this->url=$arguments['url']; - $this->username=$arguments['username']; - $this->password=$arguments['password']; - } - private function connect(){ - if($this->remote===false){ - $this->remote=OC_Connect::connect($this->url,$this->username,$this->password); - } - } - public function mkdir($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $return=$this->remote->newFile($parent,$name,'dir'); - if($return){ - $this->notifyObservers($path,OC_FILEACTION_CREATE); - } - return $return; - } - public function rmdir($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $return=$this->remote->delete($parent,$name); - if($return){ - $this->notifyObservers($path,OC_FILEACTION_DELETE); - } - return $return; - } - public function opendir($path){ - $this->connect(); - $this->cacheDir($path); - $dirs=array_keys($this->statCache); - $id=uniqid(); - global $FAKEDIRS; - $FAKEDIRS[$id]=$dirs; - if($return=opendir("fakedir://$id")){ - $this->notifyObservers($path,OC_FILEACTION_READ); - } - return $return; - } - public function is_dir($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($path); - if($path=='' or $path=='/'){ - return true; - } - if(!isset($this->statCache[$name])){ - return false; - } - return ($this->statCache[$name]['type'=='dir']); - } - public function is_file($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return ($this->statCache[$name]['type'!='dir']); - } - public function stat($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return $false; - } - return $this->statCache[$name]; - } - public function filetype($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return $this->statCache[$name]['type']; - } - public function filesize($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return $false; - } - return $this->statCache[$name]['size']; - } - public function is_readable($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return $this->statCache[$name]['readable']; - } - public function is_writeable($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return $this->statCache[$name]['writeable']; - } - public function file_exists($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - return isset($this->statCache[$name]); - } - public function readfile($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $file=$this->remote->getFile($parent,$name); - readfile($file); - unlink($file); - } - public function filectime($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return $this->statCache[$name]['ctime']; - } - public function filemtime($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return $this->statCache[$name]['mtime']; - } - public function fileatime($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return $this->statCache[$name]['atime']; - } - public function file_get_contents($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $file=$this->remote->getFile($parent,$name); - file_get_contents($file); - unlink($file); - } - public function file_put_contents($path,$data){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $file=$this->remote->getFile($parent,$name); - $file=tempnam(get_temp_dir(),'oc_'); - file_put_contents($file,$data); - if($return=$this->remote->sendTmpFile($file,$parent,$name)){ - $this->notifyObservers($path,OC_FILEACTION_WRITE); - } - } - public function unlink($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - if($return=$this->remote->delete($paren,$name)){ - $this->notifyObservers($path,OC_FILEACTION_DELETE); - } - return $return; - } - public function rename($path1,$path2){ - $this->connect(); - $parent1=dirname($path1); - $name1=substr($path1,strlen($parent1)+1); - $parent2=dirname($path2); - $name2=substr($path2,strlen($parent2)+1); - if($return=$this->remote->move($parent1,$name1,$parent2,$name2)){ - $this->notifyObservers($path1.'->'.$path2,OC_FILEACTION_RENAME); - } - return $return; - } - public function copy($path1,$path2){ - $this->connect(); - $parent1=dirname($path1); - $name1=substr($path1,strlen($parent1)+1); - $parent2=dirname($path2); - $name2=substr($path2,strlen($parent2)+1); - if($return=$this->copy->rename($parent1,$name1,$parent2,$name2)){ - $this->notifyObservers($path1.'->'.$path2,OC_FILEACTION_RENAME); - } - return $return; - } - public function fopen($path,$mode){ - $this->connect(); - $changed=false; - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - $file=$this->remote->getFile($parent,$name); - if($return=fopen($file,$mode)){ - switch($mode){ - case 'r': - $this->notifyObservers($path,OC_FILEACTION_READ); - break; - case 'r+': - case 'w+': - case 'x+': - case 'a+': - $this->notifyObservers($path,OC_FILEACTION_READ | OC_FILEACTION_WRITE); - $this->changed[]=array('dir'=>$parent,'file'=>$name,'tmp'=>$file); - break; - case 'w': - case 'x': - case 'a': - $this->notifyObservers($path,OC_FILEACTION_WRITE); - $this->changed[]=array('dir'=>$parent,'file'=>$name,'tmp'=>$file); - break; - } - } - return $return; - } - - public function getMimeType($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - if(substr($name,0,1)=='/'){ - $name=substr($name,1); - } - $this->cacheDir($parent); - if(!isset($this->statCache[$name])){ - return false; - } - return $this->statCache[$name]['mime']; - } - - public function toTmpFile($path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - if(substr($name,0,1)=='/'){ - $name=substr($name,1); - } - $filename=$this->remote->getFile($parent,$name); - if($filename){ - $this->notifyObservers($path,OC_FILEACTION_READ); - return $filename; - }else{ - return false; - } - } - - public function fromTmpFile($tmpFile,$path){ - $this->connect(); - $parent=dirname($path); - $name=substr($path,strlen($parent)+1); - if($this->remote->sendTmpFile($tmpFile,$parent,$name)){ - $this->notifyObservers($path,OC_FILEACTION_CREATE); - return true; - }else{ - return false; - } - } - - public function delTree($dir) { - $this->connect(); - $parent=dirname($dir); - $name=substr($dir,strlen($parent)+1); - $return=$this->remote->delete($parent,$name); - if($return=rmdir($dir)){ - $this->notifyObservers($dir,OC_FILEACTION_DELETE); - } - return $return; - } - - public function find($path){ - return $this->getTree($path); - } - - public function getTree($dir) { - $this->connect(); - if($return=$this->remote->getTree($dir)){ - $this->notifyObservers($dir,OC_FILEACTION_READ); - } - return $return; - } - - public function __destruct(){ - foreach($this->changed as $changed){ - $this->remote->sendTmpFile($changed['tmp'],$changed['dir'],$changed['file']); - } - } -} diff --git a/lib/filestoragecommon.php b/lib/filestoragecommon.php new file mode 100644 index 00000000000..f522d15c4e9 --- /dev/null +++ b/lib/filestoragecommon.php @@ -0,0 +1,83 @@ +<?php + +/** +* ownCloud +* +* @author Michael Gapczynski +* @copyright 2012 Michael Gapczynski GapczynskiM@gmail.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + +class OC_Filestorage_Common extends OC_Filestorage { + + public function __construct($parameters){} + public function mkdir($path){} + public function rmdir($path){} + public function opendir($path){} + public function is_dir($path){} + public function is_file($path){} + public function stat($path){} + public function filetype($path){} + public function filesize($path) { + $stat = $this->stat($path); + return $stat['size']; + } + public function is_readable($path){} + public function is_writable($path){} + public function file_exists($path){} + public function readfile($path) { + $handle = $this->fopen($path, "r"); + $chunk = 1024; + while (!feof($handle)) { + echo fread($handle, $chunk); + } + return $this->filesize($path); + } + public function filectime($path) { + $stat = $this->stat($path); + return $stat['ctime']; + } + public function filemtime($path) { + $stat = $this->stat($path); + return $stat['mtime']; + } + public function fileatime($path) { + $stat = $this->stat($path); + return $stat['atime']; + } + public function file_get_contents($path) { + $handle = $this->fopen($path, "r"); + return fread($handle, $this->filesize($path)); + } + public function file_put_contents($path,$data) { + $handle = $this->fopen($path, "w"); + return fwrite($handle, $data); + } + public function unlink($path){} + public function rename($path1,$path2){} + public function copy($path1,$path2) { + $data = $this->file_get_contents($path1); + return $this->file_put_contents($path2, $data); + } + public function fopen($path,$mode){} + public function toTmpFile($path){} + public function fromTmpFile($tmpPath,$path){} + public function fromUploadedFile($tmpPath,$path){} + public function getMimeType($path){} + public function hash($type,$path,$raw){} + public function free_space($path){} + public function search($query){} + public function getLocalFile($path){} +} diff --git a/lib/filesystem.php b/lib/filesystem.php index bd953deb210..a18072ecbc2 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -42,11 +42,15 @@ * * the &run parameter can be set to false to prevent the operation from occuring */ + class OC_Filesystem{ static private $storages=array(); static private $mounts=array(); - static private $fakeRoot=''; static private $storageTypes=array(); + public static $loaded=false; + private $fakeRoot=''; + static private $defaultInstance; + /** * classname which used for hooks handling @@ -134,31 +138,78 @@ class OC_Filesystem{ */ const signal_param_run = 'run'; - /** - * register a storage type - * @param string type - * @param string classname - * @param array arguments an associative array in the form of name=>type (eg array('datadir'=>'string')) + /** + * get the mountpoint of the storage object for a path + ( note: because a storage is not always mounted inside the fakeroot, the returned mountpoint is relative to the absolute root of the filesystem and doesn't take the chroot into account + * + * @param string path + * @return string */ - static public function registerStorageType($type,$classname,$arguments){ - self::$storageTypes[$type]=array('type'=>$type,'classname'=>$classname,'arguments'=>$arguments); + static public function getMountPoint($path){ + if(!$path){ + $path='/'; + } + if(substr($path,0,1)!=='/'){ + $path='/'.$path; + } + if(substr($path,-1)!=='/'){ + $path=$path.'/'; + } + $foundMountPoint=''; + foreach(OC_Filesystem::$mounts as $mountpoint=>$storage){ + if(substr($mountpoint,-1)!=='/'){ + $mountpoint=$mountpoint.'/'; + } + if($mountpoint==$path){ + return $mountpoint; + } + if(strpos($path,$mountpoint)===0 and strlen($mountpoint)>strlen($foundMountPoint)){ + $foundMountPoint=$mountpoint; + } + } + return $foundMountPoint; } - + /** - * check if the filesystem supports a specific storagetype - * @param string type + * get the part of the path relative to the mountpoint of the storage it's stored in + * @param string path * @return bool */ - static public function hasStorageType($type){ - return isset(self::$storageTypes[$type]); + static public function getInternalPath($path){ + $mountPoint=self::getMountPoint($path); + $internalPath=substr($path,strlen($mountPoint)); + return $internalPath; } - /** - * get the list of names of storagetypes that the filesystem supports - * @return array + * get the storage object for a path + * @param string path + * @return OC_Filestorage */ - static public function getStorageTypeNames(){ - return array_keys(self::$storageTypes); + static public function getStorage($path){ + $mountpoint=self::getMountPoint($path); + if($mountpoint){ + if(!isset(OC_Filesystem::$storages[$mountpoint])){ + $mount=OC_Filesystem::$mounts[$mountpoint]; + OC_Filesystem::$storages[$mountpoint]=OC_Filesystem::createStorage($mount['class'],$mount['arguments']); + } + return OC_Filesystem::$storages[$mountpoint]; + } + } + + static public function init($root){ + if(self::$defaultInstance){ + return false; + } + self::$defaultInstance=new OC_FilesystemView($root); + self::$loaded=true; + } + + /** + * get the default filesystem view + * @return OC_FilesystemView + */ + static public function getView(){ + return self::$defaultInstance; } /** @@ -177,13 +228,9 @@ class OC_Filesystem{ * @param array arguments * @return OC_Filestorage */ - static private function createStorage($type,$arguments){ - if(!self::hasStorageType($type)){ - return false; - } - $className=self::$storageTypes[$type]['classname']; - if(class_exists($className)){ - return new $className($arguments); + static private function createStorage($class,$arguments){ + if(class_exists($class)){ + return new $class($arguments); }else{ return false; } @@ -195,36 +242,27 @@ class OC_Filesystem{ * @return bool */ static public function chroot($fakeRoot){ - if(!$fakeRoot==''){ - if($fakeRoot[0]!=='/'){ - $fakeRoot='/'.$fakeRoot; - } - } - self::$fakeRoot=$fakeRoot; + return self::$defaultInstance->chroot($path); } - + /** - * get the part of the path relative to the mountpoint of the storage it's stored in - * @param string path - * @return bool - */ - static public function getInternalPath($path){ - $mountPoint=self::getMountPoint($path); - $path=self::$fakeRoot.$path; - $internalPath=substr($path,strlen($mountPoint)); - return $internalPath; + * get the fake root + * @return string + */ + static public function getRoot(){ + return self::$defaultInstance->getRoot(); } - + /** * mount an OC_Filestorage in our virtual filesystem * @param OC_Filestorage storage * @param string mountpoint */ - static public function mount($type,$arguments,$mountpoint){ + static public function mount($class,$arguments,$mountpoint){ if(substr($mountpoint,0,1)!=='/'){ $mountpoint='/'.$mountpoint; } - self::$mounts[$mountpoint]=array('type'=>$type,'arguments'=>$arguments); + self::$mounts[$mountpoint]=array('class'=>$class,'arguments'=>$arguments); } /** @@ -239,65 +277,13 @@ class OC_Filesystem{ } /** - * get the storage object for a path - * @param string path - * @return OC_Filestorage - */ - static public function getStorage($path){ - $mountpoint=self::getMountPoint($path); - if($mountpoint){ - if(!isset(self::$storages[$mountpoint])){ - $mount=self::$mounts[$mountpoint]; - self::$storages[$mountpoint]=self::createStorage($mount['type'],$mount['arguments']); - } - return self::$storages[$mountpoint]; - } - } - - /** - * get the mountpoint of the storage object for a path - ( note: because a storage is not always mounted inside the fakeroot, the returned mountpoint is relative to the absolute root of the filesystem and doesn't take the chroot into account - * - * @param string path - * @return string - */ - static public function getMountPoint($path){ - if(!$path){ - $path='/'; - } - if(substr($path,0,1)!=='/'){ - $path='/'.$path; - } - if(substr($path,-1)!=='/'){ - $path=$path.'/'; - } - $path=self::$fakeRoot.$path; - $foundMountPoint=''; - foreach(self::$mounts as $mountpoint=>$storage){ - if(substr($mountpoint,-1)!=='/'){ - $mountpoint=$mountpoint.'/'; - } - if($mountpoint==$path){ - return $mountpoint; - } - if(strpos($path,$mountpoint)===0 and strlen($mountpoint)>strlen($foundMountPoint)){ - $foundMountPoint=$mountpoint; - } - } - return $foundMountPoint; - } - - /** * return the path to a local version of the file * we need this because we can't know if a file is stored local or not from outside the filestorage and for some purposes a local file is needed * @param string path * @return string */ static public function getLocalFile($path){ - $parent=substr($path,0,strrpos($path,'/')); - if(self::isValidPath($parent) and $storage=self::getStorage($path)){ - return $storage->getLocalFile(self::getInternalPath($path)); - } + return self::$defaultInstance->getLocalFile($path); } /** @@ -314,262 +300,90 @@ class OC_Filesystem{ } return true; } - + /** + * following functions are equivilent to their php buildin equivilents for arguments/return values. + */ static public function mkdir($path){ - return self::basicOperation('mkdir',$path,array('create','write')); + return self::$defaultInstance->mkdir($path); } static public function rmdir($path){ - return self::basicOperation('rmdir',$path,array('delete')); + return self::$defaultInstance->rmdir($path); } static public function opendir($path){ - return self::basicOperation('opendir',$path,array('read')); + return self::$defaultInstance->opendir($path); } static public function is_dir($path){ - if($path=='/'){ - return true; - } - return self::basicOperation('is_dir',$path); + return self::$defaultInstance->is_dir($path); } static public function is_file($path){ - if($path=='/'){ - return false; - } - return self::basicOperation('is_file',$path); + return self::$defaultInstance->is_file($path); } static public function stat($path){ - return self::basicOperation('stat',$path); + return self::$defaultInstance->stat($path); } static public function filetype($path){ - return self::basicOperation('filetype',$path); + return self::$defaultInstance->filetype($path); } static public function filesize($path){ - return self::basicOperation('filesize',$path); + return self::$defaultInstance->filesize($path); } static public function readfile($path){ - return self::basicOperation('readfile',$path,array('read')); + return self::$defaultInstance->readfile($path); } static public function is_readable($path){ - return self::basicOperation('is_readable',$path); + return self::$defaultInstance->is_readable($path); } - static public function is_writeable($path){ - return self::basicOperation('is_writeable',$path); + static public function is_writable($path){ + return self::$defaultInstance->is_writable($path); } static public function file_exists($path){ - if($path=='/'){ - return true; - } - return self::basicOperation('file_exists',$path); + return self::$defaultInstance->file_exists($path); } static public function filectime($path){ - return self::basicOperation('filectime',$path); + return self::$defaultInstance->filectime($path); } static public function filemtime($path){ - return self::basicOperation('filemtime',$path); - } - static public function fileatime($path){ - return self::basicOperation('fileatime',$path); + return self::$defaultInstance->filemtime($path); } static public function file_get_contents($path){ - return self::basicOperation('file_get_contents',$path,array('read')); + return self::$defaultInstance->file_get_contents($path); } static public function file_put_contents($path,$data){ - return self::basicOperation('file_put_contents',$path,array('create','write'),$data); + return self::$defaultInstance->file_put_contents($path,$data); } static public function unlink($path){ - return self::basicOperation('unlink',$path,array('delete')); + return self::$defaultInstance->unlink($path); } static public function rename($path1,$path2){ - if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and self::is_writeable($path1) and self::isValidPath($path2)){ - $run=true; - OC_Hook::emit( self::CLASSNAME, self::signal_rename, array( self::signal_param_oldpath => $path1 , self::signal_param_newpath=>$path2, self::signal_param_run => &$run)); - if($run){ - $mp1=self::getMountPoint($path1); - $mp2=self::getMountPoint($path2); - if($mp1==$mp2){ - if($storage=self::getStorage($path1)){ - $result=$storage->rename(self::getInternalPath($path1),self::getInternalPath($path2)); - } - }elseif($storage1=self::getStorage($path1) and $storage2=self::getStorage($path2)){ - $tmpFile=$storage1->toTmpFile(self::getInternalPath($path1)); - $result=$storage2->fromTmpFile($tmpFile,self::getInternalPath($path2)); - $storage1->unlink(self::getInternalPath($path1)); - } - OC_Hook::emit( self::CLASSNAME, self::signal_post_rename, array( self::signal_param_oldpath => $path1, self::signal_param_newpath=>$path2)); - return $result; - } - } + return self::$defaultInstance->rename($path1,$path2); } static public function copy($path1,$path2){ - if(OC_FileProxy::runPreProxies('copy',$path1,$path2) and self::is_readable($path1) and self::isValidPath($path2)){ - $run=true; - OC_Hook::emit( self::CLASSNAME, self::signal_copy, array( self::signal_param_oldpath => $path1 , self::signal_param_newpath=>$path2, self::signal_param_run => &$run)); - $exists=self::file_exists($path2); - if($run and !$exists){ - OC_Hook::emit( self::CLASSNAME, self::signal_create, array( self::signal_param_path => $path2, self::signal_param_run => &$run)); - } - if($run){ - OC_Hook::emit( self::CLASSNAME, self::signal_write, array( self::signal_param_path => $path2, self::signal_param_run => &$run)); - } - if($run){ - $mp1=self::getMountPoint($path1); - $mp2=self::getMountPoint($path2); - if($mp1==$mp2){ - if($storage=self::getStorage($path1)){ - $result=$storage->copy(self::getInternalPath($path1),self::getInternalPath($path2)); - } - }elseif($storage1=self::getStorage($path1) and $storage2=self::getStorage($path2)){ - $tmpFile=$storage1->toTmpFile(self::getInternalPath($path1)); - $result=$storage2->fromTmpFile($tmpFile,self::getInternalPath($path2)); - } - OC_Hook::emit( self::CLASSNAME, self::signal_post_copy, array( self::signal_param_oldpath => $path1 , self::signal_param_newpath=>$path2)); - if(!$exists){ - OC_Hook::emit( self::CLASSNAME, self::signal_post_create, array( self::signal_param_path => $path2)); - } - OC_Hook::emit( self::CLASSNAME, self::signal_post_write, array( self::signal_param_path => $path2)); - return $result; - } - } + return self::$defaultInstance->copy($path1,$path2); } static public function fopen($path,$mode){ - $hooks=array(); - switch($mode){ - case 'r': - $hooks[]='read'; - break; - case 'r+': - case 'w+': - case 'x+': - case 'a+': - $hooks[]='read'; - $hooks[]='write'; - break; - case 'w': - case 'x': - case 'a': - $hooks[]='write'; - break; - default: - OC_Log::write('core','invalid mode ('.$mode.') for '.$path,OC_Log::ERROR); - } - - return self::basicOperation('fopen',$path,$hooks,$mode); + return self::$defaultInstance->fopen($path,$mode); } static public function toTmpFile($path){ - if(OC_FileProxy::runPreProxies('toTmpFile',$path) and self::isValidPath($path) and $storage=self::getStorage($path)){ - OC_Hook::emit( self::CLASSNAME, self::signal_read, array( self::signal_param_path => $path)); - return $storage->toTmpFile(self::getInternalPath($path)); - } + return self::$defaultInstance->toTmpFile($path); } static public function fromTmpFile($tmpFile,$path){ - if(OC_FileProxy::runPreProxies('copy',$tmpFile,$path) and self::isValidPath($path) and $storage=self::getStorage($path)){ - $run=true; - $exists=self::file_exists($path); - if(!$exists){ - OC_Hook::emit( self::CLASSNAME, self::signal_create, array( self::signal_param_path => $path, self::signal_param_run => &$run)); - } - if($run){ - OC_Hook::emit( self::CLASSNAME, self::signal_write, array( self::signal_param_path => $path, self::signal_param_run => &$run)); - } - if($run){ - $result=$storage->fromTmpFile($tmpFile,self::getInternalPath($path)); - if(!$exists){ - OC_Hook::emit( self::CLASSNAME, self::signal_post_create, array( self::signal_param_path => $path)); - } - OC_Hook::emit( self::CLASSNAME, self::signal_post_write, array( self::signal_param_path => $path)); - return $result; - } - } - } - static public function fromUploadedFile($tmpFile,$path){ - if(OC_FileProxy::runPreProxies('fromUploadedFile',$tmpFile,$path) and self::isValidPath($path) and $storage=self::getStorage($path)){ - $run=true; - $exists=self::file_exists($path); - if(!$exists){ - OC_Hook::emit( self::CLASSNAME, self::signal_create, array( self::signal_param_path => $path, self::signal_param_run => &$run)); - } - if($run){ - OC_Hook::emit( self::CLASSNAME, self::signal_write, array( self::signal_param_path => $path, self::signal_param_run => &$run)); - } - if($run){ - $result=$storage->fromUploadedFile($tmpFile,self::getInternalPath($path)); - if(!$exists){ - OC_Hook::emit( self::CLASSNAME, self::signal_post_create, array( self::signal_param_path => $path)); - } - OC_Hook::emit( self::CLASSNAME, self::signal_post_write, array( self::signal_param_path => $path)); - return $result; - } - } + return self::$defaultInstance->fromTmpFile($tmpFile,$path); } + static public function getMimeType($path){ - return self::basicOperation('getMimeType',$path); + return self::$defaultInstance->getMimeType($path); } static public function hash($type,$path){ - return self::basicOperation('hash',$path,array('read')); + return self::$defaultInstance->hash($type,$path); } static public function free_space($path='/'){ - return self::basicOperation('free_space',$path); + return self::$defaultInstance->free_space($path); } static public function search($query){ - self::mountAll(); - $files=array(); - $fakeRoot=self::$fakeRoot; - $fakeRootLength=strlen($fakeRoot); - foreach(self::$storages as $mountpoint=>$storage){ - $results=$storage->search($query); - if(is_array($results)){ - foreach($results as $result){ - $file=str_replace('//','/',$mountpoint.$result); - if(substr($file,0,$fakeRootLength)==$fakeRoot){ - $file=substr($file,$fakeRootLength); - $files[]=$file; - } - } - } - } - return $files; - - } - - static public function update_session_file_hash($sessionname,$sessionvalue){ - $_SESSION[$sessionname] = $sessionvalue; - } - - /** - * abstraction for running most basic operations - * @param string $operation - * @param string #path - * @param array (optional) hooks - * @param mixed (optional) $extraParam - * @return mixed - */ - private static function basicOperation($operation,$path,$hooks=array(),$extraParam=null){ - if(OC_FileProxy::runPreProxies($operation,$path, $extraParam) and self::isValidPath($path) and $storage=self::getStorage($path)){ - $interalPath=self::getInternalPath($path); - $run=true; - foreach($hooks as $hook){ - if($hook!='read'){ - OC_Hook::emit( self::CLASSNAME, $hook, array( self::signal_param_path => $path, self::signal_param_run => &$run)); - }else{ - OC_Hook::emit( self::CLASSNAME, $hook, array( self::signal_param_path => $path)); - } - } - if($run){ - if($extraParam){ - $result=$storage->$operation($interalPath,$extraParam); - }else{ - $result=$storage->$operation($interalPath); - } - $result=OC_FileProxy::runPostProxies($operation,$path,$result); - foreach($hooks as $hook){ - if($hook!='read'){ - OC_Hook::emit( self::CLASSNAME, 'post_'.$hook, array( self::signal_param_path => $path)); - } - } - return $result; - } - } - return null; + return OC_FileCache::search($query); } } + +require_once('filecache.php'); diff --git a/lib/filesystemview.php b/lib/filesystemview.php new file mode 100644 index 00000000000..4586507a811 --- /dev/null +++ b/lib/filesystemview.php @@ -0,0 +1,318 @@ +<?php + +/** +* ownCloud +* +* @author Frank Karlitschek +* @copyright 2010 Frank Karlitschek karlitschek@kde.org +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 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 AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* +*/ + +class OC_FilesystemView { + private $fakeRoot=''; + + public function __construct($root){ + $this->fakeRoot=$root; + } + + public function getAbsolutePath($path){ + if(!$path){ + $path='/'; + } + if(substr($path,0,1)!=='/'){ + $path='/'.$path; + } + return $this->fakeRoot.$path; + } + + + /** + * change the root to a fake toor + * @param string fakeRoot + * @return bool + */ + public function chroot($fakeRoot){ + if(!$fakeRoot==''){ + if($fakeRoot[0]!=='/'){ + $fakeRoot='/'.$fakeRoot; + } + } + $this->fakeRoot=$fakeRoot; + } + + /** + * get the fake root + * @return string + */ + public function getRoot(){ + return $this->fakeRoot; + } + + /** + * get the part of the path relative to the mountpoint of the storage it's stored in + * @param string path + * @return bool + */ + public function getInternalPath($path){ + return OC_Filesystem::getInternalPath($this->getAbsolutePath($path)); + } + /** + * get the storage object for a path + * @param string path + * @return OC_Filestorage + */ + public function getStorage($path){ + return OC_Filesystem::getStorage($this->getAbsolutePath($path)); + } + + /** + * get the mountpoint of the storage object for a path + ( note: because a storage is not always mounted inside the fakeroot, the returned mountpoint is relative to the absolute root of the filesystem and doesn't take the chroot into account + * + * @param string path + * @return string + */ + public function getMountPoint($path){ + return OC_Filesystem::getMountPoint($this->getAbsolutePath($path)); + } + + /** + * return the path to a local version of the file + * we need this because we can't know if a file is stored local or not from outside the filestorage and for some purposes a local file is needed + * @param string path + * @return string + */ + public function getLocalFile($path){ + $parent=substr($path,0,strrpos($path,'/')); + if(OC_Filesystem::isValidPath($parent) and $storage=$this->getStorage($path)){ + return $storage->getLocalFile($this->getInternalPath($path)); + } + } + + /** + * following functions are equivilent to their php buildin equivilents for arguments/return values. + */ + public function mkdir($path){ + return $this->basicOperation('mkdir',$path,array('create','write')); + } + public function rmdir($path){ + return $this->basicOperation('rmdir',$path,array('delete')); + } + public function opendir($path){ + return $this->basicOperation('opendir',$path,array('read')); + } + public function is_dir($path){ + if($path=='/'){ + return true; + } + return $this->basicOperation('is_dir',$path); + } + public function is_file($path){ + if($path=='/'){ + return false; + } + return $this->basicOperation('is_file',$path); + } + public function stat($path){ + return $this->basicOperation('stat',$path); + } + public function filetype($path){ + return $this->basicOperation('filetype',$path); + } + public function filesize($path){ + return $this->basicOperation('filesize',$path); + } + public function readfile($path){ + return $this->basicOperation('readfile',$path,array('read')); + } + public function is_readable($path){ + return $this->basicOperation('is_readable',$path); + } + public function is_writable($path){ + return $this->basicOperation('is_writable',$path); + } + public function file_exists($path){ + if($path=='/'){ + return true; + } + return $this->basicOperation('file_exists',$path); + } + public function filectime($path){ + return $this->basicOperation('filectime',$path); + } + public function filemtime($path){ + return $this->basicOperation('filemtime',$path); + } + public function file_get_contents($path){ + return $this->basicOperation('file_get_contents',$path,array('read')); + } + public function file_put_contents($path,$data){ + return $this->basicOperation('file_put_contents',$path,array('create','write'),$data); + } + public function unlink($path){ + return $this->basicOperation('unlink',$path,array('delete')); + } + public function rename($path1,$path2){ + if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and $this->is_writable($path1) and OC_Filesystem::isValidPath($path2)){ + $run=true; + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2, OC_Filesystem::signal_param_run => &$run)); + if($run){ + $mp1=$this->getMountPoint($path1); + $mp2=$this->getMountPoint($path2); + if($mp1==$mp2){ + if($storage=$this->getStorage($path1)){ + $result=$storage->rename($this->getInternalPath($path1),$this->getInternalPath($path2)); + } + }elseif($storage1=$this->getStorage($path1) and $storage2=$this->getStorage($path2)){ + $tmpFile=$storage1->toTmpFile($this->getInternalPath($path1)); + $result=$storage2->fromTmpFile($tmpFile,$this->getInternalPath($path2)); + $storage1->unlink($this->getInternalPath($path1)); + } + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, array( OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath=>$path2)); + return $result; + } + } + } + public function copy($path1,$path2){ + if(OC_FileProxy::runPreProxies('copy',$path1,$path2) and $this->is_readable($path1) and OC_Filesystem::isValidPath($path2)){ + $run=true; + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_copy, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2, OC_Filesystem::signal_param_run => &$run)); + $exists=$this->file_exists($path2); + if($run and !$exists){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array( OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run)); + } + if($run){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array( OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run)); + } + if($run){ + $mp1=$this->getMountPoint($path1); + $mp2=$this->getMountPoint($path2); + if($mp1==$mp2){ + if($storage=$this->getStorage($path1)){ + $result=$storage->copy($this->getInternalPath($path1),$this->getInternalPath($path2)); + } + }elseif($storage1=$this->getStorage($path1) and $storage2=$this->getStorage($path2)){ + $tmpFile=$storage1->toTmpFile($this->getInternalPath($path1)); + $result=$storage2->fromTmpFile($tmpFile,$this->getInternalPath($path2)); + } + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2)); + if(!$exists){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array( OC_Filesystem::signal_param_path => $path2)); + } + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path2)); + return $result; + } + } + } + public function fopen($path,$mode){ + $hooks=array(); + switch($mode){ + case 'r': + $hooks[]='read'; + break; + case 'r+': + case 'w+': + case 'x+': + case 'a+': + $hooks[]='read'; + $hooks[]='write'; + break; + case 'w': + case 'x': + case 'a': + $hooks[]='write'; + break; + default: + OC_Log::write('core','invalid mode ('.$mode.') for '.$path,OC_Log::ERROR); + } + + return $this->basicOperation('fopen',$path,$hooks,$mode); + } + public function toTmpFile($path){ + if(OC_FileProxy::runPreProxies('toTmpFile',$path) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_read, array( OC_Filesystem::signal_param_path => $path)); + return $storage->toTmpFile($this->getInternalPath($path)); + } + } + public function fromTmpFile($tmpFile,$path){ + if(OC_FileProxy::runPreProxies('copy',$tmpFile,$path) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){ + $run=true; + $exists=$this->file_exists($path); + if(!$exists){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run)); + } + if($run){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run)); + } + if($run){ + $result=$storage->fromTmpFile($tmpFile,$this->getInternalPath($path)); + if(!$exists){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array( OC_Filesystem::signal_param_path => $path)); + } + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path)); + return $result; + } + } + } + + public function getMimeType($path){ + return $this->basicOperation('getMimeType',$path); + } + public function hash($type,$path){ + return $this->basicOperation('hash',$path,array('read')); + } + + public function free_space($path='/'){ + return $this->basicOperation('free_space',$path); + } + + /** + * abstraction for running most basic operations + * @param string $operation + * @param string #path + * @param array (optional) hooks + * @param mixed (optional) $extraParam + * @return mixed + */ + private function basicOperation($operation,$path,$hooks=array(),$extraParam=null){ + if(OC_FileProxy::runPreProxies($operation,$path, $extraParam) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){ + $interalPath=$this->getInternalPath($path); + $run=true; + foreach($hooks as $hook){ + if($hook!='read'){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run)); + }else{ + OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path)); + } + } + if($run){ + if($extraParam){ + $result=$storage->$operation($interalPath,$extraParam); + }else{ + $result=$storage->$operation($interalPath); + } + $result=OC_FileProxy::runPostProxies($operation,$path,$result); + foreach($hooks as $hook){ + if($hook!='read'){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path)); + } + } + return $result; + } + } + return null; + } +} diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php index 5fd35fa3e52..c3dc2942aef 100644 --- a/lib/search/provider/file.php +++ b/lib/search/provider/file.php @@ -2,14 +2,15 @@ class OC_Search_Provider_File extends OC_Search_Provider{ function search($query){ - $files=OC_Filesystem::search($query); + $files=OC_FileCache::search($query,true); $results=array(); - foreach($files as $file){ - if(OC_Filesystem::is_dir($file)){ + foreach($files as $fileData){ + $file=$fileData['path']; + if($fileData['mime']=='httpd/unix-directory'){ $results[]=new OC_Search_Result(basename($file),'',OC_Helper::linkTo( 'files', 'index.php?dir='.$file ),'Files'); }else{ - $mime=OC_Filesystem::getMimeType($file); - $mimeBase=substr($mime,0,strpos($mime,'/')); + $mime=$fileData['mime']; + $mimeBase=$fileData['mimepart']; switch($mimeBase){ case 'audio': break; diff --git a/lib/util.php b/lib/util.php index 2fba1206bff..abd918044b5 100644 --- a/lib/util.php +++ b/lib/util.php @@ -37,7 +37,7 @@ class OC_Util { if( $user != "" ){ //if we aren't logged in, there is no use to set up the filesystem //first set up the local "root" storage - OC_Filesystem::mount('local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/'); + OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/'); OC::$CONFIG_DATADIRECTORY = $CONFIG_DATADIRECTORY_ROOT."/$user/$root"; if( !is_dir( OC::$CONFIG_DATADIRECTORY )){ @@ -45,7 +45,7 @@ class OC_Util { } //jail the user into his "home" directory - OC_Filesystem::chroot("/$user/$root"); + OC_Filesystem::init('/'.$user.'/'.$root); $quotaProxy=new OC_FileProxy_Quota(); OC_FileProxy::register($quotaProxy); self::$fsSetup=true; @@ -62,7 +62,7 @@ class OC_Util { * @return array */ public static function getVersion(){ - return array(3,00,0); + return array(3,00,1); } /** @@ -226,7 +226,7 @@ class OC_Util { $errors[]=array('error'=>'PHP module ctype is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.'); } - if(file_exists(OC::$SERVERROOT."/config/config.php") and !is_writeable(OC::$SERVERROOT."/config/config.php")){ + if(file_exists(OC::$SERVERROOT."/config/config.php") and !is_writable(OC::$SERVERROOT."/config/config.php")){ $errors[]=array('error'=>"Can't write into config directory 'config'",'hint'=>"You can usually fix this by giving the webserver use write access to the config directory in owncloud"); } |