diff options
112 files changed, 6269 insertions, 4097 deletions
diff --git a/apps/files/ajax/autocomplete.php b/apps/files/ajax/autocomplete.php index b32ba7c3d5b..7613a1cb77a 100644 --- a/apps/files/ajax/autocomplete.php +++ b/apps/files/ajax/autocomplete.php @@ -33,8 +33,8 @@ $query=strtolower($query); $files=array(); -if(OC_Filesystem::file_exists($base) and OC_Filesystem::is_dir($base)) { - $dh = OC_Filesystem::opendir($base); +if(\OC\Files\Filesystem::file_exists($base) and \OC\Files\Filesystem::is_dir($base)) { + $dh = \OC\Files\Filesystem::opendir($base); if($dh) { if(substr($base, -1, 1)!='/') { $base=$base.'/'; @@ -43,7 +43,7 @@ if(OC_Filesystem::file_exists($base) and OC_Filesystem::is_dir($base)) { if ($file != "." && $file != "..") { if(substr(strtolower($file), 0, $queryLen)==$query) { $item=$base.$file; - if((!$dirOnly or OC_Filesystem::is_dir($item))) { + if((!$dirOnly or \OC\Files\Filesystem::is_dir($item))) { $files[]=(object)array('id'=>$item, 'label'=>$item, 'name'=>$item); } } diff --git a/apps/files/ajax/delete.php b/apps/files/ajax/delete.php index 6532b76df21..8f05eaaa1b8 100644 --- a/apps/files/ajax/delete.php +++ b/apps/files/ajax/delete.php @@ -12,17 +12,19 @@ $files = isset($_POST["file"]) ? stripslashes($_POST["file"]) : stripslashes($_P $files = json_decode($files); $filesWithError = ''; + $success = true; + //Now delete -foreach($files as $file) { - if( !OC_Files::delete( $dir, $file )) { +foreach ($files as $file) { + if (($dir === '' && $file === 'Shared') || !\OC\Files\Filesystem::unlink($dir . '/' . $file)) { $filesWithError .= $file . "\n"; $success = false; } } -if($success) { - OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $files ))); +if ($success) { + OCP\JSON::success(array("data" => array("dir" => $dir, "files" => $files))); } else { - OCP\JSON::error(array("data" => array( "message" => "Could not delete:\n" . $filesWithError ))); + OCP\JSON::error(array("data" => array("message" => "Could not delete:\n" . $filesWithError))); } diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index cade7e872b3..878e4cb2159 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -32,7 +32,7 @@ if($doBreadcrumb) { // make filelist $files = array(); -foreach( OC_Files::getdirectorycontent( $dir ) as $i ) { +foreach( \OC\Files\Filesystem::getDirectoryContent( $dir ) as $i ) { $i["date"] = OCP\Util::formatDate($i["mtime"] ); $files[] = $i; } diff --git a/apps/files/ajax/move.php b/apps/files/ajax/move.php index 4ebc3f42d9f..7c1ec974a3d 100644 --- a/apps/files/ajax/move.php +++ b/apps/files/ajax/move.php @@ -11,15 +11,19 @@ $dir = stripslashes($_GET["dir"]); $file = stripslashes($_GET["file"]); $target = stripslashes(rawurldecode($_GET["target"])); -$l=OC_L10N::get('files'); - -if(OC_Filesystem::file_exists($target . '/' . $file)) { - OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s - File with this name already exists", array($file)) ))); +if(\OC\Files\Filesystem::file_exists($target . '/' . $file)) { + OCP\JSON::error(array("data" => array( "message" => "Could not move $file - File with this name already exists" ))); exit; } -if(OC_Files::move($dir, $file, $target, $file)) { - OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file ))); -} else { - OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) ))); +if ($dir != '' || $file != 'Shared') { + $targetFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file); + $sourceFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file); + if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) { + OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file ))); + } else { + OCP\JSON::error(array("data" => array( "message" => "Could not move $file" ))); + } +}else{ + OCP\JSON::error(array("data" => array( "message" => "Could not move $file" ))); } diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php index 2bac9bb20ba..38714f34a63 100644 --- a/apps/files/ajax/newfile.php +++ b/apps/files/ajax/newfile.php @@ -63,13 +63,12 @@ if($source) { $ctx = stream_context_create(null, array('notification' =>'progress')); $sourceStream=fopen($source, 'rb', false, $ctx); $target=$dir.'/'.$filename; - $result=OC_Filesystem::file_put_contents($target, $sourceStream); + $result=\OC\Files\Filesystem::file_put_contents($target, $sourceStream); if($result) { - $target = OC_Filesystem::normalizePath($target); - $meta = OC_FileCache::get($target); + $meta = \OC\Files\Filesystem::getFileInfo($target); $mime=$meta['mimetype']; - $id = OC_FileCache::getId($target); - $eventSource->send('success', array('mime'=>$mime, 'size'=>OC_Filesystem::filesize($target), 'id' => $id)); + $id = $meta['fileid']; + $eventSource->send('success', array('mime'=>$mime, 'size'=>\OC\Files\Filesystem::filesize($target), 'id' => $id)); } else { $eventSource->send('error', "Error while downloading ".$source. ' to '.$target); } @@ -77,15 +76,15 @@ if($source) { exit(); } else { if($content) { - if(OC_Filesystem::file_put_contents($dir.'/'.$filename, $content)) { - $meta = OC_FileCache::get($dir.'/'.$filename); - $id = OC_FileCache::getId($dir.'/'.$filename); + if(\OC\Files\Filesystem::file_put_contents($dir.'/'.$filename, $content)) { + $meta = \OC\Files\Filesystem::getFileInfo($dir.'/'.$filename); + $id = $meta['fileid']; OCP\JSON::success(array("data" => array('content'=>$content, 'id' => $id))); exit(); } - }elseif(OC_Files::newFile($dir, $filename, 'file')) { - $meta = OC_FileCache::get($dir.'/'.$filename); - $id = OC_FileCache::getId($dir.'/'.$filename); + }elseif(\OC\Files\Filesystem::touch($dir . '/' . $filename)) { + $meta = \OC\Files\Filesystem::getFileInfo($dir.'/'.$filename); + $id = $meta['fileid']; OCP\JSON::success(array("data" => array('content'=>$content, 'id' => $id))); exit(); } diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php index 0f1f2f14eb0..e26e1238bc6 100644 --- a/apps/files/ajax/newfolder.php +++ b/apps/files/ajax/newfolder.php @@ -19,13 +19,14 @@ if(strpos($foldername, '/')!==false) { exit(); } -if(OC_Files::newFile($dir, stripslashes($foldername), 'dir')) { +if(\OC\Files\Filesystem::mkdir($dir . '/' . stripslashes($foldername))) { if ( $dir != '/') { $path = $dir.'/'.$foldername; } else { $path = '/'.$foldername; } - $id = OC_FileCache::getId($path); + $meta = \OC\Files\Filesystem::getFileInfo($path); + $id = $meta['fileid']; OCP\JSON::success(array("data" => array('id'=>$id))); exit(); } diff --git a/apps/files/ajax/rawlist.php b/apps/files/ajax/rawlist.php index e0aa0bdac52..1cd2944483c 100644 --- a/apps/files/ajax/rawlist.php +++ b/apps/files/ajax/rawlist.php @@ -15,7 +15,7 @@ $mimetype = isset($_GET['mimetype']) ? $_GET['mimetype'] : ''; // make filelist $files = array(); -foreach( OC_Files::getdirectorycontent( $dir, $mimetype ) as $i ) { +foreach( \OC\Files\Filesystem::getDirectoryContent( $dir, $mimetype ) as $i ) { $i["date"] = OCP\Util::formatDate($i["mtime"] ); $i['mimetype_icon'] = $i['type'] == 'dir' ? \mimetype_icon('dir'): \mimetype_icon($i['mimetype']); $files[] = $i; diff --git a/apps/files/ajax/rename.php b/apps/files/ajax/rename.php index 89b4d4bba73..970aaa638da 100644 --- a/apps/files/ajax/rename.php +++ b/apps/files/ajax/rename.php @@ -11,10 +11,14 @@ $dir = stripslashes($_GET["dir"]); $file = stripslashes($_GET["file"]); $newname = stripslashes($_GET["newname"]); -// Delete -if( $newname !== '.' and OC_Files::move( $dir, $file, $dir, $newname )) { - OCP\JSON::success(array("data" => array( "dir" => $dir, "file" => $file, "newname" => $newname ))); -} else { - $l=OC_L10N::get('files'); - OCP\JSON::error(array("data" => array( "message" => $l->t("Unable to rename file") ))); +if ( $newname !== '.' and ($dir != '' || $file != 'Shared') and $newname !== '.') { + $targetFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $newname); + $sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file); + if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) { + OCP\JSON::success(array("data" => array( "dir" => $dir, "file" => $file, "newname" => $newname ))); + } else { + OCP\JSON::error(array("data" => array( "message" => "Unable to rename file" ))); + } +}else{ + OCP\JSON::error(array("data" => array( "message" => "Unable to rename file" ))); } diff --git a/apps/files/ajax/scan.php b/apps/files/ajax/scan.php index a819578e309..391b98608bd 100644 --- a/apps/files/ajax/scan.php +++ b/apps/files/ajax/scan.php @@ -1,44 +1,71 @@ <?php +set_time_limit(0); //scanning can take ages +session_write_close(); -set_time_limit(0);//scanning can take ages +$force = (isset($_GET['force']) and ($_GET['force'] === 'true')); +$dir = isset($_GET['dir']) ? $_GET['dir'] : ''; -$force=isset($_GET['force']) and $_GET['force']=='true'; -$dir=isset($_GET['dir'])?$_GET['dir']:''; -$checkOnly=isset($_GET['checkonly']) and $_GET['checkonly']=='true'; +$eventSource = new OC_EventSource(); +ScanListener::$eventSource = $eventSource; +ScanListener::$view = \OC\Files\Filesystem::getView(); -$eventSource=false; -if(!$checkOnly) { - $eventSource=new OC_EventSource(); -} +OC_Hook::connect('\OC\Files\Cache\Scanner', 'scan_folder', 'ScanListener', 'folder'); +OC_Hook::connect('\OC\Files\Cache\Scanner', 'scan_file', 'ScanListener', 'file'); -session_write_close(); +$absolutePath = \OC\Files\Filesystem::getView()->getAbsolutePath($dir); -//create the file cache if necessary -if($force or !OC_FileCache::inCache('')) { - if(!$checkOnly) { - OCP\DB::beginTransaction(); +$mountPoints = \OC\Files\Filesystem::getMountPoints($absolutePath); +$mountPoints[] = \OC\Files\Filesystem::getMountPoint($absolutePath); +$mountPoints = array_reverse($mountPoints); //start with the mount point of $dir - if(OC_Cache::isFast()) { - OC_Cache::clear('fileid/'); //make sure the old fileid's don't mess things up +foreach ($mountPoints as $mountPoint) { + $storage = \OC\Files\Filesystem::getStorage($mountPoint); + if ($storage) { + ScanListener::$mountPoints[$storage->getId()] = $mountPoint; + $scanner = $storage->getScanner(); + if ($force) { + $scanner->scan(''); + } else { + $scanner->backgroundScan(); } - - OC_FileCache::scan($dir, $eventSource); - OC_FileCache::clean(); - OCP\DB::commit(); - $eventSource->send('success', true); - } else { - OCP\JSON::success(array('data'=>array('done'=>true))); - exit; } -} else { - if($checkOnly) { - OCP\JSON::success(array('data'=>array('done'=>false))); - exit; +} + +$eventSource->send('done', ScanListener::$fileCount); +$eventSource->close(); + +class ScanListener { + + static public $fileCount = 0; + static public $lastCount = 0; + + /** + * @var \OC\Files\View $view + */ + static public $view; + + /** + * @var array $mountPoints map storage ids to mountpoints + */ + static public $mountPoints = array(); + + /** + * @var \OC_EventSource event source to pass events to + */ + static public $eventSource; + + static function folder($params) { + $internalPath = $params['path']; + $mountPoint = self::$mountPoints[$params['storage']]; + $path = self::$view->getRelativePath($mountPoint . $internalPath); + self::$eventSource->send('folder', $path); } - if(isset($eventSource)) { - $eventSource->send('success', false); - } else { - exit; + + static function file() { + self::$fileCount++; + if (self::$fileCount > self::$lastCount + 20) { //send a count update every 20 files + self::$lastCount = self::$fileCount; + self::$eventSource->send('count', self::$fileCount); + } } } -$eventSource->close(); diff --git a/apps/files/ajax/upgrade.php b/apps/files/ajax/upgrade.php new file mode 100644 index 00000000000..7237b02c0b0 --- /dev/null +++ b/apps/files/ajax/upgrade.php @@ -0,0 +1,44 @@ +<?php +set_time_limit(0); //scanning can take ages +session_write_close(); + +$user = OC_User::getUser(); +$eventSource = new OC_EventSource(); +$listener = new UpgradeListener($eventSource); +$legacy = new \OC\Files\Cache\Legacy($user); + +if ($legacy->hasItems()) { + OC_Hook::connect('\OC\Files\Cache\Upgrade', 'migrate_path', $listener, 'upgradePath'); + + OC_DB::beginTransaction(); + $upgrade = new \OC\Files\Cache\Upgrade($legacy); + $count = $legacy->getCount(); + $eventSource->send('total', $count); + $upgrade->upgradePath('/' . $user . '/files'); + OC_DB::commit(); +} +\OC\Files\Cache\Upgrade::upgradeDone($user); +$eventSource->send('done', true); +$eventSource->close(); + +class UpgradeListener { + /** + * @var OC_EventSource $eventSource + */ + private $eventSource; + + private $count = 0; + private $lastSend = 0; + + public function __construct($eventSource) { + $this->eventSource = $eventSource; + } + + public function upgradePath($path) { + $this->count++; + if ($this->count > ($this->lastSend + 5)) { + $this->lastSend = $this->count; + $this->eventSource->send('count', $this->count); + } + } +} diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index 2a2d935da6c..eea66d6b269 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -41,8 +41,8 @@ $totalSize=0; foreach($files['size'] as $size) { $totalSize+=$size; } -if($totalSize>OC_Filesystem::free_space($dir)) { - OCP\JSON::error(array('data' => array( 'message' => $l->t( 'Not enough space available' )))); +if($totalSize>\OC\Files\Filesystem::free_space($dir)) { + OCP\JSON::error(array('data' => array( 'message' => 'Not enough space available' ))); exit(); } @@ -52,14 +52,13 @@ if(strpos($dir, '..') === false) { for($i=0;$i<$fileCount;$i++) { $target = OCP\Files::buildNotExistingFileName(stripslashes($dir), $files['name'][$i]); // $path needs to be normalized - this failed within drag'n'drop upload to a sub-folder - $target = OC_Filesystem::normalizePath($target); - if(is_uploaded_file($files['tmp_name'][$i]) and OC_Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) { - $meta = OC_FileCache::get($target); - $id = OC_FileCache::getId($target); + $target = \OC\Files\Filesystem::normalizePath($target); + if(is_uploaded_file($files['tmp_name'][$i]) and \OC\Files\Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) { + $meta = \OC\Files\Filesystem::getFileInfo($target); $result[]=array( 'status' => 'success', 'mime'=>$meta['mimetype'], 'size'=>$meta['size'], - 'id'=>$id, + 'id'=>$meta['fileid'], 'name'=>basename($target)); } } diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php index 108f02930e2..ab2f3b01a29 100644 --- a/apps/files/appinfo/app.php +++ b/apps/files/appinfo/app.php @@ -1,5 +1,5 @@ <?php -$l=OC_L10N::get('files'); +$l = OC_L10N::get('files'); OCP\App::registerAdmin('files', 'admin'); diff --git a/apps/files/appinfo/filesync.php b/apps/files/appinfo/filesync.php index cbed56a6de5..47884a4f15e 100644 --- a/apps/files/appinfo/filesync.php +++ b/apps/files/appinfo/filesync.php @@ -43,7 +43,7 @@ if ($type != 'oc_chunked') { die; } -if (!OC_Filesystem::is_file($file)) { +if (!\OC\Files\Filesystem::is_file($file)) { OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); die; } @@ -51,7 +51,7 @@ if (!OC_Filesystem::is_file($file)) { switch($_SERVER['REQUEST_METHOD']) { case 'PUT': $input = fopen("php://input", "r"); - $org_file = OC_Filesystem::fopen($file, 'rb'); + $org_file = \OC\Files\Filesystem::fopen($file, 'rb'); $info = array( 'name' => basename($file), ); diff --git a/apps/files/appinfo/version b/apps/files/appinfo/version index 0664a8fd291..2bf1ca5f549 100644 --- a/apps/files/appinfo/version +++ b/apps/files/appinfo/version @@ -1 +1 @@ -1.1.6 +1.1.7 diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 0c97b009b88..f5948fd15ea 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -122,3 +122,12 @@ a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; } #scanning-message{ top:40%; left:40%; position:absolute; display:none; } div.crumb a{ padding:0.9em 0 0.7em 0; } + +#upgrade { + width: 400px; + position: absolute; + top: 200px; + left: 50%; + text-align: center; + margin-left: -200px; +} diff --git a/apps/files/download.php b/apps/files/download.php index e2149cd4135..ddd23df4125 100644 --- a/apps/files/download.php +++ b/apps/files/download.php @@ -29,7 +29,7 @@ OCP\User::checkLoggedIn(); $filename = $_GET["file"]; -if(!OC_Filesystem::file_exists($filename)) { +if(!\OC\Files\Filesystem::file_exists($filename)) { header("HTTP/1.0 404 Not Found"); $tmpl = new OCP\Template( '', '404', 'guest' ); $tmpl->assign('file', $filename); @@ -37,7 +37,7 @@ if(!OC_Filesystem::file_exists($filename)) { exit; } -$ftype=OC_Filesystem::getMimeType( $filename ); +$ftype=\OC\Files\Filesystem::getMimeType( $filename ); header('Content-Type:'.$ftype); if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) { @@ -47,7 +47,7 @@ if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) { . '; filename="' . rawurlencode( basename($filename) ) . '"' ); } OCP\Response::disableCaching(); -header('Content-Length: '.OC_Filesystem::filesize($filename)); +header('Content-Length: '.\OC\Files\Filesystem::filesize($filename)); OC_Util::obEnd(); -OC_Filesystem::readfile( $filename ); +\OC\Files\Filesystem::readfile( $filename ); diff --git a/apps/files/index.php b/apps/files/index.php index 08193eaee7b..0dce7686962 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -28,7 +28,6 @@ OCP\User::checkLoggedIn(); OCP\Util::addStyle('files', 'files'); OCP\Util::addscript('files', 'jquery.iframe-transport'); OCP\Util::addscript('files', 'jquery.fileupload'); -OCP\Util::addscript('files', 'files'); OCP\Util::addscript('files', 'filelist'); OCP\Util::addscript('files', 'fileactions'); OCP\Util::addscript('files', 'keyboardshortcuts'); @@ -37,13 +36,33 @@ OCP\App::setActiveNavigationEntry('files_index'); // Load the files $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : ''; // Redirect if directory does not exist -if (!OC_Filesystem::is_dir($dir . '/')) { +if (!\OC\Files\Filesystem::is_dir($dir . '/')) { header('Location: ' . $_SERVER['SCRIPT_NAME'] . ''); exit(); } +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']); + } +} + $files = array(); -foreach (OC_Files::getdirectorycontent($dir) as $i) { +$user = OC_User::getUser(); +if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache + $content = array(); + $needUpgrade = true; + $freeSpace = 0; +} else { + $content = \OC\Files\Filesystem::getDirectoryContent($dir); + $freeSpace = \OC\Files\Filesystem::free_space($dir); + $needUpgrade = false; +} +foreach ($content as $i) { $i['date'] = OCP\Util::formatDate($i['mtime']); if ($i['type'] == 'file') { $fileinfo = pathinfo($i['name']); @@ -54,12 +73,12 @@ foreach (OC_Files::getdirectorycontent($dir) as $i) { $i['extension'] = ''; } } - if ($i['directory'] == '/') { - $i['directory'] = ''; - } + $i['directory'] = $dir; $files[] = $i; } +usort($files, "fileCmp"); + // Make breadcrumb $breadcrumb = array(); $pathtohere = ''; @@ -83,29 +102,35 @@ $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize') $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); $maxUploadFilesize = min($upload_max_filesize, $post_max_size); -$freeSpace = OC_Filesystem::free_space($dir); $freeSpace = max($freeSpace, 0); $maxUploadFilesize = min($maxUploadFilesize, $freeSpace); $permissions = OCP\PERMISSION_READ; -if (OC_Filesystem::isUpdatable($dir . '/')) { +if (\OC\Files\Filesystem::isUpdatable($dir . '/')) { $permissions |= OCP\PERMISSION_UPDATE; } -if (OC_Filesystem::isDeletable($dir . '/')) { +if (\OC\Files\Filesystem::isDeletable($dir . '/')) { $permissions |= OCP\PERMISSION_DELETE; } -if (OC_Filesystem::isSharable($dir . '/')) { +if (\OC\Files\Filesystem::isSharable($dir . '/')) { $permissions |= OCP\PERMISSION_SHARE; } -$tmpl = new OCP\Template('files', 'index', 'user'); -$tmpl->assign('fileList', $list->fetchPage(), false); -$tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage(), false); -$tmpl->assign('dir', OC_Filesystem::normalizePath($dir)); -$tmpl->assign('isCreatable', OC_Filesystem::isCreatable($dir . '/')); -$tmpl->assign('permissions', $permissions); -$tmpl->assign('files', $files); -$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); -$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); -$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); -$tmpl->printPage(); +if ($needUpgrade) { + OCP\Util::addscript('files', 'upgrade'); + $tmpl = new OCP\Template('files', 'upgrade', 'user'); + $tmpl->printPage(); +} else { + OCP\Util::addscript('files', 'files'); + $tmpl = new OCP\Template('files', 'index', 'user'); + $tmpl->assign('fileList', $list->fetchPage(), false); + $tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage(), false); + $tmpl->assign('dir', \OC\Files\Filesystem::normalizePath($dir)); + $tmpl->assign('isCreatable', \OC\Files\Filesystem::isCreatable($dir . '/')); + $tmpl->assign('permissions', $permissions); + $tmpl->assign('files', $files); + $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); + $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); + $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); + $tmpl->printPage(); +} diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 3a4af6416e9..f560e908456 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -640,12 +640,8 @@ $(document).ready(function() { }); }); - //check if we need to scan the filesystem - $.get(OC.filePath('files','ajax','scan.php'),{checkonly:'true'}, function(response) { - if(response.data.done){ - scanFiles(); - } - }, "json"); + //do a background scan if needed + scanFiles(); var lastWidth = 0; var breadcrumbs = []; @@ -714,27 +710,23 @@ $(document).ready(function() { resizeBreadcrumbs(true); }); -function scanFiles(force,dir){ +function scanFiles(force, dir){ if(!dir){ - dir=''; + dir = ''; } - force=!!force; //cast to bool - scanFiles.scanning=true; - $('#scanning-message').show(); - $('#fileList').remove(); - var scannerEventSource=new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force:force,dir:dir}); - scanFiles.cancel=scannerEventSource.close.bind(scannerEventSource); - scannerEventSource.listen('scanning',function(data){ - $('#scan-count').text(t('files', '{count} files scanned', {count: data.count})); - $('#scan-current').text(data.file+'/'); + force = !!force; //cast to bool + scanFiles.scanning = true; + var scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force:force,dir:dir}); + scanFiles.cancel = scannerEventSource.close.bind(scannerEventSource); + scannerEventSource.listen('count',function(count){ + console.log(count + 'files scanned') + }); + scannerEventSource.listen('folder',function(path){ + console.log('now scanning ' + path) }); - scannerEventSource.listen('success',function(success){ + scannerEventSource.listen('done',function(count){ scanFiles.scanning=false; - if(success){ - window.location.reload(); - }else{ - alert(t('files', 'error while scanning')); - } + console.log('done after ' + count + 'files'); }); } scanFiles.scanning=false; diff --git a/apps/files/js/upgrade.js b/apps/files/js/upgrade.js new file mode 100644 index 00000000000..02d57fc9e6c --- /dev/null +++ b/apps/files/js/upgrade.js @@ -0,0 +1,17 @@ +$(document).ready(function () { + var eventSource, total, bar = $('#progressbar'); + console.log('start'); + bar.progressbar({value: 0}); + eventSource = new OC.EventSource(OC.filePath('files', 'ajax', 'upgrade.php')); + eventSource.listen('total', function (count) { + total = count; + console.log(count + ' files needed to be migrated'); + }); + eventSource.listen('count', function (count) { + bar.progressbar({value: (count / total) * 100}); + console.log(count); + }); + eventSource.listen('done', function () { + document.location.reload(); + }); +}); diff --git a/apps/files/settings.php b/apps/files/settings.php index 52ec9fd0fe3..30463210f71 100644 --- a/apps/files/settings.php +++ b/apps/files/settings.php @@ -36,7 +36,7 @@ OCP\Util::addscript( "files", "files" ); $dir = isset( $_GET['dir'] ) ? $_GET['dir'] : ''; $files = array(); -foreach( OC_Files::getdirectorycontent( $dir ) as $i ) { +foreach( \OC\Files\Filesystem::getDirectoryContent( $dir ) as $i ) { $i["date"] = date( $CONFIG_DATEFORMAT, $i["mtime"] ); $files[] = $i; } diff --git a/apps/files/templates/part.list.php b/apps/files/templates/part.list.php index dfac43d1b12..98fc60954fa 100644 --- a/apps/files/templates/part.list.php +++ b/apps/files/templates/part.list.php @@ -19,7 +19,7 @@ $name = str_replace('%2F', '/', $name); $directory = str_replace('+', '%20', urlencode($file['directory'])); $directory = str_replace('%2F', '/', $directory); ?> - <tr data-id="<?php echo $file['id']; ?>" + <tr data-id="<?php echo $file['fileid']; ?>" data-file="<?php echo $name;?>" data-type="<?php echo ($file['type'] == 'dir')?'dir':'file'?>" data-mime="<?php echo $file['mimetype']?>" @@ -34,7 +34,7 @@ > <?php if(!isset($_['readonly']) || !$_['readonly']): ?><input type="checkbox" /><?php endif; ?> <?php if($file['type'] == 'dir'): ?> - <a class="name" href="<?php $_['baseURL'].$directory.'/'.$name; ?>)" title=""> + <a class="name" href="<?php echo $_['baseURL'].$directory.'/'.$name; ?>)" title=""> <?php else: ?> <a class="name" href="<?php echo $_['downloadURL'].$directory.'/'.$name; ?>" title=""> <?php endif; ?> @@ -67,4 +67,4 @@ </span> </td> </tr> -<?php endforeach;
\ No newline at end of file +<?php endforeach; diff --git a/apps/files/templates/upgrade.php b/apps/files/templates/upgrade.php new file mode 100644 index 00000000000..de6cc713028 --- /dev/null +++ b/apps/files/templates/upgrade.php @@ -0,0 +1,4 @@ +<div id="upgrade"> + <?php echo $l->t('Upgrading filesystem cache...');?> + <div id="progressbar" /> +</div> diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 666fedb4e1b..e62c9b77273 100644 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -45,8 +45,8 @@ class OC_Crypt { } public static function init($login, $password) { - $view=new OC_FilesystemView('/'); - if ( ! $view->file_exists('/'.$login)) { + $view=new \OC\Files\View('/'); + if(!$view->file_exists('/'.$login)) { $view->mkdir('/'.$login); } @@ -81,7 +81,7 @@ class OC_Crypt { } } - public static function createkey($username, $passcode) { + public static function createkey($username,$passcode) { // generate a random key $key=mt_rand(10000, 99999).mt_rand(10000, 99999).mt_rand(10000, 99999).mt_rand(10000, 99999); @@ -91,7 +91,7 @@ class OC_Crypt { // Write the file $proxyEnabled=OC_FileProxy::$enabled; OC_FileProxy::$enabled=false; - $view=new OC_FilesystemView('/'.$username); + $view = new \OC\Files\View('/' . $username); $view->file_put_contents('/encryption.key', $enckey); OC_FileProxy::$enabled=$proxyEnabled; } @@ -99,7 +99,7 @@ class OC_Crypt { public static function changekeypasscode($oldPassword, $newPassword) { if (OCP\User::isLoggedIn()) { $username=OCP\USER::getUser(); - $view=new OC_FilesystemView('/'.$username); + $view=new \OC\Files\View('/'.$username); // read old key $key=$view->file_get_contents('/encryption.key'); diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index d516c0c21b2..8d5a9ff9990 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -38,8 +38,8 @@ class OC_CryptStream{ private static $rootView; public function stream_open($path, $mode, $options, &$opened_path) { - if ( ! self::$rootView) { - self::$rootView=new OC_FilesystemView(''); + if (!self::$rootView) { + self::$rootView=new \OC\Files\View(''); } $path=str_replace('crypt://', '', $path); if (dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])) { @@ -169,8 +169,8 @@ class OC_CryptStream{ public function stream_close() { $this->flush(); - if ($this->meta['mode']!='r' and $this->meta['mode']!='rb') { - OC_FileCache::put($this->path, array('encrypted'=>true, 'size'=>$this->size), ''); + if($this->meta['mode']!='r' and $this->meta['mode']!='rb') { + \OC\Files\Filesystem::putFileInfo($this->path, array('encrypted' => true, 'size' => $this->size), ''); } return fclose($this->source); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index e8dbd95c29d..ffee394047c 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -61,7 +61,8 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ * @return bool */ private static function isEncrypted($path) { - $metadata=OC_FileCache_Cached::get($path, ''); + $rootView = new \OC\Files\View(''); + $metadata=$rootView->getFileInfo($path); return isset($metadata['encrypted']) and (bool)$metadata['encrypted']; } @@ -69,15 +70,17 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ if (self::shouldEncrypt($path)) { if ( ! is_resource($data)) {//stream put contents should have been converter to fopen $size=strlen($data); + $rootView = new \OC\Files\View(''); $data=OC_Crypt::blockEncrypt($data); - OC_FileCache::put($path, array('encrypted'=>true,'size'=>$size), ''); + $rootView->putFileInfo($path, array('encrypted'=>true,'size'=>$size)); } } } public function postFile_get_contents($path, $data) { - if (self::isEncrypted($path)) { - $cached=OC_FileCache_Cached::get($path, ''); + if(self::isEncrypted($path)) { + $rootView = new \OC\Files\View(''); + $cached=$rootView->getFileInfo($path, ''); $data=OC_Crypt::blockDecrypt($data, '', $cached['size']); } return $data; @@ -91,14 +94,14 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ if (self::isEncrypted($path)) { fclose($result); $result=fopen('crypt://'.$path, $meta['mode']); - } elseif (self::shouldEncrypt($path) and $meta['mode']!='r' and $meta['mode']!='rb') { - if (OC_Filesystem::file_exists($path) and OC_Filesystem::filesize($path)>0) { + }elseif(self::shouldEncrypt($path) and $meta['mode']!='r' and $meta['mode']!='rb') { + if(\OC\Files\Filesystem::file_exists($path) and \OC\Files\Filesystem::filesize($path)>0) { //first encrypt the target file so we don't end up with a half encrypted file - OCP\Util::writeLog('files_encryption', 'Decrypting '.$path.' before writing', OCP\Util::DEBUG); + OCP\Util::writeLog('files_encryption','Decrypting '.$path.' before writing', OCP\Util::DEBUG); $tmp=fopen('php://temp'); OCP\Files::streamCopy($result, $tmp); fclose($result); - OC_Filesystem::file_put_contents($path, $tmp); + \OC\Files\Filesystem::file_put_contents($path, $tmp); fclose($tmp); } $result=fopen('crypt://'.$path, $meta['mode']); @@ -114,16 +117,18 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ } public function postStat($path, $data) { - if (self::isEncrypted($path)) { - $cached=OC_FileCache_Cached::get($path, ''); + if(self::isEncrypted($path)) { + $rootView = new \OC\Files\View(''); + $cached=$rootView->getFileInfo($path); $data['size']=$cached['size']; } return $data; } public function postFileSize($path, $size) { - if (self::isEncrypted($path)) { - $cached=OC_FileCache_Cached::get($path, ''); + if(self::isEncrypted($path)) { + $rootView = new \OC\Files\View(''); + $cached=$rootView->getFileInfo($path); return $cached['size']; } else { return $size; diff --git a/apps/files_encryption/tests/proxy.php b/apps/files_encryption/tests/proxy.php index 5aa617e7472..09b2a67943c 100644 --- a/apps/files_encryption/tests/proxy.php +++ b/apps/files_encryption/tests/proxy.php @@ -13,8 +13,8 @@ class Test_CryptProxy extends UnitTestCase { public function setUp() { $user=OC_User::getUser(); - $this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption', 'true'); - OCP\Config::setAppValue('files_encryption', 'enable_encryption', 'true'); + $this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption','true'); + OCP\Config::setAppValue('files_encryption','enable_encryption','true'); $this->oldKey=isset($_SESSION['enckey'])?$_SESSION['enckey']:null; @@ -29,13 +29,13 @@ class Test_CryptProxy extends UnitTestCase { OC_FileProxy::register(new OC_FileProxy_Encryption()); //set up temporary storage - OC_Filesystem::clearMounts(); - OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); + \OC\Files\Filesystem::clearMounts(); + \OC\Files\Filesystem::mount('\OC\Files\Storage\Temporary' ,array(), '/'); - OC_Filesystem::init('/'.$user.'/files'); + \OC\Files\Filesystem::init('/'.$user.'/files'); //set up the users home folder in the temp storage - $rootView=new OC_FilesystemView(''); + $rootView=new \OC\Files\View(''); $rootView->mkdir('/'.$user); $rootView->mkdir('/'.$user.'/files'); } @@ -51,16 +51,16 @@ class Test_CryptProxy extends UnitTestCase { $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; $original=file_get_contents($file); - OC_Filesystem::file_put_contents('/file', $original); + \OC\Files\Filesystem::file_put_contents('/file',$original); OC_FileProxy::$enabled=false; - $stored=OC_Filesystem::file_get_contents('/file'); + $stored=\OC\Files\Filesystem::file_get_contents('/file'); OC_FileProxy::$enabled=true; - $fromFile=OC_Filesystem::file_get_contents('/file'); - $this->assertNotEqual($original, $stored); + $fromFile=\OC\Files\Filesystem::file_get_contents('/file'); + $this->assertNotEqual($original,$stored); $this->assertEqual(strlen($original), strlen($fromFile)); - $this->assertEqual($original, $fromFile); + $this->assertEqual($original,$fromFile); } @@ -68,50 +68,50 @@ class Test_CryptProxy extends UnitTestCase { $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; $original=file_get_contents($file); - $rootView=new OC_FilesystemView(''); - $view=new OC_FilesystemView('/'.OC_User::getUser()); + $rootView=new \OC\Files\View(''); + $view=new \OC\Files\View('/'.OC_User::getUser()); $userDir='/'.OC_User::getUser().'/files'; - $rootView->file_put_contents($userDir.'/file', $original); + $rootView->file_put_contents($userDir.'/file',$original); OC_FileProxy::$enabled=false; $stored=$rootView->file_get_contents($userDir.'/file'); OC_FileProxy::$enabled=true; - $this->assertNotEqual($original, $stored); + $this->assertNotEqual($original,$stored); $fromFile=$rootView->file_get_contents($userDir.'/file'); - $this->assertEqual($original, $fromFile); + $this->assertEqual($original,$fromFile); $fromFile=$view->file_get_contents('files/file'); - $this->assertEqual($original, $fromFile); + $this->assertEqual($original,$fromFile); } public function testBinary() { $file=__DIR__.'/binary'; $original=file_get_contents($file); - OC_Filesystem::file_put_contents('/file', $original); + \OC\Files\Filesystem::file_put_contents('/file',$original); OC_FileProxy::$enabled=false; - $stored=OC_Filesystem::file_get_contents('/file'); + $stored=\OC\Files\Filesystem::file_get_contents('/file'); OC_FileProxy::$enabled=true; - $fromFile=OC_Filesystem::file_get_contents('/file'); - $this->assertNotEqual($original, $stored); + $fromFile=\OC\Files\Filesystem::file_get_contents('/file'); + $this->assertNotEqual($original,$stored); $this->assertEqual(strlen($original), strlen($fromFile)); - $this->assertEqual($original, $fromFile); + $this->assertEqual($original,$fromFile); $file=__DIR__.'/zeros'; $original=file_get_contents($file); - OC_Filesystem::file_put_contents('/file', $original); + \OC\Files\Filesystem::file_put_contents('/file',$original); OC_FileProxy::$enabled=false; - $stored=OC_Filesystem::file_get_contents('/file'); + $stored=\OC\Files\Filesystem::file_get_contents('/file'); OC_FileProxy::$enabled=true; - $fromFile=OC_Filesystem::file_get_contents('/file'); - $this->assertNotEqual($original, $stored); + $fromFile=\OC\Files\Filesystem::file_get_contents('/file'); + $this->assertNotEqual($original,$stored); $this->assertEqual(strlen($original), strlen($fromFile)); } } diff --git a/apps/files_external/ajax/addRootCertificate.php b/apps/files_external/ajax/addRootCertificate.php index be60b415e1b..2f67e801b2c 100644 --- a/apps/files_external/ajax/addRootCertificate.php +++ b/apps/files_external/ajax/addRootCertificate.php @@ -12,8 +12,10 @@ $data = fread($fh, filesize($_FILES['rootcert_import']['tmp_name'])); fclose($fh); $filename = $_FILES['rootcert_import']['name']; -$view = new \OC_FilesystemView('/'.\OCP\User::getUser().'/files_external/uploads'); -if ( ! $view->file_exists('')) $view->mkdir(''); +$view = new \OC\Files\View('/'.\OCP\User::getUser().'/files_external/uploads'); +if (!$view->file_exists('')){ + $view->mkdir(''); +} $isValid = openssl_pkey_get_public($data); diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index 837d35c9c63..c58cfcd0f5e 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -6,14 +6,14 @@ * See the COPYING-README file. */ -OC::$CLASSPATH['OC_FileStorage_StreamWrapper']='apps/files_external/lib/streamwrapper.php'; -OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_external/lib/ftp.php'; -OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_external/lib/webdav.php'; -OC::$CLASSPATH['OC_Filestorage_Google']='apps/files_external/lib/google.php'; -OC::$CLASSPATH['OC_Filestorage_SWIFT']='apps/files_external/lib/swift.php'; -OC::$CLASSPATH['OC_Filestorage_SMB']='apps/files_external/lib/smb.php'; -OC::$CLASSPATH['OC_Filestorage_AmazonS3']='apps/files_external/lib/amazons3.php'; -OC::$CLASSPATH['OC_Filestorage_Dropbox']='apps/files_external/lib/dropbox.php'; +OC::$CLASSPATH['OC\Files\Storage\StreamWrapper']='apps/files_external/lib/streamwrapper.php'; +OC::$CLASSPATH['OC\Files\Storage\FTP']='apps/files_external/lib/ftp.php'; +OC::$CLASSPATH['OC\Files\Storage\DAV']='apps/files_external/lib/webdav.php'; +OC::$CLASSPATH['OC\Files\Storage\Google']='apps/files_external/lib/google.php'; +OC::$CLASSPATH['OC\Files\Storage\SWIFT']='apps/files_external/lib/swift.php'; +OC::$CLASSPATH['OC\Files\Storage\SMB']='apps/files_external/lib/smb.php'; +OC::$CLASSPATH['OC\Files\Storage\AmazonS3']='apps/files_external/lib/amazons3.php'; +OC::$CLASSPATH['OC\Files\Storage\Dropbox']='apps/files_external/lib/dropbox.php'; OC::$CLASSPATH['OC_Mount_Config']='apps/files_external/lib/config.php'; OCP\App::registerAdmin('files_external', 'settings'); diff --git a/apps/files_external/lib/amazons3.php b/apps/files_external/lib/amazons3.php index e5ef4eb097c..a209f0d0507 100644 --- a/apps/files_external/lib/amazons3.php +++ b/apps/files_external/lib/amazons3.php @@ -20,20 +20,24 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ +namespace OC\Files\Storage; + require_once 'aws-sdk/sdk.class.php'; -class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { +class AmazonS3 extends \OC\Files\Storage\Common { private $s3; private $bucket; private $objects = array(); + private $id; private static $tempFiles = array(); // TODO options: storage class, encryption server side, encrypt before upload? public function __construct($params) { - $this->s3 = new AmazonS3(array('key' => $params['key'], 'secret' => $params['secret'])); + $this->id = 'amazon::'.$params['key'] . md5($params['secret']); + $this->s3 = new \AmazonS3(array('key' => $params['key'], 'secret' => $params['secret'])); $this->bucket = $params['bucket']; } @@ -57,6 +61,10 @@ class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { return false; } + public function getId(){ + return $this->id; + } + public function mkdir($path) { // Folders in Amazon S3 are 0 byte objects with a '/' at the end of the name if (substr($path, -1) != '/') { @@ -96,7 +104,7 @@ class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { foreach ($response->body->CommonPrefixes as $object) { $files[] = basename($object->Prefix); } - OC_FakeDirStream::$dirs['amazons3'.$path] = $files; + \OC_FakeDirStream::$dirs['amazons3'.$path] = $files; return opendir('fakedir://amazons3'.$path); } return false; @@ -107,15 +115,10 @@ class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { $stat['size'] = $this->s3->get_bucket_filesize($this->bucket); $stat['atime'] = time(); $stat['mtime'] = $stat['atime']; - $stat['ctime'] = $stat['atime']; - } else { - $object = $this->getObject($path); - if ($object) { - $stat['size'] = $object['Size']; - $stat['atime'] = time(); - $stat['mtime'] = strtotime($object['LastModified']); - $stat['ctime'] = $stat['mtime']; - } + } else if ($object = $this->getObject($path)) { + $stat['size'] = $object['Size']; + $stat['atime'] = time(); + $stat['mtime'] = strtotime($object['LastModified']); } if (isset($stat)) { return $stat; @@ -166,7 +169,7 @@ class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { switch ($mode) { case 'r': case 'rb': - $tmpFile = OC_Helper::tmpFile(); + $tmpFile = \OC_Helper::tmpFile(); $handle = fopen($tmpFile, 'w'); $response = $this->s3->get_object($this->bucket, $path, array('fileDownload' => $handle)); if ($response->isOK()) { @@ -190,8 +193,8 @@ class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { } else { $ext = ''; } - $tmpFile = OC_Helper::tmpFile($ext); - OC_CloseStreamWrapper::$callBacks[$tmpFile] = array($this, 'writeBack'); + $tmpFile = \OC_Helper::tmpFile($ext); + \OC_CloseStreamWrapper::$callBacks[$tmpFile] = array($this, 'writeBack'); if ($this->file_exists($path)) { $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index fd3dc2ca0d0..6b0df21461b 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -38,20 +38,20 @@ class OC_Mount_Config { * @return array */ public static function getBackends() { - - $backends['OC_Filestorage_Local']=array( + + $backends['\OC\Files\Storage\Local']=array( 'backend' => 'Local', 'configuration' => array( 'datadir' => 'Location')); - $backends['OC_Filestorage_AmazonS3']=array( + $backends['\OC\Files\Storage\AmazonS3']=array( 'backend' => 'Amazon S3', 'configuration' => array( 'key' => 'Key', 'secret' => '*Secret', 'bucket' => 'Bucket')); - $backends['OC_Filestorage_Dropbox']=array( + $backends['\OC\Files\Storage\Dropbox']=array( 'backend' => 'Dropbox', 'configuration' => array( 'configured' => '#configured', @@ -61,7 +61,7 @@ class OC_Mount_Config { 'token_secret' => '#token_secret'), 'custom' => 'dropbox'); - if(OC_Mount_Config::checkphpftp()) $backends['OC_Filestorage_FTP']=array( + if(OC_Mount_Config::checkphpftp()) $backends['\OC\Files\Storage\FTP']=array( 'backend' => 'FTP', 'configuration' => array( 'host' => 'URL', @@ -70,15 +70,15 @@ class OC_Mount_Config { 'root' => '&Root', 'secure' => '!Secure ftps://')); - $backends['OC_Filestorage_Google']=array( + $backends['\OC\Files\Storage\Google']=array( 'backend' => 'Google Drive', 'configuration' => array( 'configured' => '#configured', 'token' => '#token', 'token_secret' => '#token secret'), 'custom' => 'google'); - - $backends['OC_Filestorage_SWIFT']=array( + + $backends['\OC\Files\Storage\SWIFT']=array( 'backend' => 'OpenStack Swift', 'configuration' => array( 'host' => 'URL', @@ -86,8 +86,8 @@ class OC_Mount_Config { 'token' => '*Token', 'root' => '&Root', 'secure' => '!Secure ftps://')); - - if(OC_Mount_Config::checksmbclient()) $backends['OC_Filestorage_SMB']=array( + + if(OC_Mount_Config::checksmbclient()) $backends['\OC\Files\Storage\SMB']=array( 'backend' => 'SMB / CIFS', 'configuration' => array( 'host' => 'URL', @@ -95,8 +95,8 @@ class OC_Mount_Config { 'password' => '*Password', 'share' => 'Share', 'root' => '&Root')); - - $backends['OC_Filestorage_DAV']=array( + + $backends['\OC\Files\Storage\DAV']=array( 'backend' => 'ownCloud / WebDAV', 'configuration' => array( 'host' => 'URL', @@ -120,6 +120,10 @@ class OC_Mount_Config { if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) { foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) { foreach ($mounts as $mountPoint => $mount) { + // Update old classes to new namespace + if (strpos($mount['class'], 'OC_Filestorage_') !== false) { + $mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15); + } // Remove '/$user/files/' from mount point $mountPoint = substr($mountPoint, 13); // Merge the mount point into the current mount points @@ -139,6 +143,10 @@ class OC_Mount_Config { if (isset($mountPoints[self::MOUNT_TYPE_USER])) { foreach ($mountPoints[self::MOUNT_TYPE_USER] as $user => $mounts) { foreach ($mounts as $mountPoint => $mount) { + // Update old classes to new namespace + if (strpos($mount['class'], 'OC_Filestorage_') !== false) { + $mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15); + } // Remove '/$user/files/' from mount point $mountPoint = substr($mountPoint, 13); // Merge the mount point into the current mount points @@ -169,6 +177,10 @@ class OC_Mount_Config { $personal = array(); if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) { foreach ($mountPoints[self::MOUNT_TYPE_USER][$uid] as $mountPoint => $mount) { + // Update old classes to new namespace + if (strpos($mount['class'], 'OC_Filestorage_') !== false) { + $mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15); + } // Remove '/uid/files/' from mount point $personal[substr($mountPoint, strlen($uid) + 8)] = array('class' => $mount['class'], 'backend' => $backends[$mount['class']]['backend'], @@ -179,22 +191,6 @@ class OC_Mount_Config { } /** - * Add directory for mount point to the filesystem - * @param OC_Fileview instance $view - * @param string path to mount point - */ - private static function addMountPointDirectory($view, $path) { - $dir = ''; - foreach ( explode('/', $path) as $pathPart) { - $dir = $dir.'/'.$pathPart; - if ( !$view->file_exists($dir)) { - $view->mkdir($dir); - } - } - } - - - /** * Add a mount point to the filesystem * @param string Mount point * @param string Backend class @@ -213,36 +209,11 @@ class OC_Mount_Config { if ($isPersonal) { // Verify that the mount point applies for the current user // Prevent non-admin users from mounting local storage - if ($applicable != OCP\User::getUser() || $class == 'OC_Filestorage_Local') { + if ($applicable != OCP\User::getUser() || $class == '\OC\Files\Storage\Local') { return false; } - $view = new OC_FilesystemView('/'.OCP\User::getUser().'/files'); - self::addMountPointDirectory($view, ltrim($mountPoint, '/')); $mountPoint = '/'.$applicable.'/files/'.ltrim($mountPoint, '/'); } else { - $view = new OC_FilesystemView('/'); - switch ($mountType) { - case 'user': - if ($applicable == "all") { - $users = OCP\User::getUsers(); - foreach ( $users as $user ) { - $path = $user.'/files/'.ltrim($mountPoint, '/'); - self::addMountPointDirectory($view, $path); - } - } else { - $path = $applicable.'/files/'.ltrim($mountPoint, '/'); - self::addMountPointDirectory($view, $path); - } - break; - case 'group' : - $groupMembers = OC_Group::usersInGroups(array($applicable)); - foreach ( $groupMembers as $user ) { - $path = $user.'/files/'.ltrim($mountPoint, '/'); - self::addMountPointDirectory($view, $path); - } - break; - } - $mountPoint = '/$user/files/'.ltrim($mountPoint, '/'); } $mount = array($applicable => array($mountPoint => array('class' => $class, 'options' => $classOptions))); diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php index 33ca14cab15..9223b4ca87b 100755 --- a/apps/files_external/lib/dropbox.php +++ b/apps/files_external/lib/dropbox.php @@ -20,12 +20,15 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ +namespace OC\Files\Storage; + require_once 'Dropbox/autoload.php'; -class OC_Filestorage_Dropbox extends OC_Filestorage_Common { +class Dropbox extends \OC\Files\Storage\Common { private $dropbox; private $root; + private $id; private $metaData = array(); private static $tempFiles = array(); @@ -37,13 +40,14 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { && isset($params['token']) && isset($params['token_secret']) ) { + $this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $params['root']; $this->root=isset($params['root'])?$params['root']:''; - $oauth = new Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']); + $oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']); $oauth->setToken($params['token'], $params['token_secret']); - $this->dropbox = new Dropbox_API($oauth, 'dropbox'); + $this->dropbox = new \Dropbox_API($oauth, 'dropbox'); $this->mkdir(''); } else { - throw new Exception('Creating OC_Filestorage_Dropbox storage failed'); + throw new \Exception('Creating \OC\Files\Storage\Dropbox storage failed'); } } @@ -55,8 +59,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { if ($list) { try { $response = $this->dropbox->getMetaData($path); - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } if ($response && isset($response['contents'])) { @@ -76,21 +80,25 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { $response = $this->dropbox->getMetaData($path, 'false'); $this->metaData[$path] = $response; return $response; - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } } } } + public function getId(){ + return $this->id; + } + public function mkdir($path) { $path = $this->root.$path; try { $this->dropbox->createFolder($path); return true; - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } } @@ -106,7 +114,7 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { foreach ($contents as $file) { $files[] = basename($file['path']); } - OC_FakeDirStream::$dirs['dropbox'.$path] = $files; + \OC_FakeDirStream::$dirs['dropbox'.$path] = $files; return opendir('fakedir://dropbox'.$path); } return false; @@ -118,7 +126,6 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { $stat['size'] = $metaData['bytes']; $stat['atime'] = time(); $stat['mtime'] = (isset($metaData['modified'])) ? strtotime($metaData['modified']) : time(); - $stat['ctime'] = $stat['mtime']; return $stat; } return false; @@ -163,8 +170,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { try { $this->dropbox->delete($path); return true; - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } } @@ -175,8 +182,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { try { $this->dropbox->move($path1, $path2); return true; - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } } @@ -187,8 +194,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { try { $this->dropbox->copy($path1, $path2); return true; - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } } @@ -198,13 +205,13 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { switch ($mode) { case 'r': case 'rb': - $tmpFile = OC_Helper::tmpFile(); + $tmpFile = \OC_Helper::tmpFile(); try { $data = $this->dropbox->getFile($path); file_put_contents($tmpFile, $data); return fopen($tmpFile, 'r'); - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } case 'w': @@ -224,8 +231,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { } else { $ext = ''; } - $tmpFile = OC_Helper::tmpFile($ext); - OC_CloseStreamWrapper::$callBacks[$tmpFile] = array($this, 'writeBack'); + $tmpFile = \OC_Helper::tmpFile($ext); + \OC_CloseStreamWrapper::$callBacks[$tmpFile] = array($this, 'writeBack'); if ($this->file_exists($path)) { $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); @@ -242,8 +249,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { try { $this->dropbox->putFile(self::$tempFiles[$tmpFile], $handle); unlink($tmpFile); - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); } } } @@ -264,8 +271,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { try { $info = $this->dropbox->getAccountInfo(); return $info['quota_info']['quota'] - $info['quota_info']['normal']; - } catch (Exception $exception) { - OCP\Util::writeLog('files_external', $exception->getMessage(), OCP\Util::ERROR); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } } diff --git a/apps/files_external/lib/ftp.php b/apps/files_external/lib/ftp.php index e796ae446bf..973b33fbfd7 100644 --- a/apps/files_external/lib/ftp.php +++ b/apps/files_external/lib/ftp.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class OC_FileStorage_FTP extends OC_FileStorage_StreamWrapper{ +namespace OC\Files\Storage; + +class FTP extends \OC\Files\Storage\StreamWrapper{ private $password; private $user; private $host; @@ -38,9 +40,13 @@ class OC_FileStorage_FTP extends OC_FileStorage_StreamWrapper{ } } + public function getId(){ + return 'ftp::' . $this->user . '@' . $this->host . '/' . $this->root; + } + /** * construct the ftp url - * @param string path + * @param string $path * @return string */ public function constructUrl($path) { @@ -51,7 +57,8 @@ class OC_FileStorage_FTP extends OC_FileStorage_StreamWrapper{ $url.='://'.$this->user.':'.$this->password.'@'.$this->host.$this->root.$path; return $url; } - public function fopen($path, $mode) { + public function fopen($path,$mode) { + $this->init(); switch($mode) { case 'r': case 'rb': @@ -61,7 +68,7 @@ class OC_FileStorage_FTP extends OC_FileStorage_StreamWrapper{ case 'ab': //these are supported by the wrapper $context = stream_context_create(array('ftp' => array('overwrite' => true))); - return fopen($this->constructUrl($path), $mode, false, $context); + return fopen($this->constructUrl($path),$mode, false,$context); case 'r+': case 'w+': case 'wb+': @@ -82,11 +89,13 @@ class OC_FileStorage_FTP extends OC_FileStorage_StreamWrapper{ $this->getFile($path, $tmpFile); } self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); + return fopen('close://'.$tmpFile,$mode); } + return false; } public function writeBack($tmpFile) { + $this->init(); if (isset(self::$tempFiles[$tmpFile])) { $this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]); unlink($tmpFile); diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php index c836a5a07c0..4c485773e7b 100644 --- a/apps/files_external/lib/google.php +++ b/apps/files_external/lib/google.php @@ -20,14 +20,17 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ +namespace OC\Files\Storage; + require_once 'Google/common.inc.php'; -class OC_Filestorage_Google extends OC_Filestorage_Common { +class Google extends \OC\Files\Storage\Common { private $consumer; private $oauth_token; private $sig_method; private $entries; + private $id; private static $tempFiles = array(); @@ -38,12 +41,13 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { ) { $consumer_key = isset($params['consumer_key']) ? $params['consumer_key'] : 'anonymous'; $consumer_secret = isset($params['consumer_secret']) ? $params['consumer_secret'] : 'anonymous'; - $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); - $this->oauth_token = new OAuthToken($params['token'], $params['token_secret']); - $this->sig_method = new OAuthSignatureMethod_HMAC_SHA1(); + $this->id = 'google::' . $params['token']; + $this->consumer = new \OAuthConsumer($consumer_key, $consumer_secret); + $this->oauth_token = new \OAuthToken($params['token'], $params['token_secret']); + $this->sig_method = new \OAuthSignatureMethod_HMAC_SHA1(); $this->entries = array(); } else { - throw new Exception('Creating OC_Filestorage_Google storage failed'); + throw new \Exception('Creating \OC\Files\Storage\Google storage failed'); } } @@ -68,7 +72,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $tempStr .= '&' . urlencode($key) . '=' . urlencode($value); } $uri = preg_replace('/&/', '?', $tempStr, 1); - $request = OAuthRequest::from_consumer_and_token($this->consumer, + $request = \OAuthRequest::from_consumer_and_token($this->consumer, $this->oauth_token, $httpMethod, $uri, @@ -110,7 +114,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } if ($isDownload) { - $tmpFile = OC_Helper::tmpFile(); + $tmpFile = \OC_Helper::tmpFile(); $handle = fopen($tmpFile, 'w'); curl_setopt($curl, CURLOPT_FILE, $handle); } @@ -139,7 +143,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { private function getFeed($feedUri, $httpMethod, $postData = null) { $result = $this->sendRequest($feedUri, $httpMethod, $postData); if ($result) { - $dom = new DOMDocument(); + $dom = new \DOMDocument(); $dom->loadXML($result); return $dom; } @@ -194,6 +198,9 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { } } + public function getId(){ + return $this->id; + } public function mkdir($path) { $collection = dirname($path); @@ -266,7 +273,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $this->entries[$name] = $entry; } } - OC_FakeDirStream::$dirs['google'.$path] = $files; + \OC_FakeDirStream::$dirs['google'.$path] = $files; return opendir('fakedir://google'.$path); } @@ -287,7 +294,6 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { //$stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', // 'lastViewed')->item(0)->nodeValue); $stat['mtime'] = strtotime($entry->getElementsByTagName('updated')->item(0)->nodeValue); - $stat['ctime'] = strtotime($entry->getElementsByTagName('published')->item(0)->nodeValue); } } if (isset($stat)) { @@ -443,8 +449,8 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { } else { $ext = ''; } - $tmpFile = OC_Helper::tmpFile($ext); - OC_CloseStreamWrapper::$callBacks[$tmpFile] = array($this, 'writeBack'); + $tmpFile = \OC_Helper::tmpFile($ext); + \OC_CloseStreamWrapper::$callBacks[$tmpFile] = array($this, 'writeBack'); if ($this->file_exists($path)) { $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); @@ -482,7 +488,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { } if (isset($uploadUri) && $handle = fopen($path, 'r')) { $uploadUri .= '?convert=false'; - $mimetype = OC_Helper::getMimeType($path); + $mimetype = \OC_Helper::getMimeType($path); $size = filesize($path); $headers = array('X-Upload-Content-Type: ' => $mimetype, 'X-Upload-Content-Length: ' => $size); $postData = '<?xml version="1.0" encoding="UTF-8"?>'; @@ -590,4 +596,4 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { } -}
\ No newline at end of file +} diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 071a9cd5f95..96778b0b2e1 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -6,9 +6,11 @@ * See the COPYING-README file. */ +namespace OC\Files\Storage; + require_once 'smb4php/smb.php'; -class OC_FileStorage_SMB extends OC_FileStorage_StreamWrapper{ +class SMB extends \OC\Files\Storage\StreamWrapper{ private $password; private $user; private $host; @@ -30,14 +32,13 @@ class OC_FileStorage_SMB extends OC_FileStorage_StreamWrapper{ if ( ! $this->share || $this->share[0]!='/') { $this->share='/'.$this->share; } - if (substr($this->share, -1, 1)=='/') { - $this->share=substr($this->share, 0, -1); + if(substr($this->share, -1, 1)=='/') { + $this->share = substr($this->share,0,-1); } + } - //create the root folder if necesary - if ( ! $this->is_dir('')) { - $this->mkdir(''); - } + public function getId(){ + return 'smb::' . $this->user . '@' . $this->host . '/' . $this->share . '/' . $this->root; } public function constructUrl($path) { @@ -65,11 +66,13 @@ class OC_FileStorage_SMB extends OC_FileStorage_StreamWrapper{ /** * check if a file or folder has been updated since $time + * @param string $path * @param int $time * @return bool */ - public function hasUpdated($path, $time) { - if ( ! $path and $this->root=='/') { + public function hasUpdated($path,$time) { + $this->init(); + if(!$path and $this->root=='/') { // mtime doesn't work for shares, but giving the nature of the backend, // doing a full update is still just fast enough return true; diff --git a/apps/files_external/lib/streamwrapper.php b/apps/files_external/lib/streamwrapper.php index a386e333995..7c3ddcf8a2c 100644 --- a/apps/files_external/lib/streamwrapper.php +++ b/apps/files_external/lib/streamwrapper.php @@ -6,16 +6,33 @@ * See the COPYING-README file. */ +namespace OC\Files\Storage; + +abstract class StreamWrapper extends \OC\Files\Storage\Common{ + private $ready = false; + + protected function init(){ + if($this->ready){ + return; + } + $this->ready = true; + + //create the root folder if necesary + if(!$this->is_dir('')) { + $this->mkdir(''); + } + } -abstract class OC_FileStorage_StreamWrapper extends OC_Filestorage_Common{ abstract public function constructUrl($path); public function mkdir($path) { + $this->init(); return mkdir($this->constructUrl($path)); } public function rmdir($path) { - if ($this->file_exists($path)) { + $this->init(); + if($this->file_exists($path)) { $succes = rmdir($this->constructUrl($path)); clearstatcache(); return $succes; @@ -25,10 +42,12 @@ abstract class OC_FileStorage_StreamWrapper extends OC_Filestorage_Common{ } public function opendir($path) { + $this->init(); return opendir($this->constructUrl($path)); } public function filetype($path) { + $this->init(); return filetype($this->constructUrl($path)); } @@ -41,46 +60,54 @@ abstract class OC_FileStorage_StreamWrapper extends OC_Filestorage_Common{ } public function file_exists($path) { + $this->init(); return file_exists($this->constructUrl($path)); } public function unlink($path) { + $this->init(); $succes = unlink($this->constructUrl($path)); clearstatcache(); return $succes; } - public function fopen($path, $mode) { - return fopen($this->constructUrl($path), $mode); + public function fopen($path,$mode) { + $this->init(); + return fopen($this->constructUrl($path),$mode); } public function free_space($path) { return 0; } - public function touch($path, $mtime = null) { - if (is_null($mtime)) { - $fh = $this->fopen($path, 'a'); - fwrite($fh, ''); + public function touch($path,$mtime=null) { + $this->init(); + if(is_null($mtime)) { + $fh = $this->fopen($path,'a'); + fwrite($fh,''); fclose($fh); } else { return false;//not supported } } - public function getFile($path, $target) { - return copy($this->constructUrl($path), $target); + public function getFile($path,$target) { + $this->init(); + return copy($this->constructUrl($path),$target); } - public function uploadFile($path, $target) { - return copy($path, $this->constructUrl($target)); + public function uploadFile($path,$target) { + $this->init(); + return copy($path,$this->constructUrl($target)); } - public function rename($path1, $path2) { - return rename($this->constructUrl($path1), $this->constructUrl($path2)); + public function rename($path1,$path2) { + $this->init(); + return rename($this->constructUrl($path1),$this->constructUrl($path2)); } public function stat($path) { + $this->init(); return stat($this->constructUrl($path)); } diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index a071dfdbb03..bd1f4c572a6 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -6,24 +6,28 @@ * See the COPYING-README file. */ +namespace OC\Files\Storage; + require_once 'php-cloudfiles/cloudfiles.php'; -class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ +class SWIFT extends \OC\Files\Storage\Common{ + private $id; private $host; private $root; private $user; private $token; private $secure; + private $ready = false; /** - * @var CF_Authentication auth + * @var \CF_Authentication auth */ private $auth; /** - * @var CF_Connection conn + * @var \CF_Connection conn */ private $conn; /** - * @var CF_Container rootContainer + * @var \CF_Container rootContainer */ private $rootContainer; @@ -35,18 +39,18 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * translate directory path to container name - * @param string path + * @param string $path * @return string */ private function getContainerName($path) { - $path=trim(trim($this->root, '/')."/".$path, '/.'); + $path=trim(trim($this->root, '/') . "/".$path, '/.'); return str_replace('/', '\\', $path); } /** * get container by path - * @param string path - * @return CF_Container + * @param string $path + * @return \CF_Container */ private function getContainer($path) { if ($path=='' or $path=='/') { @@ -59,15 +63,15 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ $container=$this->conn->get_container($this->getContainerName($path)); $this->containers[$path]=$container; return $container; - } catch(NoSuchContainerException $e) { + } catch(\NoSuchContainerException $e) { return null; } } /** * create container - * @param string path - * @return CF_Container + * @param string $path + * @return \CF_Container */ private function createContainer($path) { if ($path=='' or $path=='/' or $path=='.') { @@ -89,8 +93,8 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * get object by path - * @param string path - * @return CF_Object + * @param string $path + * @return \CF_Object */ private function getObject($path) { if (isset($this->objects[$path])) { @@ -107,7 +111,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ $obj=$container->get_object(basename($path)); $this->objects[$path]=$obj; return $obj; - } catch(NoSuchObjectException $e) { + } catch(\NoSuchObjectException $e) { return null; } } @@ -132,8 +136,8 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * create object - * @param string path - * @return CF_Object + * @param string $path + * @return \CF_Object */ private function createObject($path) { $container=$this->getContainer(dirname($path)); @@ -154,7 +158,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * check if container for path exists - * @param string path + * @param string $path * @return bool */ private function containerExists($path) { @@ -163,15 +167,15 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * get the list of emulated sub containers - * @param CF_Container container + * @param \CF_Container $container * @return array */ private function getSubContainers($container) { - $tmpFile=OCP\Files::tmpFile(); + $tmpFile=\OCP\Files::tmpFile(); $obj=$this->getSubContainerFile($container); try { $obj->save_to_filename($tmpFile); - } catch(Exception $e) { + } catch(\Exception $e) { return array(); } $obj->save_to_filename($tmpFile); @@ -185,15 +189,15 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * add an emulated sub container - * @param CF_Container container - * @param string name + * @param \CF_Container $container + * @param string $name * @return bool */ private function addSubContainer($container, $name) { if ( ! $name) { return false; } - $tmpFile=OCP\Files::tmpFile(); + $tmpFile=\OCP\Files::tmpFile(); $obj=$this->getSubContainerFile($container); try { $obj->save_to_filename($tmpFile); @@ -201,16 +205,15 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ foreach ($containers as &$sub) { $sub=trim($sub); } - if (array_search($name, $containers)!==false) { + if(array_search($name, $containers) !== false) { unlink($tmpFile); return false; } else { $fh=fopen($tmpFile, 'a'); - fwrite($fh, $name."\n"); + fwrite($fh,$name . "\n"); } - } catch(Exception $e) { - $containers=array(); - file_put_contents($tmpFile, $name."\n"); + } catch(\Exception $e) { + file_put_contents($tmpFile, $name . "\n"); } $obj->load_from_filename($tmpFile); @@ -220,20 +223,20 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * remove an emulated sub container - * @param CF_Container container - * @param string name + * @param \CF_Container $container + * @param string $name * @return bool */ private function removeSubContainer($container, $name) { if ( ! $name) { return false; } - $tmpFile=OCP\Files::tmpFile(); + $tmpFile=\OCP\Files::tmpFile(); $obj=$this->getSubContainerFile($container); try { $obj->save_to_filename($tmpFile); $containers=file($tmpFile); - } catch (Exception $e) { + } catch (\Exception $e) { return false; } foreach ($containers as &$sub) { @@ -255,8 +258,8 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * ensure a subcontainer file exists and return it's object - * @param CF_Container container - * @return CF_Object + * @param \CF_Container $container + * @return \CF_Object */ private function getSubContainerFile($container) { try { @@ -283,10 +286,19 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ if ( ! $this->root || $this->root[0]!='/') { $this->root='/'.$this->root; } - $this->auth = new CF_Authentication($this->user, $this->token, null, $this->host); + + } + + private function init(){ + if($this->ready){ + return; + } + $this->ready = true; + + $this->auth = new \CF_Authentication($this->user, $this->token, null, $this->host); $this->auth->authenticate(); - $this->conn = new CF_Connection($this->auth); + $this->conn = new \CF_Connection($this->auth); if ( ! $this->containerExists('/')) { $this->rootContainer=$this->createContainer('/'); @@ -295,8 +307,13 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } } + public function getId(){ + return $this->id; + } + public function mkdir($path) { + $this->init(); if ($this->containerExists($path)) { return false; } else { @@ -306,7 +323,8 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function rmdir($path) { - if ( ! $this->containerExists($path)) { + $this->init(); + if (!$this->containerExists($path)) { return false; } else { $this->emptyContainer($path); @@ -343,6 +361,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function opendir($path) { + $this->init(); $container=$this->getContainer($path); $files=$this->getObjects($container); $i=array_search(self::SUBCONTAINER_FILE, $files); @@ -352,11 +371,12 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ $subContainers=$this->getSubContainers($container); $files=array_merge($files, $subContainers); $id=$this->getContainerName($path); - OC_FakeDirStream::$dirs[$id]=$files; + \OC_FakeDirStream::$dirs[$id]=$files; return opendir('fakedir://'.$id); } public function filetype($path) { + $this->init(); if ($this->containerExists($path)) { return 'dir'; } else { @@ -373,6 +393,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function file_exists($path) { + $this->init(); if ($this->is_dir($path)) { return true; } else { @@ -381,6 +402,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function file_get_contents($path) { + $this->init(); $obj=$this->getObject($path); if (is_null($obj)) { return false; @@ -389,6 +411,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function file_put_contents($path, $content) { + $this->init(); $obj=$this->getObject($path); if (is_null($obj)) { $container=$this->getContainer(dirname($path)); @@ -402,6 +425,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function unlink($path) { + $this->init(); if ($this->containerExists($path)) { return $this->rmdir($path); } @@ -415,6 +439,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function fopen($path, $mode) { + $this->init(); switch($mode) { case 'r': case 'rb': @@ -458,6 +483,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function touch($path, $mtime=null) { + $this->init(); $obj=$this->getObject($path); if (is_null($obj)) { return false; @@ -472,6 +498,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function rename($path1, $path2) { + $this->init(); $sourceContainer=$this->getContainer(dirname($path1)); $targetContainer=$this->getContainer(dirname($path2)); $result=$sourceContainer->move_object_to(basename($path1), $targetContainer, basename($path2)); @@ -484,6 +511,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function copy($path1, $path2) { + $this->init(); $sourceContainer=$this->getContainer(dirname($path1)); $targetContainer=$this->getContainer(dirname($path2)); $result=$sourceContainer->copy_object_to(basename($path1), $targetContainer, basename($path2)); @@ -495,6 +523,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } public function stat($path) { + $this->init(); $container=$this->getContainer($path); if ( ! is_null($container)) { return array( @@ -523,17 +552,19 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } private function getTmpFile($path) { + $this->init(); $obj=$this->getObject($path); if ( ! is_null($obj)) { - $tmpFile=OCP\Files::tmpFile(); + $tmpFile=\OCP\Files::tmpFile(); $obj->save_to_filename($tmpFile); return $tmpFile; } else { - return OCP\Files::tmpFile(); + return \OCP\Files::tmpFile(); } } private function fromTmpFile($tmpFile, $path) { + $this->init(); $obj=$this->getObject($path); if (is_null($obj)) { $obj=$this->createObject($path); @@ -544,7 +575,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ /** * remove custom mtime metadata - * @param CF_Object obj + * @param \CF_Object $obj */ private function resetMTime($obj) { if (isset($obj->metadata['Mtime'])) { diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index 920aefc12de..6d43a03058a 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -6,14 +6,17 @@ * See the COPYING-README file. */ -class OC_FileStorage_DAV extends OC_Filestorage_Common{ +namespace OC\Files\Storage; + +class DAV extends \OC\Files\Storage\Common{ private $password; private $user; private $host; private $secure; private $root; + private $ready; /** - * @var Sabre_DAV_Client + * @var \Sabre_DAV_Client */ private $client; @@ -43,6 +46,13 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ if (substr($this->root, -1, 1)!='/') { $this->root.='/'; } + } + + private function init(){ + if($this->ready){ + return; + } + $this->ready = true; $settings = array( 'baseUri' => $this->createBaseUri(), @@ -50,7 +60,7 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ 'password' => $this->password, ); - $this->client = new Sabre_DAV_Client($settings); + $this->client = new \Sabre_DAV_Client($settings); $caview = \OCP\Files::getStorage('files_external'); if ($caview) { @@ -63,6 +73,10 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ $this->mkdir(''); } + public function getId(){ + return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root; + } + private function createBaseUri() { $baseUri='http'; if ($this->secure) { @@ -73,40 +87,44 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ } public function mkdir($path) { + $this->init(); $path=$this->cleanPath($path); return $this->simpleResponse('MKCOL', $path, null, 201); } public function rmdir($path) { + $this->init(); $path=$this->cleanPath($path); return $this->simpleResponse('DELETE', $path, null, 204); } public function opendir($path) { + $this->init(); $path=$this->cleanPath($path); try { $response=$this->client->propfind($path, array(), 1); $id=md5('webdav'.$this->root.$path); - OC_FakeDirStream::$dirs[$id]=array(); + \OC_FakeDirStream::$dirs[$id]=array(); $files=array_keys($response); array_shift($files);//the first entry is the current directory foreach ($files as $file) { $file = urldecode(basename($file)); - OC_FakeDirStream::$dirs[$id][]=$file; + \OC_FakeDirStream::$dirs[$id][]=$file; } return opendir('fakedir://'.$id); - } catch(Exception $e) { + } catch(\Exception $e) { return false; } } public function filetype($path) { + $this->init(); $path=$this->cleanPath($path); try { $response=$this->client->propfind($path, array('{DAV:}resourcetype')); $responseType=$response["{DAV:}resourcetype"]->resourceType; return (count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; - } catch(Exception $e) { + } catch(\Exception $e) { error_log($e->getMessage()); \OCP\Util::writeLog("webdav client", \OCP\Util::sanitizeHTML($e->getMessage()), \OCP\Util::ERROR); return false; @@ -122,20 +140,23 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ } public function file_exists($path) { + $this->init(); $path=$this->cleanPath($path); try { $this->client->propfind($path, array('{DAV:}resourcetype')); return true;//no 404 exception - } catch(Exception $e) { + } catch(\Exception $e) { return false; } } public function unlink($path) { - return $this->simpleResponse('DELETE', $path, null, 204); + $this->init(); + return $this->simpleResponse('DELETE', $path, null ,204); } - public function fopen($path, $mode) { + public function fopen($path,$mode) { + $this->init(); $path=$this->cleanPath($path); switch($mode) { case 'r': @@ -172,9 +193,9 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ } else { $ext=''; } - $tmpFile=OCP\Files::tmpFile($ext); - OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack'); - if ($this->file_exists($path)) { + $tmpFile = \OCP\Files::tmpFile($ext); + \OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack'); + if($this->file_exists($path)) { $this->getFile($path, $tmpFile); } self::$tempFiles[$tmpFile]=$path; @@ -190,6 +211,7 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ } public function free_space($path) { + $this->init(); $path=$this->cleanPath($path); try { $response=$this->client->propfind($path, array('{DAV:}quota-available-bytes')); @@ -198,12 +220,13 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ } else { return 0; } - } catch(Exception $e) { + } catch(\Exception $e) { return 0; } } public function touch($path, $mtime=null) { + $this->init(); if (is_null($mtime)) { $mtime=time(); } @@ -211,12 +234,14 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ $this->client->proppatch($path, array('{DAV:}lastmodified' => $mtime)); } - public function getFile($path, $target) { - $source=$this->fopen($path, 'r'); - file_put_contents($target, $source); + public function getFile($path,$target) { + $this->init(); + $source=$this->fopen($path,'r'); + file_put_contents($target,$source); } - public function uploadFile($path, $target) { + public function uploadFile($path,$target) { + $this->init(); $source=fopen($path, 'r'); $curl = curl_init(); @@ -230,47 +255,46 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ curl_close ($curl); } - public function rename($path1, $path2) { + public function rename($path1,$path2) { + $this->init(); $path1=$this->cleanPath($path1); $path2=$this->root.$this->cleanPath($path2); try { $this->client->request('MOVE', $path1, null, array('Destination'=>$path2)); return true; - } catch(Exception $e) { - echo $e; - echo 'fail'; + } catch(\Exception $e) { return false; } } - public function copy($path1, $path2) { + public function copy($path1,$path2) { + $this->init(); $path1=$this->cleanPath($path1); $path2=$this->root.$this->cleanPath($path2); try { $this->client->request('COPY', $path1, null, array('Destination'=>$path2)); return true; - } catch(Exception $e) { - echo $e; - echo 'fail'; + } catch(\Exception $e) { return false; } } public function stat($path) { + $this->init(); $path=$this->cleanPath($path); try { $response=$this->client->propfind($path, array('{DAV:}getlastmodified', '{DAV:}getcontentlength')); return array( 'mtime'=>strtotime($response['{DAV:}getlastmodified']), 'size'=>(int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0, - 'ctime'=>-1, ); - } catch(Exception $e) { + } catch(\Exception $e) { return array(); } } public function getMimeType($path) { + $this->init(); $path=$this->cleanPath($path); try { $response=$this->client->propfind($path, array('{DAV:}getcontenttype', '{DAV:}resourcetype')); @@ -283,7 +307,7 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ } else { return false; } - } catch(Exception $e) { + } catch(\Exception $e) { return false; } } @@ -296,12 +320,12 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ } } - private function simpleResponse($method, $path, $body, $expected) { + private function simpleResponse($method,$path,$body,$expected) { $path=$this->cleanPath($path); try { $response=$this->client->request($method, $path, $body); return $response['statusCode']==$expected; - } catch(Exception $e) { + } catch(\Exception $e) { return false; } } diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php index 4215b28787e..268d1880232 100755 --- a/apps/files_external/personal.php +++ b/apps/files_external/personal.php @@ -24,7 +24,7 @@ OCP\Util::addScript('files_external', 'settings'); OCP\Util::addStyle('files_external', 'settings'); $backends = OC_Mount_Config::getBackends(); // Remove local storage -unset($backends['OC_Filestorage_Local']); +unset($backends['\OC\Files\Storage\Local']); $tmpl = new OCP\Template('files_external', 'settings'); $tmpl->assign('isAdminPage', false, false); $tmpl->assign('mounts', OC_Mount_Config::getPersonalMountPoints()); diff --git a/apps/files_external/tests/amazons3.php b/apps/files_external/tests/amazons3.php index 39f96fe8e55..6b3a942b5ba 100644 --- a/apps/files_external/tests/amazons3.php +++ b/apps/files_external/tests/amazons3.php @@ -20,7 +20,9 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ -class Test_Filestorage_AmazonS3 extends Test_FileStorage { +namespace Test\Files\Storage; + +class AmazonS3 extends Storage { private $config; private $id; @@ -32,12 +34,12 @@ class Test_Filestorage_AmazonS3 extends Test_FileStorage { $this->markTestSkipped('AmazonS3 backend not configured'); } $this->config['amazons3']['bucket'] = $id; // Make sure we have a new empty bucket to work in - $this->instance = new OC_Filestorage_AmazonS3($this->config['amazons3']); + $this->instance = new \OC\Files\Storage\AmazonS3($this->config['amazons3']); } public function tearDown() { if ($this->instance) { - $s3 = new AmazonS3(array('key' => $this->config['amazons3']['key'], + $s3 = new \AmazonS3(array('key' => $this->config['amazons3']['key'], 'secret' => $this->config['amazons3']['secret'])); if ($s3->delete_all_objects($this->id)) { $s3->delete_bucket($this->id); diff --git a/apps/files_external/tests/config.php b/apps/files_external/tests/config.php index ff16b1c1d8a..65127175ad7 100644 --- a/apps/files_external/tests/config.php +++ b/apps/files_external/tests/config.php @@ -8,7 +8,7 @@ return array( 'root'=>'/test', ), 'webdav'=>array( - 'run'=>false, + 'run'=>true, 'host'=>'localhost', 'user'=>'test', 'password'=>'test', @@ -30,7 +30,7 @@ return array( 'root'=>'/', ), 'smb'=>array( - 'run'=>false, + 'run'=>true, 'user'=>'test', 'password'=>'test', 'host'=>'localhost', diff --git a/apps/files_external/tests/dropbox.php b/apps/files_external/tests/dropbox.php index 304cb3ca38c..e4e598b06b0 100644 --- a/apps/files_external/tests/dropbox.php +++ b/apps/files_external/tests/dropbox.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class Test_Filestorage_Dropbox extends Test_FileStorage { +namespace Test\Files\Storage; + +class Dropbox extends Storage { private $config; public function setUp() { @@ -16,7 +18,7 @@ class Test_Filestorage_Dropbox extends Test_FileStorage { $this->markTestSkipped('Dropbox backend not configured'); } $this->config['dropbox']['root'] .= '/' . $id; //make sure we have an new empty folder to work in - $this->instance = new OC_Filestorage_Dropbox($this->config['dropbox']); + $this->instance = new \OC\Files\Storage\Dropbox($this->config['dropbox']); } public function tearDown() { diff --git a/apps/files_external/tests/ftp.php b/apps/files_external/tests/ftp.php index d0404b5f34c..9998a479bf8 100644 --- a/apps/files_external/tests/ftp.php +++ b/apps/files_external/tests/ftp.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class Test_Filestorage_FTP extends Test_FileStorage { +namespace Test\Files\Storage; + +class FTP extends Storage { private $config; public function setUp() { @@ -16,12 +18,12 @@ class Test_Filestorage_FTP extends Test_FileStorage { $this->markTestSkipped('FTP backend not configured'); } $this->config['ftp']['root'] .= '/' . $id; //make sure we have an new empty folder to work in - $this->instance = new OC_Filestorage_FTP($this->config['ftp']); + $this->instance = new \OC\Files\Storage\FTP($this->config['ftp']); } public function tearDown() { if ($this->instance) { - OCP\Files::rmdirr($this->instance->constructUrl('')); + \OCP\Files::rmdirr($this->instance->constructUrl('')); } } diff --git a/apps/files_external/tests/google.php b/apps/files_external/tests/google.php index 379bf992ff5..f344163a8b9 100644 --- a/apps/files_external/tests/google.php +++ b/apps/files_external/tests/google.php @@ -20,8 +20,9 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ -class Test_Filestorage_Google extends Test_FileStorage { +namespace Test\Files\Storage; +class Google extends Storage { private $config; public function setUp() { @@ -31,7 +32,7 @@ class Test_Filestorage_Google extends Test_FileStorage { $this->markTestSkipped('Google backend not configured'); } $this->config['google']['root'] .= '/' . $id; //make sure we have an new empty folder to work in - $this->instance = new OC_Filestorage_Google($this->config['google']); + $this->instance = new \OC\Files\Storage\Google($this->config['google']); } public function tearDown() { diff --git a/apps/files_external/tests/smb.php b/apps/files_external/tests/smb.php index 2d6268ef269..be3ea5a8308 100644 --- a/apps/files_external/tests/smb.php +++ b/apps/files_external/tests/smb.php @@ -6,7 +6,10 @@ * See the COPYING-README file. */ -class Test_Filestorage_SMB extends Test_FileStorage { +namespace Test\Files\Storage; + +class SMB extends Storage { + private $config; public function setUp() { @@ -16,12 +19,12 @@ class Test_Filestorage_SMB extends Test_FileStorage { $this->markTestSkipped('Samba backend not configured'); } $this->config['smb']['root'] .= $id; //make sure we have an new empty folder to work in - $this->instance = new OC_Filestorage_SMB($this->config['smb']); + $this->instance = new \OC\Files\Storage\SMB($this->config['smb']); } public function tearDown() { if ($this->instance) { - OCP\Files::rmdirr($this->instance->constructUrl('')); + \OCP\Files::rmdirr($this->instance->constructUrl('')); } } } diff --git a/apps/files_external/tests/swift.php b/apps/files_external/tests/swift.php index 8b25db50996..5c782840246 100644 --- a/apps/files_external/tests/swift.php +++ b/apps/files_external/tests/swift.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class Test_Filestorage_SWIFT extends Test_FileStorage { +namespace Test\Files\Storage; + +class SWIFT extends Storage { private $config; public function setUp() { @@ -16,7 +18,7 @@ class Test_Filestorage_SWIFT extends Test_FileStorage { $this->markTestSkipped('OpenStack SWIFT backend not configured'); } $this->config['swift']['root'] .= '/' . $id; //make sure we have an new empty folder to work in - $this->instance = new OC_Filestorage_SWIFT($this->config['swift']); + $this->instance = new \OC\Files\Storage\SWIFT($this->config['swift']); } diff --git a/apps/files_external/tests/webdav.php b/apps/files_external/tests/webdav.php index dd938a0c93a..1702898045e 100644 --- a/apps/files_external/tests/webdav.php +++ b/apps/files_external/tests/webdav.php @@ -6,7 +6,10 @@ * See the COPYING-README file. */ -class Test_Filestorage_DAV extends Test_FileStorage { +namespace Test\Files\Storage; + +class DAV extends Storage { + private $config; public function setUp() { @@ -16,7 +19,7 @@ class Test_Filestorage_DAV extends Test_FileStorage { $this->markTestSkipped('WebDAV backend not configured'); } $this->config['webdav']['root'] .= '/' . $id; //make sure we have an new empty folder to work in - $this->instance = new OC_Filestorage_DAV($this->config['webdav']); + $this->instance = new \OC\Files\Storage\DAV($this->config['webdav']); } public function tearDown() { diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index 0104d0d017f..d3e05cc62d8 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -2,8 +2,11 @@ OC::$CLASSPATH['OC_Share_Backend_File'] = "apps/files_sharing/lib/share/file.php"; OC::$CLASSPATH['OC_Share_Backend_Folder'] = 'apps/files_sharing/lib/share/folder.php'; -OC::$CLASSPATH['OC_Filestorage_Shared'] = "apps/files_sharing/lib/sharedstorage.php"; -OCP\Util::connectHook('OC_Filesystem', 'setup', 'OC_Filestorage_Shared', 'setup'); +OC::$CLASSPATH['OC\Files\Storage\Shared'] = "apps/files_sharing/lib/sharedstorage.php"; +OC::$CLASSPATH['OC\Files\Cache\Shared_Cache'] = 'apps/files_sharing/lib/cache.php'; +OC::$CLASSPATH['OC\Files\Cache\Shared_Permissions'] = 'apps/files_sharing/lib/permissions.php'; +OC::$CLASSPATH['OC\Files\Cache\Shared_Watcher'] = 'apps/files_sharing/lib/watcher.php'; +OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); OCP\Share::registerBackend('file', 'OC_Share_Backend_File'); OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file'); -OCP\Util::addScript('files_sharing', 'share');
\ No newline at end of file +OCP\Util::addScript('files_sharing', 'share'); diff --git a/apps/files_sharing/appinfo/update.php b/apps/files_sharing/appinfo/update.php index e998626f4a4..1d22b32b503 100644 --- a/apps/files_sharing/appinfo/update.php +++ b/apps/files_sharing/appinfo/update.php @@ -9,10 +9,12 @@ if (version_compare($installedVersion, '0.3', '<')) { OC_User::useBackend(new OC_User_Database()); OC_Group::useBackend(new OC_Group_Database()); OC_App::loadApps(array('authentication')); + $rootView = new \OC\Files\View(''); while ($row = $result->fetchRow()) { - $itemSource = OC_FileCache::getId($row['source'], ''); + $meta = $rootView->getFileInfo($$row['source']); + $itemSource = $meta['fileid']; if ($itemSource != -1) { - $file = OC_FileCache::get($row['source'], ''); + $file = $meta; if ($file['mimetype'] == 'httpd/unix-directory') { $itemType = 'folder'; } else { @@ -68,6 +70,6 @@ if (version_compare($installedVersion, '0.3.3', '<')) { OC_App::loadApps(array('authentication')); $users = OC_User::getUsers(); foreach ($users as $user) { - OC_FileCache::delete('Shared', '/'.$user.'/files/'); +// OC_FileCache::delete('Shared', '/'.$user.'/files/'); } -}
\ No newline at end of file +} diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php new file mode 100644 index 00000000000..0b187a3c3ff --- /dev/null +++ b/apps/files_sharing/lib/cache.php @@ -0,0 +1,257 @@ +<?php +/** +* ownCloud +* +* @author Michael Gapczynski +* @copyright 2012 Michael Gapczynski mtgap@owncloud.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/>. +*/ + +namespace OC\Files\Cache; + +/** + * Metadata cache for shared files + * + * don't use this class directly if you need to get metadata, use \OC\Files\Filesystem::getFileInfo instead + */ +class Shared_Cache extends Cache { + + private $files = array(); + + public function __construct($storage) { + + } + + /** + * @brief Get the source cache of a shared file or folder + * @param string $target Shared target file path + * @return \OC\Files\Cache\Cache + */ + private function getSourceCache($target) { + $source = \OC_Share_Backend_File::getSource($target); + if (isset($source['path'])) { + $source['path'] = '/'.$source['uid_owner'].'/'.$source['path']; + \OC\Files\Filesystem::initMountPoints($source['uid_owner']); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source['path']); + if ($storage) { + $this->files[$target] = $internalPath; + $cache = $storage->getCache(); + $this->storageId = $storage->getId(); + $this->numericId = $cache->getNumericStorageId(); + return $cache; + } + } + return false; + } + + /** + * get the stored metadata of a file or folder + * + * @param string/int $file + * @return array + */ + public function get($file) { + if ($file == '') { + return \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT); + } else if (is_string($file)) { + if ($cache = $this->getSourceCache($file)) { + return $cache->get($this->files[$file]); + } + } else { + $query = \OC_DB::prepare( + 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted` + FROM `*PREFIX*filecache` WHERE `fileid` = ?'); + $result = $query->execute(array($file)); + $data = $result->fetchRow(); + $data['fileid'] = (int)$data['fileid']; + $data['size'] = (int)$data['size']; + $data['mtime'] = (int)$data['mtime']; + $data['encrypted'] = (bool)$data['encrypted']; + $data['mimetype'] = $this->getMimetype($data['mimetype']); + $data['mimepart'] = $this->getMimetype($data['mimepart']); + return $data; + } + return false; + } + + /** + * get the metadata of all files stored in $folder + * + * @param string $folder + * @return array + */ + public function getFolderContents($folder) { + if ($folder == '') { + $files = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS); + foreach ($files as &$file) { + $file['mimetype'] = $this->getMimetype($file['mimetype']); + $file['mimepart'] = $this->getMimetype($file['mimepart']); + } + return $files; + } else { + if ($cache = $this->getSourceCache($folder)) { + return $cache->getFolderContents($this->files[$folder]); + } + } + return false; + } + + /** + * store meta data for a file or folder + * + * @param string $file + * @param array $data + * + * @return int file id + */ + public function put($file, array $data) { + if ($cache = $this->getSourceCache($file)) { + return $cache->put($this->files[$file], $data); + } + return false; + } + + /** + * get the file id for a file + * + * @param string $file + * @return int + */ + public function getId($file) { + if ($cache = $this->getSourceCache($file)) { + return $cache->getId($this->files[$file]); + } + return -1; + } + + /** + * check if a file is available in the cache + * + * @param string $file + * @return bool + */ + public function inCache($file) { + if ($file == '') { + return true; + } + return parent::inCache($file); + } + + /** + * remove a file or folder from the cache + * + * @param string $file + */ + public function remove($file) { + if ($cache = $this->getSourceCache($file)) { + $cache->remove($this->files[$file]); + } + } + + /** + * Move a file or folder in the cache + * + * @param string $source + * @param string $target + */ + public function move($source, $target) { + if ($cache = $this->getSourceCache($source)) { + $targetPath = \OC_Share_Backend_File::getSourcePath(dirname($target)); + if ($targetPath) { + $targetPath .= '/'.basename($target); + $cache->move($this->files[$source], $targetPath); + } + + } + } + + /** + * remove all entries for files that are stored on the storage from the cache + */ + public function clear() { + // Not a valid action for Shared Cache + } + + /** + * @param string $file + * + * @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE + */ + public function getStatus($file) { + if ($file == '') { + return self::COMPLETE; + } + if ($cache = $this->getSourceCache($file)) { + return $cache->getStatus($this->files[$file]); + } + return self::NOT_FOUND; + } + + /** + * search for files matching $pattern + * + * @param string $pattern + * @return array of file data + */ + public function search($pattern) { + // TODO + } + + /** + * search for files by mimetype + * + * @param string $part1 + * @param string $part2 + * @return array + */ + public function searchByMime($mimetype) { + if (strpos($mimetype, '/')) { + $where = '`mimetype` = ?'; + } else { + $where = '`mimepart` = ?'; + } + $ids = $this->getAll(); + $placeholders = join(',', array_fill(0, count($ids), '?')); + $query = \OC_DB::prepare(' + SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted` + FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `fileid` IN = ('.$placeholders.')' + ); + $result = $query->execute(array_merge(array($mimetype), $ids)); + return $result->fetchAll(); + } + + /** + * get the size of a folder and set it in the cache + * + * @param string $path + * @return int + */ + public function calculateFolderSize($path) { + if ($cache = $this->getSourceCache($path)) { + return $cache->calculateFolderSize($this->files[$path]); + } + return 0; + } + + /** + * get all file ids on the files on the storage + * + * @return int[] + */ + public function getAll() { + return \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL); + } + +} diff --git a/apps/files_sharing/lib/permissions.php b/apps/files_sharing/lib/permissions.php new file mode 100644 index 00000000000..2b068ff9350 --- /dev/null +++ b/apps/files_sharing/lib/permissions.php @@ -0,0 +1,85 @@ +<?php +/** +* ownCloud +* +* @author Michael Gapczynski +* @copyright 2012 Michael Gapczynski mtgap@owncloud.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/>. +*/ +namespace OC\Files\Cache; + +class Shared_Permissions extends Permissions { + + /** + * get the permissions for a single file + * + * @param int $fileId + * @param string $user + * @return int (-1 if file no permissions set) + */ + public function get($fileId, $user) { + if ($fileId == -1) { + return \OCP\PERMISSION_READ; + } + $source = \OCP\Share::getItemSharedWithBySource('file', $fileId, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE, null, true); + if ($source) { + return $source['permissions']; + } else { + return -1; + } + } + + /** + * set the permissions of a file + * + * @param int $fileId + * @param string $user + * @param int $permissions + */ + public function set($fileId, $user, $permissions) { + // Not a valid action for Shared Permissions + } + + /** + * get the permissions of multiply files + * + * @param int[] $fileIds + * @param string $user + * @return int[] + */ + public function getMultiple($fileIds, $user) { + if (count($fileIds) === 0) { + return array(); + } + foreach ($fileIds as $fileId) { + $filePermissions[$fileId] = self::get($fileId, $user); + } + return $filePermissions; + } + + /** + * remove the permissions for a file + * + * @param int $fileId + * @param string $user + */ + public function remove($fileId, $user) { + // Not a valid action for Shared Permissions + } + + public function removeMultiple($fileIds, $user) { + // Not a valid action for Shared Permissions + } +} diff --git a/apps/files_sharing/lib/share/file.php b/apps/files_sharing/lib/share/file.php index ac585236831..6d3c55a008f 100644 --- a/apps/files_sharing/lib/share/file.php +++ b/apps/files_sharing/lib/share/file.php @@ -22,16 +22,18 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent { const FORMAT_SHARED_STORAGE = 0; - const FORMAT_FILE_APP = 1; + const FORMAT_GET_FOLDER_CONTENTS = 1; const FORMAT_FILE_APP_ROOT = 2; const FORMAT_OPENDIR = 3; + const FORMAT_GET_ALL = 4; private $path; public function isValidSource($itemSource, $uidOwner) { - $path = OC_FileCache::getPath($itemSource, $uidOwner); - if ($path) { - $this->path = $path; + $query = \OC_DB::prepare('SELECT `name` FROM `*PREFIX*filecache` WHERE `fileid` = ?'); + $result = $query->execute(array($itemSource)); + if ($row = $result->fetchRow()) { + $this->path = $row['name']; return true; } return false; @@ -70,37 +72,21 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent { public function formatItems($items, $format, $parameters = null) { if ($format == self::FORMAT_SHARED_STORAGE) { // Only 1 item should come through for this format call - return array('path' => $items[key($items)]['path'], 'permissions' => $items[key($items)]['permissions']); - } else if ($format == self::FORMAT_FILE_APP) { - if (isset($parameters['mimetype_filter']) && $parameters['mimetype_filter']) { - $mimetype_filter = $parameters['mimetype_filter']; - } + return array('path' => $items[key($items)]['path'], 'permissions' => $items[key($items)]['permissions'], 'uid_owner' => $items[key($items)]['uid_owner']); + } else if ($format == self::FORMAT_GET_FOLDER_CONTENTS) { $files = array(); foreach ($items as $item) { - if (isset($mimetype_filter) - && strpos($item['mimetype'], $mimetype_filter) !== 0 - && $item['mimetype'] != 'httpd/unix-directory') { - continue; - } $file = array(); - $file['id'] = $item['file_source']; + $file['fileid'] = $item['file_source']; + $file['storage'] = $item['storage']; $file['path'] = $item['file_target']; + $file['parent'] = $item['file_parent']; $file['name'] = basename($item['file_target']); - $file['ctime'] = $item['ctime']; - $file['mtime'] = $item['mtime']; $file['mimetype'] = $item['mimetype']; + $file['mimepart'] = $item['mimepart']; $file['size'] = $item['size']; + $file['mtime'] = $item['mtime']; $file['encrypted'] = $item['encrypted']; - $file['versioned'] = $item['versioned']; - $file['directory'] = $parameters['folder']; - $file['type'] = ($item['mimetype'] == 'httpd/unix-directory') ? 'dir' : 'file'; - $file['permissions'] = $item['permissions']; - if ($file['type'] == 'file') { - // Remove Create permission if type is file - $file['permissions'] &= ~OCP\PERMISSION_CREATE; - } - // NOTE: Temporary fix to allow unsharing of files in root of Shared directory - $file['permissions'] |= OCP\PERMISSION_DELETE; $files[] = $file; } return $files; @@ -111,17 +97,48 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent { if ($item['mtime'] > $mtime) { $mtime = $item['mtime']; } - $size += $item['size']; + $size += (int)$item['size']; } - return array(0 => array('id' => -1, 'name' => 'Shared', 'mtime' => $mtime, 'mimetype' => 'httpd/unix-directory', 'size' => $size, 'writable' => false, 'type' => 'dir', 'directory' => '', 'permissions' => OCP\PERMISSION_READ)); + return array('fileid' => -1, 'name' => 'Shared', 'mtime' => $mtime, 'mimetype' => 'httpd/unix-directory', 'size' => $size); } else if ($format == self::FORMAT_OPENDIR) { $files = array(); foreach ($items as $item) { $files[] = basename($item['file_target']); } return $files; + } else if ($format == self::FORMAT_GET_ALL) { + $ids = array(); + foreach ($items as $item) { + $ids[] = $item['file_source']; + } + return $ids; } return array(); } + public static function getSource($target) { + if ($target == '') { + return false; + } + $target = '/'.$target; + $target = rtrim($target, '/'); + $pos = strpos($target, '/', 1); + // Get shared folder name + if ($pos !== false) { + $folder = substr($target, 0, $pos); + $source = \OCP\Share::getItemSharedWith('folder', $folder, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE); + if ($source) { + $source['path'] = $source['path'].substr($target, strlen($folder)); + return $source; + } + } else { + $source = \OCP\Share::getItemSharedWith('file', $target, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE); + if ($source) { + return $source; + } + } + \OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::ERROR); + return false; + } + } diff --git a/apps/files_sharing/lib/share/folder.php b/apps/files_sharing/lib/share/folder.php index d414fcf10fc..11c8c6b1e80 100644 --- a/apps/files_sharing/lib/share/folder.php +++ b/apps/files_sharing/lib/share/folder.php @@ -21,47 +21,26 @@ class OC_Share_Backend_Folder extends OC_Share_Backend_File implements OCP\Share_Backend_Collection { - public function formatItems($items, $format, $parameters = null) { - if ($format == self::FORMAT_SHARED_STORAGE) { - // Only 1 item should come through for this format call - return array('path' => $items[key($items)]['path'], 'permissions' => $items[key($items)]['permissions']); - } else if ($format == self::FORMAT_FILE_APP && isset($parameters['folder'])) { - // Only 1 item should come through for this format call - $folder = $items[key($items)]; - if (isset($parameters['mimetype_filter'])) { - $mimetype_filter = $parameters['mimetype_filter']; - } else { - $mimetype_filter = ''; - } - $path = $folder['path'].substr($parameters['folder'], 7 + strlen($folder['file_target'])); - $files = OC_FileCache::getFolderContent($path, '', $mimetype_filter); - foreach ($files as &$file) { - $file['directory'] = $parameters['folder']; - $file['type'] = ($file['mimetype'] == 'httpd/unix-directory') ? 'dir' : 'file'; - $file['permissions'] = $folder['permissions']; - if ($file['type'] == 'file') { - // Remove Create permission if type is file - $file['permissions'] &= ~OCP\PERMISSION_CREATE; - } - } - return $files; - } - return array(); - } - public function getChildren($itemSource) { $children = array(); $parents = array($itemSource); + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'); + $result = $query->execute(array('httpd/unix-directory')); + if ($row = $result->fetchRow()) { + $mimetype = $row['id']; + } else { + $mimetype = -1; + } while (!empty($parents)) { $parents = "'".implode("','", $parents)."'"; - $query = OC_DB::prepare('SELECT `id`, `name`, `mimetype` FROM `*PREFIX*fscache` WHERE `parent` IN ('.$parents.')'); + $query = OC_DB::prepare('SELECT `fileid`, `name`, `mimetype` FROM `*PREFIX*filecache` WHERE `parent` IN ('.$parents.')'); $result = $query->execute(); $parents = array(); while ($file = $result->fetchRow()) { - $children[] = array('source' => $file['id'], 'file_path' => $file['name']); + $children[] = array('source' => $file['fileid'], 'file_path' => $file['name']); // If a child folder is found look inside it - if ($file['mimetype'] == 'httpd/unix-directory') { - $parents[] = $file['id']; + if ($file['mimetype'] == $mimetype) { + $parents[] = $file['fileid']; } } } diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php index 50db9166fe7..c8756af8ed7 100644 --- a/apps/files_sharing/lib/sharedstorage.php +++ b/apps/files_sharing/lib/sharedstorage.php @@ -20,10 +20,12 @@ * */ +namespace OC\Files\Storage; + /** * Convert target path to source path and pass the function call to the correct storage provider */ -class OC_Filestorage_Shared extends OC_Filestorage_Common { +class Shared extends \OC\Files\Storage\Common { private $sharedFolder; private $files = array(); @@ -32,54 +34,36 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { $this->sharedFolder = $arguments['sharedFolder']; } + public function getId(){ + return 'shared::' . $this->sharedFolder; + } + /** - * @brief Get the source file path and the permissions granted for a shared file + * @brief Get the source file path, permissions, and owner for a shared file * @param string Shared target file path - * @return Returns array with the keys path and permissions or false if not found + * @return Returns array with the keys path, permissions, and owner or false if not found */ private function getFile($target) { - $target = '/'.$target; - $target = rtrim($target, '/'); - if (isset($this->files[$target])) { - return $this->files[$target]; - } else { - $pos = strpos($target, '/', 1); - // Get shared folder name - if ($pos !== false) { - $folder = substr($target, 0, $pos); - if (isset($this->files[$folder])) { - $file = $this->files[$folder]; - } else { - $file = OCP\Share::getItemSharedWith('folder', $folder, OC_Share_Backend_File::FORMAT_SHARED_STORAGE); - } - if ($file) { - $this->files[$target]['path'] = $file['path'].substr($target, strlen($folder)); - $this->files[$target]['permissions'] = $file['permissions']; - return $this->files[$target]; - } - } else { - $file = OCP\Share::getItemSharedWith('file', $target, OC_Share_Backend_File::FORMAT_SHARED_STORAGE); - if ($file) { - $this->files[$target] = $file; - return $this->files[$target]; - } + if (!isset($this->files[$target])) { + $source = \OC_Share_Backend_File::getSource($target); + if ($source) { + $source['path'] = '/'.$source['uid_owner'].'/'.$source['path']; } - OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, OCP\Util::ERROR); - return false; + $this->files[$target] = $source; } + return $this->files[$target]; } /** * @brief Get the source file path for a shared file * @param string Shared target file path - * @return Returns source file path or false if not found + * @return string source file path or false if not found */ private function getSourcePath($target) { - $file = $this->getFile($target); - if (isset($file['path'])) { - $uid = substr($file['path'], 1, strpos($file['path'], '/', 1) - 1); - OC_Filesystem::mount('OC_Filestorage_Local', array('datadir' => OC_User::getHome($uid)), $uid); - return $file['path']; + $source = $this->getFile($target); + if ($source) { + \OC\Files\Filesystem::initMountPoints($source['uid_owner']); + return $source['path']; } return false; } @@ -87,61 +71,42 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { /** * @brief Get the permissions granted for a shared file * @param string Shared target file path - * @return Returns CRUDS permissions granted or false if not found + * @return int CRUDS permissions granted or false if not found */ - private function getPermissions($target) { - $file = $this->getFile($target); - if (isset($file['permissions'])) { - return $file['permissions']; + public function getPermissions($target) { + $source = $this->getFile($target); + if ($source) { + return $source['permissions']; } return false; } - /** - * @brief Get the internal path to pass to the storage filesystem call - * @param string Source file path - * @return Source file path with mount point stripped out - */ - private function getInternalPath($path) { - $mountPoint = OC_Filesystem::getMountPoint($path); - $internalPath = substr($path, strlen($mountPoint)); - return $internalPath; - } - - public function getOwner($target) { - $shared_item = OCP\Share::getItemSharedWith('folder', $target, OC_Share_Backend_File::FORMAT_SHARED_STORAGE); - if ($shared_item) { - return $shared_item[0]["uid_owner"]; - } - return null; - } - public function mkdir($path) { if ($path == '' || $path == '/' || !$this->isCreatable(dirname($path))) { return false; } else if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->mkdir($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->mkdir($internalPath); } return false; } public function rmdir($path) { if (($source = $this->getSourcePath($path)) && $this->isDeletable($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->rmdir($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->rmdir($internalPath); } return false; } public function opendir($path) { if ($path == '' || $path == '/') { - $files = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_Folder::FORMAT_OPENDIR); - OC_FakeDirStream::$dirs['shared'] = $files; + $files = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_Folder::FORMAT_OPENDIR); + \OC_FakeDirStream::$dirs['shared'] = $files; return opendir('fakedir://shared'); } else if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->opendir($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->opendir($internalPath); } return false; } @@ -150,16 +115,16 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if ($path == '' || $path == '/') { return true; } else if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->is_dir($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->is_dir($internalPath); } return false; } public function is_file($path) { if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->is_file($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->is_file($internalPath); } return false; } @@ -168,11 +133,10 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if ($path == '' || $path == '/') { $stat['size'] = $this->filesize($path); $stat['mtime'] = $this->filemtime($path); - $stat['ctime'] = $this->filectime($path); return $stat; } else if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->stat($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->stat($internalPath); } return false; } @@ -181,8 +145,8 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if ($path == '' || $path == '/') { return 'dir'; } else if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->filetype($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->filetype($internalPath); } return false; } @@ -191,8 +155,8 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if ($path == '' || $path == '/' || $this->is_dir($path)) { return 0; } else if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->filesize($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->filesize($internalPath); } return false; } @@ -201,7 +165,7 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if ($path == '') { return false; } - return ($this->getPermissions($path) & OCP\PERMISSION_CREATE); + return ($this->getPermissions($path) & \OCP\PERMISSION_CREATE); } public function isReadable($path) { @@ -212,54 +176,33 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if ($path == '') { return false; } - return ($this->getPermissions($path) & OCP\PERMISSION_UPDATE); + return ($this->getPermissions($path) & \OCP\PERMISSION_UPDATE); } public function isDeletable($path) { if ($path == '') { return true; } - return ($this->getPermissions($path) & OCP\PERMISSION_DELETE); + return ($this->getPermissions($path) & \OCP\PERMISSION_DELETE); } public function isSharable($path) { if ($path == '') { return false; } - return ($this->getPermissions($path) & OCP\PERMISSION_SHARE); + return ($this->getPermissions($path) & \OCP\PERMISSION_SHARE); } public function file_exists($path) { if ($path == '' || $path == '/') { return true; } else if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->file_exists($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->file_exists($internalPath); } return false; } - public function filectime($path) { - if ($path == '' || $path == '/') { - $ctime = 0; - if ($dh = $this->opendir($path)) { - while (($filename = readdir($dh)) !== false) { - $tempctime = $this->filectime($filename); - if ($tempctime < $ctime) { - $ctime = $tempctime; - } - } - } - return $ctime; - } else { - $source = $this->getSourcePath($path); - if ($source) { - $storage = OC_Filesystem::getStorage($source); - return $storage->filectime($this->getInternalPath($source)); - } - } - } - public function filemtime($path) { if ($path == '' || $path == '/') { $mtime = 0; @@ -275,8 +218,8 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { } else { $source = $this->getSourcePath($path); if ($source) { - $storage = OC_Filesystem::getStorage($source); - return $storage->filemtime($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->filemtime($internalPath); } } } @@ -288,9 +231,9 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { 'target' => $this->sharedFolder.$path, 'source' => $source, ); - OCP\Util::emitHook('OC_Filestorage_Shared', 'file_get_contents', $info); - $storage = OC_Filesystem::getStorage($source); - return $storage->file_get_contents($this->getInternalPath($source)); + \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->file_get_contents($internalPath); } } @@ -304,9 +247,9 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { 'target' => $this->sharedFolder.$path, 'source' => $source, ); - OCP\Util::emitHook('OC_Filestorage_Shared', 'file_put_contents', $info); - $storage = OC_Filesystem::getStorage($source); - $result = $storage->file_put_contents($this->getInternalPath($source), $data); + \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + $result = $storage->file_put_contents($internalPath, $data); return $result; } return false; @@ -316,8 +259,8 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { // Delete the file if DELETE permission is granted if ($source = $this->getSourcePath($path)) { if ($this->isDeletable($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->unlink($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->unlink($internalPath); } else if (dirname($path) == '/' || dirname($path) == '.') { // Unshare the file from the user if in the root of the Shared folder if ($this->is_dir($path)) { @@ -325,7 +268,7 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { } else { $itemType = 'file'; } - return OCP\Share::unshareFromSelf($itemType, $path); + return \OCP\Share::unshareFromSelf($itemType, $path); } } return false; @@ -340,8 +283,9 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if (dirname($path1) == dirname($path2)) { // Rename the file if UPDATE permission is granted if ($this->isUpdatable($path1)) { - $storage = OC_Filesystem::getStorage($oldSource); - return $storage->rename($this->getInternalPath($oldSource), $this->getInternalPath($newSource)); + list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource); + list( , $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource); + return $storage->rename($oldInternalPath, $newInternalPath); } } else { // Move the file if DELETE and CREATE permissions are granted @@ -355,8 +299,9 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { return $this->unlink($path1); } } else { - $storage = OC_Filesystem::getStorage($oldSource); - return $storage->rename($this->getInternalPath($oldSource), $this->getInternalPath($newSource)); + list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource); + list( , $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource); + return $storage->rename($oldInternalPath, $newInternalPath); } } } @@ -369,7 +314,7 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { if ($this->isCreatable(dirname($path2))) { $source = $this->fopen($path1, 'r'); $target = $this->fopen($path2, 'w'); - return OC_Helper::streamCopy($source, $target); + return \OC_Helper::streamCopy($source, $target); } return false; } @@ -400,9 +345,9 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { 'source' => $source, 'mode' => $mode, ); - OCP\Util::emitHook('OC_Filestorage_Shared', 'fopen', $info); - $storage = OC_Filesystem::getStorage($source); - return $storage->fopen($this->getInternalPath($source), $mode); + \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->fopen($internalPath, $mode); } return false; } @@ -412,47 +357,81 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { return 'httpd/unix-directory'; } if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->getMimeType($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->getMimeType($internalPath); } return false; } public function free_space($path) { + if ($path == '') { + return -1; + } $source = $this->getSourcePath($path); if ($source) { - $storage = OC_Filesystem::getStorage($source); - return $storage->free_space($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->free_space($internalPath); } } public function getLocalFile($path) { if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->getLocalFile($this->getInternalPath($source)); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->getLocalFile($internalPath); } return false; } public function touch($path, $mtime = null) { if ($source = $this->getSourcePath($path)) { - $storage = OC_Filesystem::getStorage($source); - return $storage->touch($this->getInternalPath($source), $mtime); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->touch($internalPath, $mtime); } return false; } public static function setup($options) { - $user_dir = $options['user_dir']; - OC_Filesystem::mount('OC_Filestorage_Shared', array('sharedFolder' => '/Shared'), $user_dir.'/Shared/'); + if (\OCP\Share::getItemsSharedWith('file')) { + $user_dir = $options['user_dir']; + \OC\Files\Filesystem::mount('\OC\Files\Storage\Shared', array('sharedFolder' => '/Shared'), $user_dir.'/Shared/'); + } } - /** - * check if a file or folder has been updated since $time - * @param int $time - * @return bool - */ public function hasUpdated($path, $time) { - //TODO + if ($path == '') { + return false; + } + return $this->filemtime($path) > $time; + } + + public function getCache($path = '') { + return new \OC\Files\Cache\Shared_Cache($this); + } + + public function getScanner($path = '') { + return new \OC\Files\Cache\Scanner($this); + } + + public function getPermissionsCache($path = '') { + return new \OC\Files\Cache\Shared_Permissions($this); + } + + public function getWatcher($path = '') { + return new \OC\Files\Cache\Shared_Watcher($this); + } + + public function getOwner($path) { + if ($path == '') { + return false; + } + $source = $this->getFile($path); + if ($source) { + return $source['uid_owner']; + } return false; } + + public function getETag($path) { + + } + } diff --git a/apps/files_sharing/lib/watcher.php b/apps/files_sharing/lib/watcher.php new file mode 100644 index 00000000000..e67d1ee9086 --- /dev/null +++ b/apps/files_sharing/lib/watcher.php @@ -0,0 +1,51 @@ +<?php +/** +* ownCloud +* +* @author Michael Gapczynski +* @copyright 2012 Michael Gapczynski mtgap@owncloud.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/>. +*/ + +namespace OC\Files\Cache; + +/** + * check the storage backends for updates and change the cache accordingly + */ +class Shared_Watcher extends Watcher { + + /** + * check $path for updates + * + * @param string $path + */ + public function checkUpdate($path) { + if ($path != '') { + parent::checkUpdate($path); + } + } + + /** + * remove deleted files in $path from the cache + * + * @param string $path + */ + public function cleanFolder($path) { + if ($path != '') { + parent::cleanFolder($path); + } + } + +}
\ No newline at end of file diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index efd977a1b6a..f85fe92ff60 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -9,9 +9,10 @@ if (isset($_GET['token'])) { unset($_GET['file']); $qry = \OC_DB::prepare('SELECT `source` FROM `*PREFIX*sharing` WHERE `target` = ?', 1); $filepath = $qry->execute(array($_GET['token']))->fetchOne(); - if(isset($filepath)) { - $info = OC_FileCache_Cached::get($filepath, ''); - if(strtolower($info['mimetype']) == 'httpd/unix-directory') { + if (isset($filepath)) { + $rootView = new \OC\Files\View(''); + $info = $rootView->getFileInfo($filepath, ''); + if (strtolower($info['mimetype']) == 'httpd/unix-directory') { $_GET['dir'] = $filepath; } else { $_GET['file'] = $filepath; @@ -25,7 +26,7 @@ if (isset($_GET['token'])) { function getID($path) { // use the share table from the db to find the item source if the file was reshared because shared files //are not stored in the file cache. - if (substr(OC_Filesystem::getMountPoint($path), -7, 6) == "Shared") { + if (substr(\OC\Files\Filesystem::getMountPoint($path), -7, 6) == "Shared") { $path_parts = explode('/', $path, 5); $user = $path_parts[1]; $intPath = '/'.$path_parts[4]; @@ -37,16 +38,19 @@ function getID($path) { $row = $result->fetchRow(); $fileSource = $row['item_source']; } else { - $fileSource = OC_Filecache::getId($path, ''); + $rootView = new \OC\Files\View(''); + $meta = $rootView->getFileInfo($path); + $fileSource = $meta['fileid']; } return $fileSource; } + // Enf of backward compatibility /** * lookup file path and owner by fetching it from the fscache - * needed becaus OC_FileCache::getPath($id, $user) already requires the user + * needed because OC_FileCache::getPath($id, $user) already requires the user * @param int $id * @return array */ @@ -86,41 +90,43 @@ if (isset($_GET['t'])) { OC_Util::setupFS($fileOwner); } } -} else if (isset($_GET['file']) || isset($_GET['dir'])) { - OCP\Util::writeLog('share', 'Missing token, trying fallback file/dir links', \OCP\Util::DEBUG); - if (isset($_GET['dir'])) { - $type = 'folder'; - $path = $_GET['dir']; - if(strlen($path)>1 and substr($path, -1, 1)==='/') { - $path=substr($path, 0, -1); - } - $baseDir = $path; - $dir = $baseDir; - } else { - $type = 'file'; - $path = $_GET['file']; - if(strlen($path)>1 and substr($path, -1, 1)==='/') { - $path=substr($path, 0, -1); +} else { + if (isset($_GET['file']) || isset($_GET['dir'])) { + OCP\Util::writeLog('share', 'Missing token, trying fallback file/dir links', \OCP\Util::DEBUG); + if (isset($_GET['dir'])) { + $type = 'folder'; + $path = $_GET['dir']; + if (strlen($path) > 1 and substr($path, -1, 1) === '/') { + $path = substr($path, 0, -1); + } + $baseDir = $path; + $dir = $baseDir; + } else { + $type = 'file'; + $path = $_GET['file']; + if (strlen($path) > 1 and substr($path, -1, 1) === '/') { + $path = substr($path, 0, -1); + } } - } - $shareOwner = substr($path, 1, strpos($path, '/', 1) - 1); + $shareOwner = substr($path, 1, strpos($path, '/', 1) - 1); - if (OCP\User::userExists($shareOwner)) { - OC_Util::setupFS($shareOwner); - $fileSource = getId($path); - if ($fileSource != -1 ) { - $linkItem = OCP\Share::getItemSharedWithByLink($type, $fileSource, $shareOwner); - $pathAndUser['path'] = $path; - $path_parts = explode('/', $path, 5); - $pathAndUser['user'] = $path_parts[1]; - $fileOwner = $path_parts[1]; + if (OCP\User::userExists($shareOwner)) { + OC_Util::setupFS($shareOwner); + $fileSource = getId($path); + if ($fileSource != -1) { + $linkItem = OCP\Share::getItemSharedWithByLink($type, $fileSource, $shareOwner); + $pathAndUser['path'] = $path; + $path_parts = explode('/', $path, 5); + $pathAndUser['user'] = $path_parts[1]; + $fileOwner = $path_parts[1]; + } } } } if ($linkItem) { if (!isset($linkItem['item_type'])) { - OCP\Util::writeLog('share', 'No item type set for share id: '.$linkItem['id'], \OCP\Util::ERROR); + OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR); header('HTTP/1.0 404 Not Found'); $tmpl = new OCP\Template('', '404', 'guest'); $tmpl->printPage(); @@ -128,11 +134,13 @@ if ($linkItem) { } if (isset($linkItem['share_with'])) { // Authenticate share_with - $url = OCP\Util::linkToPublic('files').'&t='.$token; + $url = OCP\Util::linkToPublic('files') . '&t=' . $token; if (isset($_GET['file'])) { - $url .= '&file='.urlencode($_GET['file']); - } else if (isset($_GET['dir'])) { - $url .= '&dir='.urlencode($_GET['dir']); + $url .= '&file=' . urlencode($_GET['file']); + } else { + if (isset($_GET['dir'])) { + $url .= '&dir=' . urlencode($_GET['dir']); + } } if (isset($_POST['password'])) { $password = $_POST['password']; @@ -173,13 +181,13 @@ if ($linkItem) { } } } - $basePath = substr($pathAndUser['path'], strlen('/'.$fileOwner.'/files')); + $basePath = substr($pathAndUser['path'], strlen('/' . $fileOwner . '/files')); $path = $basePath; if (isset($_GET['path'])) { $path .= $_GET['path']; } - if (!$path || !OC_Filesystem::isValidPath($path) || !OC_Filesystem::file_exists($path)) { - OCP\Util::writeLog('share', 'Invalid path '.$path.' for share id '.$linkItem['id'], \OCP\Util::ERROR); + if (!$path || !\OC\Files\Filesystem::isValidPath($path) || !\OC\Files\Filesystem::file_exists($path)) { + OCP\Util::writeLog('share', 'Invalid path ' . $path . ' for share id ' . $linkItem['id'], \OCP\Util::ERROR); header('HTTP/1.0 404 Not Found'); $tmpl = new OCP\Template('', '404', 'guest'); $tmpl->printPage(); @@ -189,13 +197,15 @@ if ($linkItem) { $file = basename($path); // Download the file if (isset($_GET['download'])) { - if (isset($_GET['path']) && $_GET['path'] !== '' ) { - if ( isset($_GET['files']) ) { // download selected files + if (isset($_GET['path']) && $_GET['path'] !== '') { + if (isset($_GET['files'])) { // download selected files OC_Files::get($path, $_GET['files'], $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false); - } else if (isset($_GET['path']) && $_GET['path'] != '' ) { // download a file from a shared directory - OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false); - } else { // download the whole shared directory - OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false); + } else { + if (isset($_GET['path']) && $_GET['path'] != '') { // download a file from a shared directory + OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false); + } else { // download the whole shared directory + OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false); + } } } else { // download a single shared file OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false); @@ -209,7 +219,7 @@ if ($linkItem) { $tmpl->assign('uidOwner', $shareOwner); $tmpl->assign('dir', $dir); $tmpl->assign('filename', $file); - $tmpl->assign('mimetype', OC_Filesystem::getMimeType($path)); + $tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path)); if (isset($_GET['path'])) { $getPath = $_GET['path']; } else { @@ -220,7 +230,7 @@ if ($linkItem) { .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'') .(isset($_GET['file'])?'&file='.$_GET['file']:''); // Show file list - if (OC_Filesystem::is_dir($path)) { + if (\OC\Files\Filesystem::is_dir($path)) { OCP\Util::addStyle('files', 'files'); OCP\Util::addScript('files', 'files'); OCP\Util::addScript('files', 'filelist'); @@ -231,9 +241,9 @@ if ($linkItem) { if ($i['type'] == 'file') { $fileinfo = pathinfo($i['name']); $i['basename'] = $fileinfo['filename']; - $i['extension'] = isset($fileinfo['extension']) ? ('.'.$fileinfo['extension']) : ''; + $i['extension'] = isset($fileinfo['extension']) ? ('.' . $fileinfo['extension']) : ''; } - $i['directory'] = '/'.substr($i['directory'], $rootLength); + $i['directory'] = '/' . substr($i['directory'], $rootLength); if ($i['directory'] == '/') { $i['directory'] = ''; } @@ -250,9 +260,137 @@ if ($linkItem) { //add subdir breadcrumbs foreach (explode('/', urldecode($getPath)) as $i) { if ($i != '') { - $pathtohere .= '/'.$i; + $pathtohere .= '/' . $i; $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i); + $path = $linkItem['path']; + if (isset($_GET['path'])) { + $path .= $_GET['path']; + $dir .= $_GET['path']; + if (!\OC\Files\Filesystem::file_exists($path)) { + header('HTTP/1.0 404 Not Found'); + $tmpl = new OCP\Template('', '404', 'guest'); + $tmpl->printPage(); + exit(); + } + } + + $list = new OCP\Template('files', 'part.list', ''); + $list->assign('files', $files, false); + $list->assign('publicListView', true); + $list->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path=', false); + $list->assign('downloadURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=', false); + $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); + $breadcrumbNav->assign('breadcrumb', $breadcrumb, false); + $breadcrumbNav->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path=', false); + $folder = new OCP\Template('files', 'index', ''); + $folder->assign('fileList', $list->fetchPage(), false); + $folder->assign('breadcrumb', $breadcrumbNav->fetchPage(), false); + $folder->assign('isCreatable', false); + $folder->assign('permissions', 0); + $folder->assign('files', $files); + $folder->assign('uploadMaxFilesize', 0); + $folder->assign('uploadMaxHumanFilesize', 0); + $folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); + $tmpl->assign('folder', $folder->fetchPage(), false); + $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=' . urlencode($getPath)); + } else { + // Show file preview if viewer is available + if ($type == 'file') { + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download'); + } else { + OCP\Util::addStyle('files_sharing', 'public'); + OCP\Util::addScript('files_sharing', 'public'); + OCP\Util::addScript('files', 'fileactions'); + $tmpl = new OCP\Template('files_sharing', 'public', 'base'); + $tmpl->assign('owner', $uidOwner); + // Show file list + if (\OC\Files\Filesystem::is_dir($path)) { + OCP\Util::addStyle('files', 'files'); + OCP\Util::addScript('files', 'files'); + OCP\Util::addScript('files', 'filelist'); + $files = array(); + $rootLength = strlen($baseDir) + 1; + foreach (OC_Files::getDirectoryContent($path) as $i) { + $i['date'] = OCP\Util::formatDate($i['mtime']); + if ($i['type'] == 'file') { + $fileinfo = pathinfo($i['name']); + $i['basename'] = $fileinfo['filename']; + $i['extension'] = isset($fileinfo['extension']) ? ('.' . $fileinfo['extension']) : ''; + } + $i['directory'] = '/' . substr('/' . $uidOwner . '/files' . $i['directory'], $rootLength); + if ($i['directory'] == '/') { + $i['directory'] = ''; + } + $i['permissions'] = OCP\PERMISSION_READ; + $files[] = $i; + } + // Make breadcrumb + $breadcrumb = array(); + $pathtohere = ''; + $count = 1; + foreach (explode('/', $dir) as $i) { + if ($i != '') { + if ($i != $baseDir) { + $pathtohere .= '/' . $i; + } + if (strlen($pathtohere) < strlen($_GET['dir'])) { + continue; + } + $breadcrumb[] = array('dir' => str_replace($_GET['dir'], "", $pathtohere, $count), 'name' => $i); + } + } + $list = new OCP\Template('files', 'part.list', ''); + $list->assign('files', $files, false); + $list->assign('publicListView', true); + $list->assign('baseURL', OCP\Util::linkToPublic('files') . '&dir=' . urlencode($_GET['dir']) . '&path=', false); + $list->assign('downloadURL', OCP\Util::linkToPublic('files') . '&download&dir=' . urlencode($_GET['dir']) . '&path=', false); + $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); + $breadcrumbNav->assign('breadcrumb', $breadcrumb, false); + $breadcrumbNav->assign('baseURL', OCP\Util::linkToPublic('files') . '&dir=' . urlencode($_GET['dir']) . '&path=', false); + $folder = new OCP\Template('files', 'index', ''); + $folder->assign('fileList', $list->fetchPage(), false); + $folder->assign('breadcrumb', $breadcrumbNav->fetchPage(), false); + $folder->assign('dir', basename($dir)); + $folder->assign('isCreatable', false); + $folder->assign('permissions', 0); + $folder->assign('files', $files); + $folder->assign('uploadMaxFilesize', 0); + $folder->assign('uploadMaxHumanFilesize', 0); + $folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); + $tmpl->assign('folder', $folder->fetchPage(), false); + $tmpl->assign('uidOwner', $uidOwner); + $tmpl->assign('dir', basename($dir)); + $tmpl->assign('filename', basename($path)); + $tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path)); + $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); + if (isset($_GET['path'])) { + $getPath = $_GET['path']; + } else { + $getPath = ''; + } + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . '&download&dir=' . urlencode($_GET['dir']) . '&path=' . urlencode($getPath), false); + } else { + // Show file preview if viewer is available + $tmpl->assign('uidOwner', $uidOwner); + $tmpl->assign('dir', dirname($path)); + $tmpl->assign('filename', basename($path)); + $tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path)); + if ($type == 'file') { + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . '&file=' . urlencode($_GET['file']) . '&download', false); + } else { + if (isset($_GET['path'])) { + $getPath = $_GET['path']; + } else { + $getPath = ''; + } + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . '&download&dir=' . urlencode($_GET['dir']) . '&path=' . urlencode($getPath), false); + } + } + $tmpl->printPage(); + } } + $tmpl->printPage(); } $list = new OCP\Template('files', 'part.list', ''); @@ -278,21 +416,11 @@ if ($linkItem) { $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') .$urlLinkIdentifiers.'&download&path='.urlencode($getPath)); } else { - // Show file preview if viewer is available - if ($type == 'file') { - $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') - .$urlLinkIdentifiers.'&download'); - } else { - $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') - .$urlLinkIdentifiers.'&download&path='.urlencode($getPath)); - } + OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG); } - $tmpl->printPage(); } - exit(); -} else { - OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG); } header('HTTP/1.0 404 Not Found'); $tmpl = new OCP\Template('', '404', 'guest'); $tmpl->printPage(); + diff --git a/apps/files_versions/lib/hooks.php b/apps/files_versions/lib/hooks.php index 5fb9dc3c3c5..3a64e571d5a 100644 --- a/apps/files_versions/lib/hooks.php +++ b/apps/files_versions/lib/hooks.php @@ -21,9 +21,9 @@ class Hooks { if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - $versions = new Storage( new \OC_FilesystemView('') ); + $versions = new Storage( new \OC\Files\View('') ); - $path = $params[\OC_Filesystem::signal_param_path]; + $path = $params[\OC\Files\Filesystem::signal_param_path]; if($path<>'') $versions->store( $path ); diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php index 48be5e223ac..003d548d2b2 100644 --- a/apps/files_versions/lib/versions.php +++ b/apps/files_versions/lib/versions.php @@ -23,15 +23,15 @@ class Storage { private static $max_versions_per_interval = array( 1 => array('intervalEndsAfter' => 10, //first 10sec, one version every 2sec 'step' => 2), - 2 => array('intervalEndsAfter' => 60, //next minute, one version every 10sec
+ 2 => array('intervalEndsAfter' => 60, //next minute, one version every 10sec 'step' => 10), 3 => array('intervalEndsAfter' => 3600, //next hour, one version every minute 'step' => 60), 4 => array('intervalEndsAfter' => 86400, //next 24h, one version every hour 'step' => 3600), - 5 => array('intervalEndsAfter' => 2592000, //next 30days, one version per day
+ 5 => array('intervalEndsAfter' => 2592000, //next 30days, one version per day 'step' => 86400), - 6 => array('intervalEndsAfter' => -1, //until the end one version per week
+ 6 => array('intervalEndsAfter' => -1, //until the end one version per week 'step' => 604800), ); @@ -58,8 +58,8 @@ class Storage { public function store($filename) { if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { list($uid, $filename) = self::getUidAndFilename($filename); - $files_view = new \OC_FilesystemView('/'.$uid .'/files'); - $users_view = new \OC_FilesystemView('/'.$uid); + $files_view = new \OC\Files\View('/'.\OCP\User::getUser() .'/files'); + $users_view = new \OC\Files\View('/'.\OCP\User::getUser()); //check if source file already exist as version to avoid recursions. // todo does this check work? @@ -86,8 +86,8 @@ class Storage { // store a new version of a file $result = $users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename)); - if ( ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) {
- $versionsSize = self::calculateSize($uid);
+ if ( ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) { + $versionsSize = self::calculateSize($uid); } $versionsSize += $users_view->filesize('files'.$filename); @@ -105,42 +105,42 @@ class Storage { * Delete versions of a file */ public static function delete($filename) { - list($uid, $filename) = self::getUidAndFilename($filename);
+ list($uid, $filename) = self::getUidAndFilename($filename); $versions_fileview = new \OC_FilesystemView('/'.$uid .'/files_versions'); -
- $abs_path = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$filename.'.v';
- if( ($versions = self::getVersions($filename)) ) {
- if ( ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) {
- $versionsSize = self::calculateSize($uid);
- }
- foreach ($versions as $v) {
- unlink($abs_path . $v['version']);
- $versionsSize -= $v['size'];
- }
- \OCP\Config::setAppValue('files_versions', 'size', $versionsSize);
+ + $abs_path = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$filename.'.v'; + if( ($versions = self::getVersions($filename)) ) { + if ( ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) { + $versionsSize = self::calculateSize($uid); + } + foreach ($versions as $v) { + unlink($abs_path . $v['version']); + $versionsSize -= $v['size']; + } + \OCP\Config::setAppValue('files_versions', 'size', $versionsSize); } } - /**
- * rename versions of a file
- */
- public static function rename($oldpath, $newpath) {
+ /** + * rename versions of a file + */ + public static function rename($oldpath, $newpath) { list($uid, $oldpath) = self::getUidAndFilename($oldpath); - list($uidn, $newpath) = self::getUidAndFilename($newpath);
+ list($uidn, $newpath) = self::getUidAndFilename($newpath); $versions_view = new \OC_FilesystemView('/'.$uid .'/files_versions'); $files_view = new \OC_FilesystemView('/'.$uid .'/files'); - $abs_newpath = \OCP\Config::getSystemValue('datadirectory').$versions_view->getAbsolutePath('').$newpath;
-
+ $abs_newpath = \OCP\Config::getSystemValue('datadirectory').$versions_view->getAbsolutePath('').$newpath; + if ( $files_view->is_dir($oldpath) && $versions_view->is_dir($oldpath) ) { $versions_view->rename($oldpath, $newpath); - } else if ( ($versions = Storage::getVersions($oldpath)) ) {
- $info=pathinfo($abs_newpath);
- if(!file_exists($info['dirname'])) mkdir($info['dirname'], 0750, true);
- $versions = Storage::getVersions($oldpath);
+ } else if ( ($versions = Storage::getVersions($oldpath)) ) { + $info=pathinfo($abs_newpath); + if(!file_exists($info['dirname'])) mkdir($info['dirname'], 0750, true); + $versions = Storage::getVersions($oldpath); foreach ($versions as $v) { - $versions_view->rename($oldpath.'.v'.$v['version'], $newpath.'.v'.$v['version']);
- }
- }
+ $versions_view->rename($oldpath.'.v'.$v['version'], $newpath.'.v'.$v['version']); + } + } } /** @@ -150,7 +150,7 @@ class Storage { if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { list($uid, $filename) = self::getUidAndFilename($filename); - $users_view = new \OC_FilesystemView('/'.$uid); + $users_view = new \OC\Files\View('/'.$uid); $versionCreated = false; //first create a new version @@ -184,7 +184,7 @@ class Storage { public static function getVersions( $filename, $count = 0 ) { if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) { list($uid, $filename) = self::getUidAndFilename($filename); - $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); + $versions_fileview = new \OC\Files\View('/' . \OCP\User::getUser() . '/files_versions'); $versionsName = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath($filename); $versions = array(); @@ -202,7 +202,7 @@ class Storage { $key = $version.'#'.$filename; $versions[$key]['cur'] = 0; $versions[$key]['version'] = $version; - $versions[$key]['path'] = $filename;
+ $versions[$key]['path'] = $filename; $versions[$key]['size'] = $versions_fileview->filesize($filename.'.v'.$version); // if file with modified date exists, flag it in array as currently enabled version @@ -236,29 +236,29 @@ class Storage { } - /**
- * @brief get the size of all stored versions from a given user
- * @param $uid id from the user
- * @return size of vesions
- */
- private static function calculateSize($uid) {
- if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) {
- $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions');
- $versionsRoot = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('');
-
- $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($versionsRoot), \RecursiveIteratorIterator::CHILD_FIRST);
-
+ /** + * @brief get the size of all stored versions from a given user + * @param $uid id from the user + * @return size of vesions + */ + private static function calculateSize($uid) { + if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) { + $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); + $versionsRoot = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath(''); + + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($versionsRoot), \RecursiveIteratorIterator::CHILD_FIRST); + $size = 0; -
- foreach ($iterator as $path) {
- if ( preg_match('/^.+\.v(\d+)$/', $path, $match) ) {
+ + foreach ($iterator as $path) { + if ( preg_match('/^.+\.v(\d+)$/', $path, $match) ) { $relpath = substr($path, strlen($versionsRoot)-1); - $size += $versions_fileview->filesize($relpath);
- }
+ $size += $versions_fileview->filesize($relpath); + } } - return $size;
- }
+ return $size; + } } /** @@ -267,11 +267,11 @@ class Storage { * @return array with contains two arrays 'all' which contains all versions sorted by age and 'by_file' which contains all versions sorted by filename */ private static function getAllVersions($uid) { - if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) {
+ if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) { $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); $versionsRoot = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath(''); - $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($versionsRoot), \RecursiveIteratorIterator::CHILD_FIRST);
+ $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($versionsRoot), \RecursiveIteratorIterator::CHILD_FIRST); $versions = array(); @@ -280,7 +280,7 @@ class Storage { $relpath = substr($path, strlen($versionsRoot)-1); $versions[$match[1].'#'.$relpath] = array('path' => $relpath, 'timestamp' => $match[1]); } - }
+ } ksort($versions); @@ -288,20 +288,20 @@ class Storage { $result = array(); - foreach( $versions as $key => $value ) {
+ foreach( $versions as $key => $value ) { $i++; $size = $versions_fileview->filesize($value['path']); $filename = substr($value['path'], 0, -strlen($value['timestamp'])-2); -
+ $result['all'][$key]['version'] = $value['timestamp']; - $result['all'][$key]['path'] = $filename;
+ $result['all'][$key]['path'] = $filename; $result['all'][$key]['size'] = $size; $filename = substr($value['path'], 0, -strlen($value['timestamp'])-2); $result['by_file'][$filename][$key]['version'] = $value['timestamp']; - $result['by_file'][$filename][$key]['path'] = $filename;
+ $result['by_file'][$filename][$key]['path'] = $filename; $result['by_file'][$filename][$key]['size'] = $size; -
+ } return $result; @@ -322,7 +322,7 @@ class Storage { $quota = \OCP\Util::computerFileSize(\OC_Appconfig::getValue('files', 'default_quota')); } if ( $quota == null ) { - $quota = \OC_Filesystem::free_space('/'); + $quota = \OC\Files\Filesystem::free_space('/'); } // make sure that we have the current size of the version history @@ -332,7 +332,7 @@ class Storage { } } - // calculate available space for version history
+ // calculate available space for version history $rootInfo = \OC_FileCache::get('', '/'. $uid . '/files'); $free = $quota-$rootInfo['size']; // remaining free space for user if ( $free > 0 ) { @@ -394,7 +394,7 @@ class Storage { $nextVersion = $prevTimestamp - $step; if ( Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1 ) { $nextInterval = -1; - } else {
+ } else { $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter']; } $newInterval = true; // we changed the interval -> check same version with new interval diff --git a/db_structure.xml b/db_structure.xml index db43ef21140..f1f02572819 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -60,125 +60,186 @@ <table> - <name>*dbprefix*fscache</name> + <name>*dbprefix*storages</name> <declaration> <field> <name>id</name> - <autoincrement>1</autoincrement> + <type>text</type> + <default></default> + <notnull>true</notnull> + <length>64</length> + </field> + + <field> + <name>numeric_id</name> <type>integer</type> <default>0</default> <notnull>true</notnull> + <autoincrement>1</autoincrement> <length>4</length> </field> + <index> + <name>storages_id_index</name> + <unique>true</unique> + <field> + <name>id</name> + <sorting>ascending</sorting> + </field> + </index> + + </declaration> + + </table> + + <table> + + <name>*dbprefix*mimetypes</name> + + <declaration> + <field> - <name>path</name> - <type>text</type> - <default></default> + <name>id</name> + <type>integer</type> + <default>0</default> <notnull>true</notnull> - <length>512</length> + <autoincrement>1</autoincrement> + <length>4</length> </field> <field> - <name>path_hash</name> + <name>mimetype</name> <type>text</type> <default></default> <notnull>true</notnull> - <length>32</length> + <length>255</length> </field> + <index> + <name>mimetype_id_index</name> + <unique>true</unique> + <field> + <name>mimetype</name> + <sorting>ascending</sorting> + </field> + </index> + + </declaration> + + </table> + + <table> + + <name>*dbprefix*filecache</name> + + <declaration> + <field> - <name>parent</name> + <name>fileid</name> <type>integer</type> <default>0</default> <notnull>true</notnull> - <length>8</length> + <autoincrement>1</autoincrement> + <length>4</length> </field> <field> - <name>name</name> - <type>text</type> + <name>storage</name> + <type>integer</type> <default></default> <notnull>true</notnull> - <length>300</length> + <length>4</length> </field> <field> - <name>user</name> + <name>path</name> <type>text</type> <default></default> <notnull>true</notnull> - <length>64</length> + <length>512</length> </field> <field> - <name>size</name> - <type>integer</type> - <default>0</default> + <name>path_hash</name> + <type>text</type> + <default></default> <notnull>true</notnull> - <length>8</length> + <length>32</length> </field> <field> - <name>ctime</name> + <name>parent</name> <type>integer</type> - <default>0</default> + <default></default> <notnull>true</notnull> - <length>8</length> + <length>4</length> </field> <field> - <name>mtime</name> - <type>integer</type> - <default>0</default> + <name>name</name> + <type>text</type> + <default></default> <notnull>true</notnull> - <length>8</length> + <length>250</length> </field> <field> <name>mimetype</name> - <type>text</type> + <type>integer</type> <default></default> <notnull>true</notnull> - <length>96</length> + <length>4</length> </field> <field> <name>mimepart</name> - <type>text</type> + <type>integer</type> <default></default> <notnull>true</notnull> - <length>32</length> + <length>4</length> </field> <field> - <name>encrypted</name> + <name>size</name> <type>integer</type> - <default>0</default> + <default></default> <notnull>true</notnull> - <length>1</length> + <length>4</length> </field> <field> - <name>versioned</name> + <name>mtime</name> <type>integer</type> - <default>0</default> + <default></default> <notnull>true</notnull> - <length>1</length> + <length>4</length> </field> <field> - <name>writable</name> + <name>encrypted</name> <type>integer</type> <default>0</default> <notnull>true</notnull> - <length>1</length> + <length>4</length> + </field> + + <field> + <name>etag</name> + <type>text</type> + <default></default> + <notnull>true</notnull> + <length>40</length> </field> <index> - <name>fscache_path_hash_index</name> + <name>fs_storage_path_hash</name> + <unique>true</unique> + <field> + <name>storage</name> + <sorting>ascending</sorting> + </field> <field> <name>path_hash</name> <sorting>ascending</sorting> @@ -186,29 +247,60 @@ </index> <index> - <name>parent_index</name> + <name>fs_parent_name_hash</name> <field> <name>parent</name> <sorting>ascending</sorting> </field> - </index> - - <index> - <name>name_index</name> <field> <name>name</name> <sorting>ascending</sorting> </field> </index> + </declaration> + + </table> + + <table> + + <name>*dbprefix*permissions</name> + + <declaration> + + <field> + <name>fileid</name> + <type>integer</type> + <default>0</default> + <notnull>true</notnull> + <length>4</length> + </field> + + <field> + <name>user</name> + <type>text</type> + <default></default> + <notnull>true</notnull> + <length>64</length> + </field> + + <field> + <name>permissions</name> + <type>integer</type> + <default>0</default> + <notnull>true</notnull> + <length>4</length> + </field> + <index> - <name>parent_name_index</name> + <name>id_user_index</name> + <unique>true</unique> <field> - <name>parent</name> + <name>fileid</name> <sorting>ascending</sorting> </field> <field> - <name>name</name> + <name>user</name> <sorting>ascending</sorting> </field> </index> diff --git a/lib/app.php b/lib/app.php index 410cb4c12fc..68e1bc6a6ca 100644 --- a/lib/app.php +++ b/lib/app.php @@ -737,16 +737,16 @@ class OC_App{ /** * @param string $appid - * @return OC_FilesystemView + * @return \OC\Files\View */ public static function getStorage($appid) { if(OC_App::isEnabled($appid)) {//sanity check if(OC_User::isLoggedIn()) { - $view = new OC_FilesystemView('/'.OC_User::getUser()); + $view = new \OC\Files\View('/'.OC_User::getUser()); if(!$view->file_exists($appid)) { $view->mkdir($appid); } - return new OC_FilesystemView('/'.OC_User::getUser().'/'.$appid); + return new \OC\Files\View('/'.OC_User::getUser().'/'.$appid); }else{ OC_Log::write('core', 'Can\'t get app storage, app, user not logged in', OC_Log::ERROR); return false; diff --git a/lib/base.php b/lib/base.php index 6896c91822e..6f537cf0893 100644 --- a/lib/base.php +++ b/lib/base.php @@ -105,6 +105,8 @@ class OC $path = str_replace('\\', '/', $className) . '.php'; } elseif (strpos($className, 'Test_') === 0) { $path = 'tests/lib/' . strtolower(str_replace('_', '/', substr($className, 5)) . '.php'); + } elseif (strpos($className, 'Test\\') === 0) { + $path = 'tests/lib/' . strtolower(str_replace('\\', '/', substr($className, 5)) . '.php'); } else { return false; } diff --git a/lib/cache/file.php b/lib/cache/file.php index 27d8b19f36e..f9ecf41dcac 100644 --- a/lib/cache/file.php +++ b/lib/cache/file.php @@ -15,11 +15,11 @@ class OC_Cache_File{ } if(OC_User::isLoggedIn()) { $subdir = 'cache'; - $view = new OC_FilesystemView('/'.OC_User::getUser()); + $view = new \OC\Files\View('/'.OC_User::getUser()); if(!$view->file_exists($subdir)) { $view->mkdir($subdir); } - $this->storage = new OC_FilesystemView('/'.OC_User::getUser().'/'.$subdir); + $this->storage = new \OC\Files\View('/'.OC_User::getUser().'/'.$subdir); return $this->storage; }else{ OC_Log::write('core', 'Can\'t get cache storage, user not logged in', OC_Log::ERROR); diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index 6076aed6fcd..a7201579366 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -62,7 +62,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa } } else { $newPath = $this->path . '/' . $name; - OC_Filesystem::file_put_contents($newPath, $data); + \OC\Files\Filesystem::file_put_contents($newPath, $data); return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); } @@ -78,7 +78,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa public function createDirectory($name) { $newPath = $this->path . '/' . $name; - OC_Filesystem::mkdir($newPath); + \OC\Files\Filesystem::mkdir($newPath); } @@ -93,7 +93,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa $path = $this->path . '/' . $name; if (is_null($info)) { - $info = OC_Files::getFileInfo($path); + $info = \OC\Files\Filesystem::getFileInfo($path); } if (!$info) { @@ -116,12 +116,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa * @return Sabre_DAV_INode[] */ public function getChildren() { - $folder_content = OC_Files::getDirectoryContent($this->path); + + $folder_content = \OC\Files\Filesystem::getDirectoryContent($this->path); $paths = array(); foreach($folder_content as $info) { $paths[] = $this->path.'/'.$info['name']; + $properties[$this->path.'/'.$info['name']][self::GETETAG_PROPERTYNAME] = $info['etag']; } - $properties = array_fill_keys($paths, array()); if(count($paths)>0) { // // the number of arguments within IN conditions are limited in most databases @@ -160,7 +161,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa public function childExists($name) { $path = $this->path . '/' . $name; - return OC_Filesystem::file_exists($path); + return \OC\Files\Filesystem::file_exists($path); } @@ -173,7 +174,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa if ($this->path != "/Shared") { foreach($this->getChildren() as $child) $child->delete(); - OC_Filesystem::rmdir($this->path); + \OC\Files\Filesystem::rmdir($this->path); } } @@ -184,10 +185,10 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa * @return array */ public function getQuotaInfo() { - $rootInfo=OC_FileCache_Cached::get(''); + $rootInfo=\OC\Files\Filesystem::getFileInfo(''); return array( $rootInfo['size'], - OC_Filesystem::free_space() + \OC\Files\Filesystem::free_space() ); } diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php index 8d963a1cf8d..1c18a391742 100644 --- a/lib/connector/sabre/file.php +++ b/lib/connector/sabre/file.php @@ -45,7 +45,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D */ public function put($data) { - OC_Filesystem::file_put_contents($this->path, $data); + \OC\Files\Filesystem::file_put_contents($this->path,$data); return OC_Connector_Sabre_Node::getETagPropertyForPath($this->path); } @@ -57,7 +57,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D */ public function get() { - return OC_Filesystem::fopen($this->path, 'rb'); + return \OC\Files\Filesystem::fopen($this->path,'rb'); } @@ -68,7 +68,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D */ public function delete() { - OC_Filesystem::unlink($this->path); + \OC\Files\Filesystem::unlink($this->path); } @@ -98,16 +98,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D if (isset($properties[self::GETETAG_PROPERTYNAME])) { return $properties[self::GETETAG_PROPERTYNAME]; } - return $this->getETagPropertyForPath($this->path); - } - - /** - * Creates a ETag for this path. - * @param string $path Path of the file - * @return string|null Returns null if the ETag can not effectively be determined - */ - static protected function createETag($path) { - return OC_Filesystem::hash('md5', $path); + return null; } /** @@ -122,7 +113,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D return $this->fileinfo_cache['mimetype']; } - return OC_Filesystem::getMimeType($this->path); + return \OC\Files\Filesystem::getMimeType($this->path); } } diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php index 026ec9f7ec5..b48d3b41f24 100644 --- a/lib/connector/sabre/node.php +++ b/lib/connector/sabre/node.php @@ -84,12 +84,12 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr $newPath = $parentPath . '/' . $newName; $oldPath = $this->path; - OC_Filesystem::rename($this->path, $newPath); + \OC\Files\Filesystem::rename($this->path,$newPath); $this->path = $newPath; $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertypath` = ? WHERE `userid` = ? AND `propertypath` = ?' ); - $query->execute( array( $newPath, OC_User::getUser(), $oldPath )); + $query->execute( array( $newPath,OC_User::getUser(), $oldPath )); } @@ -104,9 +104,9 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr */ protected function getFileinfoCache() { if (!isset($this->fileinfo_cache)) { - if ($fileinfo_cache = OC_FileCache::get($this->path)) { + if ($fileinfo_cache = \OC\Files\Filesystem::getFileInfo($this->path)) { } else { - $fileinfo_cache = OC_Filesystem::stat($this->path); + $fileinfo_cache = \OC\Files\Filesystem::stat($this->path); } $this->fileinfo_cache = $fileinfo_cache; @@ -134,7 +134,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * Even if the modification time is set to a custom value the access time is set to now. */ public function touch($mtime) { - OC_Filesystem::touch($this->path, $mtime); + \OC\Files\Filesystem::touch($this->path, $mtime); } /** @@ -159,10 +159,10 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr } else { if(!array_key_exists( $propertyName, $existing )) { $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*properties` (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)' ); - $query->execute( array( OC_User::getUser(), $this->path, $propertyName, $propertyValue )); + $query->execute( array( OC_User::getUser(), $this->path, $propertyName,$propertyValue )); } else { $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ? WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' ); - $query->execute( array( $propertyValue, OC_User::getUser(), $this->path, $propertyName )); + $query->execute( array( $propertyValue,OC_User::getUser(), $this->path, $propertyName )); } } } @@ -190,6 +190,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr while( $row = $result->fetchRow()) { $this->property_cache[$row['propertyname']] = $row['propertyvalue']; } + $this->property_cache[self::GETETAG_PROPERTYNAME] = $this->getETagPropertyForPath($this->path); } // if the array was empty, we need to return everything @@ -205,57 +206,16 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr } /** - * @brief Creates a ETag for this path. - * @param string $path Path of the file - * @return string|null Returns null if the ETag can not effectively be determined - */ - static protected function createETag($path) { - if(self::$ETagFunction) { - $hash = call_user_func(self::$ETagFunction, $path); - return $hash; - }else{ - return uniqid('', true); - } - } - - /** - * @brief Returns the ETag surrounded by double-quotes for this path. + * Returns the ETag surrounded by double-quotes for this path. * @param string $path Path of the file * @return string|null Returns null if the ETag can not effectively be determined */ static public function getETagPropertyForPath($path) { - $tag = self::createETag($path); - if (empty($tag)) { - return null; + $data = \OC\Files\Filesystem::getFileInfo($path); + if (isset($data['etag'])) { + return '"'.$data['etag'].'"'; } - $etag = '"'.$tag.'"'; - $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*properties` (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)' ); - $query->execute( array( OC_User::getUser(), $path, self::GETETAG_PROPERTYNAME, $etag )); - return $etag; + return null; } - /** - * @brief Remove the ETag from the cache. - * @param string $path Path of the file - */ - static public function removeETagPropertyForPath($path) { - // remove tags from this and parent paths - $paths = array(); - while ($path != '/' && $path != '.' && $path != '' && $path != '\\') { - $paths[] = $path; - $path = dirname($path); - } - if (empty($paths)) { - return; - } - $paths[] = $path; - $path_placeholders = join(',', array_fill(0, count($paths), '?')); - $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*properties`' - .' WHERE `userid` = ?' - .' AND `propertyname` = ?' - .' AND `propertypath` IN ('.$path_placeholders.')' - ); - $vals = array( OC_User::getUser(), self::GETETAG_PROPERTYNAME ); - $query->execute(array_merge( $vals, $paths )); - } } diff --git a/lib/connector/sabre/quotaplugin.php b/lib/connector/sabre/quotaplugin.php index fbbb4a3cf6f..ce9a968eb3c 100644 --- a/lib/connector/sabre/quotaplugin.php +++ b/lib/connector/sabre/quotaplugin.php @@ -50,7 +50,7 @@ class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin { $uri='/'.$uri; } list($parentUri, $newName) = Sabre_DAV_URLUtil::splitPath($uri); - if ($length > OC_Filesystem::free_space($parentUri)) { + if ($length > \OC\Files\Filesystem::free_space($parentUri)) { throw new Sabre_DAV_Exception_InsufficientStorage(); } } diff --git a/lib/filecache.php b/lib/filecache.php deleted file mode 100644 index bde70757d31..00000000000 --- a/lib/filecache.php +++ /dev/null @@ -1,534 +0,0 @@ -<?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 associative array with the following keys: - * - size - * - mtime - * - ctime - * - mimetype - * - encrypted - * - versioned - */ - public static function get($path, $root=false) { - if(OC_FileCache_Update::hasUpdated($path, $root)) { - if($root===false) {//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem', 'post_write', array('path'=>$path)); - }else{ - OC_FileCache_Update::update($path, $root); - } - } - return OC_FileCache_Cached::get($path, $root); - } - - /** - * put filesystem info in the cache - * @param string $path - * @param array data - * @param string root (optional) - * @note $data is an associative array in the same format as returned - * by get - */ - public static function put($path, $data, $root=false) { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - $fullpath=OC_Filesystem::normalizePath($root.'/'.$path); - $parent=self::getParentId($fullpath); - $id=self::getId($fullpath, ''); - if(isset(OC_FileCache_Cached::$savedData[$fullpath])) { - $data=array_merge(OC_FileCache_Cached::$savedData[$fullpath], $data); - unset(OC_FileCache_Cached::$savedData[$fullpath]); - } - if($id!=-1) { - self::update($id, $data); - return; - } - - // add parent directory to the file cache if it does not exist yet. - if ($parent == -1 && $fullpath != $root) { - $parentDir = dirname($path); - self::scanFile($parentDir); - $parent = self::getParentId($fullpath); - } - - if(!isset($data['size']) or !isset($data['mtime'])) {//save incomplete data for the next time we write it - OC_FileCache_Cached::$savedData[$fullpath]=$data; - return; - } - if(!isset($data['encrypted'])) { - $data['encrypted']=false; - } - if(!isset($data['versioned'])) { - $data['versioned']=false; - } - $mimePart=dirname($data['mimetype']); - $data['size']=(int)$data['size']; - $data['ctime']=(int)$data['mtime']; - $data['writable']=(int)$data['writable']; - $data['encrypted']=(int)$data['encrypted']; - $data['versioned']=(int)$data['versioned']; - $user=OC_User::getUser(); - $query=OC_DB::prepare('INSERT INTO `*PREFIX*fscache`(`parent`, `name`, `path`, `path_hash`, `size`, `mtime`, `ctime`, `mimetype`, `mimepart`,`user`,`writable`,`encrypted`,`versioned`) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)'); - $result=$query->execute(array($parent, basename($fullpath), $fullpath, md5($fullpath), $data['size'], $data['mtime'], $data['ctime'], $data['mimetype'], $mimePart, $user, $data['writable'], $data['encrypted'], $data['versioned'])); - if(OC_DB::isError($result)) { - OC_Log::write('files', 'error while writing file('.$fullpath.') to cache', OC_Log::ERROR); - } - - if($cache=OC_Cache::getUserCache(true)) { - $cache->remove('fileid/'.$fullpath);//ensure we don't have -1 cached - } - } - - /** - * 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])) { - //Convert to int it args are false - if($data[$attribute] === false) { - $arguments[] = 0; - }else{ - $arguments[] = $data[$attribute]; - } - $queryParts[]='`'.$attribute.'`=?'; - } - } - if(isset($data['mimetype'])) { - $arguments[]=dirname($data['mimetype']); - $queryParts[]='`mimepart`=?'; - } - $arguments[]=$id; - - if(!empty($queryParts)) { - $sql = 'UPDATE `*PREFIX*fscache` SET '.implode(' , ', $queryParts).' WHERE `id`=?'; - $query=OC_DB::prepare($sql); - $result=$query->execute($arguments); - if(OC_DB::isError($result)) { - OC_Log::write('files', 'error while updating file('.$id.') in cache', OC_Log::ERROR); - } - } - } - - /** - * register a file move in the cache - * @param string oldPath - * @param string newPath - * @param string root (optional) - */ - public static function move($oldPath, $newPath, $root=false) { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - // If replacing an existing file, delete the file - if (self::inCache($newPath, $root)) { - self::delete($newPath, $root); - } - $oldPath=$root.$oldPath; - $newPath=$root.$newPath; - $newParent=self::getParentId($newPath); - $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `parent`=? ,`name`=?, `path`=?, `path_hash`=? WHERE `path_hash`=?'); - $query->execute(array($newParent, basename($newPath), $newPath, md5($newPath), md5($oldPath))); - - if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$oldPath)) { - $cache->set('fileid/'.$newPath, $cache->get('fileid/'.$oldPath)); - $cache->remove('fileid/'.$oldPath); - } - - $query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `path` LIKE ?'); - $oldLength=strlen($oldPath); - $updateQuery=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `path`=?, `path_hash`=? WHERE `path_hash`=?'); - while($row= $query->execute(array($oldPath.'/%'))->fetchRow()) { - $old=$row['path']; - $new=$newPath.substr($old, $oldLength); - $updateQuery->execute(array($new, md5($new), md5($old))); - - if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$old)) { - $cache->set('fileid/'.$new, $cache->get('fileid/'.$old)); - $cache->remove('fileid/'.$old); - } - } - } - - /** - * delete info from the cache - * @param string path - * @param string root (optional) - */ - public static function delete($path, $root=false) { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - $query=OC_DB::prepare('DELETE FROM `*PREFIX*fscache` WHERE `path_hash`=?'); - $query->execute(array(md5($root.$path))); - - //delete everything inside the folder - $query=OC_DB::prepare('DELETE FROM `*PREFIX*fscache` WHERE `path` LIKE ?'); - $query->execute(array($root.$path.'/%')); - - OC_Cache::remove('fileid/'.$root.$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=false) { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - $rootLen=strlen($root); - if(!$returnData) { - $select = '`path`'; - }else{ - $select = '*'; - } - if (OC_Config::getValue('dbtype') === 'oci8') { - $where = 'LOWER(`name`) LIKE LOWER(?) AND `user`=?'; - } else { - $where = '`name` LIKE ? AND `user`=?'; - } - $query=OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*fscache` WHERE '.$where); - $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=false, $mimetype_filter='') { - if(OC_FileCache_Update::hasUpdated($path, $root, true)) { - OC_FileCache_Update::updateFolder($path, $root); - } - return OC_FileCache_Cached::getFolderContent($path, $root, $mimetype_filter); - } - - /** - * 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=false) { - return self::getId($path, $root)!=-1; - } - - /** - * get the file id as used in the cache - * @param string path - * @param string root (optional) - * @return int - */ - public static function getId($path, $root=false) { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - - $fullPath=$root.$path; - if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$fullPath)) { - return $cache->get('fileid/'.$fullPath); - } - - $query=OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `path_hash`=?'); - $result=$query->execute(array(md5($fullPath))); - if(OC_DB::isError($result)) { - OC_Log::write('files', 'error while getting file id of '.$path, OC_Log::ERROR); - return -1; - } - - $result=$result->fetchRow(); - if(is_array($result)) { - $id=$result['id']; - }else{ - $id=-1; - } - if($cache=OC_Cache::getUserCache(true)) { - $cache->set('fileid/'.$fullPath, $id); - } - - return $id; - } - - /** - * get the file path from the id, relative to the home folder of the user - * @param int id - * @param string user (optional) - * @return string - */ - public static function getPath($id, $user='') { - if(!$user) { - $user=OC_User::getUser(); - } - $query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `id`=? AND `user`=?'); - $result=$query->execute(array($id, $user)); - $row=$result->fetchRow(); - $path=$row['path']; - $root='/'.$user.'/files'; - if(substr($path, 0, strlen($root))!=$root) { - return false; - } - return substr($path, strlen($root)); - } - - /** - * 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::getId(dirname($path), ''); - } - } - - /** - * adjust the size of the parent folders - * @param string $path - * @param int $sizeDiff - * @param string root (optinal) - */ - public static function increaseSize($path, $sizeDiff, $root=false) { - if($sizeDiff==0) return; - $item = OC_FileCache_Cached::get($path); - //stop walking up the filetree if we hit a non-folder or reached to root folder - if($path == '/' || $path=='' || $item['mimetype'] !== 'httpd/unix-directory') { - return; - } - $id = $item['id']; - while($id!=-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); - if($path == '' or $path =='/') { - return; - } - $parent = OC_FileCache_Cached::get($path); - $id = $parent['id']; - //stop walking up the filetree if we hit a non-folder - if($parent['mimetype'] !== 'httpd/unix-directory') { - return; - } - } - } - - /** - * recursively scan the filesystem and fill the cache - * @param string $path - * @param OC_EventSource $eventSource (optional) - * @param int $count (optional) - * @param string $root (optional) - */ - public static function scan($path, $eventSource=false,&$count=0, $root=false) { - if($eventSource) { - $eventSource->send('scanning', array('file'=>$path, 'count'=>$count)); - } - $lastSend=$count; - // NOTE: Ugly hack to prevent shared files from going into the cache (the source already exists somewhere in the cache) - if (substr($path, 0, 7) == '/Shared') { - return; - } - if($root===false) { - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView($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.'/')) { - self::scan($file, $eventSource, $count, $root); - }else{ - $totalSize+=self::scanFile($file, $root); - $count++; - if($count>$lastSend+25 and $eventSource) { - $lastSend=$count; - $eventSource->send('scanning', array('file'=>$path, 'count'=>$count)); - } - } - } - } - } - - OC_FileCache_Update::cleanFolder($path, $root); - self::increaseSize($path, $totalSize, $root); - } - - /** - * scan a single file - * @param string path - * @param string root (optional) - * @return int size of the scanned file - */ - public static function scanFile($path, $root=false) { - // NOTE: Ugly hack to prevent shared files from going into the cache (the source already exists somewhere in the cache) - if (substr($path, 0, 7) == '/Shared') { - return; - } - if($root===false) { - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView($root); - } - if(!$view->is_readable($path)) return; //cant read, nothing we can do - clearstatcache(); - $mimetype=$view->getMimeType($path); - $stat=$view->stat($path); - if($mimetype=='httpd/unix-directory') { - $stat['size'] = 0; - $writable=$view->is_writable($path.'/'); - }else{ - $writable=$view->is_writable($path); - } - $stat['mimetype']=$mimetype; - $stat['writable']=$writable; - if($path=='/') { - $path=''; - } - self::put($path, $stat, $root); - return $stat['size']; - } - - /** - * find files by mimetype - * @param string $part1 - * @param string $part2 (optional) - * @param string root (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=null, $root=false) { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - $rootLen=strlen($root); - $root .= '%'; - $user=OC_User::getUser(); - if(!$part2) { - $query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `mimepart`=? AND `user`=? AND `path` LIKE ?'); - $result=$query->execute(array($part1, $user, $root)); - }else{ - $query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `mimetype`=? AND `user`=? AND `path` LIKE ? '); - $result=$query->execute(array($part1.'/'.$part2, $user, $root)); - } - $names=array(); - while($row=$result->fetchRow()) { - $names[]=substr($row['path'], $rootLen); - } - return $names; - } - - /** - * clean old pre-path_hash entries - */ - public static function clean() { - $query=OC_DB::prepare('DELETE FROM `*PREFIX*fscache` WHERE LENGTH(`path_hash`)<30'); - $query->execute(); - } - - /** - * clear filecache entries - * @param string user (optonal) - */ - public static function clear($user='') { - if($user) { - $query=OC_DB::prepare('DELETE FROM `*PREFIX*fscache` WHERE `user`=?'); - $query->execute(array($user)); - }else{ - $query=OC_DB::prepare('DELETE FROM `*PREFIX*fscache`'); - $query->execute(); - } - } - - /** - * trigger an update for the cache by setting the mtimes to 0 - * @param string $user (optional) - */ - public static function triggerUpdate($user='') { - if($user) { - $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 WHERE `user`=? AND `mimetype`= ? '); - $query->execute(array($user,'httpd/unix-directory')); - }else{ - $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 AND `mimetype`= ? '); - $query->execute(array('httpd/unix-directory')); - } - } -} - -//watch for changes and try to keep the cache up to date -OC_Hook::connect('OC_Filesystem', 'post_write', 'OC_FileCache_Update', 'fileSystemWatcherWrite'); -OC_Hook::connect('OC_Filesystem', 'post_delete', 'OC_FileCache_Update', 'fileSystemWatcherDelete'); -OC_Hook::connect('OC_Filesystem', 'post_rename', 'OC_FileCache_Update', 'fileSystemWatcherRename'); -OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_FileCache_Update', 'deleteFromUser'); diff --git a/lib/filecache/cached.php b/lib/filecache/cached.php deleted file mode 100644 index 5e0a00746b9..00000000000 --- a/lib/filecache/cached.php +++ /dev/null @@ -1,81 +0,0 @@ -<?php -/** - * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - - -/** - * get data from the filecache without checking for updates - */ -class OC_FileCache_Cached{ - public static $savedData=array(); - - public static function get($path, $root=false) { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - $path=$root.$path; - $stmt=OC_DB::prepare('SELECT `id`, `path`,`ctime`,`mtime`,`mimetype`,`size`,`encrypted`,`versioned`,`writable` FROM `*PREFIX*fscache` WHERE `path_hash`=?'); - if ( ! OC_DB::isError($stmt) ) { - $result=$stmt->execute(array(md5($path))); - if ( ! OC_DB::isError($result) ) { - $result = $result->fetchRow(); - } else { - OC:Log::write('OC_FileCache_Cached', 'could not execute get: '. OC_DB::getErrorMessage($result), OC_Log::ERROR); - $result = false; - } - } else { - OC_Log::write('OC_FileCache_Cached', 'could not prepare get: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR); - $result = false; - } - if(is_array($result)) { - if(isset(self::$savedData[$path])) { - $result=array_merge($result, self::$savedData[$path]); - } - return $result; - }else{ - if(isset(self::$savedData[$path])) { - return self::$savedData[$path]; - }else{ - return array(); - } - } - } - - /** - * 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: - * - path - * - name - * - size - * - mtime - * - ctime - * - mimetype - * - encrypted - * - versioned - */ - public static function getFolderContent($path, $root=false, $mimetype_filter='') { - if($root===false) { - $root=OC_Filesystem::getRoot(); - } - $parent=OC_FileCache::getId($path, $root); - if($parent==-1) { - return array(); - } - $query=OC_DB::prepare('SELECT `id`,`path`,`name`,`ctime`,`mtime`,`mimetype`,`size`,`encrypted`,`versioned`,`writable` FROM `*PREFIX*fscache` WHERE `parent`=? AND (`mimetype` LIKE ? OR `mimetype` = ?)'); - $result=$query->execute(array($parent, $mimetype_filter.'%', 'httpd/unix-directory'))->fetchAll(); - if(is_array($result)) { - return $result; - }else{ - OC_Log::write('files', 'getFolderContent(): file not found in cache ('.$path.')', OC_Log::DEBUG); - return false; - } - } -} diff --git a/lib/filecache/update.php b/lib/filecache/update.php deleted file mode 100644 index bc403113e7c..00000000000 --- a/lib/filecache/update.php +++ /dev/null @@ -1,227 +0,0 @@ -<?php -/** - * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - - -/** - * handles updating the filecache according to outside changes - */ -class OC_FileCache_Update{ - /** - * check if a file or folder is updated outside owncloud - * @param string path - * @param string root (optional) - * @param boolean folder - * @return bool - */ - public static function hasUpdated($path, $root=false, $folder=false) { - if($root===false) { - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView($root); - } - if(!$view->file_exists($path)) { - return false; - } - $cachedData=OC_FileCache_Cached::get($path, $root); - if(isset($cachedData['mtime'])) { - $cachedMTime=$cachedData['mtime']; - if($folder) { - return $view->hasUpdated($path.'/', $cachedMTime); - }else{ - return $view->hasUpdated($path, $cachedMTime); - } - }else{//file not in cache, so it has to be updated - if(($path=='/' or $path=='') and $root===false) {//dont auto update the home folder, it will be scanned - return false; - } - return true; - } - } - - /** - * delete non existing files from the cache - */ - public static function cleanFolder($path, $root=false) { - if($root===false) { - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView($root); - } - - $cachedContent=OC_FileCache_Cached::getFolderContent($path, $root); - foreach($cachedContent as $fileData) { - $path=$fileData['path']; - $file=$view->getRelativePath($path); - if(!$view->file_exists($file)) { - if($root===false) {//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem', 'post_delete', array('path'=>$file)); - }else{ - self::delete($file, $root); - } - } - } - } - - /** - * update the cache according to changes in the folder - * @param string path - * @param string root (optional) - */ - public static function updateFolder($path, $root=false) { - if($root===false) { - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView($root); - } - $dh=$view->opendir($path.'/'); - if($dh) {//check for changed/new files - while (($filename = readdir($dh)) !== false) { - if($filename != '.' and $filename != '..' and $filename != '') { - $file=$path.'/'.$filename; - $isDir=$view->is_dir($file); - if(self::hasUpdated($file, $root, $isDir)) { - if($isDir) { - self::updateFolder($file, $root); - }elseif($root===false) {//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem', 'post_write', array('path'=>$file)); - }else{ - self::update($file, $root); - } - } - } - } - } - - self::cleanFolder($path, $root); - - //update the folder last, so we can calculate the size correctly - if($root===false) {//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem', 'post_write', array('path'=>$path)); - }else{ - self::update($path, $root); - } - } - - /** - * called when changes are made to files - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherWrite($params) { - $path=$params['path']; - self::update($path); - } - - /** - * called when files are deleted - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherDelete($params) { - $path=$params['path']; - self::delete($path); - } - - /** - * called when files are deleted - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherRename($params) { - $oldPath=$params['oldpath']; - $newPath=$params['newpath']; - self::rename($oldPath, $newPath); - } - - /** - * update the filecache according to changes to the filesystem - * @param string path - * @param string root (optional) - */ - public static function update($path, $root=false) { - if($root===false) { - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView($root); - } - - $mimetype=$view->getMimeType($path); - - $size=0; - $cached=OC_FileCache_Cached::get($path, $root); - $cachedSize=isset($cached['size'])?$cached['size']:0; - - if($view->is_dir($path.'/')) { - if(OC_FileCache::inCache($path, $root)) { - $cachedContent=OC_FileCache_Cached::getFolderContent($path, $root); - foreach($cachedContent as $file) { - $size+=$file['size']; - } - $mtime=$view->filemtime($path.'/'); - $ctime=$view->filectime($path.'/'); - $writable=$view->is_writable($path.'/'); - OC_FileCache::put($path, array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype, 'writable'=>$writable)); - }else{ - $count=0; - OC_FileCache::scan($path, null, $count, $root); - return; //increaseSize is already called inside scan - } - }else{ - $size=OC_FileCache::scanFile($path, $root); - } - if($path !== '' and $path !== '/') { - OC_FileCache::increaseSize(dirname($path), $size-$cachedSize, $root); - } - } - - /** - * update the filesystem after a delete has been detected - * @param string path - * @param string root (optional) - */ - public static function delete($path, $root=false) { - $cached=OC_FileCache_Cached::get($path, $root); - if(!isset($cached['size'])) { - return; - } - $size=$cached['size']; - OC_FileCache::increaseSize(dirname($path), -$size, $root); - OC_FileCache::delete($path, $root); - } - - /** - * update the filesystem after a rename has been detected - * @param string oldPath - * @param string newPath - * @param string root (optional) - */ - public static function rename($oldPath, $newPath, $root=false) { - if(!OC_FileCache::inCache($oldPath, $root)) { - return; - } - if($root===false) { - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView($root); - } - - $cached=OC_FileCache_Cached::get($oldPath, $root); - $oldSize=$cached['size']; - OC_FileCache::increaseSize(dirname($oldPath), -$oldSize, $root); - OC_FileCache::increaseSize(dirname($newPath), $oldSize, $root); - OC_FileCache::move($oldPath, $newPath); - } - - /** - * delete files owned by user from the cache - * @param string $parameters$parameters["uid"]) - */ - public static function deleteFromUser($parameters) { - OC_FileCache::clear($parameters["uid"]); - } -} diff --git a/lib/filechunking.php b/lib/filechunking.php index 55a4d730430..d63a0d72c83 100644 --- a/lib/filechunking.php +++ b/lib/filechunking.php @@ -94,49 +94,49 @@ class OC_FileChunking { } public function file_assemble($path) { - $absolutePath = OC_Filesystem::normalizePath(OC_Filesystem::getView()->getAbsolutePath($path)); + $absolutePath = \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getView()->getAbsolutePath($path)); $data = ''; // use file_put_contents as method because that best matches what this function does - if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) && OC_Filesystem::isValidPath($path)) { - $path = OC_Filesystem::getView()->getRelativePath($absolutePath); - $exists = OC_Filesystem::file_exists($path); + if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) && \OC\Files\Filesystem::isValidPath($path)) { + $path = \OC\Files\Filesystem::getView()->getRelativePath($absolutePath); + $exists = \OC\Files\Filesystem::file_exists($path); $run = true; if(!$exists) { OC_Hook::emit( - OC_Filesystem::CLASSNAME, - OC_Filesystem::signal_create, + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_create, array( - OC_Filesystem::signal_param_path => $path, - OC_Filesystem::signal_param_run => &$run + \OC\Files\Filesystem::signal_param_path => $path, + \OC\Files\Filesystem::signal_param_run => &$run ) ); } OC_Hook::emit( - OC_Filesystem::CLASSNAME, - OC_Filesystem::signal_write, + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_write, array( - OC_Filesystem::signal_param_path => $path, - OC_Filesystem::signal_param_run => &$run + \OC\Files\Filesystem::signal_param_path => $path, + \OC\Files\Filesystem::signal_param_run => &$run ) ); if(!$run) { return false; } - $target = OC_Filesystem::fopen($path, 'w'); + $target = \OC\Files\Filesystem::fopen($path, 'w'); if($target) { $count = $this->assemble($target); fclose($target); if(!$exists) { OC_Hook::emit( - OC_Filesystem::CLASSNAME, - OC_Filesystem::signal_post_create, - array( OC_Filesystem::signal_param_path => $path) + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_post_create, + array( \OC\Files\Filesystem::signal_param_path => $path) ); } OC_Hook::emit( - OC_Filesystem::CLASSNAME, - OC_Filesystem::signal_post_write, - array( OC_Filesystem::signal_param_path => $path) + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_post_write, + array( \OC\Files\Filesystem::signal_param_path => $path) ); OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); return $count > 0; diff --git a/lib/fileproxy.php b/lib/fileproxy.php index 2f81bde64a1..52ec79b4bdb 100644 --- a/lib/fileproxy.php +++ b/lib/fileproxy.php @@ -36,7 +36,7 @@ * The return value 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, + * is_writable, filemtime, filectime, file_get_contents, * getMimeType, hash, fopen, free_space and search */ diff --git a/lib/fileproxy/fileoperations.php b/lib/fileproxy/fileoperations.php index 516629adaec..47ccd8f8c26 100644 --- a/lib/fileproxy/fileoperations.php +++ b/lib/fileproxy/fileoperations.php @@ -28,10 +28,10 @@ class OC_FileProxy_FileOperations extends OC_FileProxy{ static $rootView; public function premkdir($path) { - if(!self::$rootView) { - self::$rootView = new OC_FilesystemView(''); + if(!self::$rootView){ + self::$rootView = new \OC\Files\View(''); } return !self::$rootView->file_exists($path); } -}
\ No newline at end of file +} diff --git a/lib/fileproxy/quota.php b/lib/fileproxy/quota.php index 503288142aa..7e0f631c8fb 100644 --- a/lib/fileproxy/quota.php +++ b/lib/fileproxy/quota.php @@ -22,7 +22,7 @@ */ /** - * user quota managment + * user quota management */ class OC_FileProxy_Quota extends OC_FileProxy{ @@ -57,23 +57,25 @@ class OC_FileProxy_Quota extends OC_FileProxy{ * @return int */ private function getFreeSpace($path) { - $storage=OC_Filesystem::getStorage($path); - $owner=$storage->getOwner($path); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($path); + $owner=$storage->getOwner($internalPath); + if (!$owner) { + return -1; + } $totalSpace=$this->getQuota($owner); if($totalSpace==-1) { return -1; } - $rootInfo=OC_FileCache::get('', "/".$owner."/files"); - // TODO Remove after merge of share_api - if (OC_FileCache::inCache('/Shared', "/".$owner."/files")) { - $sharedInfo=OC_FileCache::get('/Shared', "/".$owner."/files"); - } else { - $sharedInfo = null; - } + $view = new \OC\Files\View("/".$owner."/files"); + + $rootInfo=$view->getFileInfo('/'); $usedSpace=isset($rootInfo['size'])?$rootInfo['size']:0; - $usedSpace=isset($sharedInfo['size'])?$usedSpace-$sharedInfo['size']:$usedSpace; return $totalSpace-$usedSpace; } @@ -93,8 +95,8 @@ class OC_FileProxy_Quota extends OC_FileProxy{ } public function preCopy($path1, $path2) { - if(!self::$rootView) { - self::$rootView = new OC_FilesystemView(''); + if(!self::$rootView){ + self::$rootView = new \OC\Files\View(''); } return (self::$rootView->filesize($path1)<$this->getFreeSpace($path2) or $this->getFreeSpace($path2)==-1); } diff --git a/lib/files.php b/lib/files.php index f4e0f140a44..4d09946a23f 100644 --- a/lib/files.php +++ b/lib/files.php @@ -1,144 +1,48 @@ <?php /** -* ownCloud -* -* @author Frank Karlitschek -* @copyright 2012 Frank Karlitschek frank@owncloud.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/>. -* -*/ + * ownCloud + * + * @author Frank Karlitschek + * @copyright 2012 Frank Karlitschek frank@owncloud.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 for fileserver access * */ class OC_Files { - static $tmpFiles=array(); + static $tmpFiles = array(); - /** - * get the filesystem info - * @param string path - * @return array - * - * returns an associative array with the following keys: - * - size - * - mtime - * - ctime - * - mimetype - * - encrypted - * - versioned - */ - public static function getFileInfo($path) { - $path = OC_Filesystem::normalizePath($path); - if (($path == '/Shared' || substr($path, 0, 8) == '/Shared/') && OC_App::isEnabled('files_sharing')) { - if ($path == '/Shared') { - list($info) = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT); - } else { - $info = array(); - if (OC_Filesystem::file_exists($path)) { - $info['size'] = OC_Filesystem::filesize($path); - $info['mtime'] = OC_Filesystem::filemtime($path); - $info['ctime'] = OC_Filesystem::filectime($path); - $info['mimetype'] = OC_Filesystem::getMimeType($path); - $info['encrypted'] = false; - $info['versioned'] = false; - } - } - } else { - $info = OC_FileCache::get($path); - } - return $info; - } - - /** - * get the content of a directory - * @param dir $directory path under datadirectory - */ - public static function getDirectoryContent($directory, $mimetype_filter = '') { - $directory=OC_Filesystem::normalizePath($directory); - if($directory=='/') { - $directory=''; - } - $files = array(); - if (($directory == '/Shared' || substr($directory, 0, 8) == '/Shared/') && OC_App::isEnabled('files_sharing')) { - if ($directory == '/Shared') { - $files = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP, array('folder' => $directory, 'mimetype_filter' => $mimetype_filter)); - } else { - $pos = strpos($directory, '/', 8); - // Get shared folder name - if ($pos !== false) { - $itemTarget = substr($directory, 7, $pos - 7); - } else { - $itemTarget = substr($directory, 7); - } - $files = OCP\Share::getItemSharedWith('folder', $itemTarget, OC_Share_Backend_File::FORMAT_FILE_APP, array('folder' => $directory, 'mimetype_filter' => $mimetype_filter)); - } - } else { - $files = OC_FileCache::getFolderContent($directory, false, $mimetype_filter); - foreach ($files as &$file) { - $file['directory'] = $directory; - $file['type'] = ($file['mimetype'] == 'httpd/unix-directory') ? 'dir' : 'file'; - $permissions = OCP\PERMISSION_READ; - // NOTE: Remove check when new encryption is merged - if (!$file['encrypted']) { - $permissions |= OCP\PERMISSION_SHARE; - } - if ($file['type'] == 'dir' && $file['writable']) { - $permissions |= OCP\PERMISSION_CREATE; - } - if ($file['writable']) { - $permissions |= OCP\PERMISSION_UPDATE | OCP\PERMISSION_DELETE; - } - $file['permissions'] = $permissions; - } - if ($directory == '' && OC_App::isEnabled('files_sharing')) { - // Add 'Shared' folder - $files = array_merge($files, OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT)); - } - } - usort($files, "fileCmp");//TODO: remove this once ajax is merged - return $files; + static public function getFileInfo($path){ + return \OC\Files\Filesystem::getFileInfo($path); } - public static function searchByMime($mimetype_filter) { - $files = array(); - $dirs_to_check = array(''); - while (!empty($dirs_to_check)) { - // get next subdir to check - $dir = array_pop($dirs_to_check); - $dir_content = self::getDirectoryContent($dir, $mimetype_filter); - foreach($dir_content as $file) { - if ($file['type'] == 'file') { - $files[] = $dir.'/'.$file['name']; - } - else { - $dirs_to_check[] = $dir.'/'.$file['name']; - } - } - } - return $files; + static public function getDirectoryContent($path){ + return \OC\Files\Filesystem::getDirectoryContent($path); } /** - * return the content of a file or return a zip file containning multiply files - * - * @param dir $dir - * @param file $file ; seperated list of files to download - * @param boolean $only_header ; boolean to only send header of the request - */ + * return the content of a file or return a zip file containning multiply files + * + * @param string $dir + * @param string $file ; seperated list of files to download + * @param boolean $only_header ; boolean to only send header of the request + */ public static function get($dir, $files, $only_header = false) { $xsendfile = false; if (isset($_SERVER['MOD_X_SENDFILE_ENABLED']) || @@ -149,7 +53,7 @@ class OC_Files { $files=explode(';', $files); } - if(is_array($files)) { + if (is_array($files)) { self::validateZipDownload($dir, $files); $executionTime = intval(ini_get('max_execution_time')); set_time_limit(0); @@ -162,19 +66,19 @@ class OC_Files { if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { exit("cannot open <$filename>\n"); } - foreach($files as $file) { - $file=$dir.'/'.$file; - if(OC_Filesystem::is_file($file)) { - $tmpFile=OC_Filesystem::toTmpFile($file); - self::$tmpFiles[]=$tmpFile; + foreach ($files as $file) { + $file = $dir . '/' . $file; + if (\OC\Files\Filesystem::is_file($file)) { + $tmpFile = \OC\Files\Filesystem::toTmpFile($file); + self::$tmpFiles[] = $tmpFile; $zip->addFile($tmpFile, basename($file)); - }elseif(OC_Filesystem::is_dir($file)) { + } elseif (\OC\Files\Filesystem::is_dir($file)) { self::zipAddDir($file, $zip); } } $zip->close(); set_time_limit($executionTime); - }elseif(OC_Filesystem::is_dir($dir.'/'.$files)) { + } elseif (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) { self::validateZipDownload($dir, $files); $executionTime = intval(ini_get('max_execution_time')); set_time_limit(0); @@ -187,16 +91,16 @@ class OC_Files { if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { exit("cannot open <$filename>\n"); } - $file=$dir.'/'.$files; + $file = $dir . '/' . $files; self::zipAddDir($file, $zip); $zip->close(); set_time_limit($executionTime); - }else{ - $zip=false; - $filename=$dir.'/'.$files; + } else { + $zip = false; + $filename = $dir . '/' . $files; } OC_Util::obEnd(); - if($zip or OC_Filesystem::is_readable($filename)) { + if ($zip or \OC\Files\Filesystem::isReadable($filename)) { if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) { header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' ); } else { @@ -205,35 +109,35 @@ class OC_Files { } header('Content-Transfer-Encoding: binary'); OC_Response::disableCaching(); - if($zip) { + if ($zip) { ini_set('zlib.output_compression', 'off'); header('Content-Type: application/zip'); header('Content-Length: ' . filesize($filename)); self::addSendfileHeader($filename); }else{ - header('Content-Type: '.OC_Filesystem::getMimeType($filename)); - header("Content-Length: ".OC_Filesystem::filesize($filename)); - $storage = OC_Filesystem::getStorage($filename); - if ($storage instanceof OC_Filestorage_Local) { - self::addSendfileHeader(OC_Filesystem::getLocalFile($filename)); + header('Content-Type: '.\OC\Files\Filesystem::getMimeType($filename)); + header("Content-Length: ".\OC\Files\Filesystem::filesize($filename)); + list($storage) = \OC\Files\Filesystem::resolvePath($filename); + if ($storage instanceof \OC\File\Storage\Local) { + self::addSendfileHeader(\OC\Files\Filesystem::getLocalFile($filename)); } } - }elseif($zip or !OC_Filesystem::file_exists($filename)) { + } elseif ($zip or !\OC\Files\Filesystem::file_exists($filename)) { header("HTTP/1.0 404 Not Found"); - $tmpl = new OC_Template( '', '404', 'guest' ); + $tmpl = new OC_Template('', '404', 'guest'); $tmpl->assign('file', $filename); $tmpl->printPage(); - }else{ + } else { header("HTTP/1.0 403 Forbidden"); die('403 Forbidden'); } if($only_header) { return ; } - if($zip) { - $handle=fopen($filename, 'r'); + if ($zip) { + $handle = fopen($filename, 'r'); if ($handle) { - $chunkSize = 8*1024;// 1 MB chunks + $chunkSize = 8 * 1024; // 1 MB chunks while (!feof($handle)) { echo fread($handle, $chunkSize); flush(); @@ -243,10 +147,10 @@ class OC_Files { unlink($filename); } }else{ - OC_Filesystem::readfile($filename); + \OC\Files\Filesystem::readfile($filename); } - foreach(self::$tmpFiles as $tmpFile) { - if(file_exists($tmpFile) and is_file($tmpFile)) { + foreach (self::$tmpFiles as $tmpFile) { + if (file_exists($tmpFile) and is_file($tmpFile)) { unlink($tmpFile); } } @@ -269,97 +173,27 @@ class OC_Files { foreach($files as $file) { $filename=$file['name']; $file=$dir.'/'.$filename; - if(OC_Filesystem::is_file($file)) { - $tmpFile=OC_Filesystem::toTmpFile($file); + if(\OC\Files\Filesystem::is_file($file)) { + $tmpFile=\OC\Files\Filesystem::toTmpFile($file); OC_Files::$tmpFiles[]=$tmpFile; $zip->addFile($tmpFile, $internalDir.$filename); - }elseif(OC_Filesystem::is_dir($file)) { + }elseif(\OC\Files\Filesystem::is_dir($file)) { self::zipAddDir($file, $zip, $internalDir); } } } - /** - * move a file or folder - * - * @param dir $sourceDir - * @param file $source - * @param dir $targetDir - * @param file $target - */ - public static function move($sourceDir, $source, $targetDir, $target) { - if(OC_User::isLoggedIn() && ($sourceDir != '' || $source != 'Shared')) { - $targetFile=self::normalizePath($targetDir.'/'.$target); - $sourceFile=self::normalizePath($sourceDir.'/'.$source); - return OC_Filesystem::rename($sourceFile, $targetFile); - } else { - return false; - } - } - - /** - * copy a file or folder - * - * @param dir $sourceDir - * @param file $source - * @param dir $targetDir - * @param file $target - */ - public static function copy($sourceDir, $source, $targetDir, $target) { - if(OC_User::isLoggedIn()) { - $targetFile=$targetDir.'/'.$target; - $sourceFile=$sourceDir.'/'.$source; - return OC_Filesystem::copy($sourceFile, $targetFile); - } - } - - /** - * create a new file or folder - * - * @param dir $dir - * @param file $name - * @param type $type - */ - public static function newFile($dir, $name, $type) { - if(OC_User::isLoggedIn()) { - $file=$dir.'/'.$name; - if($type=='dir') { - return OC_Filesystem::mkdir($file); - }elseif($type=='file') { - $fileHandle=OC_Filesystem::fopen($file, 'w'); - if($fileHandle) { - fclose($fileHandle); - return true; - }else{ - return false; - } - } - } - } /** - * deletes a file or folder - * - * @param dir $dir - * @param file $name - */ - public static function delete($dir, $file) { - if(OC_User::isLoggedIn() && ($dir!= '' || $file != 'Shared')) { - $file=$dir.'/'.$file; - return OC_Filesystem::unlink($file); - } - } - - /** - * checks if the selected files are within the size constraint. If not, outputs an error page. - * - * @param dir $dir - * @param files $files - */ + * checks if the selected files are within the size constraint. If not, outputs an error page. + * + * @param dir $dir + * @param files $files + */ static function validateZipDownload($dir, $files) { - if(!OC_Config::getValue('allowZipDownload', true)) { + if (!OC_Config::getValue('allowZipDownload', true)) { $l = OC_L10N::get('lib'); header("HTTP/1.0 409 Conflict"); - $tmpl = new OC_Template( '', 'error', 'user' ); + $tmpl = new OC_Template('', 'error', 'user'); $errors = array( array( 'error' => $l->t('ZIP download is turned off.'), @@ -372,19 +206,19 @@ class OC_Files { } $zipLimit = OC_Config::getValue('maxZipInputSize', OC_Helper::computerFileSize('800 MB')); - if($zipLimit > 0) { + if ($zipLimit > 0) { $totalsize = 0; - if(is_array($files)) { - foreach($files as $file) { - $totalsize += OC_Filesystem::filesize($dir.'/'.$file); + if (is_array($files)) { + foreach ($files as $file) { + $totalsize += \OC\Files\Filesystem::filesize($dir . '/' . $file); } - }else{ - $totalsize += OC_Filesystem::filesize($dir.'/'.$files); + } else { + $totalsize += \OC\Files\Filesystem::filesize($dir . '/' . $files); } - if($totalsize > $zipLimit) { + if ($totalsize > $zipLimit) { $l = OC_L10N::get('lib'); header("HTTP/1.0 409 Conflict"); - $tmpl = new OC_Template( '', 'error', 'user' ); + $tmpl = new OC_Template('', 'error', 'user'); $errors = array( array( 'error' => $l->t('Selected files too large to generate zip file.'), @@ -399,78 +233,31 @@ class OC_Files { } /** - * try to detect the mime type of a file - * - * @param string path - * @return string guessed mime type - */ - static function getMimeType($path) { - return OC_Filesystem::getMimeType($path); - } - - /** - * get a file tree - * - * @param string path - * @return array - */ - static function getTree($path) { - return OC_Filesystem::getTree($path); - } - - /** - * pull a file from a remote server - * @param string source - * @param string token - * @param string dir - * @param string file - * @return string guessed mime type - */ - static function pull($source, $token, $dir, $file) { - $tmpfile=tempnam(get_temp_dir(), 'remoteCloudFile'); - $fp=fopen($tmpfile, 'w+'); - $url=$source.="/files/pull.php?token=$token"; - $ch=curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_exec($ch); - fclose($fp); - $info=curl_getinfo($ch); - $httpCode=$info['http_code']; - curl_close($ch); - if($httpCode==200 or $httpCode==0) { - OC_Filesystem::fromTmpFile($tmpfile, $dir.'/'.$file); - return true; - }else{ - return false; - } - } - - /** * set the maximum upload size limit for apache hosts using .htaccess + * * @param int size filesisze in bytes * @return false on failure, size on success */ static function setUploadLimit($size) { //don't allow user to break his config -- upper boundary - if($size > PHP_INT_MAX) { + if ($size > PHP_INT_MAX) { //max size is always 1 byte lower than computerFileSize returns - if($size > PHP_INT_MAX+1) + if ($size > PHP_INT_MAX + 1) return false; - $size -=1; + $size -= 1; } else { - $size=OC_Helper::humanFileSize($size); - $size=substr($size, 0, -1);//strip the B - $size=str_replace(' ', '', $size); //remove the space between the size and the postfix + $size = OC_Helper::humanFileSize($size); + $size = substr($size, 0, -1); //strip the B + $size = str_replace(' ', '', $size); //remove the space between the size and the postfix } //don't allow user to break his config -- broken or malicious size input - if(intval($size) == 0) { + if (intval($size) == 0) { return false; } - $htaccess = @file_get_contents(OC::$SERVERROOT.'/.htaccess'); //supress errors in case we don't have permissions for - if(!$htaccess) { + $htaccess = @file_get_contents(OC::$SERVERROOT . '/.htaccess'); //supress errors in case we don't have permissions for + if (!$htaccess) { return false; } @@ -479,52 +266,26 @@ class OC_Files { 'post_max_size' ); - foreach($phpValueKeys as $key) { - $pattern = '/php_value '.$key.' (\S)*/'; - $setting = 'php_value '.$key.' '.$size; - $hasReplaced = 0; - $content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced); - if($content !== null) { + foreach ($phpValueKeys as $key) { + $pattern = '/php_value ' . $key . ' (\S)*/'; + $setting = 'php_value ' . $key . ' ' . $size; + $hasReplaced = 0; + $content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced); + if ($content !== null) { $htaccess = $content; } - if($hasReplaced == 0) { + if ($hasReplaced == 0) { $htaccess .= "\n" . $setting; } } //check for write permissions - if(is_writable(OC::$SERVERROOT.'/.htaccess')) { - file_put_contents(OC::$SERVERROOT.'/.htaccess', $htaccess); + if (is_writable(OC::$SERVERROOT . '/.htaccess')) { + file_put_contents(OC::$SERVERROOT . '/.htaccess', $htaccess); return OC_Helper::computerFileSize($size); } else { - OC_Log::write('files', 'Can\'t write upload limit to '.OC::$SERVERROOT.'/.htaccess. Please check the file permissions', OC_Log::WARN); + OC_Log::write('files', 'Can\'t write upload limit to ' . OC::$SERVERROOT . '/.htaccess. Please check the file permissions', OC_Log::WARN); } - return false; } - - /** - * normalize a path, removing any double, add leading /, etc - * @param string $path - * @return string - */ - static public function normalizePath($path) { - $path='/'.$path; - $old=''; - while($old!=$path) {//replace any multiplicity of slashes with a single one - $old=$path; - $path=str_replace('//', '/', $path); - } - 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/files/cache/cache.php b/lib/files/cache/cache.php new file mode 100644 index 00000000000..5c306c2ed16 --- /dev/null +++ b/lib/files/cache/cache.php @@ -0,0 +1,496 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * Metadata cache for the filesystem + * + * don't use this class directly if you need to get metadata, use \OC\Files\Filesystem::getFileInfo instead + */ +class Cache { + const NOT_FOUND = 0; + const PARTIAL = 1; //only partial data available, file not cached in the database + const SHALLOW = 2; //folder in cache, but not all child files are completely scanned + const COMPLETE = 3; + + /** + * @var array partial data for the cache + */ + private $partial = array(); + + /** + * @var string + */ + private $storageId; + + /** + * numeric storage id + * + * @var int $numericId + */ + private $numericId; + + private $mimetypeIds = array(); + private $mimetypes = array(); + + /** + * @param \OC\Files\Storage\Storage|string $storage + */ + public function __construct($storage) { + if ($storage instanceof \OC\Files\Storage\Storage) { + $this->storageId = $storage->getId(); + } else { + $this->storageId = $storage; + } + + $query = \OC_DB::prepare('SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'); + $result = $query->execute(array($this->storageId)); + if ($row = $result->fetchRow()) { + $this->numericId = $row['numeric_id']; + } else { + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*storages`(`id`) VALUES(?)'); + $query->execute(array($this->storageId)); + $this->numericId = \OC_DB::insertid('*PREFIX*filecache'); + } + } + + public function getNumericStorageId() { + return $this->numericId; + } + + /** + * normalize mimetypes + * + * @param string $mime + * @return int + */ + public function getMimetypeId($mime) { + if (!isset($this->mimetypeIds[$mime])) { + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'); + $result = $query->execute(array($mime)); + if ($row = $result->fetchRow()) { + $this->mimetypeIds[$mime] = $row['id']; + } else { + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*mimetypes`(`mimetype`) VALUES(?)'); + $query->execute(array($mime)); + $this->mimetypeIds[$mime] = \OC_DB::insertid('*PREFIX*mimetypes'); + } + $this->mimetypes[$this->mimetypeIds[$mime]] = $mime; + } + return $this->mimetypeIds[$mime]; + } + + public function getMimetype($id) { + if (!isset($this->mimetypes[$id])) { + $query = \OC_DB::prepare('SELECT `mimetype` FROM `*PREFIX*mimetypes` WHERE `id` = ?'); + $result = $query->execute(array($id)); + if ($row = $result->fetchRow()) { + $this->mimetypes[$id] = $row['mimetype']; + } else { + return null; + } + } + return $this->mimetypes[$id]; + } + + /** + * get the stored metadata of a file or folder + * + * @param string/int $file + * @return array + */ + public function get($file) { + if (is_string($file) or $file == '') { + $where = 'WHERE `storage` = ? AND `path_hash` = ?'; + $params = array($this->numericId, md5($file)); + } else { //file id + $where = 'WHERE `fileid` = ?'; + $params = array($file); + } + $query = \OC_DB::prepare( + 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + FROM `*PREFIX*filecache` ' . $where); + $result = $query->execute($params); + $data = $result->fetchRow(); + + //merge partial data + if (!$data and is_string($file)) { + if (isset($this->partial[$file])) { + $data = $this->partial[$file]; + } + } else { + //fix types + $data['fileid'] = (int)$data['fileid']; + $data['size'] = (int)$data['size']; + $data['mtime'] = (int)$data['mtime']; + $data['encrypted'] = (bool)$data['encrypted']; + $data['mimetype'] = $this->getMimetype($data['mimetype']); + $data['mimepart'] = $this->getMimetype($data['mimepart']); + } + + return $data; + } + + /** + * get the metadata of all files stored in $folder + * + * @param string $folder + * @return array + */ + public function getFolderContents($folder) { + $fileId = $this->getId($folder); + if ($fileId > -1) { + $query = \OC_DB::prepare( + 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + FROM `*PREFIX*filecache` WHERE parent = ? ORDER BY `name` ASC'); + $result = $query->execute(array($fileId)); + $files = $result->fetchAll(); + foreach ($files as &$file) { + $file['mimetype'] = $this->getMimetype($file['mimetype']); + $file['mimepart'] = $this->getMimetype($file['mimepart']); + } + return $files; + } else { + return array(); + } + } + + /** + * store meta data for a file or folder + * + * @param string $file + * @param array $data + * + * @return int file id + */ + public function put($file, array $data) { + if (($id = $this->getId($file)) > -1) { + $this->update($id, $data); + return $id; + } else { + if (isset($this->partial[$file])) { //add any saved partial data + $data = array_merge($this->partial[$file], $data); + unset($this->partial[$file]); + } + + $requiredFields = array('size', 'mtime', 'mimetype'); + foreach ($requiredFields as $field) { + if (!isset($data[$field])) { //data not complete save as partial and return + $this->partial[$file] = $data; + return -1; + } + } + + $data['path'] = $file; + $data['parent'] = $this->getParentId($file); + $data['name'] = basename($file); + $data['encrypted'] = isset($data['encrypted']) ? ((int)$data['encrypted']) : 0; + + list($queryParts, $params) = $this->buildParts($data); + $queryParts[] = '`storage`'; + $params[] = $this->numericId; + $valuesPlaceholder = array_fill(0, count($queryParts), '?'); + + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`(' . implode(', ', $queryParts) . ') VALUES(' . implode(', ', $valuesPlaceholder) . ')'); + $query->execute($params); + + return (int)\OC_DB::insertid('*PREFIX*filecache'); + } + } + + /** + * update the metadata in the cache + * + * @param int $id + * @param array $data + */ + public function update($id, array $data) { + list($queryParts, $params) = $this->buildParts($data); + $params[] = $id; + + $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? WHERE fileid = ?'); + $query->execute($params); + } + + /** + * extract query parts and params array from data array + * + * @param array $data + * @return array + */ + function buildParts(array $data) { + $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted', 'etag'); + $params = array(); + $queryParts = array(); + foreach ($data as $name => $value) { + if (array_search($name, $fields) !== false) { + if ($name === 'path') { + $params[] = md5($value); + $queryParts[] = '`path_hash`'; + } elseif ($name === 'mimetype') { + $params[] = $this->getMimetypeId(substr($value, 0, strpos($value, '/'))); + $queryParts[] = '`mimepart`'; + $value = $this->getMimetypeId($value); + } + $params[] = $value; + $queryParts[] = '`' . $name . '`'; + } + } + return array($queryParts, $params); + } + + /** + * get the file id for a file + * + * @param string $file + * @return int + */ + public function getId($file) { + $pathHash = md5($file); + + $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'); + $result = $query->execute(array($this->numericId, $pathHash)); + + if ($row = $result->fetchRow()) { + return $row['fileid']; + } else { + return -1; + } + } + + /** + * get the id of the parent folder of a file + * + * @param string $file + * @return int + */ + public function getParentId($file) { + if ($file === '') { + return -1; + } else { + $parent = dirname($file); + if ($parent === '.') { + $parent = ''; + } + return $this->getId($parent); + } + } + + /** + * check if a file is available in the cache + * + * @param string $file + * @return bool + */ + public function inCache($file) { + return $this->getId($file) != -1; + } + + /** + * remove a file or folder from the cache + * + * @param string $file + */ + public function remove($file) { + $entry = $this->get($file); + if ($entry['mimetype'] === 'httpd/unix-directory') { + $children = $this->getFolderContents($file); + foreach ($children as $child) { + $this->remove($child['path']); + } + } + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?'); + $query->execute(array($entry['fileid'])); + } + + /** + * Move a file or folder in the cache + * + * @param string $source + * @param string $target + */ + public function move($source, $target) { + $sourceId = $this->getId($source); + $newParentId = $this->getParentId($target); + + //find all child entries + $query = \OC_DB::prepare('SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `path` LIKE ?'); + $result = $query->execute(array($source . '/%')); + $childEntries = $result->fetchAll(); + $sourceLength = strlen($source); + $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); + + foreach ($childEntries as $child) { + $targetPath = $target . substr($child['path'], $sourceLength); + $query->execute(array($targetPath, md5($targetPath), $child['fileid'])); + } + + $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `parent` =? WHERE `fileid` = ?'); + $query->execute(array($target, md5($target), $newParentId, $sourceId)); + } + + /** + * remove all entries for files that are stored on the storage from the cache + */ + public function clear() { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE storage = ?'); + $query->execute(array($this->numericId)); + + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*storages` WHERE id = ?'); + $query->execute(array($this->storageId)); + } + + /** + * @param string $file + * + * @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE + */ + public function getStatus($file) { + $pathHash = md5($file); + $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'); + $result = $query->execute(array($this->numericId, $pathHash)); + if ($row = $result->fetchRow()) { + if ((int)$row['size'] === -1) { + return self::SHALLOW; + } else { + return self::COMPLETE; + } + } else { + if (isset($this->partial[$file])) { + return self::PARTIAL; + } else { + return self::NOT_FOUND; + } + } + } + + /** + * search for files matching $pattern + * + * @param string $pattern + * @return array of file data + */ + public function search($pattern) { + $query = \OC_DB::prepare(' + SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?' + ); + $result = $query->execute(array($pattern, $this->numericId)); + $files = array(); + while ($row = $result->fetchRow()) { + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } + return $files; + } + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return array + */ + public function searchByMime($mimetype) { + if (strpos($mimetype, '/')) { + $where = '`mimetype` = ?'; + } else { + $where = '`mimepart` = ?'; + } + $query = \OC_DB::prepare(' + SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?' + ); + $mimetype = $this->getMimetypeId($mimetype); + $result = $query->execute(array($mimetype, $this->numericId)); + return $result->fetchAll(); + } + + /** + * update the folder size and the size of all parent folders + * + * @param $path + */ + public function correctFolderSize($path) { + $this->calculateFolderSize($path); + if ($path !== '') { + $parent = dirname($path); + if ($parent === '.') { + $parent = ''; + } + $this->correctFolderSize($parent); + } + } + + /** + * get the size of a folder and set it in the cache + * + * @param string $path + * @return int + */ + public function calculateFolderSize($path) { + $id = $this->getId($path); + if ($id === -1) { + return 0; + } + $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*filecache` WHERE `parent` = ? AND `storage` = ?'); + $result = $query->execute(array($id, $this->numericId)); + $totalSize = 0; + $hasChilds = 0; + while ($row = $result->fetchRow()) { + $hasChilds = true; + $size = (int)$row['size']; + if ($size === -1) { + $totalSize = -1; + break; + } else { + $totalSize += $size; + } + } + + if ($hasChilds) { + $this->update($id, array('size' => $totalSize)); + } + return $totalSize; + } + + /** + * get all file ids on the files on the storage + * + * @return int[] + */ + public function getAll() { + $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?'); + $result = $query->execute(array($this->numericId)); + $ids = array(); + while ($row = $result->fetchRow()) { + $ids[] = $row['fileid']; + } + return $ids; + } + + /** + * find a folder in the cache which has not been fully scanned + * + * If multiply incomplete folders are in the cache, the one with the highest id will be returned, + * use the one with the highest id gives the best result with the background scanner, since that is most + * likely the folder where we stopped scanning previously + * + * @return string|bool the path of the folder or false when no folder matched + */ + public function getIncomplete() { + $query = \OC_DB::prepare('SELECT `path` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC LIMIT 1'); + $query->execute(array($this->numericId)); + if ($row = $query->fetchRow()) { + return $row['path']; + } else { + return false; + } + } +} diff --git a/lib/files/cache/legacy.php b/lib/files/cache/legacy.php new file mode 100644 index 00000000000..33d4b8e7c9f --- /dev/null +++ b/lib/files/cache/legacy.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * Provide read only support for the old filecache + */ +class Legacy { + private $user; + + private $cacheHasItems = null; + + public function __construct($user) { + $this->user = $user; + } + + function getCount() { + $query = \OC_DB::prepare('SELECT COUNT(`id`) AS `count` FROM `*PREFIX*fscache` WHERE `user` = ?'); + $result = $query->execute(array($this->user)); + if ($row = $result->fetchRow()) { + return $row['count']; + } else { + return 0; + } + } + + /** + * check if a legacy cache is present and holds items + * + * @return bool + */ + function hasItems() { + if (!is_null($this->cacheHasItems)) { + return $this->cacheHasItems; + } + try { + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `user` = ? LIMIT 1'); + } catch (\Exception $e) { + $this->cacheHasItems = false; + return false; + } + try { + $result = $query->execute(array($this->user)); + } catch (\Exception $e) { + $this->cacheHasItems = false; + return false; + } + $this->cacheHasItems = (bool)$result->fetchRow(); + return $this->cacheHasItems; + } + + /** + * @param string|int $path + * @return array + */ + function get($path) { + if (is_numeric($path)) { + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `id` = ?'); + } else { + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?'); + } + $result = $query->execute(array($path)); + return $result->fetchRow(); + } + + /** + * @param int $id + * @return array + */ + function getChildren($id) { + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?'); + $result = $query->execute(array($id)); + return $result->fetchAll(); + } +} diff --git a/lib/files/cache/permissions.php b/lib/files/cache/permissions.php new file mode 100644 index 00000000000..d0968337f02 --- /dev/null +++ b/lib/files/cache/permissions.php @@ -0,0 +1,102 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +class Permissions { + /** + * @var string $storageId + */ + private $storageId; + + /** + * @param \OC\Files\Storage\Storage|string $storage + */ + public function __construct($storage){ + if($storage instanceof \OC\Files\Storage\Storage){ + $this->storageId = $storage->getId(); + }else{ + $this->storageId = $storage; + } + } + + /** + * get the permissions for a single file + * + * @param int $fileId + * @param string $user + * @return int (-1 if file no permissions set) + */ + public function get($fileId, $user) { + $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*permissions` WHERE `user` = ? AND `fileid` = ?'); + $result = $query->execute(array($user, $fileId)); + if ($row = $result->fetchRow()) { + return $row['permissions']; + } else { + return -1; + } + } + + /** + * set the permissions of a file + * + * @param int $fileId + * @param string $user + * @param int $permissions + */ + public function set($fileId, $user, $permissions) { + if (self::get($fileId, $user) !== -1) { + $query = \OC_DB::prepare('UPDATE `*PREFIX*permissions` SET `permissions` = ? WHERE `user` = ? AND `fileid` = ?'); + } else { + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*permissions`(`permissions`, `user`, `fileid`) VALUES(?, ?,? )'); + } + $query->execute(array($permissions, $user, $fileId)); + } + + /** + * get the permissions of multiply files + * + * @param int[] $fileIds + * @param string $user + * @return int[] + */ + public function getMultiple($fileIds, $user) { + if (count($fileIds) === 0) { + return array(); + } + $params = $fileIds; + $params[] = $user; + $inPart = implode(', ', array_fill(0, count($fileIds), '?')); + + $query = \OC_DB::prepare('SELECT `fileid`, `permissions` FROM `*PREFIX*permissions` WHERE `fileid` IN (' . $inPart . ') AND `user` = ?'); + $result = $query->execute($params); + $filePermissions = array(); + while ($row = $result->fetchRow()) { + $filePermissions[$row['fileid']] = $row['permissions']; + } + return $filePermissions; + } + + /** + * remove the permissions for a file + * + * @param int $fileId + * @param string $user + */ + public function remove($fileId, $user) { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'); + $query->execute(array($fileId, $user)); + } + + public function removeMultiple($fileIds, $user) { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'); + foreach($fileIds as $fileId){ + $query->execute(array($fileId, $user)); + } + } +} diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php new file mode 100644 index 00000000000..b62a093cec7 --- /dev/null +++ b/lib/files/cache/scanner.php @@ -0,0 +1,130 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +class Scanner { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage; + + /** + * @var string $storageId + */ + private $storageId; + + /** + * @var \OC\Files\Cache\Cache $cache + */ + private $cache; + + const SCAN_RECURSIVE = true; + const SCAN_SHALLOW = false; + + public function __construct(\OC\Files\Storage\Storage $storage) { + $this->storage = $storage; + $this->storageId = $this->storage->getId(); + $this->cache = $storage->getCache(); + } + + /** + * get all the metadata of a file or folder + * * + * + * @param string $path + * @return array with metadata of the file + */ + public function getData($path) { + $data = array(); + if (!$this->storage->isReadable($path)) return null; //cant read, nothing we can do + $data['mimetype'] = $this->storage->getMimeType($path); + $data['mtime'] = $this->storage->filemtime($path); + if ($data['mimetype'] == 'httpd/unix-directory') { + $data['size'] = -1; //unknown + } else { + $data['size'] = $this->storage->filesize($path); + } + $data['etag'] = $this->storage->getETag($path); + return $data; + } + + /** + * scan a single file and store it in the cache + * + * @param string $file + * @return array with metadata of the scanned file + */ + public function scanFile($file) { + \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId)); + $data = $this->getData($file); + if ($data) { + if ($file) { + $parent = dirname($file); + if ($parent === '.') { + $parent = ''; + } + if (!$this->cache->inCache($parent)) { + $this->scanFile($parent); + } + } + $id = $this->cache->put($file, $data); + } + return $data; + } + + /** + * scan all the files in a folder and store them in the cache + * + * @param string $path + * @param SCAN_RECURSIVE/SCAN_SHALLOW $recursive + * @return int the size of the scanned folder or -1 if the size is unknown at this stage + */ + public function scan($path, $recursive = self::SCAN_RECURSIVE) { + \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_folder', array('path' => $path, 'storage' => $this->storageId)); + $this->scanFile($path); + + $size = 0; + if ($dh = $this->storage->opendir($path)) { + while ($file = readdir($dh)) { + if ($file !== '.' and $file !== '..') { + $child = ($path) ? $path . '/' . $file : $file; + $data = $this->scanFile($child); + if ($data) { + if ($data['mimetype'] === 'httpd/unix-directory') { + if ($recursive === self::SCAN_RECURSIVE) { + $data['size'] = $this->scan($child, self::SCAN_RECURSIVE); + } else { + $data['size'] = -1; + } + } + if ($data['size'] === -1) { + $size = -1; + } elseif ($size !== -1) { + $size += $data['size']; + } + } + } + } + if ($size !== -1) { + $this->cache->put($path, array('size' => $size)); + } + } + return $size; + } + + /** + * walk over any folders that are not fully scanned yet and scan them + */ + public function backgroundScan() { + while ($path = $this->cache->getIncomplete()) { + $this->scan($path); + $this->cache->correctFolderSize($path); + } + } +} diff --git a/lib/files/cache/updater.php b/lib/files/cache/updater.php new file mode 100644 index 00000000000..8b0d3835033 --- /dev/null +++ b/lib/files/cache/updater.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * listen to filesystem hooks and change the cache accordingly + */ +class Updater { + + /** + * resolve a path to a storage and internal path + * + * @param string $path + * @return array consisting of the storage and the internal path + */ + static public function resolvePath($path) { + $view = \OC\Files\Filesystem::getView(); + return $view->resolvePath($path); + } + + static public function writeUpdate($path) { + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = self::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Scanner::SCAN_SHALLOW); + $cache->correctFolderSize($internalPath); + self::eTagUpdate($path); + } + } + + static public function deleteUpdate($path) { + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = self::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $cache->remove($internalPath); + $cache->correctFolderSize($internalPath); + self::eTagUpdate($path); + } + } + + static public function eTagUpdate($path) { + if ($path !== '' && $path !== '/') { + $parent = dirname($path); + if ($parent === '.') { + $parent = ''; + } + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = self::resolvePath($parent); + if ($storage) { + $cache = $storage->getCache(); + $id = $cache->getId($internalPath); + if ($id !== -1) { + $cache->update($id, array('etag' => $storage->getETag($internalPath))); + self::eTagUpdate($parent); + } + } + } + } + + /** + * @param array $params + */ + static public function writeHook($params) { + self::writeUpdate($params['path']); + } + + /** + * @param array $params + */ + static public function renameHook($params) { + self::deleteUpdate($params['oldpath']); + self::writeUpdate($params['newpath']); + } + + /** + * @param array $params + */ + static public function deleteHook($params) { + self::deleteUpdate($params['path']); + } +} diff --git a/lib/files/cache/upgrade.php b/lib/files/cache/upgrade.php new file mode 100644 index 00000000000..cd9a9e91a8c --- /dev/null +++ b/lib/files/cache/upgrade.php @@ -0,0 +1,163 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +class Upgrade { + /** + * @var Legacy $legacy + */ + private $legacy; + + private $permissionsCaches = array(); + + private $numericIds = array(); + + private $mimeTypeIds = array(); + + /** + * @param Legacy $legacy + */ + public function __construct($legacy) { + $this->legacy = $legacy; + } + + /** + * Preform a shallow upgrade + * + * @param string $path + * @param int $mode + */ + function upgradePath($path, $mode = Scanner::SCAN_RECURSIVE) { + if (!$this->legacy->hasItems()) { + return; + } + \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $path); + + if ($row = $this->legacy->get($path)) { + $data = $this->getNewData($row); + $this->insert($data); + + $this->upgradeChilds($data['id'], $mode); + } + } + + /** + * @param int $id + */ + function upgradeChilds($id, $mode = Scanner::SCAN_RECURSIVE) { + $children = $this->legacy->getChildren($id); + foreach ($children as $child) { + $childData = $this->getNewData($child); + \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $child['path']); + $this->insert($childData); + if ($mode == Scanner::SCAN_RECURSIVE) { + $this->upgradeChilds($child['id']); + } + } + } + + /** + * @param array $data the data for the new cache + */ + function insert($data) { + $insertQuery = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` + ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted` ) + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); + + $insertQuery->execute(array($data['id'], $data['storage'], $data['path'], $data['path_hash'], $data['parent'], $data['name'], + $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'])); + + $permissionsCache = $this->getPermissionsCache($data['storage_object']); + $permissionsCache->set($data['id'], $data['user'], $data['permissions']); + } + + /** + * get the new data array from the old one + * + * @param array $data the data from the old cache + * @return array + */ + function getNewData($data) { + $newData = $data; + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath; + */ + $newData['path_hash'] = md5($internalPath); + $newData['path'] = $internalPath; + $newData['storage'] = $this->getNumericId($storage); + $newData['parent'] = ($internalPath === '') ? -1 : $data['parent']; + $newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ; + $newData['storage_object'] = $storage; + $newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage); + $newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage); + return $newData; + } + + /** + * @param \OC\Files\Storage\Storage $storage + * @return Permissions + */ + function getPermissionsCache($storage) { + $storageId = $storage->getId(); + if (!isset($this->permissionsCaches[$storageId])) { + $this->permissionsCaches[$storageId] = $storage->getPermissionsCache(); + } + return $this->permissionsCaches[$storageId]; + } + + /** + * get the numeric storage id + * + * @param \OC\Files\Storage\Storage $storage + * @return int + */ + function getNumericId($storage) { + $storageId = $storage->getId(); + if (!isset($this->numericIds[$storageId])) { + $cache = $storage->getCache(); + $this->numericIds[$storageId] = $cache->getNumericStorageId(); + } + return $this->numericIds[$storageId]; + } + + /** + * @param string $mimetype + * @param \OC\Files\Storage\Storage $storage + * @return int + */ + function getMimetypeId($mimetype, $storage) { + if (!isset($this->mimeTypeIds[$mimetype])) { + $cache = new Cache($storage); + $this->mimeTypeIds[$mimetype] = $cache->getMimetypeId($mimetype); + } + return $this->mimeTypeIds[$mimetype]; + } + + /** + * check if a cache upgrade is required for $user + * + * @param string $user + * @return bool + */ + static function needUpgrade($user) { + $cacheVersion = (int)\OCP\Config::getUserValue($user, 'files', 'cache_version', 4); + return $cacheVersion < 5; + } + + /** + * mark the filecache as upgrade + * + * @param string $user + */ + static function upgradeDone($user) { + \OCP\Config::setUserValue($user, 'files', 'cache_version', 5); + } +} diff --git a/lib/files/cache/watcher.php b/lib/files/cache/watcher.php new file mode 100644 index 00000000000..31059ec7f56 --- /dev/null +++ b/lib/files/cache/watcher.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * check the storage backends for updates and change the cache accordingly + */ +class Watcher { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage; + + /** + * @var Cache $cache + */ + private $cache; + + /** + * @var Scanner $scanner; + */ + private $scanner; + + /** + * @param \OC\Files\Storage\Storage $storage + */ + public function __construct(\OC\Files\Storage\Storage $storage) { + $this->storage = $storage; + $this->cache = $storage->getCache(); + $this->scanner = $storage->getScanner(); + } + + /** + * check $path for updates + * + * @param string $path + */ + public function checkUpdate($path) { + $cachedEntry = $this->cache->get($path); + if ($this->storage->hasUpdated($path, $cachedEntry['mtime'])) { + if ($this->storage->is_dir($path)) { + $this->scanner->scan($path, Scanner::SCAN_SHALLOW); + } else { + $this->scanner->scanFile($path); + } + if ($cachedEntry['mimetype'] === 'httpd/unix-directory') { + $this->cleanFolder($path); + } + $this->cache->correctFolderSize($path); + } + } + + /** + * remove deleted files in $path from the cache + * + * @param string $path + */ + public function cleanFolder($path) { + $cachedContent = $this->cache->getFolderContents($path); + foreach ($cachedContent as $entry) { + if (!$this->storage->file_exists($entry['path'])) { + $this->cache->remove($entry['path']); + } + } + } +} diff --git a/lib/files/file.php b/lib/files/file.php new file mode 100644 index 00000000000..0d33cea7ee7 --- /dev/null +++ b/lib/files/file.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files; + +/** + * representation of the location a file or folder is stored + */ + +class File{ + /** + * @var Storage\Storage $storage + */ + private $storage; + /** + * @var string internalPath + */ + private $internalPath; + + public function __construct(Storage\Storage $storage, $internalPath){ + $this->storage = $storage; + $this->internalPath = $internalPath; + } + + public static function resolve($fullPath){ + $storage = null; + $internalPath = ''; + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($fullPath); + return new File($storage, $internalPath); + } + + /** + * get the internal path of the file inside the filestorage + * @return string + */ + public function getInternalPath(){ + return $this->internalPath; + } + + /** + * get the storage the file is stored in + * @return \OC\Files\Storage\Storage + */ + public function getStorage(){ + return $this->storage; + } + + /** + * get the id of the storage the file is stored in + * @return string + */ + public function getStorageId(){ + return $this->storage->getId(); + } + +} diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php new file mode 100644 index 00000000000..28e8b046896 --- /dev/null +++ b/lib/files/filesystem.php @@ -0,0 +1,675 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class for abstraction of filesystem functions + * This class won't call any filesystem functions for itself but but will pass them to the correct OC_Filestorage object + * this class should also handle all the file permission related stuff + * + * Hooks provided: + * read(path) + * write(path, &run) + * post_write(path) + * create(path, &run) (when a file is created, both create and write will be emitted in that order) + * post_create(path) + * delete(path, &run) + * post_delete(path) + * rename(oldpath,newpath, &run) + * post_rename(oldpath,newpath) + * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order) + * post_rename(oldpath,newpath) + * + * the &run parameter can be set to false to prevent the operation from occurring + */ + +namespace OC\Files; + +class Filesystem { + static private $storages = array(); + static private $mounts = array(); + public static $loaded = false; + /** + * @var \OC\Files\View $defaultInstance + */ + static private $defaultInstance; + + + /** + * classname which used for hooks handling + * used as signalclass in OC_Hooks::emit() + */ + const CLASSNAME = 'OC_Filesystem'; + + /** + * signalname emitted before file renaming + * + * @param string $oldpath + * @param string $newpath + */ + const signal_rename = 'rename'; + + /** + * signal emitted after file renaming + * + * @param string $oldpath + * @param string $newpath + */ + const signal_post_rename = 'post_rename'; + + /** + * signal emitted before file/dir creation + * + * @param string $path + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_create = 'create'; + + /** + * signal emitted after file/dir creation + * + * @param string $path + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_post_create = 'post_create'; + + /** + * signal emits before file/dir copy + * + * @param string $oldpath + * @param string $newpath + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_copy = 'copy'; + + /** + * signal emits after file/dir copy + * + * @param string $oldpath + * @param string $newpath + */ + const signal_post_copy = 'post_copy'; + + /** + * signal emits before file/dir save + * + * @param string $path + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_write = 'write'; + + /** + * signal emits after file/dir save + * + * @param string $path + */ + const signal_post_write = 'post_write'; + + /** + * signal emits when reading file/dir + * + * @param string $path + */ + const signal_read = 'read'; + + /** + * signal emits when removing file/dir + * + * @param string $path + */ + const signal_delete = 'delete'; + + /** + * parameters definitions for signals + */ + const signal_param_path = 'path'; + const signal_param_oldpath = 'oldpath'; + const signal_param_newpath = 'newpath'; + + /** + * run - changing this flag to false in hook handler will cancel event + */ + const signal_param_run = 'run'; + + /** + * 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) { + $path = self::normalizePath($path) . '/'; + \OC_Hook::emit(self::CLASSNAME, 'get_mountpoint', array('path' => $path)); + $foundMountPoint = ''; + $mountPoints = array_keys(self::$mounts); + foreach ($mountPoints as $mountpoint) { + if ($mountpoint == $path) { + return $mountpoint; + } + if (strpos($path, $mountpoint) === 0 and strlen($mountpoint) > strlen($foundMountPoint)) { + $foundMountPoint = $mountpoint; + } + } + return $foundMountPoint; + } + + /** + * get a list of all mount points in a directory + * + * @param string $path + * @return string[] + */ + static public function getMountPoints($path) { + $path = self::normalizePath($path); + if (strlen($path) > 1) { + $path .= '/'; + } + $pathLength = strlen($path); + + $mountPoints = array_keys(self::$mounts); + $result = array(); + foreach ($mountPoints as $mountPoint) { + if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) { + $result[] = $mountPoint; + } + } + return $result; + } + + /** + * get the storage mounted at $mountPoint + * + * @param string $mountPoint + * @return \OC\Files\Storage\Storage + */ + public static function getStorage($mountPoint) { + if (!isset(self::$storages[$mountPoint])) { + $mount = self::$mounts[$mountPoint]; + self::$storages[$mountPoint] = self::createStorage($mount['class'], $mount['arguments']); + } + return self::$storages[$mountPoint]; + } + + /** + * resolve a path to a storage and internal path + * + * @param string $path + * @return array consisting of the storage and the internal path + */ + static public function resolvePath($path) { + $mountpoint = self::getMountPoint($path); + if ($mountpoint) { + $storage = self::getStorage($mountpoint); + if ($mountpoint === $path or $mountpoint . '/' === $path) { + $internalPath = ''; + } else { + $internalPath = substr($path, strlen($mountpoint)); + } + return array($storage, $internalPath); + } else { + return array(null, null); + } + } + + static public function init($root) { + if (self::$defaultInstance) { + return false; + } + self::$defaultInstance = new View($root); + + //load custom mount config + self::initMountPoints(); + + self::$loaded = true; + + return true; + } + + /** + * Initialize system and personal mount points for a user + * + * @param string $user + */ + public static function initMountPoints($user = '') { + if ($user == '') { + $user = \OC_User::getUser(); + } + // Load system mount points + if (is_file(\OC::$SERVERROOT.'/config/mount.php')) { + $mountConfig = include 'config/mount.php'; + if (isset($mountConfig['global'])) { + foreach ($mountConfig['global'] as $mountPoint => $options) { + self::mount($options['class'], $options['options'], $mountPoint); + } + } + if (isset($mountConfig['group'])) { + foreach ($mountConfig['group'] as $group => $mounts) { + if (\OC_Group::inGroup($user, $group)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + self::mount($options['class'], $options['options'], $mountPoint); + } + } + } + } + if (isset($mountConfig['user'])) { + foreach ($mountConfig['user'] as $mountUser => $mounts) { + if ($user === 'all' or strtolower($mountUser) === strtolower($user)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + self::mount($options['class'], $options['options'], $mountPoint); + } + } + } + } + } + // Load personal mount points + $root = \OC_User::getHome($user); + self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user); + if (is_file($root.'/mount.php')) { + $mountConfig = include $root.'/mount.php'; + if (isset($mountConfig['user'][$user])) { + foreach ($mountConfig['user'][$user] as $mountPoint => $options) { + self::mount($options['class'], $options['options'], $mountPoint); + } + } + } + } + + /** + * fill in the correct values for $user, and $password placeholders + * + * @param string $input + * @return string + */ + private static function setUserVars($user, $input) { + return str_replace('$user', $user, $input); + } + + /** + * get the default filesystem view + * + * @return View + */ + static public function getView() { + return self::$defaultInstance; + } + + /** + * tear down the filesystem, removing all storage providers + */ + static public function tearDown() { + self::$storages = array(); + } + + /** + * create a new storage of a specific type + * + * @param string $type + * @param array $arguments + * @return \OC\Files\Storage\Storage + */ + static private function createStorage($class, $arguments) { + if (class_exists($class)) { + try { + return new $class($arguments); + } catch (\Exception $exception) { + \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR); + return false; + } + } else { + \OC_Log::write('core', 'storage backend ' . $class . ' not found', \OC_Log::ERROR); + return false; + } + } + + /** + * @brief get the relative path of the root data directory for the current user + * @return string + * + * Returns path like /admin/files + */ + static public function getRoot() { + return self::$defaultInstance->getRoot(); + } + + /** + * clear all mounts and storage backends + */ + public static function clearMounts() { + self::$mounts = array(); + self::$storages = array(); + } + + /** + * mount an \OC\Files\Storage\Storage in our virtual filesystem + * + * @param \OC\Files\Storage\Storage|string $class + * @param array $arguments + * @param string $mountpoint + */ + static public function mount($class, $arguments, $mountpoint) { + $mountpoint = self::normalizePath($mountpoint); + if (strlen($mountpoint) > 1) { + $mountpoint .= '/'; + } + if ($class instanceof \OC\Files\Storage\Storage) { + self::$mounts[$mountpoint] = array('class' => get_class($class), 'arguments' => $arguments); + self::$storages[$mountpoint] = $class; + } else { + // Update old classes to new namespace + if (strpos($class, 'OC_Filestorage_') !== false) { + $class = '\OC\Files\Storage\\'.substr($class, 15); + } + self::$mounts[$mountpoint] = array('class' => $class, 'arguments' => $arguments); + } + } + + /** + * 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) { + return self::$defaultInstance->getLocalFile($path); + } + + /** + * @param string $path + * @return string + */ + static public function getLocalFolder($path) { + return self::$defaultInstance->getLocalFolder($path); + } + + /** + * return path to file which reflects one visible in browser + * + * @param string $path + * @return string + */ + static public function getLocalPath($path) { + $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files'; + $newpath = $path; + if (strncmp($newpath, $datadir, strlen($datadir)) == 0) { + $newpath = substr($path, strlen($datadir)); + } + return $newpath; + } + + /** + * check if the requested path is valid + * + * @param string $path + * @return bool + */ + static public function isValidPath($path) { + $path = self::normalizePath($path); + if (!$path || $path[0] !== '/') { + $path = '/' . $path; + } + if (strstr($path, '/../') || strrchr($path, '/') === '/..') { + return false; + } + return true; + } + + /** + * checks if a file is blacklisted for storage in the filesystem + * Listens to write and rename hooks + * + * @param array $data from hook + */ + static public function isBlacklisted($data) { + $blacklist = array('.htaccess'); + if (isset($data['path'])) { + $path = $data['path']; + } else if (isset($data['newpath'])) { + $path = $data['newpath']; + } + if (isset($path)) { + $filename = strtolower(basename($path)); + if (in_array($filename, $blacklist)) { + $data['run'] = false; + } + } + } + + /** + * following functions are equivalent to their php builtin equivalents for arguments/return values. + */ + static public function mkdir($path) { + return self::$defaultInstance->mkdir($path); + } + + static public function rmdir($path) { + return self::$defaultInstance->rmdir($path); + } + + static public function opendir($path) { + return self::$defaultInstance->opendir($path); + } + + static public function readdir($path) { + return self::$defaultInstance->readdir($path); + } + + static public function is_dir($path) { + return self::$defaultInstance->is_dir($path); + } + + static public function is_file($path) { + return self::$defaultInstance->is_file($path); + } + + static public function stat($path) { + return self::$defaultInstance->stat($path); + } + + static public function filetype($path) { + return self::$defaultInstance->filetype($path); + } + + static public function filesize($path) { + return self::$defaultInstance->filesize($path); + } + + static public function readfile($path) { + return self::$defaultInstance->readfile($path); + } + + static public function isCreatable($path) { + return self::$defaultInstance->isCreatable($path); + } + + static public function isReadable($path) { + return self::$defaultInstance->isReadable($path); + } + + static public function isUpdatable($path) { + return self::$defaultInstance->isUpdatable($path); + } + + static public function isDeletable($path) { + return self::$defaultInstance->isDeletable($path); + } + + static public function isSharable($path) { + return self::$defaultInstance->isSharable($path); + } + + static public function file_exists($path) { + return self::$defaultInstance->file_exists($path); + } + + static public function filemtime($path) { + return self::$defaultInstance->filemtime($path); + } + + static public function touch($path, $mtime = null) { + return self::$defaultInstance->touch($path, $mtime); + } + + static public function file_get_contents($path) { + return self::$defaultInstance->file_get_contents($path); + } + + static public function file_put_contents($path, $data) { + return self::$defaultInstance->file_put_contents($path, $data); + } + + static public function unlink($path) { + return self::$defaultInstance->unlink($path); + } + + static public function rename($path1, $path2) { + return self::$defaultInstance->rename($path1, $path2); + } + + static public function copy($path1, $path2) { + return self::$defaultInstance->copy($path1, $path2); + } + + static public function fopen($path, $mode) { + return self::$defaultInstance->fopen($path, $mode); + } + + static public function toTmpFile($path) { + return self::$defaultInstance->toTmpFile($path); + } + + static public function fromTmpFile($tmpFile, $path) { + return self::$defaultInstance->fromTmpFile($tmpFile, $path); + } + + static public function getMimeType($path) { + return self::$defaultInstance->getMimeType($path); + } + + static public function hash($type, $path, $raw = false) { + return self::$defaultInstance->hash($type, $path, $raw); + } + + static public function free_space($path = '/') { + return self::$defaultInstance->free_space($path); + } + + static public function search($query) { + return self::$defaultInstance->search($query); + } + + static public function searchByMime($query) { + return self::$defaultInstance->searchByMime($query); + } + + /** + * check if a file or folder has been updated since $time + * + * @param int $time + * @return bool + */ + static public function hasUpdated($path, $time) { + return self::$defaultInstance->hasUpdated($path, $time); + } + + /** + * normalize a path + * + * @param string $path + * @param bool $stripTrailingSlash + * @return string + */ + public static function normalizePath($path, $stripTrailingSlash = true) { + if ($path == '') { + return '/'; + } +//no windows style slashes + $path = str_replace('\\', '/', $path); +//add leading slash + if ($path[0] !== '/') { + $path = '/' . $path; + } +//remove duplicate slashes + while (strpos($path, '//') !== false) { + $path = str_replace('//', '/', $path); + } +//remove trailing slash + if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') { + $path = substr($path, 0, -1); + } +//normalize unicode if possible + if (class_exists('Normalizer')) { + $path = \Normalizer::normalize($path); + } + return $path; + } + + /** + * get the filesystem info + * + * @param string $path + * @return array + * + * returns an associative array with the following keys: + * - size + * - mtime + * - mimetype + * - encrypted + * - versioned + */ + public static function getFileInfo($path) { + return self::$defaultInstance->getFileInfo($path); + } + + /** + * change file metadata + * + * @param string $path + * @param array $data + * @return int + * + * returns the fileid of the updated file + */ + public static function putFileInfo($path, $data) { + return self::$defaultInstance->putFileInfo($path, $data); + } + + /** + * get the content of a directory + * + * @param string $directory path under datadirectory + * @return array + */ + public static function getDirectoryContent($directory, $mimetype_filter = '') { + return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter); + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + static public function getETag($path){ + return self::$defaultInstance->getETag($path); + } +} + +\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook'); +\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook'); +\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook'); + +\OC_Util::setupFS(); diff --git a/lib/filestorage/common.php b/lib/files/storage/common.php index b97eb79d8d4..591803f0440 100644 --- a/lib/filestorage/common.php +++ b/lib/files/storage/common.php @@ -1,51 +1,34 @@ <?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/>. -*/ + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; /** * Storage backend class for providing common filesystem operation methods * which are not storage-backend specific. * - * OC_Filestorage_Common is never used directly; it is extended by all other + * \OC\Files\Storage\Common is never used directly; it is extended by all other * storage backends, where its methods may be overridden, and additional * (backend-specific) methods are defined. * - * Some OC_Filestorage_Common methods call functions which are first defined + * Some \OC\Files\Storage\Common methods call functions which are first defined * in classes which extend it, e.g. $this->stat() . */ -abstract class OC_Filestorage_Common extends OC_Filestorage { +abstract class Common implements \OC\Files\Storage\Storage { public function __construct($parameters) {} -// abstract public function mkdir($path); -// abstract public function rmdir($path); -// abstract public function opendir($path); public function is_dir($path) { return $this->filetype($path)=='dir'; } public function is_file($path) { return $this->filetype($path)=='file'; } -// abstract public function stat($path); -// abstract public function filetype($path); public function filesize($path) { if($this->is_dir($path)) { return 0;//by definition @@ -55,29 +38,40 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { } } public function isCreatable($path) { - return $this->isUpdatable($path); + if ($this->is_dir($path) && $this->isUpdatable($path)) { + return true; + } + return false; } -// abstract public function isReadable($path); -// abstract public function isUpdatable($path); public function isDeletable($path) { return $this->isUpdatable($path); } public function isSharable($path) { return $this->isReadable($path); } -// abstract public function file_exists($path); - public function filectime($path) { - $stat = $this->stat($path); - return $stat['ctime']; + public function getPermissions($path){ + $permissions = 0; + if($this->isCreatable($path)){ + $permissions |= \OCP\PERMISSION_CREATE; + } + if($this->isReadable($path)){ + $permissions |= \OCP\PERMISSION_READ; + } + if($this->isUpdatable($path)){ + $permissions |= \OCP\PERMISSION_UPDATE; + } + if($this->isDeletable($path)){ + $permissions |= \OCP\PERMISSION_DELETE; + } + if($this->isSharable($path)){ + $permissions |= \OCP\PERMISSION_SHARE; + } + return $permissions; } 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"); if(!$handle) { @@ -89,94 +83,58 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { } return fread($handle, $size); } - public function file_put_contents($path, $data) { + public function file_put_contents($path,$data) { $handle = $this->fopen($path, "w"); return fwrite($handle, $data); } -// abstract public function unlink($path); - public function rename($path1, $path2) { - if($this->copy($path1, $path2)) { + public function rename($path1,$path2) { + if($this->copy($path1,$path2)) { return $this->unlink($path1); }else{ return false; } } - public function copy($path1, $path2) { - $source=$this->fopen($path1, 'r'); - $target=$this->fopen($path2, 'w'); - $count=OC_Helper::streamCopy($source, $target); + public function copy($path1,$path2) { + $source=$this->fopen($path1,'r'); + $target=$this->fopen($path2,'w'); + $count=\OC_Helper::streamCopy($source,$target); return $count>0; } -// abstract public function fopen($path, $mode); /** * @brief Deletes all files and folders recursively within a directory - * @param $directory The directory whose contents will be deleted - * @param $empty Flag indicating whether directory will be emptied - * @returns true/false + * @param string $directory The directory whose contents will be deleted + * @param bool $empty Flag indicating whether directory will be emptied + * @returns bool * * @note By default the directory specified by $directory will be * deleted together with its contents. To avoid this set $empty to true */ public function deleteAll( $directory, $empty = false ) { - - // strip leading slash - if( substr( $directory, 0, 1 ) == "/" ) { - - $directory = substr( $directory, 1 ); - - } - - // strip trailing slash - if( substr( $directory, -1) == "/" ) { - - $directory = substr( $directory, 0, -1 ); - - } + $directory = trim($directory,'/'); if ( !$this->file_exists( \OCP\USER::getUser() . '/' . $directory ) || !$this->is_dir( \OCP\USER::getUser() . '/' . $directory ) ) { - return false; - - } elseif( !$this->is_readable( \OCP\USER::getUser() . '/' . $directory ) ) { - + } elseif( !$this->isReadable( \OCP\USER::getUser() . '/' . $directory ) ) { return false; - } else { - $directoryHandle = $this->opendir( \OCP\USER::getUser() . '/' . $directory ); - while ( $contents = readdir( $directoryHandle ) ) { - if ( $contents != '.' && $contents != '..') { - $path = $directory . "/" . $contents; - if ( $this->is_dir( $path ) ) { - - deleteAll( $path ); - + $this->deleteAll( $path ); } else { - $this->unlink( \OCP\USER::getUser() .'/' . $path ); // TODO: make unlink use same system path as is_dir - } } - } - //$this->closedir( $directoryHandle ); // TODO: implement closedir in OC_FSV - if ( $empty == false ) { - if ( !$this->rmdir( $directory ) ) { - - return false; - + return false; } - } - return true; } @@ -188,73 +146,71 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { if($this->is_dir($path)) { return 'httpd/unix-directory'; } - $source=$this->fopen($path, 'r'); + $source=$this->fopen($path,'r'); if(!$source) { return false; } - $head=fread($source, 8192);//8kb should suffice to determine a mimetype - if($pos=strrpos($path, '.')) { - $extension=substr($path, $pos); + $head=fread($source,8192);//8kb should suffice to determine a mimetype + if($pos=strrpos($path,'.')) { + $extension=substr($path,$pos); }else{ $extension=''; } - $tmpFile=OC_Helper::tmpFile($extension); - file_put_contents($tmpFile, $head); - $mime=OC_Helper::getMimeType($tmpFile); + $tmpFile=\OC_Helper::tmpFile($extension); + file_put_contents($tmpFile,$head); + $mime=\OC_Helper::getMimeType($tmpFile); unlink($tmpFile); return $mime; } - public function hash($type, $path, $raw = false) { - $tmpFile=$this->getLocalFile(); - $hash=hash($type, $tmpFile, $raw); + public function hash($type,$path,$raw = false) { + $tmpFile=$this->getLocalFile($path); + $hash=hash($type,$tmpFile,$raw); unlink($tmpFile); return $hash; } -// abstract public function free_space($path); public function search($query) { return $this->searchInDir($query); } public function getLocalFile($path) { return $this->toTmpFile($path); } - private function toTmpFile($path) {//no longer in the storage api, still usefull here - $source=$this->fopen($path, 'r'); + private function toTmpFile($path) {//no longer in the storage api, still useful here + $source=$this->fopen($path,'r'); if(!$source) { return false; } - if($pos=strrpos($path, '.')) { - $extension=substr($path, $pos); + if($pos=strrpos($path,'.')) { + $extension=substr($path,$pos); }else{ $extension=''; } - $tmpFile=OC_Helper::tmpFile($extension); - $target=fopen($tmpFile, 'w'); - OC_Helper::streamCopy($source, $target); + $tmpFile=\OC_Helper::tmpFile($extension); + $target=fopen($tmpFile,'w'); + \OC_Helper::streamCopy($source,$target); return $tmpFile; } public function getLocalFolder($path) { - $baseDir=OC_Helper::tmpFolder(); - $this->addLocalFolder($path, $baseDir); + $baseDir=\OC_Helper::tmpFolder(); + $this->addLocalFolder($path,$baseDir); return $baseDir; } - private function addLocalFolder($path, $target) { + private function addLocalFolder($path,$target) { if($dh=$this->opendir($path)) { while($file=readdir($dh)) { if($file!=='.' and $file!=='..') { if($this->is_dir($path.'/'.$file)) { mkdir($target.'/'.$file); - $this->addLocalFolder($path.'/'.$file, $target.'/'.$file); + $this->addLocalFolder($path.'/'.$file,$target.'/'.$file); }else{ $tmp=$this->toTmpFile($path.'/'.$file); - rename($tmp, $target.'/'.$file); + rename($tmp,$target.'/'.$file); } } } } } -// abstract public function touch($path, $mtime=null); - protected function searchInDir($query, $dir='') { + protected function searchInDir($query,$dir='') { $files=array(); $dh=$this->opendir($dir); if($dh) { @@ -264,7 +220,7 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { $files[]=$dir.'/'.$item; } if($this->is_dir($dir.'/'.$item)) { - $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item)); + $files=array_merge($files,$this->searchInDir($query,$dir.'/'.$item)); } } } @@ -273,19 +229,52 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { /** * check if a file or folder has been updated since $time + * @param string $path * @param int $time * @return bool */ - public function hasUpdated($path, $time) { + public function hasUpdated($path,$time) { return $this->filemtime($path)>$time; } + public function getCache($path=''){ + return new \OC\Files\Cache\Cache($this); + } + + public function getScanner($path=''){ + return new \OC\Files\Cache\Scanner($this); + } + + public function getPermissionsCache($path=''){ + return new \OC\Files\Cache\Permissions($this); + } + + public function getWatcher($path=''){ + return new \OC\Files\Cache\Watcher($this); + } + /** * get the owner of a path - * @param $path The path to get the owner + * @param string $path The path to get the owner * @return string uid or false */ public function getOwner($path) { - return OC_User::getUser(); + return \OC_User::getUser(); + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path){ + $ETagFunction = \OC_Connector_Sabre_Node::$ETagFunction; + if($ETagFunction) { + $hash = call_user_func($ETagFunction, $path); + return $hash; + }else{ + return uniqid(); + } } } diff --git a/lib/filestorage/commontest.php b/lib/files/storage/commontest.php index 3b038b3fda9..fbdb7fbf110 100644 --- a/lib/filestorage/commontest.php +++ b/lib/files/storage/commontest.php @@ -22,20 +22,25 @@ */ /** - * test implementation for OC_FileStorage_Common with OC_FileStorage_Local + * test implementation for \OC\Files\Storage\Common with \OC\Files\Storage\Local */ -class OC_Filestorage_CommonTest extends OC_Filestorage_Common{ +namespace OC\Files\Storage; + +class CommonTest extends \OC\Files\Storage\Common{ /** * underlying local storage used for missing functions - * @var OC_FileStorage_Local + * @var \OC\Files\Storage\Local */ private $storage; public function __construct($params) { - $this->storage=new OC_Filestorage_Local($params); + $this->storage=new \OC\Files\Storage\Local($params); } + public function getId(){ + return 'test::'.$this->storage->getId(); + } public function mkdir($path) { return $this->storage->mkdir($path); } diff --git a/lib/filestorage/local.php b/lib/files/storage/local.php index 910b3fa039d..53e1c5b4f01 100644 --- a/lib/filestorage/local.php +++ b/lib/files/storage/local.php @@ -1,8 +1,17 @@ <?php /** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +/** * for local filestore, we only have to map the paths */ -class OC_Filestorage_Local extends OC_Filestorage_Common{ +class Local extends \OC\Files\Storage\Common{ protected $datadir; public function __construct($arguments) { $this->datadir=$arguments['datadir']; @@ -10,6 +19,9 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{ $this->datadir.='/'; } } + public function getId(){ + return 'local::'.$this->datadir; + } public function mkdir($path) { return @mkdir($this->datadir.$path); } @@ -20,7 +32,7 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{ return opendir($this->datadir.$path); } public function is_dir($path) { - if(substr($path, -1)=='/') { + if(substr($path,-1)=='/') { $path=substr($path, 0, -1); } return is_dir($this->datadir.$path); @@ -68,9 +80,6 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{ public function file_exists($path) { return file_exists($this->datadir.$path); } - public function filectime($path) { - return filectime($this->datadir.$path); - } public function filemtime($path) { return filemtime($this->datadir.$path); } @@ -100,11 +109,11 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{ } public function rename($path1, $path2) { if (!$this->isUpdatable($path1)) { - OC_Log::write('core', 'unable to rename, file is not writable : '.$path1, OC_Log::ERROR); + \OC_Log::write('core','unable to rename, file is not writable : '.$path1,\OC_Log::ERROR); return false; } if(! $this->file_exists($path1)) { - OC_Log::write('core', 'unable to rename, file does not exists : '.$path1, OC_Log::ERROR); + \OC_Log::write('core','unable to rename, file does not exists : '.$path1,\OC_Log::ERROR); return false; } @@ -143,7 +152,7 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{ public function getMimeType($path) { if($this->isReadable($path)) { - return OC_Helper::getMimeType($this->datadir.$path); + return \OC_Helper::getMimeType($this->datadir . $path); }else{ return false; } diff --git a/lib/files/storage/storage.php b/lib/files/storage/storage.php new file mode 100644 index 00000000000..2cc835236ba --- /dev/null +++ b/lib/files/storage/storage.php @@ -0,0 +1,88 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +/** + * Provide a common interface to all different storage options + */ +interface Storage{ + public function __construct($parameters); + public function getId(); + 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); + public function isCreatable($path); + public function isReadable($path); + public function isUpdatable($path); + public function isDeletable($path); + public function isSharable($path); + public function getPermissions($path); + public function file_exists($path); + public function filemtime($path); + public function file_get_contents($path); + public function file_put_contents($path,$data); + public function unlink($path); + public function rename($path1,$path2); + public function copy($path1,$path2); + public function fopen($path,$mode); + public function getMimeType($path); + public function hash($type,$path,$raw = false); + public function free_space($path); + public function search($query); + public function touch($path, $mtime=null); + public function getLocalFile($path);// get a path to a local version of the file, whether the original file is local or remote + public function getLocalFolder($path);// get a path to a local version of the folder, whether the original file is local or remote + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + public function hasUpdated($path,$time); + + /** + * @param string $path + * @return \OC\Files\Cache\Cache + */ + public function getCache($path=''); + /** + * @param string $path + * @return \OC\Files\Cache\Scanner + */ + public function getScanner($path=''); + + public function getOwner($path); + + /** + * @param string $path + * @return \OC\Files\Cache\Permissions + */ + public function getPermissionsCache($path=''); + + /** + * @param string $path + * @return \OC\Files\Cache\Watcher + */ + public function getWatcher($path=''); + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path); +} diff --git a/lib/files/storage/temporary.php b/lib/files/storage/temporary.php new file mode 100644 index 00000000000..ffc55e27507 --- /dev/null +++ b/lib/files/storage/temporary.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +/** + * local storage backnd in temporary folder for testing purpores + */ +class Temporary extends Local{ + public function __construct($arguments) { + $this->datadir=\OC_Helper::tmpFolder(); + } + + public function cleanUp() { + \OC_Helper::rmdirr($this->datadir); + } + + public function __destruct() { + $this->cleanUp(); + } +} diff --git a/lib/files/view.php b/lib/files/view.php new file mode 100644 index 00000000000..06027910123 --- /dev/null +++ b/lib/files/view.php @@ -0,0 +1,930 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class to provide access to ownCloud filesystem via a "view", and methods for + * working with files within that view (e.g. read, write, delete, etc.). Each + * view is restricted to a set of directories via a virtual root. The default view + * uses the currently logged in user's data directory as root (parts of + * OC_Filesystem are merely a wrapper for OC_FilesystemView). + * + * Apps that need to access files outside of the user data folders (to modify files + * belonging to a user other than the one currently logged in, for example) should + * use this class directly rather than using OC_Filesystem, or making use of PHP's + * built-in file manipulation functions. This will ensure all hooks and proxies + * are triggered correctly. + * + * Filesystem functions are not called directly; they are passed to the correct + * \OC\Files\Storage\Storage object + */ + +namespace OC\Files; + +class View { + private $fakeRoot = ''; + private $internal_path_cache = array(); + private $storage_cache = array(); + + public function __construct($root) { + $this->fakeRoot = $root; + } + + public function getAbsolutePath($path = '/') { + if (!$path) { + $path = '/'; + } + if ($path[0] !== '/') { + $path = '/' . $path; + } + return $this->fakeRoot . $path; + } + + /** + * change the root to a fake root + * + * @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 path relative to the root of the view + * + * @param string $path + * @return string + */ + public function getRelativePath($path) { + if ($this->fakeRoot == '') { + return $path; + } + if (strpos($path, $this->fakeRoot) !== 0) { + return null; + } else { + $path = substr($path, strlen($this->fakeRoot)); + if (strlen($path) === 0) { + return '/'; + } else { + return $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 Filesystem::getMountPoint($this->getAbsolutePath($path)); + } + + /** + * resolve a path to a storage and internal path + * + * @param string $path + * @return array consisting of the storage and the internal path + */ + public function resolvePath($path) { + return Filesystem::resolvePath($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, '/')); + $path = $this->getAbsolutePath($path); + list($storage, $internalPath) = Filesystem::resolvePath($path); + if (Filesystem::isValidPath($parent) and $storage) { + return $storage->getLocalFile($internalPath); + } else { + return null; + } + } + + /** + * @param string $path + * @return string + */ + public function getLocalFolder($path) { + $parent = substr($path, 0, strrpos($path, '/')); + $path = $this->getAbsolutePath($path); + list($storage, $internalPath) = Filesystem::resolvePath($path); + if (Filesystem::isValidPath($parent) and $storage) { + return $storage->getLocalFolder($internalPath); + } else { + return null; + } + } + + /** + * the following functions operate with arguments and return values identical + * to those of their PHP built-in equivalents. Mostly they are merely wrappers + * for \OC\Files\Storage\Storage via basicOperation(). + */ + 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 readdir($handle) { + $fsLocal = new Storage\Local(array('datadir' => '/')); + return $fsLocal->readdir($handle); + } + + 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) { + @ob_end_clean(); + $handle = $this->fopen($path, 'rb'); + if ($handle) { + $chunkSize = 8192; // 8 MB chunks + while (!feof($handle)) { + echo fread($handle, $chunkSize); + flush(); + } + $size = $this->filesize($path); + return $size; + } + return false; + } + + public function isCreatable($path) { + return $this->basicOperation('isCreatable', $path); + } + + public function isReadable($path) { + return $this->basicOperation('isReadable', $path); + } + + public function isUpdatable($path) { + return $this->basicOperation('isUpdatable', $path); + } + + public function isDeletable($path) { + return $this->basicOperation('isDeletable', $path); + } + + public function isSharable($path) { + return $this->basicOperation('isSharable', $path); + } + + public function file_exists($path) { + if ($path == '/') { + return true; + } + return $this->basicOperation('file_exists', $path); + } + + public function filemtime($path) { + return $this->basicOperation('filemtime', $path); + } + + public function touch($path, $mtime = null) { + if (!is_null($mtime) and !is_numeric($mtime)) { + $mtime = strtotime($mtime); + } + return $this->basicOperation('touch', $path, array('write'), $mtime); + } + + public function file_get_contents($path) { + return $this->basicOperation('file_get_contents', $path, array('read')); + } + + public function file_put_contents($path, $data) { + if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier + $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); + if (\OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) && Filesystem::isValidPath($path)) { + $path = $this->getRelativePath($absolutePath); + $exists = $this->file_exists($path); + $run = true; + if ($this->fakeRoot == Filesystem::getRoot()) { + if (!$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_create, + array( + Filesystem::signal_param_path => $path, + Filesystem::signal_param_run => &$run + ) + ); + } + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_write, + array( + Filesystem::signal_param_path => $path, + Filesystem::signal_param_run => &$run + ) + ); + } + if (!$run) { + return false; + } + $target = $this->fopen($path, 'w'); + if ($target) { + $count = \OC_Helper::streamCopy($data, $target); + fclose($target); + fclose($data); + if ($this->fakeRoot == Filesystem::getRoot()) { + if (!$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_create, + array(Filesystem::signal_param_path => $path) + ); + } + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_write, + array(Filesystem::signal_param_path => $path) + ); + } + \OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); + return $count > 0; + } else { + return false; + } + } else { + return false; + } + } else { + return $this->basicOperation('file_put_contents', $path, array('create', 'write'), $data); + } + } + + public function unlink($path) { + return $this->basicOperation('unlink', $path, array('delete')); + } + + public function deleteAll($directory, $empty = false) { + return $this->basicOperation('deleteAll', $directory, array('delete'), $empty); + } + + public function rename($path1, $path2) { + $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; + $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; + $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); + $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); + if (\OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2) and Filesystem::isValidPath($path2)) { + $path1 = $this->getRelativePath($absolutePath1); + $path2 = $this->getRelativePath($absolutePath2); + + if ($path1 == null or $path2 == null) { + return false; + } + $run = true; + if ($this->fakeRoot == Filesystem::getRoot()) { + \OC_Hook::emit( + Filesystem::CLASSNAME, Filesystem::signal_rename, + array( + Filesystem::signal_param_oldpath => $path1, + Filesystem::signal_param_newpath => $path2, + Filesystem::signal_param_run => &$run + ) + ); + } + if ($run) { + $mp1 = $this->getMountPoint($path1 . $postFix1); + $mp2 = $this->getMountPoint($path2 . $postFix2); + if ($mp1 == $mp2) { + list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); + list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); + if ($storage) { + $result = $storage->rename($internalPath1, $internalPath2); + } else { + $result = false; + } + } else { + $source = $this->fopen($path1 . $postFix1, 'r'); + $target = $this->fopen($path2 . $postFix2, 'w'); + $count = \OC_Helper::streamCopy($source, $target); + list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); + $storage1->unlink($internalPath1); + $result = $count > 0; + } + if ($this->fakeRoot == Filesystem::getRoot()) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_rename, + array( + Filesystem::signal_param_oldpath => $path1, + Filesystem::signal_param_newpath => $path2 + ) + ); + } + return $result; + } else { + return false; + } + } else { + return false; + } + } + + public function copy($path1, $path2) { + $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; + $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; + $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); + $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); + if (\OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and Filesystem::isValidPath($path2)) { + $path1 = $this->getRelativePath($absolutePath1); + $path2 = $this->getRelativePath($absolutePath2); + + if ($path1 == null or $path2 == null) { + return false; + } + $run = true; + $exists = $this->file_exists($path2); + if ($this->fakeRoot == Filesystem::getRoot()) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_copy, + array( + Filesystem::signal_param_oldpath => $path1, + Filesystem::signal_param_newpath => $path2, + Filesystem::signal_param_run => &$run + ) + ); + if ($run and !$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_create, + array( + Filesystem::signal_param_path => $path2, + Filesystem::signal_param_run => &$run + ) + ); + } + if ($run) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_write, + array( + Filesystem::signal_param_path => $path2, + Filesystem::signal_param_run => &$run + ) + ); + } + } + if ($run) { + $mp1 = $this->getMountPoint($path1 . $postFix1); + $mp2 = $this->getMountPoint($path2 . $postFix2); + if ($mp1 == $mp2) { + list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); + list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); + if ($storage) { + $result = $storage->copy($internalPath1, $internalPath2); + } else { + $result = false; + } + } else { + $source = $this->fopen($path1 . $postFix1, 'r'); + $target = $this->fopen($path2 . $postFix2, 'w'); + $result = \OC_Helper::streamCopy($source, $target); + } + if ($this->fakeRoot == Filesystem::getRoot()) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_copy, + array( + Filesystem::signal_param_oldpath => $path1, + Filesystem::signal_param_newpath => $path2 + ) + ); + if (!$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_create, + array(Filesystem::signal_param_path => $path2) + ); + } + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_write, + array(Filesystem::signal_param_path => $path2) + ); + } + return $result; + } else { + return false; + } + } else { + return false; + } + } + + public function fopen($path, $mode) { + $hooks = array(); + switch ($mode) { + case 'r': + case 'rb': + $hooks[] = 'read'; + break; + case 'r+': + case 'rb+': + case 'w+': + case 'wb+': + case 'x+': + case 'xb+': + case 'a+': + case 'ab+': + $hooks[] = 'read'; + $hooks[] = 'write'; + break; + case 'w': + case 'wb': + case 'x': + case 'xb': + case 'a': + case 'ab': + $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 (Filesystem::isValidPath($path)) { + $source = $this->fopen($path, 'r'); + if ($source) { + $extension = ''; + $extOffset = strpos($path, '.'); + if ($extOffset !== false) { + $extension = substr($path, strrpos($path, '.')); + } + $tmpFile = \OC_Helper::tmpFile($extension); + file_put_contents($tmpFile, $source); + return $tmpFile; + } else { + return false; + } + } else { + return false; + } + } + + public function fromTmpFile($tmpFile, $path) { + if (Filesystem::isValidPath($path)) { + if (!$tmpFile) { + debug_print_backtrace(); + } + $source = fopen($tmpFile, 'r'); + if ($source) { + $this->file_put_contents($path, $source); + unlink($tmpFile); + return true; + } else { + return false; + } + } else { + return false; + } + } + + public function getMimeType($path) { + return $this->basicOperation('getMimeType', $path); + } + + public function hash($type, $path, $raw = false) { + $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; + $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); + if (\OC_FileProxy::runPreProxies('hash', $absolutePath) && Filesystem::isValidPath($path)) { + $path = $this->getRelativePath($absolutePath); + if ($path == null) { + return false; + } + if (Filesystem::$loaded && $this->fakeRoot == Filesystem::getRoot()) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_read, + array(Filesystem::signal_param_path => $path) + ); + } + list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); + if ($storage) { + $result = $storage->hash($type, $internalPath, $raw); + $result = \OC_FileProxy::runPostProxies('hash', $absolutePath, $result); + return $result; + } + } + return null; + } + + public function free_space($path = '/') { + return $this->basicOperation('free_space', $path); + } + + /** + * @brief abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage + * @param string $operation + * @param string $path + * @param array $hooks (optional) + * @param mixed $extraParam (optional) + * @return mixed + * + * This method takes requests for basic filesystem functions (e.g. reading & writing + * files), processes hooks and proxies, sanitises paths, and finally passes them on to + * \OC\Files\Storage\Storage for delegation to a storage backend for execution + */ + private function basicOperation($operation, $path, $hooks = array(), $extraParam = null) { + $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; + $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); + if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) and Filesystem::isValidPath($path)) { + $path = $this->getRelativePath($absolutePath); + if ($path == null) { + return false; + } + $run = $this->runHooks($hooks, $path); + list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); + if ($run and $storage) { + if (!is_null($extraParam)) { + $result = $storage->$operation($internalPath, $extraParam); + } else { + $result = $storage->$operation($internalPath); + } + $result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result); + if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot()) { + if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open + $this->runHooks($hooks, $path, true); + } + } + return $result; + } + } + return null; + } + + private function runHooks($hooks, $path, $post = false) { + $prefix = ($post) ? 'post_' : ''; + $run = true; + if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot()) { + foreach ($hooks as $hook) { + if ($hook != 'read') { + \OC_Hook::emit( + Filesystem::CLASSNAME, + $prefix . $hook, + array( + Filesystem::signal_param_run => &$run, + Filesystem::signal_param_path => $path + ) + ); + } elseif (!$post) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + $prefix . $hook, + array( + Filesystem::signal_param_path => $path + ) + ); + } + } + } + return $run; + } + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + */ + public function hasUpdated($path, $time) { + return $this->basicOperation('hasUpdated', $path, array(), $time); + } + + /** + * get the filesystem info + * + * @param string $path + * @return array + * + * returns an associative array with the following keys: + * - size + * - mtime + * - mimetype + * - encrypted + * - versioned + */ + public function getFileInfo($path) { + $data = array(); + $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = Filesystem::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $permissionsCache = $storage->getPermissionsCache($internalPath); + $user = \OC_User::getUser(); + + if (!$cache->inCache($internalPath)) { + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); + } else { + $watcher = $storage->getWatcher($internalPath); + $watcher->checkUpdate($internalPath); + } + + $data = $cache->get($internalPath); + + if ($data and $data['fileid']) { + if ($data['mimetype'] === 'httpd/unix-directory') { + //add the sizes of other mountpoints to the folder + $mountPoints = Filesystem::getMountPoints($path); + foreach ($mountPoints as $mountPoint) { + $subStorage = Filesystem::getStorage($mountPoint); + if ($subStorage) { + $subCache = $subStorage->getCache(''); + $rootEntry = $subCache->get(''); + $data['size'] += $rootEntry['size']; + } + } + } + + $permissions = $permissionsCache->get($data['fileid'], $user); + if ($permissions === -1) { + $permissions = $storage->getPermissions($internalPath); + $permissionsCache->set($data['fileid'], $user, $permissions); + } + $data['permissions'] = $permissions; + } + } + return $data; + } + + /** + * get the content of a directory + * + * @param string $directory path under datadirectory + * @return array + */ + public function getDirectoryContent($directory, $mimetype_filter = '') { + $result = array(); + $path = Filesystem::normalizePath($this->fakeRoot . '/' . $directory); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = Filesystem::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $permissionsCache = $storage->getPermissionsCache($internalPath); + $user = \OC_User::getUser(); + + if ($cache->getStatus($internalPath) < Cache\Cache::COMPLETE) { + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); + } else { + $watcher = $storage->getWatcher($internalPath); + $watcher->checkUpdate($internalPath); + } + + $files = $cache->getFolderContents($internalPath); //TODO: mimetype_filter + + $ids = array(); + foreach ($files as $i => $file) { + $files[$i]['type'] = $file['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; + $ids[] = $file['fileid']; + + $permissions = $permissionsCache->get($file['fileid'], $user); + if ($permissions === -1) { + $permissions = $storage->getPermissions($file['path']); + $permissionsCache->set($file['fileid'], $user, $permissions); + } + $files[$i]['permissions'] = $permissions; + } + + //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders + $mountPoints = Filesystem::getMountPoints($path); + $dirLength = strlen($path); + foreach ($mountPoints as $mountPoint) { + $subStorage = Filesystem::getStorage($mountPoint); + if ($subStorage) { + $subCache = $subStorage->getCache(''); + + if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) { + $subScanner = $subStorage->getScanner(''); + $subScanner->scanFile(''); + } else { + $subWatcher = $subStorage->getWatcher(''); + $subWatcher->checkUpdate(''); + } + + $rootEntry = $subCache->get(''); + if ($rootEntry) { + $relativePath = trim(substr($mountPoint, $dirLength), '/'); + if ($pos = strpos($relativePath, '/')) { //mountpoint inside subfolder add size to the correct folder + $entryName = substr($relativePath, 0, $pos); + foreach ($files as &$entry) { + if ($entry['name'] === $entryName) { + $entry['size'] += $rootEntry['size']; + } + } + } else { //mountpoint in this folder, add an entry for it + $rootEntry['name'] = $relativePath; + $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; + $subPermissionsCache = $subStorage->getPermissionsCache(''); + $permissions = $subPermissionsCache->get($rootEntry['fileid'], $user); + if ($permissions === -1) { + $permissions = $subStorage->getPermissions($rootEntry['path']); + $subPermissionsCache->set($rootEntry['fileid'], $user, $permissions); + } + $rootEntry['permissions'] = $permissions; + $files[] = $rootEntry; + } + } + } + } + + if ($mimetype_filter) { + foreach ($files as $file) { + if (strpos($mimetype_filter, '/')) { + if ($file['mimetype'] === $mimetype_filter) { + $result[] = $file; + } + } else { + if ($file['mimepart'] === $mimetype_filter) { + $result[] = $file; + } + } + } + } else { + $result = $files; + } + } + return $result; + } + + /** + * change file metadata + * + * @param string $path + * @param array $data + * @return int + * + * returns the fileid of the updated file + */ + public function putFileInfo($path, $data) { + $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = Filesystem::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($path); + + if (!$cache->inCache($internalPath)) { + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); + } + + return $cache->put($internalPath, $data); + } else { + return -1; + } + } + + /** + * search for files with the name matching $query + * + * @param string $query + * @return array + */ + public function search($query) { + return $this->searchCommon('%' . $query . '%', 'search'); + } + + /** + * search for files by mimetype + * + * @param string $query + * @return array + */ + public function searchByMime($mimetype) { + return $this->searchCommon($mimetype, 'searchByMime'); + } + + /** + * @param string $query + * @param string $method + * @return array + */ + private function searchCommon($query, $method) { + $files = array(); + $rootLength = strlen($this->fakeRoot); + + $mountPoint = Filesystem::getMountPoint($this->fakeRoot); + $storage = Filesystem::getStorage($mountPoint); + if ($storage) { + $cache = $storage->getCache(''); + + $results = $cache->$method($query); + foreach ($results as $result) { + if (substr($mountPoint . $result['path'], 0, $rootLength) === $this->fakeRoot) { + $result['path'] = substr($mountPoint . $result['path'], $rootLength); + $files[] = $result; + } + } + + $mountPoints = Filesystem::getMountPoints($this->fakeRoot); + foreach ($mountPoints as $mountPoint) { + $storage = Filesystem::getStorage($mountPoint); + if ($storage) { + $cache = $storage->getCache(''); + + $relativeMountPoint = substr($mountPoint, $rootLength); + $results = $cache->$method($query); + foreach ($results as $result) { + $result['path'] = $relativeMountPoint . $result['path']; + $files[] = $result; + } + } + } + } + return $files; + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path) { + /** + * @var Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = $this->resolvePath($path); + if ($storage) { + return $storage->getETag($internalPath); + } else { + return null; + } + } +} diff --git a/lib/filestorage.php b/lib/filestorage.php deleted file mode 100644 index 2e03c4cb6da..00000000000 --- a/lib/filestorage.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php - -/** -* ownCloud -* -* @author Frank Karlitschek -* @copyright 2012 Frank Karlitschek frank@owncloud.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/>. -*/ - -/** - * Provide a common interface to all different storage options - */ -abstract class OC_Filestorage{ - abstract public function __construct($parameters); - abstract public function mkdir($path); - abstract public function rmdir($path); - abstract public function opendir($path); - abstract public function is_dir($path); - abstract public function is_file($path); - abstract public function stat($path); - abstract public function filetype($path); - abstract public function filesize($path); - abstract public function isCreatable($path); - abstract public function isReadable($path); - abstract public function isUpdatable($path); - abstract public function isDeletable($path); - abstract public function isSharable($path); - abstract public function file_exists($path); - abstract public function filectime($path); - abstract public function filemtime($path); - abstract public function file_get_contents($path); - abstract public function file_put_contents($path, $data); - abstract public function unlink($path); - abstract public function rename($path1, $path2); - abstract public function copy($path1, $path2); - abstract public function fopen($path, $mode); - abstract public function getMimeType($path); - abstract public function hash($type, $path, $raw = false); - abstract public function free_space($path); - abstract public function search($query); - abstract public function touch($path, $mtime=null); - abstract public function getLocalFile($path);// get a path to a local version of the file, whether the original file is local or remote - abstract public function getLocalFolder($path);// get a path to a local version of the folder, whether the original file is local or remote - /** - * check if a file or folder has been updated since $time - * @param int $time - * @return bool - * - * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. - * returning true for other changes in the folder is optional - */ - abstract public function hasUpdated($path, $time); - abstract public function getOwner($path); -} diff --git a/lib/filestorage/temporary.php b/lib/filestorage/temporary.php deleted file mode 100644 index 876ba045a63..00000000000 --- a/lib/filestorage/temporary.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php -/** - * local storage backnd in temporary folder for testing purpores - */ -class OC_Filestorage_Temporary extends OC_Filestorage_Local{ - public function __construct($arguments) { - $this->datadir=OC_Helper::tmpFolder(); - } - - public function cleanUp() { - OC_Helper::rmdirr($this->datadir); - } - - public function __destruct() { - $this->cleanUp(); - } -} diff --git a/lib/filesystem.php b/lib/filesystem.php index f185d777def..57cca902303 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -1,26 +1,11 @@ <?php /** -* ownCloud -* -* @author Frank Karlitschek -* @copyright 2012 Frank Karlitschek frank@owncloud.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/>. -* -*/ - + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ /** * Class for abstraction of filesystem functions @@ -31,578 +16,397 @@ * read(path) * write(path, &run) * post_write(path) - * create(path, &run) (when a file is created, both create and write will be emited in that order) + * create(path, &run) (when a file is created, both create and write will be emitted in that order) * post_create(path) * delete(path, &run) * post_delete(path) - * rename(oldpath, newpath, &run) - * post_rename(oldpath, newpath) - * copy(oldpath, newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emited in that order) - * post_rename(oldpath, newpath) + * rename(oldpath,newpath, &run) + * post_rename(oldpath,newpath) + * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order) + * post_rename(oldpath,newpath) * - * the &run parameter can be set to false to prevent the operation from occuring + * the &run parameter can be set to false to prevent the operation from occurring */ -class OC_Filesystem{ - static private $storages=array(); - static private $mounts=array(); - static private $loadedUsers=array(); - public static $loaded=false; - /** - * @var OC_Filestorage $defaultInstance - */ - static private $defaultInstance; - - - /** - * classname which used for hooks handling - * used as signalclass in OC_Hooks::emit() - */ - const CLASSNAME = 'OC_Filesystem'; - - /** - * signalname emited before file renaming - * @param oldpath - * @param newpath - */ - const signal_rename = 'rename'; - - /** - * signal emited after file renaming - * @param oldpath - * @param newpath - */ - const signal_post_rename = 'post_rename'; - - /** - * signal emited before file/dir creation - * @param path - * @param run changing this flag to false in hook handler will cancel event - */ - const signal_create = 'create'; - - /** - * signal emited after file/dir creation - * @param path - * @param run changing this flag to false in hook handler will cancel event - */ - const signal_post_create = 'post_create'; - - /** - * signal emits before file/dir copy - * @param oldpath - * @param newpath - * @param run changing this flag to false in hook handler will cancel event - */ - const signal_copy = 'copy'; - - /** - * signal emits after file/dir copy - * @param oldpath - * @param newpath - */ - const signal_post_copy = 'post_copy'; - - /** - * signal emits before file/dir save - * @param path - * @param run changing this flag to false in hook handler will cancel event - */ - const signal_write = 'write'; - - /** - * signal emits after file/dir save - * @param path - */ - const signal_post_write = 'post_write'; - - /** - * signal emits when reading file/dir - * @param path - */ - const signal_read = 'read'; - - /** - * signal emits when removing file/dir - * @param path - */ - const signal_delete = 'delete'; - +/** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ +class OC_Filesystem { /** - * parameters definitions for signals + * 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 + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return string */ - const signal_param_path = 'path'; - const signal_param_oldpath = 'oldpath'; - const signal_param_newpath = 'newpath'; + static public function getMountPoint($path) { + return \OC\Files\Filesystem::getMountPoint($path); + } /** - * run - changing this flag to false in hook handler will cancel event + * resolve a path to a storage and internal path + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return array consisting of the storage and the internal path */ - const signal_param_run = 'run'; + static public function resolvePath($path) { + return \OC\Files\Filesystem::resolvePath($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 + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem */ - static public function getMountPoint($path) { - OC_Hook::emit(self::CLASSNAME, 'get_mountpoint', array('path'=>$path)); - if(!$path) { - $path='/'; - } - if($path[0]!=='/') { - $path='/'.$path; - } - $path=str_replace('//', '/', $path); - $foundMountPoint=''; - $mountPoints=array_keys(OC_Filesystem::$mounts); - foreach($mountPoints as $mountpoint) { - if($mountpoint==$path) { - return $mountpoint; - } - if(strpos($path, $mountpoint)===0 and strlen($mountpoint)>strlen($foundMountPoint)) { - $foundMountPoint=$mountpoint; - } - } - return $foundMountPoint; - } - - /** - * 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); - $internalPath=substr($path, strlen($mountPoint)); - return $internalPath; - } - - static private function mountPointsLoaded($user) { - return in_array($user, self::$loadedUsers); - } - - /** - * get the storage object for a path - * @param string path - * @return OC_Filestorage - */ - static public function getStorage($path) { - $user = ltrim(substr($path, 0, strpos($path, '/', 1)), '/'); - // check mount points if file was shared from a different user - if ($user != OC_User::getUser() && !self::mountPointsLoaded($user)) { - OC_Util::loadUserMountPoints($user); - self::loadSystemMountPoints($user); - self::$loadedUsers[] = $user; - } - - $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 private function loadSystemMountPoints($user) { - if(is_file(OC::$SERVERROOT.'/config/mount.php')) { - $mountConfig=include OC::$SERVERROOT.'/config/mount.php'; - if(isset($mountConfig['global'])) { - foreach($mountConfig['global'] as $mountPoint=>$options) { - self::mount($options['class'], $options['options'], $mountPoint); - } - } - - if(isset($mountConfig['group'])) { - foreach($mountConfig['group'] as $group=>$mounts) { - if(OC_Group::inGroup($user, $group)) { - foreach($mounts as $mountPoint=>$options) { - $mountPoint=self::setUserVars($mountPoint, $user); - foreach($options as &$option) { - $option=self::setUserVars($option, $user); - } - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } - } - - if(isset($mountConfig['user'])) { - foreach($mountConfig['user'] as $mountUser=>$mounts) { - if($user==='all' or strtolower($mountUser)===strtolower($user)) { - foreach($mounts as $mountPoint=>$options) { - $mountPoint=self::setUserVars($mountPoint, $user); - foreach($options as &$option) { - $option=self::setUserVars($option, $user); - } - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } - } - - $mtime=filemtime(OC::$SERVERROOT.'/config/mount.php'); - $previousMTime=OC_Appconfig::getValue('files', 'mountconfigmtime', 0); - if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated - OC_FileCache::triggerUpdate(); - OC_Appconfig::setValue('files', 'mountconfigmtime', $mtime); - } - } - } - - static public function init($root, $user = '') { - if(self::$defaultInstance) { - return false; - } - self::$defaultInstance=new OC_FilesystemView($root); - - //load custom mount config - if (!isset($user)) { - $user = OC_User::getUser(); - } - self::loadSystemMountPoints($user); - - self::$loaded=true; - } - - /** - * fill in the correct values for $user, and $password placeholders - * @param string intput - * @return string - */ - private static function setUserVars($input, $user) { - if (isset($user)) { - return str_replace('$user', $user, $input); - } else { - return str_replace('$user', OC_User::getUser(), $input); - } + static public function init($root) { + return \OC\Files\Filesystem::init($root); } /** * get the default filesystem view - * @return OC_FilesystemView + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @return \OC\Files\View */ static public function getView() { - return self::$defaultInstance; + return \OC\Files\Filesystem::getView(); } /** * tear down the filesystem, removing all storage providers + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem */ static public function tearDown() { - self::$storages=array(); - } - - /** - * create a new storage of a specific type - * @param string type - * @param array arguments - * @return OC_Filestorage - */ - static private function createStorage($class, $arguments) { - if(class_exists($class)) { - try { - return new $class($arguments); - } catch (Exception $exception) { - OC_Log::write('core', $exception->getMessage(), OC_Log::ERROR); - return false; - } - }else{ - OC_Log::write('core', 'storage backend '.$class.' not found', OC_Log::ERROR); - return false; - } - } - - /** - * change the root to a fake root - * @param string fakeRoot - * @return bool - */ - static public function chroot($fakeRoot) { - return self::$defaultInstance->chroot($fakeRoot); + \OC\Files\Filesystem::tearDown(); } /** * @brief get the relative path of the root data directory for the current user * @return string * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem * Returns path like /admin/files */ static public function getRoot() { - return self::$defaultInstance->getRoot(); + return \OC\Files\Filesystem::getRoot(); } /** * clear all mounts and storage backends + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem */ public static function clearMounts() { - self::$mounts=array(); - self::$storages=array(); + \OC\Files\Filesystem::clearMounts(); } /** - * mount an OC_Filestorage in our virtual filesystem - * @param OC_Filestorage storage - * @param string mountpoint - */ + * mount an \OC\Files\Storage\Storage in our virtual filesystem + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param \OC\Files\Storage\Storage $class + * @param array $arguments + * @param string $mountpoint + */ static public function mount($class, $arguments, $mountpoint) { - if($mountpoint[0]!='/') { - $mountpoint='/'.$mountpoint; - } - if(substr($mountpoint, -1)!=='/') { - $mountpoint=$mountpoint.'/'; - } - self::$mounts[$mountpoint]=array('class'=>$class, 'arguments'=>$arguments); + \OC\Files\Filesystem::mount($class, $arguments, $mountpoint); } /** - * 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 - */ + * 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 + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return string + */ static public function getLocalFile($path) { - return self::$defaultInstance->getLocalFile($path); + return \OC\Files\Filesystem::getLocalFile($path); } + /** - * @param string path + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path * @return string */ static public function getLocalFolder($path) { - return self::$defaultInstance->getLocalFolder($path); + return \OC\Files\Filesystem::getLocalFolder($path); } /** - * return path to file which reflects one visible in browser - * @param string path - * @return string - */ + * return path to file which reflects one visible in browser + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return string + */ static public function getLocalPath($path) { - $datadir = OC_User::getHome(OC_User::getUser()).'/files'; - $newpath = $path; - if (strncmp($newpath, $datadir, strlen($datadir)) == 0) { - $newpath = substr($path, strlen($datadir)); - } - return $newpath; + return \OC\Files\Filesystem::getLocalPath($path); } /** * check if the requested path is valid - * @param string path + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path * @return bool */ static public function isValidPath($path) { - $path = self::normalizePath($path); - if(!$path || $path[0]!=='/') { - $path='/'.$path; - } - if(strstr($path, '/../') || strrchr($path, '/') === '/..' ) { - return false; - } - if(self::isFileBlacklisted($path)) { - return false; - } - return true; + return \OC\Files\Filesystem::isValidPath($path); } /** - * checks if a file is blacklsited for storage in the filesystem + * checks if a file is blacklisted for storage in the filesystem * Listens to write and rename hooks + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem * @param array $data from hook */ static public function isBlacklisted($data) { - if (isset($data['path'])) { - $path = $data['path']; - } else if (isset($data['newpath'])) { - $path = $data['newpath']; - } - if (isset($path)) { - $data['run'] = !self::isFileBlacklisted($path); - } - } - - static public function isFileBlacklisted($path) { - $blacklist = array('.htaccess'); - $filename = strtolower(basename($path)); - return in_array($filename, $blacklist); + \OC\Files\Filesystem::isBlacklisted($data); } /** - * following functions are equivilent to their php buildin equivilents for arguments/return values. + * following functions are equivalent to their php builtin equivalents for arguments/return values. + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem */ static public function mkdir($path) { - return self::$defaultInstance->mkdir($path); + return \OC\Files\Filesystem::mkdir($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function rmdir($path) { - return self::$defaultInstance->rmdir($path); + return \OC\Files\Filesystem::rmdir($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function opendir($path) { - return self::$defaultInstance->opendir($path); + return \OC\Files\Filesystem::opendir($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function readdir($path) { - return self::$defaultInstance->readdir($path); + return \OC\Files\Filesystem::readdir($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function is_dir($path) { - return self::$defaultInstance->is_dir($path); + return \OC\Files\Filesystem::is_dir($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function is_file($path) { - return self::$defaultInstance->is_file($path); + return \OC\Files\Filesystem::is_file($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function stat($path) { - return self::$defaultInstance->stat($path); + return \OC\Files\Filesystem::stat($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function filetype($path) { - return self::$defaultInstance->filetype($path); + return \OC\Files\Filesystem::filetype($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function filesize($path) { - return self::$defaultInstance->filesize($path); + return \OC\Files\Filesystem::filesize($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function readfile($path) { - return self::$defaultInstance->readfile($path); + return \OC\Files\Filesystem::readfile($path); } + /** - * @deprecated Replaced by isReadable() as part of CRUDS - */ + * @deprecated Replaced by isReadable() as part of CRUDS + */ static public function is_readable($path) { - return self::$defaultInstance->is_readable($path); + return \OC\Files\Filesystem::isReadable($path); } + /** - * @deprecated Replaced by isCreatable(), isUpdatable(), isDeletable() as part of CRUDS - */ - static public function is_writable($path) { - return self::$defaultInstance->is_writable($path); - } + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function isCreatable($path) { - return self::$defaultInstance->isCreatable($path); + return \OC\Files\Filesystem::isCreatable($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function isReadable($path) { - return self::$defaultInstance->isReadable($path); + return \OC\Files\Filesystem::isReadable($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function isUpdatable($path) { - return self::$defaultInstance->isUpdatable($path); + return \OC\Files\Filesystem::isUpdatable($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function isDeletable($path) { - return self::$defaultInstance->isDeletable($path); + return \OC\Files\Filesystem::isDeletable($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function isSharable($path) { - return self::$defaultInstance->isSharable($path); + return \OC\Files\Filesystem::isSharable($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function file_exists($path) { - return self::$defaultInstance->file_exists($path); - } - static public function filectime($path) { - return self::$defaultInstance->filectime($path); + return \OC\Files\Filesystem::file_exists($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function filemtime($path) { - return self::$defaultInstance->filemtime($path); + return \OC\Files\Filesystem::filemtime($path); } - static public function touch($path, $mtime=null) { - return self::$defaultInstance->touch($path, $mtime); + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function touch($path, $mtime = null) { + return \OC\Files\Filesystem::touch($path, $mtime); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function file_get_contents($path) { - return self::$defaultInstance->file_get_contents($path); + return \OC\Files\Filesystem::file_get_contents($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function file_put_contents($path, $data) { - return self::$defaultInstance->file_put_contents($path, $data); + return \OC\Files\Filesystem::file_put_contents($path, $data); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function unlink($path) { - return self::$defaultInstance->unlink($path); + return \OC\Files\Filesystem::unlink($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function rename($path1, $path2) { - return self::$defaultInstance->rename($path1, $path2); + return \OC\Files\Filesystem::rename($path1, $path2); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function copy($path1, $path2) { - return self::$defaultInstance->copy($path1, $path2); + return \OC\Files\Filesystem::copy($path1, $path2); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function fopen($path, $mode) { - return self::$defaultInstance->fopen($path, $mode); + return \OC\Files\Filesystem::fopen($path, $mode); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function toTmpFile($path) { - return self::$defaultInstance->toTmpFile($path); + return \OC\Files\Filesystem::toTmpFile($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function fromTmpFile($tmpFile, $path) { - return self::$defaultInstance->fromTmpFile($tmpFile, $path); + return \OC\Files\Filesystem::fromTmpFile($tmpFile, $path); } + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function getMimeType($path) { - return self::$defaultInstance->getMimeType($path); + return \OC\Files\Filesystem::getMimeType($path); } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function hash($type, $path, $raw = false) { - return self::$defaultInstance->hash($type, $path, $raw); + return \OC\Files\Filesystem::hash($type, $path, $raw); } - static public function free_space($path='/') { - return self::$defaultInstance->free_space($path); + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function free_space($path = '/') { + return \OC\Files\Filesystem::free_space($path); } + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ static public function search($query) { - return OC_FileCache::search($query); + return \OC\Files\Filesystem::search($query); } /** * check if a file or folder has been updated since $time + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path * @param int $time * @return bool */ static public function hasUpdated($path, $time) { - return self::$defaultInstance->hasUpdated($path, $time); - } - - static public function removeETagHook($params, $root = false) { - if (isset($params['path'])) { - $path=$params['path']; - } else { - $path=$params['oldpath']; - } - - if ($root) { // reduce path to the required part of it (no 'username/files') - $fakeRootView = new OC_FilesystemView($root); - $count = 1; - $path=str_replace(OC_App::getStorage("files")->getAbsolutePath(), "", $fakeRootView->getAbsolutePath($path), $count); - } - - $path = self::normalizePath($path); - OC_Connector_Sabre_Node::removeETagPropertyForPath($path); + return \OC\Files\Filesystem::hasUpdated($path, $time); } /** * normalize a path - * @param string path + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path * @param bool $stripTrailingSlash * @return string */ - public static function normalizePath($path, $stripTrailingSlash=true) { - if($path=='') { - return '/'; - } - //no windows style slashes - $path=str_replace('\\', '/', $path); - //add leading slash - if($path[0]!=='/') { - $path='/'.$path; - } - //remove trainling slash - if($stripTrailingSlash and strlen($path)>1 and substr($path, -1, 1)==='/') { - $path=substr($path, 0, -1); - } - //remove duplicate slashes - while(strpos($path, '//')!==false) { - $path=str_replace('//', '/', $path); - } - //normalize unicode if possible - if(class_exists('Normalizer')) { - $path=Normalizer::normalize($path); - } - return $path; + public static function normalizePath($path, $stripTrailingSlash = true) { + return \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash); } } -OC_Hook::connect('OC_Filesystem', 'post_write', 'OC_Filesystem', 'removeETagHook'); -OC_Hook::connect('OC_Filesystem', 'post_delete', 'OC_Filesystem', 'removeETagHook'); -OC_Hook::connect('OC_Filesystem', 'post_rename', 'OC_Filesystem', 'removeETagHook'); - -OC_Util::setupFS(); -require_once 'filecache.php'; diff --git a/lib/filesystemview.php b/lib/filesystemview.php index ea9cbecee0e..d6bca62e06a 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -1,658 +1,9 @@ <?php /** - * ownCloud - * - * @author Frank Karlitschek - * @copyright 2012 Frank Karlitschek frank@owncloud.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/>. - */ + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ - -/** - * Class to provide access to ownCloud filesystem via a "view", and methods for - * working with files within that view (e.g. read, write, delete, etc.). Each - * view is restricted to a set of directories via a virtual root. The default view - * uses the currently logged in user's data directory as root (parts of - * OC_Filesystem are merely a wrapper for OC_FilesystemView). - * - * Apps that need to access files outside of the user data folders (to modify files - * belonging to a user other than the one currently logged in, for example) should - * use this class directly rather than using OC_Filesystem, or making use of PHP's - * built-in file manipulation functions. This will ensure all hooks and proxies - * are triggered correctly. - * - * Filesystem functions are not called directly; they are passed to the correct - * OC_Filestorage object - */ - -class OC_FilesystemView { - private $fakeRoot=''; - private $internal_path_cache=array(); - private $storage_cache=array(); - - public function __construct($root) { - $this->fakeRoot=$root; - } - - public function getAbsolutePath($path = '/') { - if(!$path || $path[0]!=='/') { - $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) { - if (!isset($this->internal_path_cache[$path])) { - $this->internal_path_cache[$path] = OC_Filesystem::getInternalPath($this->getAbsolutePath($path)); - } - return $this->internal_path_cache[$path]; - } - - /** - * get path relative to the root of the view - * @param string path - * @return string - */ - public function getRelativePath($path) { - if($this->fakeRoot=='') { - return $path; - } - if(strpos($path, $this->fakeRoot)!==0) { - return null; - }else{ - $path=substr($path, strlen($this->fakeRoot)); - if(strlen($path)===0) { - return '/'; - }else{ - return $path; - } - } - } - - /** - * get the storage object for a path - * @param string path - * @return OC_Filestorage - */ - public function getStorage($path) { - if (!isset($this->storage_cache[$path])) { - $this->storage_cache[$path] = OC_Filesystem::getStorage($this->getAbsolutePath($path)); - } - return $this->storage_cache[$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)); - } - } - /** - * @param string path - * @return string - */ - public function getLocalFolder($path) { - $parent=substr($path, 0, strrpos($path, '/')); - if(OC_Filesystem::isValidPath($parent) and $storage=$this->getStorage($path)) { - return $storage->getLocalFolder($this->getInternalPath($path)); - } - } - - /** - * the following functions operate with arguments and return values identical - * to those of their PHP built-in equivalents. Mostly they are merely wrappers - * for OC_Filestorage via basicOperation(). - */ - 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 readdir($handle) { - $fsLocal= new OC_Filestorage_Local( array( 'datadir' => '/' ) ); - return $fsLocal->readdir( $handle ); - } - 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) { - OC_Util::obEnd(); - $handle=$this->fopen($path, 'rb'); - if ($handle) { - $chunkSize = 8192;// 8 MB chunks - while (!feof($handle)) { - echo fread($handle, $chunkSize); - flush(); - } - $size=$this->filesize($path); - return $size; - } - return false; - } - /** - * @deprecated Replaced by isReadable() as part of CRUDS - */ - public function is_readable($path) { - return $this->basicOperation('isReadable', $path); - } - /** - * @deprecated Replaced by isCreatable(), isUpdatable(), isDeletable() as part of CRUDS - */ - public function is_writable($path) { - return $this->basicOperation('isUpdatable', $path); - } - public function isCreatable($path) { - return $this->basicOperation('isCreatable', $path); - } - public function isReadable($path) { - return $this->basicOperation('isReadable', $path); - } - public function isUpdatable($path) { - return $this->basicOperation('isUpdatable', $path); - } - public function isDeletable($path) { - return $this->basicOperation('isDeletable', $path); - } - public function isSharable($path) { - return $this->basicOperation('isSharable', $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 touch($path, $mtime=null) { - if(!is_null($mtime) and !is_numeric($mtime)) { - $mtime = strtotime($mtime); - } - return $this->basicOperation('touch', $path, array('write'), $mtime); - } - public function file_get_contents($path) { - return $this->basicOperation('file_get_contents', $path, array('read')); - } - public function file_put_contents($path, $data) { - if(is_resource($data)) {//not having to deal with streams in file_put_contents makes life easier - $absolutePath = OC_Filesystem::normalizePath($this->getAbsolutePath($path)); - if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) && OC_Filesystem::isValidPath($path)) { - $path = $this->getRelativePath($absolutePath); - $exists = $this->file_exists($path); - $run = true; - if( $this->fakeRoot==OC_Filesystem::getRoot() ) { - 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 - ) - ); - } - 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) { - return false; - } - $target=$this->fopen($path, 'w'); - if($target) { - $count=OC_Helper::streamCopy($data, $target); - fclose($target); - fclose($data); - if( $this->fakeRoot==OC_Filesystem::getRoot() ) { - 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) - ); - } - OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); - return $count > 0; - }else{ - return false; - } - } - }else{ - return $this->basicOperation('file_put_contents', $path, array('create', 'write'), $data); - } - } - public function unlink($path) { - return $this->basicOperation('unlink', $path, array('delete')); - } - public function deleteAll( $directory, $empty = false ) { - return $this->basicOperation( 'deleteAll', $directory, array('delete'), $empty ); - } - public function rename($path1, $path2) { - $postFix1=(substr($path1, -1, 1)==='/')?'/':''; - $postFix2=(substr($path2, -1, 1)==='/')?'/':''; - $absolutePath1 = OC_Filesystem::normalizePath($this->getAbsolutePath($path1)); - $absolutePath2 = OC_Filesystem::normalizePath($this->getAbsolutePath($path2)); - if(OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) { - $path1 = $this->getRelativePath($absolutePath1); - $path2 = $this->getRelativePath($absolutePath2); - - if($path1 == null or $path2 == null) { - return false; - } - $run=true; - if( $this->fakeRoot==OC_Filesystem::getRoot() ) { - 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.$postFix1); - $mp2 = $this->getMountPoint($path2.$postFix2); - if($mp1 == $mp2) { - if($storage = $this->getStorage($path1)) { - $result = $storage->rename($this->getInternalPath($path1.$postFix1), $this->getInternalPath($path2.$postFix2)); - } - } else { - $source = $this->fopen($path1.$postFix1, 'r'); - $target = $this->fopen($path2.$postFix2, 'w'); - $count = OC_Helper::streamCopy($source, $target); - $storage1 = $this->getStorage($path1); - $storage1->unlink($this->getInternalPath($path1.$postFix1)); - $result = $count>0; - } - if( $this->fakeRoot==OC_Filesystem::getRoot() ) { - 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) { - $postFix1=(substr($path1, -1, 1)==='/')?'/':''; - $postFix2=(substr($path2, -1, 1)==='/')?'/':''; - $absolutePath1 = OC_Filesystem::normalizePath($this->getAbsolutePath($path1)); - $absolutePath2 = OC_Filesystem::normalizePath($this->getAbsolutePath($path2)); - if(OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) { - $path1 = $this->getRelativePath($absolutePath1); - $path2 = $this->getRelativePath($absolutePath2); - - if($path1 == null or $path2 == null) { - return false; - } - $run=true; - if( $this->fakeRoot==OC_Filesystem::getRoot() ) { - 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.$postFix1); - $mp2=$this->getMountPoint($path2.$postFix2); - if($mp1 == $mp2) { - if($storage = $this->getStorage($path1.$postFix1)) { - $result=$storage->copy($this->getInternalPath($path1.$postFix1), $this->getInternalPath($path2.$postFix2)); - } - } else { - $source = $this->fopen($path1.$postFix1, 'r'); - $target = $this->fopen($path2.$postFix2, 'w'); - $result = OC_Helper::streamCopy($source, $target); - } - if( $this->fakeRoot==OC_Filesystem::getRoot() ) { - // If the file to be copied originates within - // the user's data directory - - 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) - ); - - } else { - // If this is not a normal file copy operation - // and the file originates somewhere else - // (e.g. a version rollback operation), do not - // perform all the other post_write actions - - // Update webdav properties - OC_Filesystem::removeETagHook(array("path" => $path2), $this->fakeRoot); - - $splitPath2 = explode( '/', $path2 ); - - // Only cache information about files - // that are being copied from within - // the user files directory. Caching - // other files, like VCS backup files, - // serves no purpose - if ( $splitPath2[1] == 'files' ) { - - OC_FileCache_Update::update($path2, $this->fakeRoot); - - } - - } - - return $result; - - } - } - } - public function fopen($path, $mode) { - $hooks=array(); - switch($mode) { - case 'r': - case 'rb': - $hooks[]='read'; - break; - case 'r+': - case 'rb+': - case 'w+': - case 'wb+': - case 'x+': - case 'xb+': - case 'a+': - case 'ab+': - $hooks[]='read'; - $hooks[]='write'; - break; - case 'w': - case 'wb': - case 'x': - case 'xb': - case 'a': - case 'ab': - $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_Filesystem::isValidPath($path)) { - $source = $this->fopen($path, 'r'); - if($source) { - $extension=''; - $extOffset=strpos($path, '.'); - if($extOffset !== false) { - $extension=substr($path, strrpos($path, '.')); - } - $tmpFile = OC_Helper::tmpFile($extension); - file_put_contents($tmpFile, $source); - return $tmpFile; - } - } - } - public function fromTmpFile($tmpFile, $path) { - if(OC_Filesystem::isValidPath($path)) { - if(!$tmpFile) { - debug_print_backtrace(); - } - $source=fopen($tmpFile, 'r'); - if($source) { - $this->file_put_contents($path, $source); - unlink($tmpFile); - return true; - } else { - } - } else { - return false; - } - } - - public function getMimeType($path) { - return $this->basicOperation('getMimeType', $path); - } - public function hash($type, $path, $raw = false) { - $postFix=(substr($path, -1, 1)==='/')?'/':''; - $absolutePath = OC_Filesystem::normalizePath($this->getAbsolutePath($path)); - if (OC_FileProxy::runPreProxies('hash', $absolutePath) && OC_Filesystem::isValidPath($path)) { - $path = $this->getRelativePath($absolutePath); - if ($path == null) { - return false; - } - if (OC_Filesystem::$loaded && $this->fakeRoot == OC_Filesystem::getRoot()) { - OC_Hook::emit( - OC_Filesystem::CLASSNAME, - OC_Filesystem::signal_read, - array( OC_Filesystem::signal_param_path => $path) - ); - } - if ($storage = $this->getStorage($path.$postFix)) { - $result = $storage->hash($type, $this->getInternalPath($path.$postFix), $raw); - $result = OC_FileProxy::runPostProxies('hash', $absolutePath, $result); - return $result; - } - } - return null; - } - - public function free_space($path='/') { - return $this->basicOperation('free_space', $path); - } - - /** - * @brief abstraction layer for basic filesystem functions: wrapper for OC_Filestorage - * @param string $operation - * @param string #path - * @param array (optional) hooks - * @param mixed (optional) $extraParam - * @return mixed - * - * This method takes requests for basic filesystem functions (e.g. reading & writing - * files), processes hooks and proxies, sanitises paths, and finally passes them on to - * OC_Filestorage for delegation to a storage backend for execution - */ - private function basicOperation($operation, $path, $hooks=array(), $extraParam=null) { - $postFix=(substr($path, -1, 1)==='/')?'/':''; - $absolutePath = OC_Filesystem::normalizePath($this->getAbsolutePath($path)); - if(OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) and OC_Filesystem::isValidPath($path)) { - $path = $this->getRelativePath($absolutePath); - if($path == null) { - return false; - } - $internalPath = $this->getInternalPath($path.$postFix); - $run=$this->runHooks($hooks, $path); - if($run and $storage = $this->getStorage($path.$postFix)) { - if(!is_null($extraParam)) { - $result = $storage->$operation($internalPath, $extraParam); - } else { - $result = $storage->$operation($internalPath); - } - $result = OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result); - if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()) { - if($operation!='fopen') {//no post hooks for fopen, the file stream is still open - $this->runHooks($hooks, $path, true); - } - } - return $result; - } - } - return null; - } - - private function runHooks($hooks, $path, $post=false) { - $prefix=($post)?'post_':''; - $run=true; - if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()) { - foreach($hooks as $hook) { - if($hook!='read') { - OC_Hook::emit( - OC_Filesystem::CLASSNAME, - $prefix.$hook, - array( - OC_Filesystem::signal_param_run => &$run, - OC_Filesystem::signal_param_path => $path - ) - ); - } elseif(!$post) { - OC_Hook::emit( - OC_Filesystem::CLASSNAME, - $prefix.$hook, - array( - OC_Filesystem::signal_param_path => $path - ) - ); - } - } - } - return $run; - } - - /** - * check if a file or folder has been updated since $time - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - return $this->basicOperation('hasUpdated', $path, array(), $time); - } -} +class OC_FilesystemView extends \OC\Files\View {} diff --git a/lib/helper.php b/lib/helper.php index 5d7e3fa4894..6b1eaa4e6ee 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -326,7 +326,7 @@ class OC_Helper { self::copyr("$src/$file", "$dest/$file"); } } - }elseif(file_exists($src) && !OC_Filesystem::isFileBlacklisted($src)) { + }elseif(file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) { copy($src, $dest); } } @@ -620,7 +620,7 @@ class OC_Helper { $newpath = $path . '/' . $filename; $counter = 2; - while (OC_Filesystem::file_exists($newpath)) { + while (\OC\Files\Filesystem::file_exists($newpath)) { $newname = $name . ' (' . $counter . ')' . $ext; $newpath = $path . '/' . $newname; $counter++; diff --git a/lib/image.php b/lib/image.php index cfc6d477395..eaa35350bcb 100644 --- a/lib/image.php +++ b/lib/image.php @@ -455,7 +455,7 @@ class OC_Image { default: // this is mostly file created from encrypted file - $this->resource = imagecreatefromstring(\OC_Filesystem::file_get_contents(\OC_Filesystem::getLocalPath($imagepath))); + $this->resource = imagecreatefromstring(\OC\Files\Filesystem::file_get_contents(\OC\Files\Filesystem::getLocalPath($imagepath))); $itype = IMAGETYPE_PNG; OC_Log::write('core', 'OC_Image->loadFromFile, Default', OC_Log::DEBUG); break; diff --git a/lib/ocs/cloud.php b/lib/ocs/cloud.php index 2d18b1db3f2..179ed8f3107 100644 --- a/lib/ocs/cloud.php +++ b/lib/ocs/cloud.php @@ -45,11 +45,11 @@ class OC_OCS_Cloud { if(OC_User::userExists($parameters['user'])) { // calculate the disc space $userDir = '/'.$parameters['user'].'/files'; - OC_Filesystem::init($userDir); - $rootInfo = OC_FileCache::get(''); - $sharedInfo = OC_FileCache::get('/Shared'); + \OC\Files\Filesystem::init($useDir); + $rootInfo = \OC\Files\Filesystem::getFileInfo(''); + $sharedInfo = \OC\Files\Filesystem::getFileInfo('/Shared'); $used = $rootInfo['size'] - $sharedInfo['size']; - $free = OC_Filesystem::free_space(); + $free = \OC\Files\Filesystem::free_space(); $total = $free + $used; if($total===0) $total = 1; // prevent division by zero $relative = round(($used/$total)*10000)/100; diff --git a/lib/public/files.php b/lib/public/files.php index 75e1d2fbbc1..f6b3e0ee38a 100644 --- a/lib/public/files.php +++ b/lib/public/files.php @@ -99,7 +99,7 @@ class Files { /** * @param string appid * @param $app app - * @return OC_FilesystemView + * @return \OC\Files\View */ public static function getStorage( $app ) { return \OC_App::getStorage( $app ); diff --git a/lib/public/share.php b/lib/public/share.php index cda583aa073..9d2a64b4590 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -37,8 +37,7 @@ class Share { const SHARE_TYPE_REMOTE = 6; /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask - * Construct permissions for share() and setPermissions with Or (|) - * e.g. Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE + * Construct permissions for share() and setPermissions with Or (|) e.g. Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE * Check if permission is granted with And (&) e.g. Check if delete is granted: if ($permissions & PERMISSION_DELETE) * Remove permissions with And (&) and Not (~) e.g. Remove the update permission: $permissions &= ~PERMISSION_UPDATE * Apps are required to handle permissions on their own, this class only stores and manages the permissions of shares @@ -67,17 +66,14 @@ class Share { public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) { if (self::isEnabled()) { if (!isset(self::$backendTypes[$itemType])) { - self::$backendTypes[$itemType] = array('class' => $class, - 'collectionOf' => $collectionOf, - 'supportedFileExtensions' => $supportedFileExtensions); + self::$backendTypes[$itemType] = array('class' => $class, 'collectionOf' => $collectionOf, 'supportedFileExtensions' => $supportedFileExtensions); if(count(self::$backendTypes) === 1) { \OC_Util::addScript('core', 'share'); \OC_Util::addStyle('core', 'share'); } return true; } - \OC_Log::write('OCP\Share', 'Sharing backend '.$class.' not registered, ' - .self::$backendTypes[$itemType]['class'].' is already registered for '.$itemType, \OC_Log::WARN); + \OC_Log::write('OCP\Share', 'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class'].' is already registered for '.$itemType, \OC_Log::WARN); } return false; } @@ -103,20 +99,8 @@ class Share { * @param int Number of items to return (optional) Returns all by default * @return Return depends on format */ - public static function getItemsSharedWith($itemType, - $format = self::FORMAT_NONE, - $parameters = null, - $limit = -1, - $includeCollections = false) { - return self::getItems($itemType, - null, - self::$shareTypeUserAndGroups, - \OC_User::getUser(), - null, - $format, - $parameters, - $limit, - $includeCollections); + public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) { + return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, $limit, $includeCollections); } /** @@ -126,20 +110,8 @@ class Share { * @param int Format (optional) Format type must be defined by the backend * @return Return depends on format */ - public static function getItemSharedWith($itemType, - $itemTarget, - $format = self::FORMAT_NONE, - $parameters = null, - $includeCollections = false) { - return self::getItems($itemType, - $itemTarget, - self::$shareTypeUserAndGroups, - \OC_User::getUser(), - null, - $format, - $parameters, - 1, - $includeCollections); + public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) { + return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections); } /** @@ -149,20 +121,8 @@ class Share { * @param int Format (optional) Format type must be defined by the backend * @return Return depends on format */ - public static function getItemSharedWithBySource($itemType, - $itemSource, - $format = self::FORMAT_NONE, - $parameters = null, - $includeCollections = false) { - return self::getItems($itemType, - $itemSource, - self::$shareTypeUserAndGroups, - \OC_User::getUser(), - null, - $format, - $parameters, - 1, - $includeCollections, true); + public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) { + return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections, true); } /** @@ -173,14 +133,7 @@ class Share { * @return Item */ public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) { - return self::getItems($itemType, - $itemSource, - self::SHARE_TYPE_LINK, - null, - $uidOwner, - self::FORMAT_NONE, - null, - 1); + return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1); } /** @@ -189,7 +142,7 @@ class Share { * @return Item */ public static function getShareByToken($token) { - $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1); + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?',1); $result = $query->execute(array($token)); if (\OC_DB::isError($result)) { \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', token=' . $token, \OC_Log::ERROR); @@ -204,20 +157,8 @@ class Share { * @param int Number of items to return (optional) Returns all by default * @return Return depends on format */ - public static function getItemsShared($itemType, - $format = self::FORMAT_NONE, - $parameters = null, - $limit = -1, - $includeCollections = false) { - return self::getItems($itemType, - null, - null, - null, - \OC_User::getUser(), - $format, - $parameters, - $limit, - $includeCollections); + public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) { + return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format, $parameters, $limit, $includeCollections); } /** @@ -227,20 +168,8 @@ class Share { * @param int Format (optional) Format type must be defined by the backend * @return Return depends on format */ - public static function getItemShared($itemType, - $itemSource, - $format = self::FORMAT_NONE, - $parameters = null, - $includeCollections = false) { - return self::getItems($itemType, - $itemSource, - null, - null, - \OC_User::getUser(), - $format, - $parameters, - -1, - $includeCollections); + public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) { + return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format, $parameters, -1, $includeCollections); } /** @@ -270,26 +199,14 @@ class Share { if ($sharingPolicy == 'groups_only') { $inGroup = array_intersect(\OC_Group::getUserGroups($uidOwner), \OC_Group::getUserGroups($shareWith)); if (empty($inGroup)) { - $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is not a member' - .' of any groups that '.$uidOwner.' is a member of'; + $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is not a member of any groups that '.$uidOwner.' is a member of'; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } } // Check if the item source is already shared with the user, either from the same owner or a different user - $checkExists = self::getItems($itemType, - $itemSource, - self::$shareTypeUserAndGroups, - $shareWith, - null, - self::FORMAT_NONE, - null, - 1, - true, - true); - if ($checkExists) { - // Only allow the same share to occur again if it is the same owner and is not a user share, - // this use case is for increasing permissions for a specific user + if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { + // Only allow the same share to occur again if it is the same owner and is not a user share, this use case is for increasing permissions for a specific user if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { $message = 'Sharing '.$itemSource.' failed, because this item is already shared with '.$shareWith; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); @@ -303,26 +220,14 @@ class Share { throw new \Exception($message); } if ($sharingPolicy == 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) { - $message = 'Sharing '.$itemSource.' failed, because '.$uidOwner - .' is not a member of the group '.$shareWith; + $message = 'Sharing '.$itemSource.' failed, because '.$uidOwner.' is not a member of the group '.$shareWith; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } // Check if the item source is already shared with the group, either from the same owner or a different user // The check for each user in the group is done inside the put() function - $checkExists = self::getItems($itemType, - $itemSource, - self::SHARE_TYPE_GROUP, - $shareWith, - null, - self::FORMAT_NONE, - null, - 1, - true, - true); - if ($checkExists) { - // Only allow the same share to occur again if it is the same owner and is not a group share, - // this use case is for increasing permissions for a specific user + if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { + // Only allow the same share to occur again if it is the same owner and is not a group share, this use case is for increasing permissions for a specific user if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { $message = 'Sharing '.$itemSource.' failed, because this item is already shared with '.$shareWith; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); @@ -337,15 +242,7 @@ class Share { } else if ($shareType === self::SHARE_TYPE_LINK) { if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') { // when updating a link share - $checkExists = self::getItems($itemType, - $itemSource, - self::SHARE_TYPE_LINK, - null, - $uidOwner, - self::FORMAT_NONE, - null, - 1); - if ($checkExists) { + if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1)) { // remember old token $oldToken = $checkExists['token']; //delete the old share @@ -365,14 +262,7 @@ class Share { } else { $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); } - $result = self::put($itemType, - $itemSource, - $shareType, - $shareWith, - $uidOwner, - $permissions, - null, - $token); + $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token); if ($result) { return $token; } else { @@ -412,11 +302,11 @@ class Share { // If the item is a folder, scan through the folder looking for equivalent item types if ($itemType == 'folder') { $parentFolder = self::put('folder', $itemSource, $shareType, $shareWith, $uidOwner, $permissions, true); - if ($parentFolder && $files = \OC_Files::getDirectoryContent($itemSource)) { + if ($parentFolder && $files = \OC\Files\Filesystem::getDirectoryContent($itemSource)) { for ($i = 0; $i < count($files); $i++) { $name = substr($files[$i]['name'], strpos($files[$i]['name'], $itemSource) - strlen($itemSource)); if ($files[$i]['mimetype'] == 'httpd/unix-directory' - && $children = \OC_Files::getDirectoryContent($name, '/') + && $children = \OC\Files\Filesystem::getDirectoryContent($name, '/') ) { // Continue scanning into child folders array_push($files, $children); @@ -424,17 +314,12 @@ class Share { // Check file extension for an equivalent item type to convert to $extension = strtolower(substr($itemSource, strrpos($itemSource, '.') + 1)); foreach (self::$backends as $type => $backend) { - if (isset($backend->dependsOn) - && $backend->dependsOn == 'file' - && isset($backend->supportedFileExtensions) - && in_array($extension, $backend->supportedFileExtensions) - ) { + if (isset($backend->dependsOn) && $backend->dependsOn == 'file' && isset($backend->supportedFileExtensions) && in_array($extension, $backend->supportedFileExtensions)) { $itemType = $type; break; } } - // Pass on to put() to check if this item should be converted, - // the item won't be inserted into the database unless it can be converted + // Pass on to put() to check if this item should be converted, the item won't be inserted into the database unless it can be converted self::put($itemType, $name, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder); } } @@ -456,15 +341,7 @@ class Share { * @return Returns true on success or false on failure */ public static function unshare($itemType, $itemSource, $shareType, $shareWith) { - $item = self::getItems($itemType, - $itemSource, - $shareType, - $shareWith, - \OC_User::getUser(), - self::FORMAT_NONE, - null, - 1); - if ($item) { + if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), self::FORMAT_NONE, null, 1)) { self::delete($item['id']); return true; } @@ -478,8 +355,7 @@ class Share { * @return Returns true on success or false on failure */ public static function unshareAll($itemType, $itemSource) { - $shares = self::getItemShared($itemType, $itemSource); - if ($shares) { + if ($shares = self::getItemShared($itemType, $itemSource)) { foreach ($shares as $share) { self::delete($share['id']); } @@ -498,27 +374,11 @@ class Share { * */ public static function unshareFromSelf($itemType, $itemTarget) { - $item = self::getItemSharedWith($itemType, $itemTarget); - if ($item) { + if ($item = self::getItemSharedWith($itemType, $itemTarget)) { if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) { - // Insert an extra row for the group share and set permission to 0 - // to prevent it from showing up for the user - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (' - .'`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, ' - .'`uid_owner`, `permissions`, `stime`, `file_source`, `file_target`' - .') VALUES (?,?,?,?,?,?,?,?,?,?,?)'); - $query->execute(array( - $item['item_type'], - $item['item_source'], - $item['item_target'], - $item['id'], - self::$shareTypeGroupUserUnique, - \OC_User::getUser(), - $item['uid_owner'], - 0, - $item['stime'], - $item['file_source'], - $item['file_target'])); + // Insert an extra row for the group share and set permission to 0 to prevent it from showing up for the user + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)'); + $query->execute(array($item['item_type'], $item['item_source'], $item['item_target'], $item['id'], self::$shareTypeGroupUserUnique, \OC_User::getUser(), $item['uid_owner'], 0, $item['stime'], $item['file_source'], $item['file_target'])); \OC_DB::insertid('*PREFIX*share'); // Delete all reshares by this user of the group share self::delete($item['id'], true, \OC_User::getUser()); @@ -545,24 +405,13 @@ class Share { * @return Returns true on success or false on failure */ public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) { - $item = self::getItems($itemType, - $itemSource, - $shareType, - $shareWith, - \OC_User::getUser(), - self::FORMAT_NONE, - null, - 1, - false); - if ($item) { - // Check if this item is a reshare and - // verify that the permissions granted don't exceed the parent shared item + if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) { + // Check if this item is a reshare and verify that the permissions granted don't exceed the parent shared item if (isset($item['parent'])) { $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*share` WHERE `id` = ?', 1); $result = $query->execute(array($item['parent']))->fetchRow(); if (~(int)$result['permissions'] & $permissions) { - $message = 'Setting permissions for '.$itemSource.' failed, ' - .'because the permissions exceed permissions granted to '.\OC_User::getUser(); + $message = 'Setting permissions for '.$itemSource.' failed, because the permissions exceed permissions granted to '.\OC_User::getUser(); \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } @@ -579,12 +428,9 @@ class Share { $parents = array($item['id']); while (!empty($parents)) { $parents = "'".implode("','", $parents)."'"; - $query = \OC_DB::prepare('SELECT `id`, `permissions`' - .' FROM `*PREFIX*share`' - .' WHERE `parent` IN ('.$parents.')'); + $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')'); $result = $query->execute(); - // Reset parents array, - // only go through loop again if items are found that need permissions removed + // Reset parents array, only go through loop again if items are found that need permissions removed $parents = array(); while ($item = $result->fetchRow()) { // Check if permissions need to be removed @@ -598,9 +444,7 @@ class Share { // Remove the permissions for all reshares of this item if (!empty($ids)) { $ids = "'".implode("','", $ids)."'"; - $query = \OC_DB::prepare('UPDATE `*PREFIX*share`' - .' SET `permissions` = `permissions` & ?' - .' WHERE `id` IN ('.$ids.')'); + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = `permissions` & ? WHERE `id` IN ('.$ids.')'); $query->execute(array($permissions)); } } @@ -613,16 +457,7 @@ class Share { } public static function setExpirationDate($itemType, $itemSource, $date) { - $items = self::getItems($itemType, - $itemSource, - null, - null, - \OC_User::getUser(), - self::FORMAT_NONE, - null, - -1, - false); - if ($items) { + if ($items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), self::FORMAT_NONE, null, -1, false)) { if (!empty($items)) { if ($date == '') { $date = null; @@ -684,8 +519,7 @@ class Share { if (!self::getBackend($itemType) instanceof Share_Backend_Collection) { unset($collectionTypes[0]); } - // Return array if collections were found or the item type is a collection itself - // - collections can be inside collections + // Return array if collections were found or the item type is a collection itself - collections can be inside collections if (count($collectionTypes) > 0) { return $collectionTypes; } @@ -696,8 +530,7 @@ class Share { * @brief Get shared items from the database * @param string Item type * @param string Item source or target (optional) - * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, - * $shareTypeUserAndGroups, or $shareTypeGroupUserUnique + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique * @param string User or group the item is being shared with * @param string User that is the owner of shared items (optional) * @param int Format to convert items to with formatItems() @@ -709,16 +542,7 @@ class Share { * See public functions getItem(s)... for parameter usage * */ - private static function getItems($itemType, - $item = null, - $shareType = null, - $shareWith = null, - $uidOwner = null, - $format = self::FORMAT_NONE, - $parameters = null, - $limit = -1, - $includeCollections = false, - $itemShareWithBySource = false) { + private static function getItems($itemType, $item = null, $shareType = null, $shareWith = null, $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false, $itemShareWithBySource = false) { if (!self::isEnabled()) { if ($limit == 1 || (isset($uidOwner) && isset($item))) { return false; @@ -727,11 +551,10 @@ class Share { } } $backend = self::getBackend($itemType); - // Get filesystem root to add it to the file target and remove from the file source, - // match file_source with the file cache + // Get filesystem root to add it to the file target and remove from the file source, match file_source with the file cache if ($itemType == 'file' || $itemType == 'folder') { - $root = \OC_Filesystem::getRoot(); - $where = 'INNER JOIN `*PREFIX*fscache` ON `file_source` = `*PREFIX*fscache`.`id`'; + $root = \OC\Files\Filesystem::getRoot(); + $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid`'; if (!isset($item)) { $where .= ' WHERE `file_target` IS NOT NULL'; } @@ -817,7 +640,7 @@ class Share { } else { if ($itemType == 'file' || $itemType == 'folder') { $where .= ' `file_target` = ?'; - $item = \OC_Filesystem::normalizePath($item); + $item = \OC\Files\Filesystem::normalizePath($item); } else { $where .= ' `item_target` = ?'; } @@ -831,8 +654,7 @@ class Share { } if ($limit != -1 && !$includeCollections) { if ($shareType == self::$shareTypeUserAndGroups) { - // Make sure the unique user target is returned if it exists, - // unique targets should follow the group share in the database + // Make sure the unique user target is returned if it exists, unique targets should follow the group share in the database // If the limit is not 1, the filtering can be done later $where .= ' ORDER BY `*PREFIX*share`.`id` DESC'; } @@ -848,19 +670,16 @@ class Share { // TODO Optimize selects if ($format == self::FORMAT_STATUSES) { if ($itemType == 'file' || $itemType == 'folder') { - $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, ' - .'`share_type`, `file_source`, `path`, `expiration`'; + $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `file_source`, `path`, `expiration`'; } else { $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `expiration`'; } } else { if (isset($uidOwner)) { if ($itemType == 'file' || $itemType == 'folder') { - $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, ' - .'`share_with`, `file_source`, `path`, `permissions`, `stime`, `expiration`, `token`'; + $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`, `expiration`, `token`'; } else { - $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, ' - .'`permissions`, `stime`, `file_source`, `expiration`, `token`'; + $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`, `stime`, `file_source`, `expiration`, `token`'; } } else { if ($fileDependent) { @@ -873,9 +692,7 @@ class Share { .'`expiration`, `name`, `ctime`, `mtime`, `mimetype`, `size`, `encrypted`, ' .'`versioned`, `writable`'; } else { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, ' - .'`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, `file_source`, ' - .'`path`, `file_target`, `permissions`, `stime`, `expiration`, `token`'; + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`'; } } else { $select = '*'; @@ -886,9 +703,7 @@ class Share { $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit); $result = $query->execute($queryArgs); if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) - . ', select=' . $select - . ' where=' . $where, \OC_Log::ERROR); + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, \OC_Log::ERROR); } $items = array(); $targets = array(); @@ -905,8 +720,7 @@ class Share { } else if (!isset($uidOwner)) { // Check if the same target already exists if (isset($targets[$row[$column]])) { - // Check if the same owner shared with the user twice through a group and user share - // - this is allowed + // Check if the same owner shared with the user twice through a group and user share - this is allowed $id = $targets[$row[$column]]; if ($items[$id]['uid_owner'] == $row['uid_owner']) { // Switch to group share type to ensure resharing conditions aren't bypassed @@ -914,11 +728,8 @@ class Share { $items[$id]['share_type'] = self::SHARE_TYPE_GROUP; $items[$id]['share_with'] = $row['share_with']; } - // Switch ids if sharing permission is granted on only one share - // to ensure correct parent is used if resharing - if (~(int)$items[$id]['permissions'] & PERMISSION_SHARE - && (int)$row['permissions'] & PERMISSION_SHARE - ) { + // Switch ids if sharing permission is granted on only one share to ensure correct parent is used if resharing + if (~(int)$items[$id]['permissions'] & PERMISSION_SHARE && (int)$row['permissions'] & PERMISSION_SHARE) { $items[$row['id']] = $items[$id]; unset($items[$id]); $id = $row['id']; @@ -936,7 +747,8 @@ class Share { if (isset($row['parent'])) { $row['path'] = '/Shared/'.basename($row['path']); } else { - $row['path'] = substr($row['path'], $root); + // Strip 'files' from path + $row['path'] = substr($row['path'], 5); } } if (isset($row['expiration'])) { @@ -952,7 +764,7 @@ class Share { $collectionItems = array(); foreach ($items as &$row) { // Return only the item instead of a 2-dimensional array - if ($limit == 1 && $row['item_type'] == $itemType && $row[$column] == $item) { + if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) { if ($format == self::FORMAT_NONE) { return $row; } else { @@ -961,9 +773,7 @@ class Share { } // Check if this is a collection of the requested item type if ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) { - if (($collectionBackend = self::getBackend($row['item_type'])) - && $collectionBackend instanceof Share_Backend_Collection - ) { + if (($collectionBackend = self::getBackend($row['item_type'])) && $collectionBackend instanceof Share_Backend_Collection) { // Collections can be inside collections, check if the item is a collection if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) { $collectionItems[] = $row; @@ -987,9 +797,10 @@ class Share { if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { $childItem['file_source'] = $child['source']; } else { - $childItem['file_source'] = \OC_FileCache::getId($child['file_path']); + $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']); + $childItem['file_source'] = $meta['fileid']; } - $childItem['file_target'] = \OC_Filesystem::normalizePath($child['file_path']); + $childItem['file_target'] = \OC\Files\Filesystem::normalizePath($child['file_path']); } if (isset($item)) { if ($childItem[$column] == $item) { @@ -1020,6 +831,9 @@ class Share { if (!empty($collectionItems)) { $items = array_merge($items, $collectionItems); } + if (empty($items) && $limit == 1) { + return false; + } if ($format == self::FORMAT_NONE) { return $items; } else if ($format == self::FORMAT_STATUSES) { @@ -1055,18 +869,10 @@ class Share { * @param bool|array Parent folder target (optional) * @return bool Returns true on success or false on failure */ - private static function put($itemType, - $itemSource, - $shareType, - $shareWith, - $uidOwner, - $permissions, - $parentFolder = null, - $token = null) { + private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder = null, $token = null) { $backend = self::getBackend($itemType); // Check if this is a reshare - $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true); - if ($checkReshare) { + if ($checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true)) { // Check if attempting to share back to owner if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) { $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is the original sharer'; @@ -1076,8 +882,7 @@ class Share { // Check if share permissions is granted if ((int)$checkReshare['permissions'] & PERMISSION_SHARE) { if (~(int)$checkReshare['permissions'] & $permissions) { - $message = 'Sharing '.$itemSource.' failed, ' - .'because the permissions exceed permissions granted to '.$uidOwner; + $message = 'Sharing '.$itemSource.' failed, because the permissions exceed permissions granted to '.$uidOwner; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } else { @@ -1099,8 +904,7 @@ class Share { $suggestedItemTarget = null; $suggestedFileTarget = null; if (!$backend->isValidSource($itemSource, $uidOwner)) { - $message = 'Sharing '.$itemSource.' failed, ' - .'because the sharing backend for '.$itemType.' could not find its source'; + $message = 'Sharing '.$itemSource.' failed, because the sharing backend for '.$itemType.' could not find its source'; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } @@ -1110,7 +914,8 @@ class Share { if ($itemType == 'file' || $itemType == 'folder') { $fileSource = $itemSource; } else { - $fileSource = \OC_FileCache::getId($filePath); + $meta = \OC\Files\Filesystem::getFileInfo($filePath); + $fileSource = $meta['fileid']; } if ($fileSource == -1) { $message = 'Sharing '.$itemSource.' failed, because the file could not be found in the file cache'; @@ -1122,27 +927,14 @@ class Share { $fileSource = null; } } - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`,' - .' `share_type`, `share_with`, `uid_owner`, `permissions`,' - .' `stime`, `file_source`, `file_target`, `token`' - .') VALUES (?,?,?,?,?,?,?,?,?,?,?,?)'); + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`, `token`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)'); // Share with a group if ($shareType == self::SHARE_TYPE_GROUP) { - $groupItemTarget = self::generateTarget($itemType, - $itemSource, - $shareType, - $shareWith['group'], - $uidOwner, - $suggestedItemTarget); + $groupItemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget); if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { - $groupFileTarget = self::generateTarget('file', - $filePath, - $shareType, - $shareWith['group'], - $uidOwner, - $suggestedFileTarget); + $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget); // Set group default file target for future use $parentFolders[0]['folder'] = $groupFileTarget; } else { @@ -1151,50 +943,21 @@ class Share { $parent = $parentFolder[0]['id']; } } else { - $groupFileTarget = self::generateTarget('file', - $filePath, - $shareType, - $shareWith['group'], - $uidOwner, - $suggestedFileTarget); + $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget); } } else { $groupFileTarget = null; } - $query->execute(array( - $itemType, - $itemSource, - $groupItemTarget, - $parent, - $shareType, - $shareWith['group'], - $uidOwner, - $permissions, - time(), - $fileSource, - $groupFileTarget, - $token)); + $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget, $token)); // Save this id, any extra rows for this group share will need to reference it $parent = \OC_DB::insertid('*PREFIX*share'); // Loop through all users of this group in case we need to add an extra row foreach ($shareWith['users'] as $uid) { - $itemTarget = self::generateTarget($itemType, - $itemSource, - self::SHARE_TYPE_USER, - $uid, - $uidOwner, - $suggestedItemTarget, - $parent); + $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedItemTarget, $parent); if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { - $fileTarget = self::generateTarget('file', - $filePath, - self::SHARE_TYPE_USER, - $uid, - $uidOwner, - $suggestedFileTarget, - $parent); + $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent); if ($fileTarget != $groupFileTarget) { $parentFolders[$uid]['folder'] = $fileTarget; } @@ -1203,13 +966,7 @@ class Share { $parent = $parentFolder[$uid]['id']; } } else { - $fileTarget = self::generateTarget('file', - $filePath, - self::SHARE_TYPE_USER, - $uid, - $uidOwner, - $suggestedFileTarget, - $parent); + $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent); } } else { $fileTarget = null; @@ -1230,19 +987,7 @@ class Share { )); // Insert an extra row for the group share if the item or file target is unique for this user if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { - $query->execute(array( - $itemType, - $itemSource, - $itemTarget, - $parent, - self::$shareTypeGroupUserUnique, - $uid, - $uidOwner, - $permissions, - time(), - $fileSource, - $fileTarget, - $token)); + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), $fileSource, $fileTarget, $token)); $id = \OC_DB::insertid('*PREFIX*share'); } } @@ -1251,50 +996,23 @@ class Share { return $parentFolders; } } else { - $itemTarget = self::generateTarget($itemType, - $itemSource, - $shareType, - $shareWith, - $uidOwner, - $suggestedItemTarget); + $itemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedItemTarget); if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { - $fileTarget = self::generateTarget('file', - $filePath, - $shareType, - $shareWith, - $uidOwner, - $suggestedFileTarget); + $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget); $parentFolders['folder'] = $fileTarget; } else { $fileTarget = $parentFolder['folder'].$itemSource; $parent = $parentFolder['id']; } } else { - $fileTarget = self::generateTarget('file', - $filePath, - $shareType, - $shareWith, - $uidOwner, - $suggestedFileTarget); + $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget); } } else { $fileTarget = null; } - $query->execute(array( - $itemType, - $itemSource, - $itemTarget, - $parent, - $shareType, - $shareWith, - $uidOwner, - $permissions, - time(), - $fileSource, - $fileTarget, - $token)); + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, $permissions, time(), $fileSource, $fileTarget, $token)); $id = \OC_DB::insertid('*PREFIX*share'); \OC_Hook::emit('OCP\Share', 'post_shared', array( 'itemType' => $itemType, @@ -1329,13 +1047,7 @@ class Share { * @param int The id of the parent group share (optional) * @return string Item target */ - private static function generateTarget($itemType, - $itemSource, - $shareType, - $shareWith, - $uidOwner, - $suggestedTarget = null, - $groupParent = null) { + private static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) { $backend = self::getBackend($itemType); if ($shareType == self::SHARE_TYPE_LINK) { if (isset($suggestedTarget)) { @@ -1387,7 +1099,8 @@ class Share { } if ($item['uid_owner'] == $uidOwner) { if ($itemType == 'file' || $itemType == 'folder') { - if ($item['file_source'] == \OC_FileCache::getId($itemSource)) { + $meta = \OC\Files\Filesystem::getFileInfo($itemSource); + if ($item['file_source'] == $meta['fileid']) { return $target; } } else if ($item['item_source'] == $itemSource) { @@ -1401,43 +1114,18 @@ class Share { // Find similar targets to improve backend's chances to generate a unqiue target if ($userAndGroups) { if ($column == 'file_target') { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'`' - .' FROM `*PREFIX*share`' - .' WHERE `item_type` IN (\'file\', \'folder\')' - .' AND `share_type` IN (?,?,?)' - .' AND `share_with`' - .' IN (\''.implode('\',\'', $userAndGroups).'\')'); - $result = $checkTargets->execute(array( - self::SHARE_TYPE_USER, - self::SHARE_TYPE_GROUP, - self::$shareTypeGroupUserUnique)); + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); } else { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'`' - .' FROM `*PREFIX*share`' - .' WHERE `item_type` = ?' - .' AND `share_type` IN (?,?,?)' - .' AND `share_with`' - .' IN (\''.implode('\',\'', $userAndGroups).'\')'); - $result = $checkTargets->execute(array( - $itemType, - self::SHARE_TYPE_USER, - self::SHARE_TYPE_GROUP, - self::$shareTypeGroupUserUnique)); + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); } } else { if ($column == 'file_target') { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'`' - .' FROM `*PREFIX*share`' - .' WHERE `item_type` IN (\'file\', \'folder\')' - .' AND `share_type` = ?' - .' AND `share_with` = ?'); + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` = ? AND `share_with` = ?'); $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith)); } else { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'`' - .' FROM `*PREFIX*share`' - .' WHERE `item_type` = ?' - .' AND `share_type` = ?' - .' AND `share_with` = ?'); + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?'); $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith)); } } @@ -1465,43 +1153,21 @@ class Share { $parents = array($parent); while (!empty($parents)) { $parents = "'".implode("','", $parents)."'"; - // Check the owner on the first search of reshares, - // useful for finding and deleting the reshares by a single user of a group share + // Check the owner on the first search of reshares, useful for finding and deleting the reshares by a single user of a group share if (count($ids) == 1 && isset($uidOwner)) { - $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent`' - .' FROM `*PREFIX*share`' - .' WHERE `parent` IN ('.$parents.')' - .' AND `uid_owner` = ?'); + $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?'); $result = $query->execute(array($uidOwner)); } else { - $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner`' - .' FROM `*PREFIX*share`' - .' WHERE `parent` IN ('.$parents.')'); + $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')'); $result = $query->execute(); } // Reset parents array, only go through loop again if items are found $parents = array(); while ($item = $result->fetchRow()) { - // Search for a duplicate parent share, - // this occurs when an item is shared to the same user through a group and user - // or the same item is shared by different users + // Search for a duplicate parent share, this occurs when an item is shared to the same user through a group and user or the same item is shared by different users $userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner'])); - $query = \OC_DB::prepare('SELECT `id`, `permissions`' - .' FROM `*PREFIX*share`' - .' WHERE `item_type` = ?' - .' AND `item_target` = ?' - .' AND `share_type` IN (?,?,?)' - .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')' - .' AND `uid_owner` != ?' - .' AND `id` != ?'); - $duplicateParent = $query->execute(array( - $item['item_type'], - $item['item_target'], - self::SHARE_TYPE_USER, - self::SHARE_TYPE_GROUP, - self::$shareTypeGroupUserUnique, - $item['uid_owner'], - $item['parent']))->fetchRow(); + $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share` WHERE `item_type` = ? AND `item_target` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\') AND `uid_owner` != ? AND `id` != ?'); + $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, $item['uid_owner'], $item['parent']))->fetchRow(); if ($duplicateParent) { // Change the parent to the other item id if share permission is granted if ($duplicateParent['permissions'] & PERMISSION_SHARE) { @@ -1530,10 +1196,7 @@ class Share { public static function post_deleteUser($arguments) { // Delete any items shared with the deleted user - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`' - .' WHERE `share_with` = ?' - .' AND `share_type` = ?' - .' OR `share_type` = ?'); + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `share_with` = ? AND `share_type` = ? OR `share_type` = ?'); $result = $query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique)); // Delete any items the deleted user shared $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?'); @@ -1547,46 +1210,21 @@ class Share { // Find the group shares and check if the user needs a unique target $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'); $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'])); - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`,' - .' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,' - .' `file_target`)' - .' VALUES (?,?,?,?,?,?,?,?,?,?,?)'); + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)'); while ($item = $result->fetchRow()) { if ($item['item_type'] == 'file' || $item['item_type'] == 'file') { $itemTarget = null; } else { - $itemTarget = self::generateTarget($item['item_type'], - $item['item_source'], - self::SHARE_TYPE_USER, - $arguments['uid'], - $item['uid_owner'], - $item['item_target'], - $item['id']); + $itemTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, $arguments['uid'], $item['uid_owner'], $item['item_target'], $item['id']); } if (isset($item['file_source'])) { - $fileTarget = self::generateTarget($item['item_type'], - $item['item_source'], - self::SHARE_TYPE_USER, - $arguments['uid'], - $item['uid_owner'], - $item['file_target'], - $item['id']); + $fileTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, $arguments['uid'], $item['uid_owner'], $item['file_target'], $item['id']); } else { $fileTarget = null; } // Insert an extra row for the group share if the item or file target is unique for this user if ($itemTarget != $item['item_target'] || $fileTarget != $item['file_target']) { - $query->execute(array($item['item_type'], - $item['item_source'], - $itemTarget, - $item['id'], - self::$shareTypeGroupUserUnique, - $arguments['uid'], - $item['uid_owner'], - $item['permissions'], - $item['stime'], - $item['file_source'], - $fileTarget)); + $query->execute(array($item['item_type'], $item['item_source'], $itemTarget, $item['id'], self::$shareTypeGroupUserUnique, $arguments['uid'], $item['uid_owner'], $item['permissions'], $item['stime'], $item['file_source'], $fileTarget)); \OC_DB::insertid('*PREFIX*share'); } } @@ -1594,15 +1232,8 @@ class Share { public static function post_removeFromGroup($arguments) { // TODO Don't call if user deleted? - $query = \OC_DB::prepare('SELECT `id`, `share_type`' - .' FROM `*PREFIX*share`' - .' WHERE (`share_type` = ? AND `share_with` = ?)' - .' OR (`share_type` = ? AND `share_with` = ?)'); - $result = $query->execute(array( - self::SHARE_TYPE_GROUP, - $arguments['gid'], - self::$shareTypeGroupUserUnique, - $arguments['uid'])); + $query = \OC_DB::prepare('SELECT `id`, `share_type` FROM `*PREFIX*share` WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)'); + $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'], self::$shareTypeGroupUserUnique, $arguments['uid'])); while ($item = $result->fetchRow()) { if ($item['share_type'] == self::SHARE_TYPE_GROUP) { // Delete all reshares by this user of the group share @@ -1659,13 +1290,10 @@ interface Share_Backend { * @param int Format * @return ? * - * The items array is a 3-dimensional array with the item_source as the first key - * and the share id as the second key to an array with the share info. + * The items array is a 3-dimensional array with the item_source as the first key and the share id as the second key to an array with the share info. * The key/value pairs included in the share info depend on the function originally called: - * If called by getItem(s)Shared: id, item_type, item, item_source, - * share_type, share_with, permissions, stime, file_source - * If called by getItem(s)SharedWith: id, item_type, item, item_source, - * item_target, share_type, share_with, permissions, stime, file_source, file_target + * If called by getItem(s)Shared: id, item_type, item, item_source, share_type, share_with, permissions, stime, file_source + * If called by getItem(s)SharedWith: id, item_type, item, item_source, item_target, share_type, share_with, permissions, stime, file_source, file_target * This function allows the backend to control the output of shared items with custom formats. * It is only called through calls to the public getItem(s)Shared(With) functions. */ @@ -1698,8 +1326,7 @@ interface Share_Backend_Collection extends Share_Backend { /** * @brief Get the sources of the children of the item * @param string Item source - * @return array Returns an array of children each inside an array with the keys: - * source, target, and file_path if applicable + * @return array Returns an array of children each inside an array with the keys: source, target, and file_path if applicable */ public function getChildren($itemSource); diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php index ea536ef77de..4d88c2a87f1 100644 --- a/lib/search/provider/file.php +++ b/lib/search/provider/file.php @@ -2,7 +2,7 @@ class OC_Search_Provider_File extends OC_Search_Provider{ function search($query) { - $files=OC_FileCache::search($query, true); + $files=\OC\Files\Filesystem::search($query, true); $results=array(); $l=OC_L10N::get('lib'); foreach($files as $fileData) { diff --git a/lib/util.php b/lib/util.php index 374baa43dbe..59566c9f4fb 100755 --- a/lib/util.php +++ b/lib/util.php @@ -39,7 +39,7 @@ class OC_Util { $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); //first set up the local "root" storage if(!self::$rootMounted) { - OC_Filesystem::mount('OC_Filestorage_Local', array('datadir'=>$CONFIG_DATADIRECTORY), '/'); + \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir'=>$CONFIG_DATADIRECTORY), '/'); self::$rootMounted=true; } @@ -51,51 +51,30 @@ class OC_Util { mkdir( $userdirectory, 0755, true ); } //jail the user into his "home" directory - OC_Filesystem::mount('OC_Filestorage_Local', array('datadir' => $user_root), $user); - OC_Filesystem::init($user_dir, $user); + \OC\Files\Filesystem::init($user_dir); + $quotaProxy=new OC_FileProxy_Quota(); $fileOperationProxy = new OC_FileProxy_FileOperations(); OC_FileProxy::register($quotaProxy); OC_FileProxy::register($fileOperationProxy); - // Load personal mount config - self::loadUserMountPoints($user); + OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $user_dir)); } + return true; } public static function tearDownFS() { - OC_Filesystem::tearDown(); + \OC\Files\Filesystem::tearDown(); self::$fsSetup=false; } - public static function loadUserMountPoints($user) { - $user_dir = '/'.$user.'/files'; - $user_root = OC_User::getHome($user); - $userdirectory = $user_root . '/files'; - if (is_file($user_root.'/mount.php')) { - $mountConfig = include $user_root.'/mount.php'; - if (isset($mountConfig['user'][$user])) { - foreach ($mountConfig['user'][$user] as $mountPoint => $options) { - OC_Filesystem::mount($options['class'], $options['options'], $mountPoint); - } - } - - $mtime=filemtime($user_root.'/mount.php'); - $previousMTime=OC_Preferences::getValue($user, 'files', 'mountconfigmtime', 0); - if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated - OC_FileCache::triggerUpdate($user); - OC_Preferences::setValue($user, 'files', 'mountconfigmtime', $mtime); - } - } - } - /** * get the current installed version of ownCloud * @return array */ public static function getVersion() { // hint: We only can count up. So the internal version number of ownCloud 4.5 will be 4.90.0. This is not visible to the user - return array(4, 91, 02); + return array(4,91,07); } /** @@ -157,14 +136,14 @@ class OC_Util { * @param string $text the text content for the element */ public static function addHeader( $tag, $attributes, $text='') { - self::$headers[]=array('tag'=>$tag,'attributes'=>$attributes, 'text'=>$text); + self::$headers[] = array('tag'=>$tag, 'attributes'=>$attributes, 'text'=>$text); } /** * formats a timestamp in the "right" way * * @param int timestamp $timestamp - * @param bool dateOnly option to ommit time from the result + * @param bool dateOnly option to omit time from the result */ public static function formatDate( $timestamp, $dateOnly=false) { if(isset($_SESSION['timezone'])) {//adjust to clients timezone if we know it @@ -398,6 +377,17 @@ class OC_Util { } /** + * @brief Static lifespan (in seconds) when a request token expires. + * @see OC_Util::callRegister() + * @see OC_Util::isCallRegistered() + * @description + * Also required for the client side to compute the piont in time when to + * request a fresh token. The client will do so when nearly 97% of the + * timespan coded here has expired. + */ + public static $callLifespan = 3600; // 3600 secs = 1 hour + + /** * @brief Register an get/post call. Important to prevent CSRF attacks. * @todo Write howto: CSRF protection guide * @return $token Generated token. @@ -405,6 +395,8 @@ class OC_Util { * Creates a 'request token' (random) and stores it inside the session. * Ever subsequent (ajax) request must use such a valid token to succeed, * otherwise the request will be denied as a protection against CSRF. + * The tokens expire after a fixed lifespan. + * @see OC_Util::$callLifespan * @see OC_Util::isCallRegistered() */ public static function callRegister() { @@ -423,6 +415,7 @@ class OC_Util { /** * @brief Check an ajax get/post call if the request token is valid. * @return boolean False if request token is not set or is invalid. + * @see OC_Util::$callLifespan * @see OC_Util::callRegister() */ public static function isCallRegistered() { diff --git a/settings/personal.php b/settings/personal.php index 47dbcc53ebc..31ab8b783bd 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -16,11 +16,11 @@ OC_Util::addStyle( '3rdparty', 'chosen' ); OC_App::setActiveNavigationEntry( 'personal' ); // calculate the disc space -$rootInfo=OC_FileCache::get(''); -$sharedInfo=OC_FileCache::get('/Shared'); +$rootInfo=\OC\Files\Filesystem::getFileInfo(''); +$sharedInfo=\OC\Files\Filesystem::getFileInfo('/Shared'); $used=$rootInfo['size']; if($used<0) $used=0; -$free=OC_Filesystem::free_space(); +$free=\OC\Files\Filesystem::free_space(); $total=$free+$used; if($total==0) $total=1; // prevent division by zero $relative=round(($used/$total)*10000)/100; diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php index d64627198e0..5dcd3268804 100644 --- a/tests/lib/cache/file.php +++ b/tests/lib/cache/file.php @@ -38,8 +38,8 @@ class Test_Cache_File extends Test_Cache { } //set up temporary storage - OC_Filesystem::clearMounts(); - OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); + \OC\Files\Filesystem::clearMounts(); + \OC\Files\Filesystem::mount('\OC\Files\Storage\Temporary',array(),'/'); OC_User::clearBackends(); OC_User::useBackend(new OC_User_Dummy()); @@ -51,7 +51,7 @@ class Test_Cache_File extends Test_Cache { OC_User::setUserId('test'); //set up the users dir - $rootView=new OC_FilesystemView(''); + $rootView=new \OC\Files\View(''); $rootView->mkdir('/test'); $this->instance=new OC_Cache_File(); diff --git a/tests/lib/files/cache/cache.php b/tests/lib/files/cache/cache.php new file mode 100644 index 00000000000..a2b131ac0ac --- /dev/null +++ b/tests/lib/files/cache/cache.php @@ -0,0 +1,208 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Cache; + +class Cache extends \UnitTestCase { + /** + * @var \OC\Files\Storage\Temporary $storage; + */ + private $storage; + + /** + * @var \OC\Files\Cache\Cache $cache + */ + private $cache; + + public function testSimple() { + $file1 = 'foo'; + $file2 = 'foo/bar'; + $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder'); + $data2 = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file'); + + $this->assertFalse($this->cache->inCache($file1)); + $this->assertEqual($this->cache->get($file1), null); + + $id1 = $this->cache->put($file1, $data1); + $this->assertTrue($this->cache->inCache($file1)); + $cacheData1 = $this->cache->get($file1); + foreach ($data1 as $key => $value) { + $this->assertEqual($value, $cacheData1[$key]); + } + $this->assertEqual($cacheData1['mimepart'], 'foo'); + $this->assertEqual($cacheData1['fileid'], $id1); + $this->assertEqual($id1, $this->cache->getId($file1)); + + $this->assertFalse($this->cache->inCache($file2)); + $id2 = $this->cache->put($file2, $data2); + $this->assertTrue($this->cache->inCache($file2)); + $cacheData2 = $this->cache->get($file2); + foreach ($data2 as $key => $value) { + $this->assertEqual($value, $cacheData2[$key]); + } + $this->assertEqual($cacheData1['fileid'], $cacheData2['parent']); + $this->assertEqual($cacheData2['fileid'], $id2); + $this->assertEqual($id2, $this->cache->getId($file2)); + $this->assertEqual($id1, $this->cache->getParentId($file2)); + + $newSize = 1050; + $newId2 = $this->cache->put($file2, array('size' => $newSize)); + $cacheData2 = $this->cache->get($file2); + $this->assertEqual($newId2, $id2); + $this->assertEqual($cacheData2['size'], $newSize); + $this->assertEqual($cacheData1, $this->cache->get($file1)); + + $this->cache->remove($file2); + $this->assertFalse($this->cache->inCache($file2)); + $this->assertEqual($this->cache->get($file2), null); + $this->assertTrue($this->cache->inCache($file1)); + + $this->assertEqual($cacheData1, $this->cache->get($id1)); + } + + public function testPartial() { + $file1 = 'foo'; + + $this->cache->put($file1, array('size' => 10)); + $this->assertEqual(array('size' => 10), $this->cache->get($file1)); + + $this->cache->put($file1, array('mtime' => 15)); + $this->assertEqual(array('size' => 10, 'mtime' => 15), $this->cache->get($file1)); + + $this->cache->put($file1, array('size' => 12)); + $this->assertEqual(array('size' => 12, 'mtime' => 15), $this->cache->get($file1)); + } + + public function testFolder() { + $file1 = 'folder'; + $file2 = 'folder/bar'; + $file3 = 'folder/foo'; + $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory'); + $fileData = array(); + $fileData['bar'] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file'); + $fileData['foo'] = array('size' => 20, 'mtime' => 25, 'mimetype' => 'foo/file'); + + $this->cache->put($file1, $data1); + $this->cache->put($file2, $fileData['bar']); + $this->cache->put($file3, $fileData['foo']); + + $content = $this->cache->getFolderContents($file1); + $this->assertEqual(count($content), 2); + foreach ($content as $cachedData) { + $data = $fileData[$cachedData['name']]; + foreach ($data as $name => $value) { + $this->assertEqual($value, $cachedData[$name]); + } + } + + $file4 = 'folder/unkownSize'; + $fileData['unkownSize'] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'foo/file'); + $this->cache->put($file4, $fileData['unkownSize']); + + $this->assertEquals(-1, $this->cache->calculateFolderSize($file1)); + + $fileData['unkownSize'] = array('size' => 5, 'mtime' => 25, 'mimetype' => 'foo/file'); + $this->cache->put($file4, $fileData['unkownSize']); + + $this->assertEquals(1025, $this->cache->calculateFolderSize($file1)); + + $this->cache->remove('folder'); + $this->assertFalse($this->cache->inCache('folder/foo')); + $this->assertFalse($this->cache->inCache('folder/bar')); + } + + function testStatus() { + $this->assertEquals(\OC\Files\Cache\Cache::NOT_FOUND, $this->cache->getStatus('foo')); + $this->cache->put('foo', array('size' => -1)); + $this->assertEquals(\OC\Files\Cache\Cache::PARTIAL, $this->cache->getStatus('foo')); + $this->cache->put('foo', array('size' => -1, 'mtime' => 20, 'mimetype' => 'foo/file')); + $this->assertEquals(\OC\Files\Cache\Cache::SHALLOW, $this->cache->getStatus('foo')); + $this->cache->put('foo', array('size' => 10)); + $this->assertEquals(\OC\Files\Cache\Cache::COMPLETE, $this->cache->getStatus('foo')); + } + + function testSearch() { + $file1 = 'folder'; + $file2 = 'folder/foobar'; + $file3 = 'folder/foo'; + $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder'); + $fileData = array(); + $fileData['foobar'] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file'); + $fileData['foo'] = array('size' => 20, 'mtime' => 25, 'mimetype' => 'foo/file'); + + $this->cache->put($file1, $data1); + $this->cache->put($file2, $fileData['foobar']); + $this->cache->put($file3, $fileData['foo']); + + $this->assertEquals(2, count($this->cache->search('%foo%'))); + $this->assertEquals(1, count($this->cache->search('foo'))); + $this->assertEquals(1, count($this->cache->search('%folder%'))); + $this->assertEquals(1, count($this->cache->search('folder%'))); + $this->assertEquals(3, count($this->cache->search('%'))); + + $this->assertEquals(3, count($this->cache->searchByMime('foo'))); + $this->assertEquals(2, count($this->cache->searchByMime('foo/file'))); + } + + function testMove() { + $file1 = 'folder'; + $file2 = 'folder/bar'; + $file3 = 'folder/foo'; + $file4 = 'folder/foo/1'; + $file5 = 'folder/foo/2'; + $data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/bar'); + + $this->cache->put($file1, $data); + $this->cache->put($file2, $data); + $this->cache->put($file3, $data); + $this->cache->put($file4, $data); + $this->cache->put($file5, $data); + + $this->cache->move('folder/foo', 'folder/foobar'); + + $this->assertFalse($this->cache->inCache('folder/foo')); + $this->assertFalse($this->cache->inCache('folder/foo/1')); + $this->assertFalse($this->cache->inCache('folder/foo/2')); + + $this->assertTrue($this->cache->inCache('folder/bar')); + $this->assertTrue($this->cache->inCache('folder/foobar')); + $this->assertTrue($this->cache->inCache('folder/foobar/1')); + $this->assertTrue($this->cache->inCache('folder/foobar/2')); + } + + function testGetIncomplete() { + $file1 = 'folder1'; + $file2 = 'folder2'; + $file3 = 'folder3'; + $file4 = 'folder4'; + $data = array('size' => 10, 'mtime' => 50, 'mimetype' => 'foo/bar'); + + $this->cache->put($file1, $data); + $data['size'] = -1; + $this->cache->put($file2, $data); + $this->cache->put($file3, $data); + $data['size'] = 12; + $this->cache->put($file4, $data); + + $this->assertEquals($file3, $this->cache->getIncomplete()); + } + + function testNonExisting() { + $this->assertFalse($this->cache->get('foo.txt')); + $this->assertEquals(array(), $this->cache->getFolderContents('foo')); + } + + public function tearDown() { + $this->cache->clear(); + } + + public function setUp() { + $this->storage = new \OC\Files\Storage\Temporary(array()); + $this->cache = new \OC\Files\Cache\Cache($this->storage); + } +} diff --git a/tests/lib/files/cache/permissions.php b/tests/lib/files/cache/permissions.php new file mode 100644 index 00000000000..56dbbc4518e --- /dev/null +++ b/tests/lib/files/cache/permissions.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Cache; + +class Permissions extends \PHPUnit_Framework_TestCase { + /*** + * @var \OC\Files\Cache\Permissions $permissionsCache + */ + private $permissionsCache; + + function setUp(){ + $this->permissionsCache=new \OC\Files\Cache\Permissions('dummy'); + } + + function testSimple() { + $ids = range(1, 10); + $user = uniqid(); + + $this->assertEquals(-1, $this->permissionsCache->get(1, $user)); + $this->permissionsCache->set(1, $user, 1); + $this->assertEquals(1, $this->permissionsCache->get(1, $user)); + $this->assertEquals(-1, $this->permissionsCache->get(2, $user)); + $this->assertEquals(-1, $this->permissionsCache->get(1, $user . '2')); + + $this->permissionsCache->set(1, $user, 2); + $this->assertEquals(2, $this->permissionsCache->get(1, $user)); + + $this->permissionsCache->set(2, $user, 1); + $this->assertEquals(1, $this->permissionsCache->get(2, $user)); + + $this->permissionsCache->remove(1, $user); + $this->assertEquals(-1, $this->permissionsCache->get(1, $user)); + $this->permissionsCache->remove(1, $user . '2'); + $this->assertEquals(1, $this->permissionsCache->get(2, $user)); + + $expected = array(); + foreach ($ids as $id) { + $this->permissionsCache->set($id, $user, 10 + $id); + $expected[$id] = 10 + $id; + } + $this->assertEquals($expected, $this->permissionsCache->getMultiple($ids, $user)); + + $this->permissionsCache->removeMultiple(array(10, 9), $user); + unset($expected[9]); + unset($expected[10]); + $this->assertEquals($expected, $this->permissionsCache->getMultiple($ids, $user)); + + $this->permissionsCache->removeMultiple($ids, $user); + } +} diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php new file mode 100644 index 00000000000..6d26150d82b --- /dev/null +++ b/tests/lib/files/cache/scanner.php @@ -0,0 +1,141 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Cache; + +class Scanner extends \UnitTestCase { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage; + + /** + * @var \OC\Files\Cache\Scanner $scanner + */ + private $scanner; + + /** + * @var \OC\Files\Cache\Cache $cache + */ + private $cache; + + function testFile() { + $data = "dummy file data\n"; + $this->storage->file_put_contents('foo.txt', $data); + $this->scanner->scanFile('foo.txt'); + + $this->assertEqual($this->cache->inCache('foo.txt'), true); + $cachedData = $this->cache->get('foo.txt'); + $this->assertEqual($cachedData['size'], strlen($data)); + $this->assertEqual($cachedData['mimetype'], 'text/plain'); + $this->assertNotEqual($cachedData['parent'], -1); //parent folders should be scanned automatically + + $data = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); + $this->storage->file_put_contents('foo.png', $data); + $this->scanner->scanFile('foo.png'); + + $this->assertEqual($this->cache->inCache('foo.png'), true); + $cachedData = $this->cache->get('foo.png'); + $this->assertEqual($cachedData['size'], strlen($data)); + $this->assertEqual($cachedData['mimetype'], 'image/png'); + } + + private function fillTestFolders() { + $textData = "dummy file data\n"; + $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); + $this->storage->mkdir('folder'); + $this->storage->file_put_contents('foo.txt', $textData); + $this->storage->file_put_contents('foo.png', $imgData); + $this->storage->file_put_contents('folder/bar.txt', $textData); + } + + function testFolder() { + $this->fillTestFolders(); + + $this->scanner->scan(''); + $this->assertEqual($this->cache->inCache(''), true); + $this->assertEqual($this->cache->inCache('foo.txt'), true); + $this->assertEqual($this->cache->inCache('foo.png'), true); + $this->assertEqual($this->cache->inCache('folder'), true); + $this->assertEqual($this->cache->inCache('folder/bar.txt'), true); + + $cachedDataText = $this->cache->get('foo.txt'); + $cachedDataText2 = $this->cache->get('foo.txt'); + $cachedDataImage = $this->cache->get('foo.png'); + $cachedDataFolder = $this->cache->get(''); + $cachedDataFolder2 = $this->cache->get('folder'); + + $this->assertEqual($cachedDataImage['parent'], $cachedDataText['parent']); + $this->assertEqual($cachedDataFolder['fileid'], $cachedDataImage['parent']); + $this->assertEqual($cachedDataFolder['size'], $cachedDataImage['size'] + $cachedDataText['size'] + $cachedDataText2['size']); + $this->assertEqual($cachedDataFolder2['size'], $cachedDataText2['size']); + } + + function testShallow() { + $this->fillTestFolders(); + + $this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW); + $this->assertEqual($this->cache->inCache(''), true); + $this->assertEqual($this->cache->inCache('foo.txt'), true); + $this->assertEqual($this->cache->inCache('foo.png'), true); + $this->assertEqual($this->cache->inCache('folder'), true); + $this->assertEqual($this->cache->inCache('folder/bar.txt'), false); + + $cachedDataFolder = $this->cache->get(''); + $cachedDataFolder2 = $this->cache->get('folder'); + + $this->assertEqual(-1, $cachedDataFolder['size']); + $this->assertEqual(-1, $cachedDataFolder2['size']); + + $this->scanner->scan('folder', \OC\Files\Cache\Scanner::SCAN_SHALLOW); + + $cachedDataFolder2 = $this->cache->get('folder'); + + $this->assertNotEqual($cachedDataFolder2['size'], -1); + + $this->cache->correctFolderSize('folder'); + + $cachedDataFolder = $this->cache->get(''); + $this->assertNotEqual($cachedDataFolder['size'], -1); + } + + function testBackgroundScan(){ + $this->fillTestFolders(); + $this->storage->mkdir('folder2'); + $this->storage->file_put_contents('folder2/bar.txt', 'foobar'); + + $this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW); + $this->assertFalse($this->cache->inCache('folder/bar.txt')); + $this->assertFalse($this->cache->inCache('folder/2bar.txt')); + $cachedData = $this->cache->get(''); + $this->assertEquals(-1, $cachedData['size']); + + $this->scanner->backgroundScan(); + + $this->assertTrue($this->cache->inCache('folder/bar.txt')); + $this->assertTrue($this->cache->inCache('folder/bar.txt')); + + $cachedData = $this->cache->get(''); + $this->assertnotEquals(-1, $cachedData['size']); + + $this->assertFalse($this->cache->getIncomplete()); + } + + function setUp() { + $this->storage = new \OC\Files\Storage\Temporary(array()); + $this->scanner = new \OC\Files\Cache\Scanner($this->storage); + $this->cache = new \OC\Files\Cache\Cache($this->storage); + } + + function tearDown() { + $ids = $this->cache->getAll(); + $permissionsCache = $this->storage->getPermissionsCache(); + $permissionsCache->removeMultiple($ids, \OC_User::getUser()); + $this->cache->clear(); + } +} diff --git a/tests/lib/files/cache/updater.php b/tests/lib/files/cache/updater.php new file mode 100644 index 00000000000..cad3d9d46fc --- /dev/null +++ b/tests/lib/files/cache/updater.php @@ -0,0 +1,139 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Cache; + +use \OC\Files\Filesystem as Filesystem; + +class Updater extends \PHPUnit_Framework_TestCase { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage; + + /** + * @var \OC\Files\Cache\Scanner $scanner + */ + private $scanner; + + /** + * @var \OC\Files\Cache\Cache $cache + */ + private $cache; + + private static $user; + + public function setUp() { + $this->storage = new \OC\Files\Storage\Temporary(array()); + $textData = "dummy file data\n"; + $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); + $this->storage->mkdir('folder'); + $this->storage->file_put_contents('foo.txt', $textData); + $this->storage->file_put_contents('foo.png', $imgData); + $this->storage->file_put_contents('folder/bar.txt', $textData); + $this->storage->file_put_contents('folder/bar2.txt', $textData); + + $this->scanner = $this->storage->getScanner(); + $this->scanner->scan(''); + $this->cache = $this->storage->getCache(); + + if (!self::$user) { + if (!\OC\Files\Filesystem::getView()) { + self::$user = uniqid(); + \OC\Files\Filesystem::init('/' . self::$user . '/files'); + } else { + self::$user = \OC_User::getUser(); + } + } + + Filesystem::clearMounts(); + Filesystem::mount($this->storage, array(), '/' . self::$user . '/files'); + + \OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook'); + \OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook'); + \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook'); + + } + + public function tearDown() { + if($this->cache){ + $this->cache->clear(); + } + Filesystem::tearDown(); + } + + public function testWrite() { + $textSize = strlen("dummy file data\n"); + $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png'); + $rootCachedData = $this->cache->get(''); + $this->assertEquals(3 * $textSize + $imageSize, $rootCachedData['size']); + + $fooCachedData = $this->cache->get('foo.txt'); + Filesystem::file_put_contents('foo.txt', 'asd'); + $cachedData = $this->cache->get('foo.txt'); + $this->assertEquals(3, $cachedData['size']); + $this->assertNotEquals($fooCachedData['etag'], $cachedData['etag']); + $cachedData = $this->cache->get(''); + $this->assertEquals(2 * $textSize + $imageSize + 3, $cachedData['size']); + $this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']); + $rootCachedData = $cachedData; + + $this->assertFalse($this->cache->inCache('bar.txt')); + Filesystem::file_put_contents('bar.txt', 'asd'); + $this->assertTrue($this->cache->inCache('bar.txt')); + $cachedData = $this->cache->get('bar.txt'); + $this->assertEquals(3, $cachedData['size']); + $cachedData = $this->cache->get(''); + $this->assertEquals(2 * $textSize + $imageSize + 2 * 3, $cachedData['size']); + $this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']); + } + + public function testDelete() { + $textSize = strlen("dummy file data\n"); + $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png'); + $rootCachedData = $this->cache->get(''); + $this->assertEquals(3 * $textSize + $imageSize, $rootCachedData['size']); + + $this->assertTrue($this->cache->inCache('foo.txt')); + Filesystem::unlink('foo.txt', 'asd'); + $this->assertFalse($this->cache->inCache('foo.txt')); + $cachedData = $this->cache->get(''); + $this->assertEquals(2 * $textSize + $imageSize, $cachedData['size']); + $this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']); + $rootCachedData = $cachedData; + + Filesystem::mkdir('bar_folder'); + $this->assertTrue($this->cache->inCache('bar_folder')); + $cachedData = $this->cache->get(''); + $this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']); + $rootCachedData = $cachedData; + Filesystem::rmdir('bar_folder'); + $this->assertFalse($this->cache->inCache('bar_folder')); + $cachedData = $this->cache->get(''); + $this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']); + } + + public function testRename() { + $textSize = strlen("dummy file data\n"); + $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png'); + $rootCachedData = $this->cache->get(''); + $this->assertEquals(3 * $textSize + $imageSize, $rootCachedData['size']); + + $this->assertTrue($this->cache->inCache('foo.txt')); + $fooCachedData = $this->cache->get('foo.txt'); + $this->assertFalse($this->cache->inCache('bar.txt')); + Filesystem::rename('foo.txt', 'bar.txt'); + $this->assertFalse($this->cache->inCache('foo.txt')); + $this->assertTrue($this->cache->inCache('bar.txt')); + $cachedData = $this->cache->get('foo.txt'); + $this->assertNotEquals($fooCachedData['etag'], $cachedData['etag']); + $cachedData = $this->cache->get(''); + $this->assertEquals(3 * $textSize + $imageSize, $cachedData['size']); + $this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']); + } +} diff --git a/tests/lib/files/cache/watcher.php b/tests/lib/files/cache/watcher.php new file mode 100644 index 00000000000..e8a1689cab0 --- /dev/null +++ b/tests/lib/files/cache/watcher.php @@ -0,0 +1,121 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Cache; + +class Watcher extends \PHPUnit_Framework_TestCase { + + /** + * @var \OC\Files\Storage\Storage[] $storages; + */ + private $storages = array(); + + public function setUp() { + \OC\Files\Filesystem::clearMounts(); + } + + public function tearDown() { + foreach ($this->storages as $storage) { + $cache = $storage->getCache(); + $ids = $cache->getAll(); + $permissionsCache = $storage->getPermissionsCache(); + $permissionsCache->removeMultiple($ids, \OC_User::getUser()); + $cache->clear(); + } + } + + function testWatcher() { + $storage = $this->getTestStorage(); + $cache = $storage->getCache(); + $updater = $storage->getWatcher(); + + //set the mtime to the past so it can detect an mtime change + $cache->put('', array('mtime' => 10)); + + $this->assertTrue($cache->inCache('folder/bar.txt')); + $this->assertTrue($cache->inCache('folder/bar2.txt')); + + $this->assertFalse($cache->inCache('bar.test')); + $storage->file_put_contents('bar.test', 'foo'); + $updater->checkUpdate(''); + $this->assertTrue($cache->inCache('bar.test')); + $cachedData = $cache->get('bar.test'); + $this->assertEquals(3, $cachedData['size']); + + $cache->put('bar.test', array('mtime' => 10)); + $storage->file_put_contents('bar.test', 'test data'); + + $updater->checkUpdate('bar.test'); + $cachedData = $cache->get('bar.test'); + $this->assertEquals(9, $cachedData['size']); + + $cache->put('folder', array('mtime' => 10)); + + $storage->unlink('folder/bar2.txt'); + $updater->checkUpdate('folder'); + + $this->assertTrue($cache->inCache('folder/bar.txt')); + $this->assertFalse($cache->inCache('folder/bar2.txt')); + } + + public function testFileToFolder() { + $storage = $this->getTestStorage(); + $cache = $storage->getCache(); + $updater = $storage->getWatcher(); + + //set the mtime to the past so it can detect an mtime change + $cache->put('', array('mtime' => 10)); + + $storage->unlink('foo.txt'); + $storage->rename('folder', 'foo.txt'); + $updater->checkUpdate(''); + + $entry = $cache->get('foo.txt'); + $this->assertEquals(-1, $entry['size']); + $this->assertEquals('httpd/unix-directory', $entry['mimetype']); + $this->assertFalse($cache->inCache('folder')); + $this->assertFalse($cache->inCache('folder/bar.txt')); + + $storage = $this->getTestStorage(); + $cache = $storage->getCache(); + $updater = $storage->getWatcher(); + + //set the mtime to the past so it can detect an mtime change + $cache->put('foo.txt', array('mtime' => 10)); + + $storage->unlink('foo.txt'); + $storage->rename('folder', 'foo.txt'); + $updater->checkUpdate('foo.txt'); + + $entry = $cache->get('foo.txt'); + $this->assertEquals('httpd/unix-directory', $entry['mimetype']); + $this->assertTrue($cache->inCache('foo.txt/bar.txt')); + } + + /** + * @param bool $scan + * @return \OC\Files\Storage\Storage + */ + private function getTestStorage($scan = true) { + $storage = new \OC\Files\Storage\Temporary(array()); + $textData = "dummy file data\n"; + $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); + $storage->mkdir('folder'); + $storage->file_put_contents('foo.txt', $textData); + $storage->file_put_contents('foo.png', $imgData); + $storage->file_put_contents('folder/bar.txt', $textData); + $storage->file_put_contents('folder/bar2.txt', $textData); + + if ($scan) { + $scanner = $storage->getScanner(); + $scanner->scan(''); + } + $this->storages[] = $storage; + return $storage; + } +} diff --git a/tests/lib/files/filesystem.php b/tests/lib/files/filesystem.php new file mode 100644 index 00000000000..5837093fdd6 --- /dev/null +++ b/tests/lib/files/filesystem.php @@ -0,0 +1,110 @@ +<?php +/** + * ownCloud + * + * @author Robin Appelman + * @copyright 2012 Robin Appelman icewind@owncloud.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/>. + * + */ + +namespace Test\Files; + +class Filesystem extends \PHPUnit_Framework_TestCase { + /** + * @var array tmpDirs + */ + private $tmpDirs=array(); + + /** + * @return array + */ + private function getStorageData() { + $dir = \OC_Helper::tmpFolder(); + $this->tmpDirs[] = $dir; + return array('datadir' => $dir); + } + + public function tearDown() { + foreach ($this->tmpDirs as $dir) { + \OC_Helper::rmdirr($dir); + } + } + + public function setUp() { + \OC\Files\Filesystem::clearMounts(); + } + + public function testMount() { + \OC\Files\Filesystem::mount('\OC\Files\Storage\Local',self::getStorageData(),'/'); + $this->assertEquals('/',\OC\Files\Filesystem::getMountPoint('/')); + $this->assertEquals('/',\OC\Files\Filesystem::getMountPoint('/some/folder')); + list( , $internalPath)=\OC\Files\Filesystem::resolvePath('/'); + $this->assertEquals('',$internalPath); + list( , $internalPath)=\OC\Files\Filesystem::resolvePath('/some/folder'); + $this->assertEquals('some/folder',$internalPath); + + \OC\Files\Filesystem::mount('\OC\Files\Storage\Local',self::getStorageData(),'/some'); + $this->assertEquals('/',\OC\Files\Filesystem::getMountPoint('/')); + $this->assertEquals('/some/',\OC\Files\Filesystem::getMountPoint('/some/folder')); + $this->assertEquals('/some/',\OC\Files\Filesystem::getMountPoint('/some/')); + $this->assertEquals('/some/',\OC\Files\Filesystem::getMountPoint('/some')); + list( , $internalPath)=\OC\Files\Filesystem::resolvePath('/some/folder'); + $this->assertEquals('folder',$internalPath); + } + + public function testNormalize() { + $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('/path/')); + $this->assertEquals('/path/', \OC\Files\Filesystem::normalizePath('/path/', false)); + $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('path')); + $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('\path')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo//bar/')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo////bar')); + if (class_exists('Normalizer')) { + $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("/foo/baru\xCC\x88")); + } + } + + public function testHooks() { + if(\OC\Files\Filesystem::getView()){ + $user = \OC_User::getUser(); + }else{ + $user=uniqid(); + \OC\Files\Filesystem::init('/'.$user.'/files'); + } + \OC_Hook::clear('OC_Filesystem'); + \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); + + \OC\Files\Filesystem::mount('OC\Files\Storage\Temporary', array(), '/'); + + $rootView=new \OC\Files\View(''); + $rootView->mkdir('/'.$user); + $rootView->mkdir('/'.$user.'/files'); + + \OC\Files\Filesystem::file_put_contents('/foo', 'foo'); + \OC\Files\Filesystem::mkdir('/bar'); + \OC\Files\Filesystem::file_put_contents('/bar//foo', 'foo'); + + $tmpFile = \OC_Helper::tmpFile(); + file_put_contents($tmpFile, 'foo'); + $fh = fopen($tmpFile, 'r'); + \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh); + } + + public function dummyHook($arguments) { + $path = $arguments['path']; + $this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized + } +} diff --git a/tests/lib/filestorage/commontest.php b/tests/lib/files/storage/commontest.php index 6719fcff4e8..744d4608420 100644 --- a/tests/lib/filestorage/commontest.php +++ b/tests/lib/files/storage/commontest.php @@ -20,7 +20,9 @@ * */ -class Test_Filestorage_CommonTest extends Test_FileStorage { +namespace Test\Files\Storage; + +class CommonTest extends Storage { /** * @var string tmpDir */ @@ -30,11 +32,10 @@ class Test_Filestorage_CommonTest extends Test_FileStorage { if(!file_exists($this->tmpDir)) { mkdir($this->tmpDir); } - $this->instance=new OC_Filestorage_CommonTest(array('datadir'=>$this->tmpDir)); + $this->instance=new \OC\Files\Storage\CommonTest(array('datadir'=>$this->tmpDir)); } public function tearDown() { - OC_Helper::rmdirr($this->tmpDir); + \OC_Helper::rmdirr($this->tmpDir); } } - diff --git a/tests/lib/filestorage/local.php b/tests/lib/files/storage/local.php index d7d71e8f372..1aad138aa33 100644 --- a/tests/lib/filestorage/local.php +++ b/tests/lib/files/storage/local.php @@ -20,18 +20,20 @@ * */ -class Test_Filestorage_Local extends Test_FileStorage { +namespace Test\Files\Storage; + +class Local extends Storage { /** * @var string tmpDir */ private $tmpDir; public function setUp() { - $this->tmpDir=OC_Helper::tmpFolder(); - $this->instance=new OC_Filestorage_Local(array('datadir'=>$this->tmpDir)); + $this->tmpDir=\OC_Helper::tmpFolder(); + $this->instance=new \OC\Files\Storage\Local(array('datadir'=>$this->tmpDir)); } public function tearDown() { - OC_Helper::rmdirr($this->tmpDir); + \OC_Helper::rmdirr($this->tmpDir); } } diff --git a/tests/lib/filestorage.php b/tests/lib/files/storage/storage.php index e82a6f54e3d..5d8a2241263 100644 --- a/tests/lib/filestorage.php +++ b/tests/lib/files/storage/storage.php @@ -20,9 +20,11 @@ * */ -abstract class Test_FileStorage extends UnitTestCase { +namespace Test\Files\Storage; + +abstract class Storage extends \UnitTestCase { /** - * @var OC_Filestorage instance + * @var \OC\Files\Storage\Storage instance */ protected $instance; @@ -36,7 +38,7 @@ abstract class Test_FileStorage extends UnitTestCase { $this->assertFalse($this->instance->is_file('/'), 'Root folder is a file'); $this->assertEqual('dir', $this->instance->filetype('/')); - //without this, any further testing would be useless, not an acutal requirement for filestorage though + //without this, any further testing would be useless, not an actual requirement for filestorage though $this->assertTrue($this->instance->isUpdatable('/'), 'Root folder is not writable'); } @@ -83,7 +85,7 @@ abstract class Test_FileStorage extends UnitTestCase { * test the various uses of file_get_contents and file_put_contents */ public function testGetPutContents() { - $sourceFile = OC::$SERVERROOT . '/tests/data/lorem.txt'; + $sourceFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; $sourceText = file_get_contents($sourceFile); //fill a file with string data @@ -103,21 +105,21 @@ abstract class Test_FileStorage extends UnitTestCase { $this->assertEqual('httpd/unix-directory', $this->instance->getMimeType('/')); $this->assertEqual(false, $this->instance->getMimeType('/non/existing/file')); - $textFile = OC::$SERVERROOT . '/tests/data/lorem.txt'; + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile, 'r')); $this->assertEqual('text/plain', $this->instance->getMimeType('/lorem.txt')); - $pngFile = OC::$SERVERROOT . '/tests/data/logo-wide.png'; + $pngFile = \OC::$SERVERROOT . '/tests/data/logo-wide.png'; $this->instance->file_put_contents('/logo-wide.png', file_get_contents($pngFile, 'r')); $this->assertEqual('image/png', $this->instance->getMimeType('/logo-wide.png')); - $svgFile = OC::$SERVERROOT . '/tests/data/logo-wide.svg'; + $svgFile = \OC::$SERVERROOT . '/tests/data/logo-wide.svg'; $this->instance->file_put_contents('/logo-wide.svg', file_get_contents($svgFile, 'r')); $this->assertEqual('image/svg+xml', $this->instance->getMimeType('/logo-wide.svg')); } public function testCopyAndMove() { - $textFile = OC::$SERVERROOT . '/tests/data/lorem.txt'; + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; $this->instance->file_put_contents('/source.txt', file_get_contents($textFile)); $this->instance->copy('/source.txt', '/target.txt'); $this->assertTrue($this->instance->file_exists('/target.txt')); @@ -130,7 +132,7 @@ abstract class Test_FileStorage extends UnitTestCase { } public function testLocal() { - $textFile = OC::$SERVERROOT . '/tests/data/lorem.txt'; + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); $localFile = $this->instance->getLocalFile('/lorem.txt'); $this->assertTrue(file_exists($localFile)); @@ -151,7 +153,7 @@ abstract class Test_FileStorage extends UnitTestCase { } public function testStat() { - $textFile = OC::$SERVERROOT . '/tests/data/lorem.txt'; + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; $ctimeStart = time(); $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); $this->assertTrue($this->instance->isReadable('/lorem.txt')); @@ -165,7 +167,7 @@ abstract class Test_FileStorage extends UnitTestCase { $this->assertEqual(filesize($textFile), $this->instance->filesize('/lorem.txt')); $stat = $this->instance->stat('/lorem.txt'); - //only size and mtime are requered in the result + //only size and mtime are required in the result $this->assertEqual($stat['size'], $this->instance->filesize('/lorem.txt')); $this->assertEqual($stat['mtime'], $mTime); @@ -200,11 +202,11 @@ abstract class Test_FileStorage extends UnitTestCase { } public function testSearch() { - $textFile = OC::$SERVERROOT . '/tests/data/lorem.txt'; + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile, 'r')); - $pngFile = OC::$SERVERROOT . '/tests/data/logo-wide.png'; + $pngFile = \OC::$SERVERROOT . '/tests/data/logo-wide.png'; $this->instance->file_put_contents('/logo-wide.png', file_get_contents($pngFile, 'r')); - $svgFile = OC::$SERVERROOT . '/tests/data/logo-wide.svg'; + $svgFile = \OC::$SERVERROOT . '/tests/data/logo-wide.svg'; $this->instance->file_put_contents('/logo-wide.svg', file_get_contents($svgFile, 'r')); $result = $this->instance->search('logo'); $this->assertEqual(2, count($result)); @@ -213,7 +215,7 @@ abstract class Test_FileStorage extends UnitTestCase { } public function testFOpen() { - $textFile = OC::$SERVERROOT . '/tests/data/lorem.txt'; + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; $fh = @$this->instance->fopen('foo', 'r'); if ($fh) { diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php new file mode 100644 index 00000000000..53271142672 --- /dev/null +++ b/tests/lib/files/view.php @@ -0,0 +1,216 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ + +namespace Test\Files; + +class View extends \PHPUnit_Framework_TestCase { + /** + * @var \OC\Files\Storage\Storage[] $storages; + */ + private $storages = array(); + + public function setUp() { + \OC\Files\Filesystem::clearMounts(); + } + + public function tearDown() { + foreach ($this->storages as $storage) { + $cache = $storage->getCache(); + $ids = $cache->getAll(); + $permissionsCache = $storage->getPermissionsCache(); + $permissionsCache->removeMultiple($ids, \OC_User::getUser()); + $cache->clear(); + } + } + + public function testCacheAPI() { + $storage1 = $this->getTestStorage(); + $storage2 = $this->getTestStorage(); + $storage3 = $this->getTestStorage(); + \OC\Files\Filesystem::mount($storage1, array(), '/'); + \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); + \OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage'); + $textSize = strlen("dummy file data\n"); + $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png'); + $storageSize = $textSize * 2 + $imageSize; + + $rootView = new \OC\Files\View(''); + + $cachedData = $rootView->getFileInfo('/foo.txt'); + $this->assertEquals($textSize, $cachedData['size']); + $this->assertEquals('text/plain', $cachedData['mimetype']); + $this->assertNotEquals(-1, $cachedData['permissions']); + + $cachedData = $rootView->getFileInfo('/'); + $this->assertEquals($storageSize * 3, $cachedData['size']); + $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); + + $cachedData = $rootView->getFileInfo('/folder'); + $this->assertEquals($storageSize + $textSize, $cachedData['size']); + $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); + + $folderData = $rootView->getDirectoryContent('/'); + /** + * expected entries: + * folder + * foo.png + * foo.txt + * substorage + */ + $this->assertEquals(4, count($folderData)); + $this->assertEquals('folder', $folderData[0]['name']); + $this->assertEquals('foo.png', $folderData[1]['name']); + $this->assertEquals('foo.txt', $folderData[2]['name']); + $this->assertEquals('substorage', $folderData[3]['name']); + + $this->assertEquals($storageSize + $textSize, $folderData[0]['size']); + $this->assertEquals($imageSize, $folderData[1]['size']); + $this->assertEquals($textSize, $folderData[2]['size']); + $this->assertEquals($storageSize, $folderData[3]['size']); + + $folderData = $rootView->getDirectoryContent('/substorage'); + /** + * expected entries: + * folder + * foo.png + * foo.txt + */ + $this->assertEquals(3, count($folderData)); + $this->assertEquals('folder', $folderData[0]['name']); + $this->assertEquals('foo.png', $folderData[1]['name']); + $this->assertEquals('foo.txt', $folderData[2]['name']); + + $folderView = new \OC\Files\View('/folder'); + $this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/')); + + $cachedData = $rootView->getFileInfo('/foo.txt'); + $this->assertFalse($cachedData['encrypted']); + $id = $rootView->putFileInfo('/foo.txt', array('encrypted' => true)); + $cachedData = $rootView->getFileInfo('/foo.txt'); + $this->assertTrue($cachedData['encrypted']); + $this->assertEquals($cachedData['fileid'], $id); + + $this->assertFalse($rootView->getFileInfo('/non/existing')); + $this->assertEquals(array(), $rootView->getDirectoryContent('/non/existing')); + } + + function testCacheIncompleteFolder() { + $storage1 = $this->getTestStorage(false); + \OC\Files\Filesystem::mount($storage1, array(), '/'); + $rootView = new \OC\Files\View(''); + + $entries = $rootView->getDirectoryContent('/'); + $this->assertEquals(3, count($entries)); + + // /folder will already be in the cache but not scanned + $entries = $rootView->getDirectoryContent('/folder'); + $this->assertEquals(1, count($entries)); + } + + public function testAutoScan() { + $storage1 = $this->getTestStorage(false); + $storage2 = $this->getTestStorage(false); + \OC\Files\Filesystem::mount($storage1, array(), '/'); + \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); + $textSize = strlen("dummy file data\n"); + + $rootView = new \OC\Files\View(''); + + $cachedData = $rootView->getFileInfo('/'); + $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); + $this->assertEquals(-1, $cachedData['size']); + + $folderData = $rootView->getDirectoryContent('/substorage/folder'); + $this->assertEquals('text/plain', $folderData[0]['mimetype']); + $this->assertEquals($textSize, $folderData[0]['size']); + } + + function testSearch() { + $storage1 = $this->getTestStorage(); + $storage2 = $this->getTestStorage(); + $storage3 = $this->getTestStorage(); + \OC\Files\Filesystem::mount($storage1, array(), '/'); + \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); + \OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage'); + + $rootView = new \OC\Files\View(''); + + $results = $rootView->search('foo'); + $this->assertEquals(6, count($results)); + $paths = array(); + foreach ($results as $result) { + $this->assertEquals($result['path'], \OC\Files\Filesystem::normalizePath($result['path'])); + $paths[] = $result['path']; + } + $this->assertContains('/foo.txt', $paths); + $this->assertContains('/foo.png', $paths); + $this->assertContains('/substorage/foo.txt', $paths); + $this->assertContains('/substorage/foo.png', $paths); + $this->assertContains('/folder/anotherstorage/foo.txt', $paths); + $this->assertContains('/folder/anotherstorage/foo.png', $paths); + + $folderView = new \OC\Files\View('/folder'); + $results = $folderView->search('bar'); + $this->assertEquals(2, count($results)); + $paths = array(); + foreach ($results as $result) { + $paths[] = $result['path']; + } + $this->assertContains('/anotherstorage/folder/bar.txt', $paths); + $this->assertContains('/bar.txt', $paths); + + $results = $folderView->search('foo'); + $this->assertEquals(2, count($results)); + $paths = array(); + foreach ($results as $result) { + $paths[] = $result['path']; + } + $this->assertContains('/anotherstorage/foo.txt', $paths); + $this->assertContains('/anotherstorage/foo.png', $paths); + + $this->assertEquals(6, count($rootView->searchByMime('text'))); + $this->assertEquals(3, count($folderView->searchByMime('text'))); + } + + function testWatcher() { + $storage1 = $this->getTestStorage(); + \OC\Files\Filesystem::mount($storage1, array(), '/'); + + $rootView = new \OC\Files\View(''); + + $cachedData = $rootView->getFileInfo('foo.txt'); + $this->assertEquals(16, $cachedData['size']); + + $rootView->putFileInfo('foo.txt', array('mtime' => 10)); + $storage1->file_put_contents('foo.txt', 'foo'); + clearstatcache(); + + $cachedData = $rootView->getFileInfo('foo.txt'); + $this->assertEquals(3, $cachedData['size']); + } + + /** + * @param bool $scan + * @return \OC\Files\Storage\Storage + */ + private function getTestStorage($scan = true) { + $storage = new \OC\Files\Storage\Temporary(array()); + $textData = "dummy file data\n"; + $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); + $storage->mkdir('folder'); + $storage->file_put_contents('foo.txt', $textData); + $storage->file_put_contents('foo.png', $imgData); + $storage->file_put_contents('folder/bar.txt', $textData); + + if ($scan) { + $scanner = $storage->getScanner(); + $scanner->scan(''); + } + $this->storages[] = $storage; + return $storage; + } +} diff --git a/tests/lib/filesystem.php b/tests/lib/filesystem.php deleted file mode 100644 index 5cced4946d9..00000000000 --- a/tests/lib/filesystem.php +++ /dev/null @@ -1,139 +0,0 @@ -<?php -/** - * ownCloud - * - * @author Robin Appelman - * @copyright 2012 Robin Appelman icewind@owncloud.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 Test_Filesystem extends UnitTestCase { - /** - * @var array tmpDirs - */ - private $tmpDirs = array(); - - /** - * @return array - */ - private function getStorageData() { - $dir = OC_Helper::tmpFolder(); - $this->tmpDirs[] = $dir; - return array('datadir' => $dir); - } - - public function tearDown() { - foreach ($this->tmpDirs as $dir) { - OC_Helper::rmdirr($dir); - } - } - - public function setUp() { - OC_Filesystem::clearMounts(); - } - - public function testMount() { - OC_Filesystem::mount('OC_Filestorage_Local', self::getStorageData(), '/'); - $this->assertEqual('/', OC_Filesystem::getMountPoint('/')); - $this->assertEqual('/', OC_Filesystem::getMountPoint('/some/folder')); - $this->assertEqual('', OC_Filesystem::getInternalPath('/')); - $this->assertEqual('some/folder', OC_Filesystem::getInternalPath('/some/folder')); - - OC_Filesystem::mount('OC_Filestorage_Local', self::getStorageData(), '/some'); - $this->assertEqual('/', OC_Filesystem::getMountPoint('/')); - $this->assertEqual('/some/', OC_Filesystem::getMountPoint('/some/folder')); - $this->assertEqual('/some/', OC_Filesystem::getMountPoint('/some/')); - $this->assertEqual('/', OC_Filesystem::getMountPoint('/some')); - $this->assertEqual('folder', OC_Filesystem::getInternalPath('/some/folder')); - } - - public function testNormalize() { - $this->assertEqual('/path', OC_Filesystem::normalizePath('/path/')); - $this->assertEqual('/path/', OC_Filesystem::normalizePath('/path/', false)); - $this->assertEqual('/path', OC_Filesystem::normalizePath('path')); - $this->assertEqual('/path', OC_Filesystem::normalizePath('\path')); - $this->assertEqual('/foo/bar', OC_Filesystem::normalizePath('/foo//bar/')); - $this->assertEqual('/foo/bar', OC_Filesystem::normalizePath('/foo////bar')); - if (class_exists('Normalizer')) { - $this->assertEqual("/foo/bar\xC3\xBC", OC_Filesystem::normalizePath("/foo/baru\xCC\x88")); - } - } - - public function testBlacklist() { - OC_Hook::clear('OC_Filesystem'); - OC::registerFilesystemHooks(); - - $run = true; - OC_Hook::emit( - OC_Filesystem::CLASSNAME, - OC_Filesystem::signal_write, - array( - OC_Filesystem::signal_param_path => '/test/.htaccess', - OC_Filesystem::signal_param_run => &$run - ) - ); - $this->assertFalse($run); - - if (OC_Filesystem::getView()) { - $user = OC_User::getUser(); - } else { - $user = uniqid(); - OC_Filesystem::init('/' . $user . '/files'); - } - - OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); - - $rootView = new OC_FilesystemView(''); - $rootView->mkdir('/' . $user); - $rootView->mkdir('/' . $user . '/files'); - - $this->assertFalse($rootView->file_put_contents('/.htaccess', 'foo')); - $this->assertFalse(OC_Filesystem::file_put_contents('/.htaccess', 'foo')); - $fh = fopen(__FILE__, 'r'); - $this->assertFalse(OC_Filesystem::file_put_contents('/.htaccess', $fh)); - } - - public function testHooks() { - if (OC_Filesystem::getView()) { - $user = OC_User::getUser(); - } else { - $user = uniqid(); - OC_Filesystem::init('/' . $user . '/files'); - } - OC_Hook::clear('OC_Filesystem'); - OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); - - OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); - - $rootView = new OC_FilesystemView(''); - $rootView->mkdir('/' . $user); - $rootView->mkdir('/' . $user . '/files'); - - OC_Filesystem::file_put_contents('/foo', 'foo'); - OC_Filesystem::mkdir('/bar'); - OC_Filesystem::file_put_contents('/bar//foo', 'foo'); - - $tmpFile = OC_Helper::tmpFile(); - file_put_contents($tmpFile, 'foo'); - $fh = fopen($tmpFile, 'r'); - OC_Filesystem::file_put_contents('/bar//foo', $fh); - } - - public function dummyHook($arguments) { - $path = $arguments['path']; - $this->assertEqual($path, OC_Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized - } -} |