diff options
author | Tom Needham <needham.thomas@gmail.com> | 2013-02-04 18:36:39 +0000 |
---|---|---|
committer | Tom Needham <needham.thomas@gmail.com> | 2013-02-04 18:36:39 +0000 |
commit | 406922fc6a49fc8a46dbfea5186cbfcd44938d3e (patch) | |
tree | 768a9f086b971d9295d12be244a024a3926a2c04 /lib | |
parent | aec5ab3ad2adc33a32158156a59f4c00606f8be9 (diff) | |
parent | 301afac2913e81414140c25bc21ede563563f76e (diff) | |
download | nextcloud-server-406922fc6a49fc8a46dbfea5186cbfcd44938d3e.tar.gz nextcloud-server-406922fc6a49fc8a46dbfea5186cbfcd44938d3e.zip |
Merge master
Diffstat (limited to 'lib')
99 files changed, 5078 insertions, 3483 deletions
diff --git a/lib/api.php b/lib/api.php index 8d728d4311f..abf1c3b0036 100644 --- a/lib/api.php +++ b/lib/api.php @@ -90,10 +90,15 @@ class OC_API { if(self::isAuthorised(self::$actions[$name])) { if(is_callable(self::$actions[$name]['action'])) { $response = call_user_func(self::$actions[$name]['action'], $parameters); + if(!($response instanceof OC_OCS_Result)) { + $response = new OC_OCS_Result(null, 996, 'Internal Server Error'); + } } else { $response = new OC_OCS_Result(null, 998, 'Api method not found'); } } else { + header('WWW-Authenticate: Basic realm="Authorization Required"'); + header('HTTP/1.0 401 Unauthorized'); $response = new OC_OCS_Result(null, 997, 'Unauthorised'); } // Send the response @@ -183,10 +188,13 @@ class OC_API { private static function toXML($array, $writer) { foreach($array as $k => $v) { - if (is_numeric($k)) { + if ($k[0] === '@') { + $writer->writeAttribute(substr($k, 1), $v); + continue; + } else if (is_numeric($k)) { $k = 'element'; } - if (is_array($v)) { + if(is_array($v)) { $writer->startElement($k); self::toXML($v, $writer); $writer->endElement(); diff --git a/lib/app.php b/lib/app.php index 410cb4c12fc..fa3e14ce4d2 100644 --- a/lib/app.php +++ b/lib/app.php @@ -63,17 +63,17 @@ class OC_App{ if (!defined('DEBUG') || !DEBUG) { if (is_null($types) - && empty(OC_Util::$core_scripts) - && empty(OC_Util::$core_styles)) { + && empty(OC_Util::$core_scripts) + && empty(OC_Util::$core_styles)) { OC_Util::$core_scripts = OC_Util::$scripts; - OC_Util::$scripts = array(); - OC_Util::$core_styles = OC_Util::$styles; - OC_Util::$styles = array(); - } + OC_Util::$scripts = array(); + OC_Util::$core_styles = OC_Util::$styles; + OC_Util::$styles = array(); } - // return - return true; } + // return + return true; +} /** * load a single app @@ -142,6 +142,8 @@ class OC_App{ * check if app is shipped * @param string $appid the id of the app to check * @return bool + * + * Check if an app that is installed is a shipped app or installed from the appstore. */ public static function isShipped($appid){ $info = self::getAppInfo($appid); @@ -177,7 +179,7 @@ class OC_App{ * This function checks whether or not an app is enabled. */ public static function isEnabled( $app ) { - if( 'files'==$app or 'yes' == OC_Appconfig::getValue( $app, 'enabled' )) { + if( 'files'==$app or ('yes' == OC_Appconfig::getValue( $app, 'enabled' ))) { return true; } @@ -197,9 +199,10 @@ class OC_App{ if(!is_numeric($app)) { $app = OC_Installer::installShippedApp($app); }else{ + $appdata=OC_OCSClient::getApplication($app); $download=OC_OCSClient::getApplicationDownload($app, 1); if(isset($download['downloadlink']) and $download['downloadlink']!='') { - $app=OC_Installer::installApp(array('source'=>'http', 'href'=>$download['downloadlink'])); + $app=OC_Installer::installApp(array('source'=>'http', 'href'=>$download['downloadlink'],'appdata'=>$appdata)); } } } @@ -212,6 +215,9 @@ class OC_App{ return false; }else{ OC_Appconfig::setValue( $app, 'enabled', 'yes' ); + if(isset($appdata['id'])) { + OC_Appconfig::setValue( $app, 'ocsid', $appdata['id'] ); + } return true; } }else{ @@ -227,8 +233,13 @@ class OC_App{ * This function set an app as disabled in appconfig. */ public static function disable( $app ) { - // check if app is a shiped app or not. if not delete + // check if app is a shipped app or not. if not delete OC_Appconfig::setValue( $app, 'enabled', 'no' ); + + // check if app is a shipped app or not. if not delete + if(!OC_App::isShipped( $app )){ + OC_Installer::removeApp( $app ); + } } /** @@ -299,7 +310,7 @@ class OC_App{ if(OC_Config::getValue('knowledgebaseenabled', true)==true) { $settings = array( array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkToRoute( "settings_help" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" )) - ); + ); } // if the user is logged-in @@ -495,7 +506,7 @@ class OC_App{ * @return string */ public static function getCurrentApp() { - $script=substr($_SERVER["SCRIPT_NAME"], strlen(OC::$WEBROOT)+1); + $script=substr(OC_Request::scriptName(), strlen(OC::$WEBROOT)+1); $topFolder=substr($script, 0, strpos($script, '/')); if (empty($topFolder)) { $path_info = OC_Request::getPathInfo(); @@ -519,16 +530,16 @@ class OC_App{ $forms=array(); switch($type) { case 'settings': - $source=self::$settingsForms; - break; + $source=self::$settingsForms; + break; case 'admin': - $source=self::$adminForms; - break; + $source=self::$adminForms; + break; case 'personal': - $source=self::$personalForms; - break; + $source=self::$personalForms; + break; default: - return array(); + return array(); } foreach($source as $form) { $forms[]=include $form; @@ -589,6 +600,76 @@ class OC_App{ } /** + * @brief: Lists all apps, this is used in apps.php + * @return array + */ + public static function listAllApps() { + $installedApps = OC_App::getAllApps(); + + //TODO which apps do we want to blacklist and how do we integrate blacklisting with the multi apps folder feature? + + $blacklist = array('files');//we dont want to show configuration for these + $appList = array(); + + foreach ( $installedApps as $app ) { + if ( array_search( $app, $blacklist ) === false ) { + + $info=OC_App::getAppInfo($app); + + if (!isset($info['name'])) { + OC_Log::write('core', 'App id "'.$app.'" has no name in appinfo', OC_Log::ERROR); + continue; + } + + if ( OC_Appconfig::getValue( $app, 'enabled', 'no') == 'yes' ) { + $active = true; + } else { + $active = false; + } + + $info['active'] = $active; + + if(isset($info['shipped']) and ($info['shipped']=='true')) { + $info['internal']=true; + $info['internallabel']='Internal App'; + $info['internalclass']=''; + $info['update']=false; + } else { + $info['internal']=false; + $info['internallabel']='3rd Party App'; + $info['internalclass']='externalapp'; + $info['update']=OC_Installer::isUpdateAvailable($app); + } + + $info['preview'] = OC_Helper::imagePath('settings', 'trans.png'); + $info['version'] = OC_App::getAppVersion($app); + $appList[] = $info; + } + } + $remoteApps = OC_App::getAppstoreApps(); + if ( $remoteApps ) { + // Remove duplicates + foreach ( $appList as $app ) { + foreach ( $remoteApps AS $key => $remote ) { + if ( + $app['name'] == $remote['name'] + // To set duplicate detection to use OCS ID instead of string name, + // enable this code, remove the line of code above, + // and add <ocs_id>[ID]</ocs_id> to info.xml of each 3rd party app: + // OR $app['ocs_id'] == $remote['ocs_id'] + ) { + unset( $remoteApps[$key]); + } + } + } + $combinedApps = array_merge( $appList, $remoteApps ); + } else { + $combinedApps = $appList; + } + return $combinedApps; +} + + /** * @brief: get a list of all apps on apps.owncloud.com * @return array, multi-dimensional array of apps. Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description */ @@ -609,6 +690,15 @@ class OC_App{ $app1[$i]['author'] = $app['personid']; $app1[$i]['ocs_id'] = $app['id']; $app1[$i]['internal'] = $app1[$i]['active'] = 0; + $app1[$i]['update'] = false; + if($app['label']=='recommended'){ + $app1[$i]['internallabel'] = 'Recommended'; + $app1[$i]['internalclass'] = 'recommendedapp'; + }else{ + $app1[$i]['internallabel'] = '3rd Party'; + $app1[$i]['internalclass'] = 'externalapp'; + } + // rating img if($app['score']>=0 and $app['score']<5) $img=OC_Helper::imagePath( "core", "rating/s1.png" ); @@ -737,18 +827,18 @@ 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); + OC_Log::write('core', 'Can\'t get app storage, app '.$appid.', user not logged in', OC_Log::ERROR); return false; } }else{ diff --git a/lib/archive/tar.php b/lib/archive/tar.php index 0fa633c6038..117d88e5f42 100644 --- a/lib/archive/tar.php +++ b/lib/archive/tar.php @@ -308,7 +308,7 @@ class OC_Archive_TAR extends OC_Archive{ if($mode=='r' or $mode=='rb') { return fopen($tmpFile, $mode); }else{ - OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack'); + \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); self::$tempFiles[$tmpFile]=$path; return fopen('close://'.$tmpFile, $mode); } diff --git a/lib/archive/zip.php b/lib/archive/zip.php index 1c967baa08f..8e31795ded1 100644 --- a/lib/archive/zip.php +++ b/lib/archive/zip.php @@ -171,7 +171,7 @@ class OC_Archive_ZIP extends OC_Archive{ $ext=''; } $tmpFile=OCP\Files::tmpFile($ext); - OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack'); + \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); if($this->fileExists($path)) { $this->extractFile($path, $tmpFile); } diff --git a/lib/base.php b/lib/base.php index 6896c91822e..90e64f13af6 100644 --- a/lib/base.php +++ b/lib/base.php @@ -27,10 +27,9 @@ require_once 'public/constants.php'; * No, we can not put this class in its own file because it is used by * OC_autoload! */ -class OC -{ +class OC { /** - * Assoziative array for autoloading. classname => filename + * Associative array for autoloading. classname => filename */ public static $CLASSPATH = array(); /** @@ -78,13 +77,12 @@ class OC /** * SPL autoload */ - public static function autoload($className) - { + public static function autoload($className) { if (array_key_exists($className, OC::$CLASSPATH)) { $path = OC::$CLASSPATH[$className]; /** @TODO: Remove this when necessary - Remove "apps/" from inclusion path for smooth migration to mutli app dir - */ + Remove "apps/" from inclusion path for smooth migration to mutli app dir + */ if (strpos($path, 'apps/') === 0) { OC_Log::write('core', 'include path for class "' . $className . '" starts with "apps/"', OC_Log::DEBUG); $path = str_replace('apps/', '', $path); @@ -96,7 +94,14 @@ class OC } elseif (strpos($className, 'OCP\\') === 0) { $path = 'public/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); } elseif (strpos($className, 'OCA\\') === 0) { - $path = 'apps/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + foreach (self::$APPSROOTS as $appDir) { + $path = $appDir['path'] . '/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $fullPath = stream_resolve_include_path($path); + if (file_exists($fullPath)) { + require_once $fullPath; + return false; + } + } } elseif (strpos($className, 'Sabre_') === 0) { $path = str_replace('_', '/', $className) . '.php'; } elseif (strpos($className, 'Symfony\\Component\\Routing\\') === 0) { @@ -105,6 +110,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; } @@ -115,12 +122,18 @@ class OC return false; } - public static function initPaths() - { + public static function initPaths() { // calculate the root directories OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4)); + + // ensure we can find OC_Config + set_include_path( + OC::$SERVERROOT . '/lib' . PATH_SEPARATOR . + get_include_path() + ); + OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT))); - $scriptName = $_SERVER["SCRIPT_NAME"]; + $scriptName = OC_Request::scriptName(); if (substr($scriptName, -1) == '/') { $scriptName .= 'index.php'; //make sure suburi follows the same rules as scriptName @@ -138,12 +151,6 @@ class OC OC::$WEBROOT = '/' . OC::$WEBROOT; } - // ensure we can find OC_Config - set_include_path( - OC::$SERVERROOT . '/lib' . PATH_SEPARATOR . - get_include_path() - ); - // search the 3rdparty folder if (OC_Config::getValue('3rdpartyroot', '') <> '' and OC_Config::getValue('3rdpartyurl', '') <> '') { OC::$THIRDPARTYROOT = OC_Config::getValue('3rdpartyroot', ''); @@ -179,17 +186,18 @@ class OC exit; } $paths = array(); - foreach (OC::$APPSROOTS as $path) + foreach (OC::$APPSROOTS as $path) { $paths[] = $path['path']; + } // set the right include path set_include_path( OC::$SERVERROOT . '/lib' . PATH_SEPARATOR . - OC::$SERVERROOT . '/config' . PATH_SEPARATOR . - OC::$THIRDPARTYROOT . '/3rdparty' . PATH_SEPARATOR . - implode($paths, PATH_SEPARATOR) . PATH_SEPARATOR . - get_include_path() . PATH_SEPARATOR . - OC::$SERVERROOT + OC::$SERVERROOT . '/config' . PATH_SEPARATOR . + OC::$THIRDPARTYROOT . '/3rdparty' . PATH_SEPARATOR . + implode($paths, PATH_SEPARATOR) . PATH_SEPARATOR . + get_include_path() . PATH_SEPARATOR . + OC::$SERVERROOT ); } @@ -202,8 +210,7 @@ class OC } } - public static function checkInstalled() - { + public static function checkInstalled() { // Redirect to installer if not installed if (!OC_Config::getValue('installed', false) && OC::$SUBURI != '/index.php') { if (!OC::$CLI) { @@ -214,14 +221,13 @@ class OC } } - public static function checkSSL() - { + public static function checkSSL() { // redirect to https site if configured if (OC_Config::getValue("forcessl", false)) { header('Strict-Transport-Security: max-age=31536000'); ini_set("session.cookie_secure", "on"); if (OC_Request::serverProtocol() <> 'https' and !OC::$CLI) { - $url = "https://" . OC_Request::serverHost() . $_SERVER['REQUEST_URI']; + $url = "https://" . OC_Request::serverHost() . OC_Request::requestUri(); header("Location: $url"); exit(); } @@ -231,6 +237,12 @@ class OC public static function checkMaintenanceMode() { // Allow ajax update script to execute without being stopped if (OC_Config::getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') { + // send http status 503 + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + header('Retry-After: 120'); + + // render error page $tmpl = new OC_Template('', 'error', 'guest'); $tmpl->assign('errors', array(1 => array('error' => 'ownCloud is in maintenance mode'))); $tmpl->printPage(); @@ -246,6 +258,7 @@ class OC if ($showTemplate && !OC_Config::getValue('maintenance', false)) { OC_Config::setValue('maintenance', true); OC_Log::write('core', 'starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, OC_Log::DEBUG); + OC_Util::addscript('update'); $tmpl = new OC_Template('', 'update', 'guest'); $tmpl->assign('version', OC_Util::getVersionString()); $tmpl->printPage(); @@ -258,11 +271,10 @@ class OC } } - public static function initTemplateEngine() - { + public static function initTemplateEngine() { // Add the stuff we need always OC_Util::addScript("jquery-1.7.2.min"); - OC_Util::addScript("jquery-ui-1.8.16.custom.min"); + OC_Util::addScript("jquery-ui-1.10.0.custom"); OC_Util::addScript("jquery-showpassword"); OC_Util::addScript("jquery.infieldlabel"); OC_Util::addScript("jquery-tipsy"); @@ -276,12 +288,12 @@ class OC OC_Util::addStyle("styles"); OC_Util::addStyle("multiselect"); - OC_Util::addStyle("jquery-ui-1.8.16.custom"); + OC_Util::addStyle("jquery-ui-1.10.0.custom"); OC_Util::addStyle("jquery-tipsy"); + OC_Util::addScript("oc-requesttoken"); } - public static function initSession() - { + public static function initSession() { // prevents javascript from accessing php session cookies ini_set('session.cookie_httponly', '1;'); @@ -311,8 +323,7 @@ class OC $_SESSION['LAST_ACTIVITY'] = time(); } - public static function getRouter() - { + public static function getRouter() { if (!isset(OC::$router)) { OC::$router = new OC_Router(); OC::$router->loadRoutes(); @@ -321,8 +332,18 @@ class OC return OC::$router; } - public static function init() - { + + public static function loadAppClassPaths() { + foreach (OC_APP::getEnabledApps() as $app) { + $file = OC_App::getAppPath($app) . '/appinfo/classpath.php'; + if (file_exists($file)) { + require_once $file; + } + } + } + + + public static function init() { // register autoloader spl_autoload_register(array('OC', 'autoload')); setlocale(LC_ALL, 'en_US.UTF-8'); @@ -393,18 +414,16 @@ class OC } // register the stream wrappers - require_once 'streamwrappers.php'; - stream_wrapper_register("fakedir", "OC_FakeDirStream"); - stream_wrapper_register('static', 'OC_StaticStreamWrapper'); - stream_wrapper_register('close', 'OC_CloseStreamWrapper'); + stream_wrapper_register('fakedir', 'OC\Files\Stream\Dir'); + stream_wrapper_register('static', 'OC\Files\Stream\StaticStream'); + stream_wrapper_register('close', 'OC\Files\Stream\Close'); + stream_wrapper_register('oc', 'OC\Files\Stream\OC'); self::checkConfig(); self::checkInstalled(); self::checkSSL(); self::initSession(); self::initTemplateEngine(); - self::checkMaintenanceMode(); - self::checkUpgrade(); $errors = OC_Util::checkServer(); if (count($errors) > 0) { @@ -477,7 +496,7 @@ class OC // write error into log if locale can't be set if (OC_Util::issetlocaleworking() == false) { - OC_Log::write('core', 'setting locate to en_US.UTF-8 failed. Support is probably not installed on your system', OC_Log::ERROR); + OC_Log::write('core', 'setting locale to en_US.UTF-8 failed. Support is probably not installed on your system', OC_Log::ERROR); } if (OC_Config::getValue('installed', false)) { if (OC_Appconfig::getValue('core', 'backgroundjobs_mode', 'ajax') == 'ajax') { @@ -489,8 +508,7 @@ class OC /** * register hooks for the cache */ - public static function registerCacheHooks() - { + public static function registerCacheHooks() { // register cache cleanup jobs OC_BackgroundJob_RegularTask::register('OC_Cache_FileGlobal', 'gc'); OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener'); @@ -499,8 +517,7 @@ class OC /** * register hooks for the filesystem */ - public static function registerFilesystemHooks() - { + public static function registerFilesystemHooks() { // Check for blacklisted files OC_Hook::connect('OC_Filesystem', 'write', 'OC_Filesystem', 'isBlacklisted'); OC_Hook::connect('OC_Filesystem', 'rename', 'OC_Filesystem', 'isBlacklisted'); @@ -509,8 +526,7 @@ class OC /** * register hooks for sharing */ - public static function registerShareHooks() - { + public static function registerShareHooks() { OC_Hook::connect('OC_User', 'post_deleteUser', 'OCP\Share', 'post_deleteUser'); OC_Hook::connect('OC_User', 'post_addToGroup', 'OCP\Share', 'post_addToGroup'); OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OCP\Share', 'post_removeFromGroup'); @@ -520,23 +536,22 @@ class OC /** * @brief Handle the request */ - public static function handleRequest() - { + public static function handleRequest() { + // load all the classpaths from the enabled apps so they are available + // in the routing files of each app + OC::loadAppClassPaths(); + + // Check if ownCloud is installed or in maintenance (update) mode if (!OC_Config::getValue('installed', false)) { require_once 'core/setup.php'; exit(); } - // Handle redirect URL for logged in users - if (isset($_REQUEST['redirect_url']) && OC_User::isLoggedIn()) { - $location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url'])); - header('Location: ' . $location); - return; - } - // Handle WebDAV - if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') { - header('location: ' . OC_Helper::linkToRemote('webdav')); - return; + $request = OC_Request::getPathInfo(); + if(substr($request, -3) !== '.js'){// we need these files during the upgrade + self::checkMaintenanceMode(); + self::checkUpgrade(); } + try { OC::getRouter()->match(OC_Request::getPathInfo()); return; @@ -546,6 +561,7 @@ class OC OC_Response::setStatus(405); return; } + $app = OC::$REQUESTEDAPP; $file = OC::$REQUESTEDFILE; $param = array('app' => $app, 'file' => $file); @@ -554,6 +570,19 @@ class OC self::loadCSSFile($param); return; } + + // Handle redirect URL for logged in users + if (isset($_REQUEST['redirect_url']) && OC_User::isLoggedIn()) { + $location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url'])); + header('Location: ' . $location); + return; + } + // Handle WebDAV + if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') { + header('location: ' . OC_Helper::linkToRemote('webdav')); + return; + } + // Someone is logged in : if (OC_User::isLoggedIn()) { OC_App::loadApps(); @@ -571,7 +600,7 @@ class OC $file_ext = substr($param['file'], -3); if ($file_ext != 'php' || !self::loadAppScriptFile($param) - ) { + ) { header('HTTP/1.0 404 Not Found'); } } @@ -581,8 +610,7 @@ class OC self::handleLogin(); } - public static function loadAppScriptFile($param) - { + public static function loadAppScriptFile($param) { OC_App::loadApps(); $app = $param['app']; $file = $param['file']; @@ -596,8 +624,7 @@ class OC return false; } - public static function loadCSSFile($param) - { + public static function loadCSSFile($param) { $app = $param['app']; $file = $param['file']; $app_path = OC_App::getAppPath($app); @@ -610,27 +637,25 @@ class OC } } - protected static function handleLogin() - { + protected static function handleLogin() { OC_App::loadApps(array('prelogin')); $error = array(); // remember was checked after last login if (OC::tryRememberLogin()) { $error[] = 'invalidcookie'; - // Someone wants to log in : + // Someone wants to log in : } elseif (OC::tryFormLogin()) { $error[] = 'invalidpassword'; - // The user is already authenticated using Apaches AuthType Basic... very usable in combination with LDAP + // The user is already authenticated using Apaches AuthType Basic... very usable in combination with LDAP } elseif (OC::tryBasicAuthLogin()) { $error[] = 'invalidpassword'; } OC_Util::displayLoginPage(array_unique($error)); } - protected static function cleanupLoginTokens($user) - { + protected static function cleanupLoginTokens($user) { $cutoff = time() - OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); $tokens = OC_Preferences::getKeys($user, 'login_token'); foreach ($tokens as $token) { @@ -641,13 +666,12 @@ class OC } } - protected static function tryRememberLogin() - { + protected static function tryRememberLogin() { if (!isset($_COOKIE["oc_remember_login"]) || !isset($_COOKIE["oc_token"]) || !isset($_COOKIE["oc_username"]) || !$_COOKIE["oc_remember_login"] - ) { + ) { return false; } OC_App::loadApps(array('authentication')); @@ -682,8 +706,7 @@ class OC return true; } - protected static function tryFormLogin() - { + protected static function tryFormLogin() { if (!isset($_POST["user"]) || !isset($_POST['password'])) { return false; } @@ -716,18 +739,17 @@ class OC return true; } - protected static function tryBasicAuthLogin() - { + protected static function tryBasicAuthLogin() { if (!isset($_SERVER["PHP_AUTH_USER"]) || !isset($_SERVER["PHP_AUTH_PW"]) - ) { + ) { return false; } OC_App::loadApps(array('authentication')); if (OC_User::login($_SERVER["PHP_AUTH_USER"], $_SERVER["PHP_AUTH_PW"])) { //OC_Log::write('core',"Logged in with HTTP Authentication", OC_Log::DEBUG); OC_User::unsetMagicInCookie(); - $_REQUEST['redirect_url'] = (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''); + $_REQUEST['redirect_url'] = OC_Request::requestUri(); OC_Util::redirectToDefaultPage(); } return true; @@ -741,8 +763,7 @@ if (!isset($RUNTIME_NOAPPS)) { } if (!function_exists('get_temp_dir')) { - function get_temp_dir() - { + function get_temp_dir() { if ($temp = ini_get('upload_tmp_dir')) return $temp; if ($temp = getenv('TMP')) return $temp; if ($temp = getenv('TEMP')) return $temp; 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..b210602bbf4 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 @@ -137,7 +138,9 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa $propertypath = $row['propertypath']; $propertyname = $row['propertyname']; $propertyvalue = $row['propertyvalue']; - $properties[$propertypath][$propertyname] = $propertyvalue; + if($propertyname !== self::GETETAG_PROPERTYNAME) { + $properties[$propertypath][$propertyname] = $propertyvalue; + } } } } @@ -160,7 +163,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 +176,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 +187,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..52995630211 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); } /** @@ -154,15 +154,17 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr } } else { - if( strcmp( $propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0 ) { + if( strcmp( $propertyName, self::GETETAG_PROPERTYNAME) === 0 ) { + \OC\Files\Filesystem::putFileInfo($this->path, array('etag'=> $propertyValue)); + } elseif( strcmp( $propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0 ) { $this->touch($propertyValue); } 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 +192,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 +208,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/connector/sabre/request.php b/lib/connector/sabre/request.php new file mode 100644 index 00000000000..97a27996bf3 --- /dev/null +++ b/lib/connector/sabre/request.php @@ -0,0 +1,50 @@ +<?php + +/** + * ownCloud + * + * @author Stefan Herbrechtsmeier + * @copyright 2012 Stefan Herbrechtsmeier <stefan@herbrechtsmeier.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +class OC_Connector_Sabre_Request extends Sabre_HTTP_Request { + /** + * Returns the requested uri + * + * @return string + */ + public function getUri() { + return OC_Request::requestUri(); + } + + /** + * Returns a specific item from the _SERVER array. + * + * Do not rely on this feature, it is for internal use only. + * + * @param string $field + * @return string + */ + public function getRawServerValue($field) { + if($field == 'REQUEST_URI'){ + return $this->getUri(); + } + else{ + return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null; + } + } +} diff --git a/lib/db.php b/lib/db.php index 5224d5ee7da..51f7c7679d4 100644 --- a/lib/db.php +++ b/lib/db.php @@ -184,7 +184,14 @@ class OC_DB { try{ self::$PDO=new PDO($dsn, $user, $pass, $opts); }catch(PDOException $e) { - OC_Template::printErrorPage( 'can not connect to database, using '.$type.'. ('.$e->getMessage().')' ); + OC_Log::write('core', $e->getMessage(), OC_Log::FATAL); + OC_User::setUserId(null); + + // send http status 503 + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + OC_Template::printErrorPage('Failed to connect to database'); + die(); } // We always, really always want associative arrays self::$PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); @@ -281,7 +288,13 @@ class OC_DB { if( PEAR::isError( self::$MDB2 )) { OC_Log::write('core', self::$MDB2->getUserInfo(), OC_Log::FATAL); OC_Log::write('core', self::$MDB2->getMessage(), OC_Log::FATAL); - OC_Template::printErrorPage( 'can not connect to database, using '.$type.'. ('.self::$MDB2->getUserInfo().')' ); + OC_User::setUserId(null); + + // send http status 503 + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + OC_Template::printErrorPage('Failed to connect to database'); + die(); } // We always, really always want associative arrays @@ -440,6 +453,9 @@ class OC_DB { $CONFIG_DBTABLEPREFIX = OC_Config::getValue( "dbtableprefix", "oc_" ); $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" ); + // cleanup the cached queries + self::$preparedQueries = array(); + self::connectScheme(); // read file 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..e3245653f99 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 containing multiple files + * + * @param string $dir + * @param string $file ; separated 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,20 @@ 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(); + $name = basename($dir) . '.zip'; 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,53 +92,55 @@ 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(); + $name = $files . '.zip'; set_time_limit($executionTime); - }else{ - $zip=false; - $filename=$dir.'/'.$files; + } else { + $zip = false; + $filename = $dir . '/' . $files; + $name = $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) ) . '"' ); + header( 'Content-Disposition: attachment; filename="' . rawurlencode($name) . '"' ); } else { - header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) ) - . '; filename="' . rawurlencode( basename($filename) ) . '"' ); + header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode($name) + . '; filename="' . rawurlencode($name) . '"' ); } 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->assign('file', $filename); + $tmpl = new OC_Template('', '404', 'guest'); + $tmpl->assign('file', $name); $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 +150,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 +176,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 +209,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 +236,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 +269,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..dcb6e8fd39a --- /dev/null +++ b/lib/files/cache/cache.php @@ -0,0 +1,527 @@ +<?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['storage'] = $this->storageId; + $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)); + $files = array(); + while ($row = $result->fetchRow()) { + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } + return $files; + } + + /** + * 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; + } + } + + /** + * get the storage id of the storage for a file and the internal path of the file + * + * @return array, first element holding the storage id, second the path + */ + static public function getById($id) { + $query = \OC_DB::prepare('SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?'); + $result = $query->execute(array($id)); + if ($row = $result->fetchRow()) { + $numericId = $row['storage']; + $path = $row['path']; + } else { + return null; + } + + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?'); + $result = $query->execute(array($numericId)); + if ($row = $result->fetchRow()) { + return array($row['id'], $path); + } else { + return null; + } + } +} 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..8d504af6163 --- /dev/null +++ b/lib/files/cache/scanner.php @@ -0,0 +1,146 @@ +<?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 + * @param bool $onlyChilds + * @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, $onlyChilds = false) { + \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_folder', array('path' => $path, 'storage' => $this->storageId)); + $childQueue = array(); + if (!$onlyChilds) { + $this->scanFile($path); + } + + $size = 0; + if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) { + \OC_DB::beginTransaction(); + 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) { + $childQueue[] = $child; + $data['size'] = 0; + } else { + $data['size'] = -1; + } + } else { + } + if ($data['size'] === -1) { + $size = -1; + } elseif ($size !== -1) { + $size += $data['size']; + } + } + } + } + \OC_DB::commit(); + foreach ($childQueue as $child) { + $childSize = $this->scan($child, self::SCAN_RECURSIVE, true); + if ($childSize === -1) { + $size = -1; + } else { + $size += $childSize; + } + } + 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..d04541c219f --- /dev/null +++ b/lib/files/cache/updater.php @@ -0,0 +1,105 @@ +<?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::correctFolder($path, $storage->filemtime($internalPath)); + } + } + + 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::correctFolder($path, time()); + } + } + + /** + * Update the mtime and ETag of all parent folders + * + * @param string $path + * @param string $time + */ + static public function correctFolder($path, $time) { + 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('mtime' => $time, 'etag' => $storage->getETag($internalPath))); + self::correctFolder($parent, $time); + } + } + } + } + + /** + * @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..eb8c7297c3e --- /dev/null +++ b/lib/files/cache/upgrade.php @@ -0,0 +1,159 @@ +<?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 $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) { + if (!$this->inCache($data['storage'], $data['path_hash'])) { + $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'])); + } + } + + /** + * @param string $storage + * @param string $pathHash + * @return bool + */ + function inCache($storage, $pathHash) { + $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'); + $result = $query->execute(array($storage, $pathHash)); + return (bool)$result->fetchRow(); + } + + /** + * 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; + } + + /** + * 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/filesystem.php b/lib/files/filesystem.php new file mode 100644 index 00000000000..65d9ffab485 --- /dev/null +++ b/lib/files/filesystem.php @@ -0,0 +1,638 @@ +<?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 { + 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) { + $mount = Mount::find($path); + if ($mount) { + return $mount->getMountPoint(); + } else { + return ''; + } + } + + /** + * get a list of all mount points in a directory + * + * @param string $path + * @return string[] + */ + static public function getMountPoints($path) { + $result = array(); + $mounts = Mount::findIn($path); + foreach ($mounts as $mount) { + $result[] = $mount->getMountPoint(); + } + return $result; + } + + /** + * get the storage mounted at $mountPoint + * + * @param string $mountPoint + * @return \OC\Files\Storage\Storage + */ + public static function getStorage($mountPoint) { + $mount = Mount::find($mountPoint); + return $mount->getStorage(); + } + + /** + * 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) { + $mount = Mount::find($path); + if ($mount) { + return array($mount->getStorage(), $mount->getInternalPath($path)); + } 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 + * @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::clearMounts(); + } + + /** + * @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() { + Mount::clear(); + } + + /** + * 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) { + new Mount($class, $mountpoint, $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 = \OC_Config::getValue('blacklisted_files', 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 string $path + * @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) { + return self::$defaultInstance->getDirectoryContent($directory); + } + + /** + * Get the path of a file by id + * + * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file + * + * @param int $id + * @return string + */ + public static function getPath($id) { + return self::$defaultInstance->getPath($id); + } + + /** + * Get the owner for a file or folder + * + * @param string $path + * @return string + */ + public static function getOwner($path) { + return self::$defaultInstance->getOwner($path); + } + + /** + * 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/files/mount.php b/lib/files/mount.php new file mode 100644 index 00000000000..74ee483b1be --- /dev/null +++ b/lib/files/mount.php @@ -0,0 +1,188 @@ +<?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; + +class Mount { + /** + * @var Mount[] + */ + static private $mounts = array(); + + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage = null; + private $class; + private $storageId; + private $arguments = array(); + private $mountPoint; + + /** + * @param string|\OC\Files\Storage\Storage $storage + * @param string $mountpoint + * @param array $arguments (optional) + */ + public function __construct($storage, $mountpoint, $arguments = null) { + if (is_null($arguments)) { + $arguments = array(); + } + + $mountpoint = self::formatPath($mountpoint); + if ($storage instanceof \OC\Files\Storage\Storage) { + $this->class = get_class($storage); + $this->storage = $storage; + } else { + // Update old classes to new namespace + if (strpos($storage, 'OC_Filestorage_') !== false) { + $storage = '\OC\Files\Storage\\' . substr($storage, 15); + } + $this->class = $storage; + $this->arguments = $arguments; + } + $this->mountPoint = $mountpoint; + + self::$mounts[$this->mountPoint] = $this; + } + + /** + * @return string + */ + public function getMountPoint() { + return $this->mountPoint; + } + + /** + * @return \OC\Files\Storage\Storage + */ + private function createStorage() { + if (class_exists($this->class)) { + try { + return new $this->class($this->arguments); + } catch (\Exception $exception) { + \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR); + return null; + } + } else { + \OC_Log::write('core', 'storage backend ' . $this->class . ' not found', \OC_Log::ERROR); + return null; + } + } + + /** + * @return \OC\Files\Storage\Storage + */ + public function getStorage() { + if (is_null($this->storage)) { + $this->storage = $this->createStorage(); + } + return $this->storage; + } + + /** + * @return string + */ + public function getStorageId() { + if (!$this->storageId) { + if (is_null($this->storage)) { + $this->storage = $this->createStorage(); + } + $this->storageId = $this->storage->getId(); + } + return $this->storageId; + } + + /** + * @param string $path + * @return string + */ + public function getInternalPath($path) { + if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) { + $internalPath = ''; + } else { + $internalPath = substr($path, strlen($this->mountPoint)); + } + return $internalPath; + } + + /** + * @param string $path + * @return string + */ + private static function formatPath($path) { + $path = Filesystem::normalizePath($path); + if (strlen($path) > 1) { + $path .= '/'; + } + return $path; + } + + /** + * Find the mount for $path + * + * @param $path + * @return Mount + */ + public static function find($path) { + $path = self::formatPath($path); + if (isset(self::$mounts[$path])) { + return self::$mounts[$path]; + } + + \OC_Hook::emit('OC_Filesystem', 'get_mountpoint', array('path' => $path)); + $foundMountPoint = ''; + $mountPoints = array_keys(self::$mounts); + foreach ($mountPoints as $mountpoint) { + if (strpos($path, $mountpoint) === 0 and strlen($mountpoint) > strlen($foundMountPoint)) { + $foundMountPoint = $mountpoint; + } + } + if (isset(self::$mounts[$foundMountPoint])) { + return self::$mounts[$foundMountPoint]; + } else { + return null; + } + } + + /** + * Find all mounts in $path + * + * @param $path + * @return Mount[] + */ + public static function findIn($path) { + $path = self::formatPath($path); + $result = array(); + $pathLength = strlen($path); + $mountPoints = array_keys(self::$mounts); + foreach ($mountPoints as $mountPoint) { + if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) { + $result[] = self::$mounts[$mountPoint]; + } + } + return $result; + } + + public static function clear() { + self::$mounts = array(); + } + + /** + * @param string $id + * @return \OC\Files\Storage\Storage[] + */ + public static function findById($id) { + $result = array(); + foreach (self::$mounts as $mount) { + if ($mount->getStorageId() === $id) { + $result[] = $mount; + } + } + return $result; + } +} 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..9fc9d375bb3 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); } @@ -92,7 +101,7 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{ public function file_get_contents($path) { return file_get_contents($this->datadir.$path); } - public function file_put_contents($path, $data) { + public function file_put_contents($path, $data) {//trigger_error("$path = ".var_export($path, 1)); return file_put_contents($this->datadir.$path, $data); } public function unlink($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/stream/close.php b/lib/files/stream/close.php new file mode 100644 index 00000000000..80de3497c36 --- /dev/null +++ b/lib/files/stream/close.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright (c) 2013 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\Stream; + +/** + * stream wrapper that provides a callback on stream close + */ +class Close { + private static $callBacks = array(); + private $path = ''; + private $source; + private static $open = array(); + + public function stream_open($path, $mode, $options, &$opened_path) { + $path = substr($path, strlen('close://')); + $this->path = $path; + $this->source = fopen($path, $mode); + if (is_resource($this->source)) { + $this->meta = stream_get_meta_data($this->source); + } + self::$open[] = $path; + return is_resource($this->source); + } + + public function stream_seek($offset, $whence = SEEK_SET) { + fseek($this->source, $offset, $whence); + } + + public function stream_tell() { + return ftell($this->source); + } + + public function stream_read($count) { + return fread($this->source, $count); + } + + public function stream_write($data) { + return fwrite($this->source, $data); + } + + public function stream_set_option($option, $arg1, $arg2) { + switch ($option) { + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->source, $arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->source, $arg1, $arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->source, $arg1, $arg2); + } + } + + public function stream_stat() { + return fstat($this->source); + } + + public function stream_lock($mode) { + flock($this->source, $mode); + } + + public function stream_flush() { + return fflush($this->source); + } + + public function stream_eof() { + return feof($this->source); + } + + public function url_stat($path) { + $path = substr($path, strlen('close://')); + if (file_exists($path)) { + return stat($path); + } else { + return false; + } + } + + public function stream_close() { + fclose($this->source); + if (isset(self::$callBacks[$this->path])) { + call_user_func(self::$callBacks[$this->path], $this->path); + } + } + + public function unlink($path) { + $path = substr($path, strlen('close://')); + return unlink($path); + } + + public static function registerCallback($path, $callback) { + self::$callBacks[$path] = $callback; + } +} diff --git a/lib/files/stream/dir.php b/lib/files/stream/dir.php new file mode 100644 index 00000000000..6ca884fc994 --- /dev/null +++ b/lib/files/stream/dir.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright (c) 2013 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\Stream; + +class Dir { + private static $dirs = array(); + private $name; + private $index; + + public function dir_opendir($path, $options) { + $this->name = substr($path, strlen('fakedir://')); + $this->index = 0; + if (!isset(self::$dirs[$this->name])) { + self::$dirs[$this->name] = array(); + } + return true; + } + + public function dir_readdir() { + if ($this->index >= count(self::$dirs[$this->name])) { + return false; + } + $filename = self::$dirs[$this->name][$this->index]; + $this->index++; + return $filename; + } + + public function dir_closedir() { + $this->name = ''; + return true; + } + + public function dir_rewinddir() { + $this->index = 0; + return true; + } + + public static function register($path, $content) { + self::$dirs[$path] = $content; + } +} diff --git a/lib/files/stream/oc.php b/lib/files/stream/oc.php new file mode 100644 index 00000000000..88e7e062df9 --- /dev/null +++ b/lib/files/stream/oc.php @@ -0,0 +1,129 @@ +<?php +/** + * Copyright (c) 2013 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\Stream; + +/** + * a stream wrappers for ownCloud's virtual filesystem + */ +class OC { + /** + * @var \OC\Files\View + */ + static private $rootView; + + private $path; + private $dirSource; + private $fileSource; + private $meta; + + private function setup(){ + if (!self::$rootView) { + self::$rootView = new \OC\Files\View(''); + } + } + + public function stream_open($path, $mode, $options, &$opened_path) { + $this->setup(); + $path = substr($path, strlen('oc://')); + $this->path = $path; + $this->fileSource = self::$rootView->fopen($path, $mode); + if (is_resource($this->fileSource)) { + $this->meta = stream_get_meta_data($this->fileSource); + } + return is_resource($this->fileSource); + } + + public function stream_seek($offset, $whence = SEEK_SET) { + fseek($this->fileSource, $offset, $whence); + } + + public function stream_tell() { + return ftell($this->fileSource); + } + + public function stream_read($count) { + return fread($this->fileSource, $count); + } + + public function stream_write($data) { + return fwrite($this->fileSource, $data); + } + + public function stream_set_option($option, $arg1, $arg2) { + switch ($option) { + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->fileSource, $arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->fileSource, $arg1, $arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->fileSource, $arg1, $arg2); + } + } + + public function stream_stat() { + return fstat($this->fileSource); + } + + public function stream_lock($mode) { + flock($this->fileSource, $mode); + } + + public function stream_flush() { + return fflush($this->fileSource); + } + + public function stream_eof() { + return feof($this->fileSource); + } + + public function url_stat($path) { + $this->setup(); + $path = substr($path, strlen('oc://')); + if (self::$rootView->file_exists($path)) { + return self::$rootView->stat($path); + } else { + return false; + } + } + + public function stream_close() { + fclose($this->fileSource); + } + + public function unlink($path) { + $this->setup(); + $path = substr($path, strlen('oc://')); + return self::$rootView->unlink($path); + } + + public function dir_opendir($path, $options) { + $this->setup(); + $path = substr($path, strlen('oc://')); + $this->path = $path; + $this->dirSource = self::$rootView->opendir($path); + if (is_resource($this->dirSource)) { + $this->meta = stream_get_meta_data($this->dirSource); + } + return is_resource($this->dirSource); + } + + public function dir_readdir() { + return readdir($this->dirSource); + } + + public function dir_closedir() { + closedir($this->dirSource); + } + + public function dir_rewinddir() { + rewinddir($this->dirSource); + } +} diff --git a/lib/streamwrappers.php b/lib/files/stream/staticstream.php index 981c280f0dd..7725a6a5a04 100644 --- a/lib/streamwrappers.php +++ b/lib/files/stream/staticstream.php @@ -1,54 +1,30 @@ <?php +/** + * Copyright (c) 2013 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 OC_FakeDirStream{ - public static $dirs=array(); - private $name; - private $index; - - public function dir_opendir($path, $options) { - $this->name=substr($path, strlen('fakedir://')); - $this->index=0; - if(!isset(self::$dirs[$this->name])) { - self::$dirs[$this->name]=array(); - } - return true; - } - - public function dir_readdir() { - if($this->index>=count(self::$dirs[$this->name])) { - return false; - } - $filename=self::$dirs[$this->name][$this->index]; - $this->index++; - return $filename; - } - - public function dir_closedir() { - $this->name=''; - return true; - } - - public function dir_rewinddir() { - $this->index=0; - return true; - } -} +namespace OC\Files\Stream; -class OC_StaticStreamWrapper { +class StaticStream { public $context; protected static $data = array(); - protected $path = ''; + protected $path = ''; protected $pointer = 0; protected $writable = false; - public function stream_close() {} + public function stream_close() { + } public function stream_eof() { return $this->pointer >= strlen(self::$data[$this->path]); } - public function stream_flush() {} + public function stream_flush() { + } public function stream_open($path, $mode, $options, &$opened_path) { switch ($mode[0]) { @@ -213,89 +189,3 @@ class OC_StaticStreamWrapper { return false; } } - -/** - * stream wrapper that provides a callback on stream close - */ -class OC_CloseStreamWrapper{ - public static $callBacks=array(); - private $path=''; - private $source; - private static $open=array(); - public function stream_open($path, $mode, $options, &$opened_path) { - $path=substr($path, strlen('close://')); - $this->path=$path; - $this->source=fopen($path, $mode); - if(is_resource($this->source)) { - $this->meta=stream_get_meta_data($this->source); - } - self::$open[]=$path; - return is_resource($this->source); - } - - public function stream_seek($offset, $whence=SEEK_SET) { - fseek($this->source, $offset, $whence); - } - - public function stream_tell() { - return ftell($this->source); - } - - public function stream_read($count) { - return fread($this->source, $count); - } - - public function stream_write($data) { - return fwrite($this->source, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->source); - } - - public function stream_lock($mode) { - flock($this->source, $mode); - } - - public function stream_flush() { - return fflush($this->source); - } - - public function stream_eof() { - return feof($this->source); - } - - public function url_stat($path) { - $path=substr($path, strlen('close://')); - if(file_exists($path)) { - return stat($path); - }else{ - return false; - } - } - - public function stream_close() { - fclose($this->source); - if(isset(self::$callBacks[$this->path])) { - call_user_func(self::$callBacks[$this->path], $this->path); - } - } - - public function unlink($path) { - $path=substr($path, strlen('close://')); - return unlink($path); - } -} diff --git a/lib/files/view.php b/lib/files/view.php new file mode 100644 index 00000000000..dfcb770328b --- /dev/null +++ b/lib/files/view.php @@ -0,0 +1,974 @@ +<?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(); + if (!Filesystem::isValidPath($path)) { + return $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($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(); + if (!Filesystem::isValidPath($directory)) { + return $result; + } + $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(''); + } + + $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; + + //remove any existing entry with the same name + foreach ($files as $i => $file) { + if ($file['name'] === $rootEntry['name']) { + unset($files[$i]); + break; + } + } + $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 owner for a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path) { + return $this->basicOperation('getOwner', $path); + } + + /** + * 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; + } + } + + /** + * Get the path of a file by id, relative to the view + * + * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file + * + * @param int $id + * @return string + */ + public function getPath($id) { + list($storage, $internalPath) = Cache\Cache::getById($id); + $mounts = Mount::findById($storage); + foreach ($mounts as $mount) { + /** + * @var \OC\Files\Mount $mount + */ + $fullPath = $mount->getMountPoint() . $internalPath; + if (!is_null($path = $this->getRelativePath($fullPath))) { + return $path; + } + } + 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/group.php b/lib/group.php index ed9482418bd..5afef769361 100644 --- a/lib/group.php +++ b/lib/group.php @@ -286,4 +286,33 @@ class OC_Group { } return $users; } + + /**
+ * @brief get a list of all display names in a group
+ * @returns array with display names (value) and user ids(key)
+ */
+ public static function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) {
+ $displayNames=array();
+ foreach(self::$_usedBackends as $backend) {
+ $displayNames = array_merge($backend->displayNamesInGroup($gid, $search, $limit, $offset), $displayNames);
+ }
+ return $displayNames;
+ } + + /**
+ * @brief get a list of all display names in several groups
+ * @param array $gids
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
+ * @return array with display names (Key) user ids (value)
+ */
+ public static function displayNamesInGroups($gids, $search = '', $limit = -1, $offset = 0) {
+ $displayNames = array();
+ foreach ($gids as $gid) {
+ // TODO Need to apply limits to groups as total
+ $displayNames = array_merge(array_diff(self::displayNamesInGroup($gid, $search, $limit, $offset), $displayNames), $displayNames);
+ }
+ return $displayNames;
+ } } diff --git a/lib/group/backend.php b/lib/group/backend.php index 9ff432d0663..4f6570c3be3 100644 --- a/lib/group/backend.php +++ b/lib/group/backend.php @@ -133,5 +133,23 @@ abstract class OC_Group_Backend implements OC_Group_Interface { public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { return array(); } + + /**
+ * @brief get a list of all display names in a group
+ * @param string $gid
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
+ * @return array with display names (value) and user ids (key)
+ */
+ public function DisplayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) {
+ $displayNames = '';
+ $users = $this->usersInGroup($gid, $search, $limit, $offset);
+ foreach ( $users as $user ) {
+ $DisplayNames[$user] = $user;
+ }
+
+ return $DisplayNames;
+ } } diff --git a/lib/group/database.php b/lib/group/database.php index 6eca98ba019..1e2328f4c08 100644 --- a/lib/group/database.php +++ b/lib/group/database.php @@ -208,4 +208,25 @@ class OC_Group_Database extends OC_Group_Backend { } return $users; } + + /**
+ * @brief get a list of all display names in a group
+ * @param string $gid
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
+ * @return array with display names (value) and user ids (key)
+ */
+ public function DisplayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) {
+ $displayNames = ''; + + $stmt = OC_DB::prepare('SELECT `*PREFIX*users`.`uid`, `*PREFIX*users`.`displayname` FROM `*PREFIX*users` INNER JOIN `*PREFIX*group_user` ON `*PREFIX*group_user`.`uid` = `*PREFIX*users`.`uid` WHERE `gid` = ? AND `*PREFIX*group_user.uid` LIKE ?', $limit, $offset);
+ $result = $stmt->execute(array($gid, $search.'%'));
+ $users = array();
+ while ($row = $result->fetchRow()) { + $displayName = trim($row['displayname'], ' ');
+ $displayNames[$row['uid']] = empty($displayName) ? $row['uid'] : $displayName;
+ }
+ return $displayNames;
+ } } diff --git a/lib/helper.php b/lib/helper.php index 5d7e3fa4894..0e549d006a1 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -78,11 +78,8 @@ class OC_Helper { } } - if (!empty($args)) { - $urlLinkTo .= '?'; - foreach($args as $k => $v) { - $urlLinkTo .= '&'.$k.'='.urlencode($v); - } + if ($args && $query = http_build_query($args, '', '&')) { + $urlLinkTo .= '?'.$query; } return $urlLinkTo; @@ -193,8 +190,9 @@ class OC_Helper { if(isset($alias[$mimetype])) { $mimetype=$alias[$mimetype]; } - // Replace slash with a minus + // Replace slash and backslash with a minus $mimetype = str_replace( "/", "-", $mimetype ); + $mimetype = str_replace( "\\", "-", $mimetype ); // Is it a dir? if( $mimetype == "dir" ) { @@ -326,7 +324,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 +618,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++; @@ -679,8 +677,8 @@ class OC_Helper { $start = intval($start); $length = intval($length); $string = mb_substr($string, 0, $start, $encoding) . - $replacement . - mb_substr($string, $start+$length, mb_strlen($string, 'UTF-8')-$start, $encoding); + $replacement . + mb_substr($string, $start+$length, mb_strlen($string, 'UTF-8')-$start, $encoding); return $string; } @@ -749,6 +747,23 @@ class OC_Helper { } /** + * @brief calculates the maximum upload size respecting system settings, free space and user quota + * + * @param $dir the current folder where the user currently operates + * @return number of bytes representing + */ + public static function maxUploadFilesize($dir) { + $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\Files\Filesystem::free_space($dir); + $freeSpace = max($freeSpace, 0); + + return min($maxUploadFilesize, $freeSpace); + } + + /** * Checks if a function is available * @param string $function_name * @return bool @@ -767,4 +782,23 @@ class OC_Helper { } return true; } + + /** + * Calculate the disc space + */ + public static function getStorageInfo() { + $rootInfo = \OC\Files\Filesystem::getFileInfo('/'); + $used = $rootInfo['size']; + if ($used < 0) { + $used = 0; + } + $free = \OC\Files\Filesystem::free_space(); + $total = $free + $used; + if ($total == 0) { + $total = 1; // prevent division by zero + } + $relative = round(($used / $total) * 10000) / 100; + + return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); + } } 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/installer.php b/lib/installer.php index 7dc8b0cef8d..c86f801b5fc 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -141,13 +141,17 @@ class OC_Installer{ return false; } - //check if an app with the same id is already installed - if(self::isInstalled( $info['id'] )) { - OC_Log::write('core', 'App already installed', OC_Log::WARN); + // check if shipped tag is set which is only allowed for apps that are shipped with ownCloud + if(isset($info['shipped']) and ($info['shipped']=='true')) { + OC_Log::write('core', 'App can\'t be installed because it contains the <shipped>true</shippe> tag which is not allowed for non shipped apps', OC_Log::ERROR); + OC_Helper::rmdirr($extractDir); + return false; + } + + // check if the ocs version is the same as the version in info.xml/version + if(!isset($info['version']) or ($info['version']<>$data['appdata']['version'])) { + OC_Log::write('core', 'App can\'t be installed because the version in info.xml/version is not the same as the version reported from the app store', OC_Log::ERROR); OC_Helper::rmdirr($extractDir); - if($data['source']=='http') { - unlink($path); - } return false; } @@ -226,7 +230,6 @@ class OC_Installer{ /** * @brief Update an application * @param $data array with all information - * @returns integer * * This function installs an app. All information needed are passed in the * associative array $data. @@ -250,9 +253,55 @@ class OC_Installer{ * * upgrade.php can determine the current installed version of the app using "OC_Appconfig::getValue($appid, 'installed_version')" */ - public static function upgradeApp( $data = array()) { - // TODO: write function - return true; + public static function updateApp( $app ) { + $ocsid=OC_Appconfig::getValue( $app, 'ocsid'); + OC_App::disable($app); + OC_App::enable($ocsid); + return(true); + } + + /** + * @brief Check if an update for the app is available + * @param $name name of the application + * @returns empty string is no update available or the version number of the update + * + * The function will check if an update for a version is available + */ + public static function isUpdateAvailable( $app ) { + $ocsid=OC_Appconfig::getValue( $app, 'ocsid', ''); + + if($ocsid<>''){ + + $ocsdata=OC_OCSClient::getApplication($ocsid); + $ocsversion= (string) $ocsdata['version']; + $currentversion=OC_App::getAppVersion($app); + if($ocsversion<>$currentversion){ + return($ocsversion); + + }else{ + return(''); + } + + }else{ + return(''); + } + + } + + /** + * @brief Check if app is already downloaded + * @param $name name of the application to remove + * @returns true/false + * + * The function will check if the app is already downloaded in the apps repository + */ + public static function isDownloaded( $name ) { + + $downloaded=false; + foreach(OC::$APPSROOTS as $dir) { + if(is_dir($dir['path'].'/'.$name)) $downloaded=true; + } + return($downloaded); } /** @@ -276,8 +325,36 @@ class OC_Installer{ * this has to be done by the function oc_app_uninstall(). */ public static function removeApp( $name, $options = array()) { - // TODO: write function - return true; + + if(isset($options['keeppreferences']) and $options['keeppreferences']==false ){ + // todo + // remove preferences + } + + if(isset($options['keepappconfig']) and $options['keepappconfig']==false ){ + // todo + // remove app config + } + + if(isset($options['keeptables']) and $options['keeptables']==false ){ + // todo + // remove app database tables + } + + if(isset($options['keepfiles']) and $options['keepfiles']==false ){ + // todo + // remove user files + } + + if(OC_Installer::isDownloaded( $name )) { + $appdir=OC_App::getInstallPath().'/'.$name; + OC_Helper::rmdirr($appdir); + + }else{ + OC_Log::write('core', 'can\'t remove app '.$name.'. It is not installed.', OC_Log::ERROR); + + } + } /** diff --git a/lib/l10n.php b/lib/l10n.php index ca53b3cf65c..ee879009265 100644 --- a/lib/l10n.php +++ b/lib/l10n.php @@ -287,7 +287,7 @@ class OC_L10N{ } if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - $accepted_languages = preg_split('/,\s*/', $_SERVER['HTTP_ACCEPT_LANGUAGE']); + $accepted_languages = preg_split('/,\s*/', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); if(is_array($app)) { $available = $app; } diff --git a/lib/l10n/ca.php b/lib/l10n/ca.php index b3321ef82e1..f6401fa39b6 100644 --- a/lib/l10n/ca.php +++ b/lib/l10n/ca.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Els fitxers s'han de baixar d'un en un.", "Back to Files" => "Torna a Fitxers", "Selected files too large to generate zip file." => "Els fitxers seleccionats son massa grans per generar un fitxer zip.", +"couldn't be determined" => "no s'ha pogut determinar", "Application is not enabled" => "L'aplicació no està habilitada", "Authentication error" => "Error d'autenticació", "Token expired. Please reload page." => "El testimoni ha expirat. Torneu a carregar la pàgina.", diff --git a/lib/l10n/cs_CZ.php b/lib/l10n/cs_CZ.php index fa11e886774..2c823194b96 100644 --- a/lib/l10n/cs_CZ.php +++ b/lib/l10n/cs_CZ.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Soubory musí být stahovány jednotlivě.", "Back to Files" => "Zpět k souborům", "Selected files too large to generate zip file." => "Vybrané soubory jsou příliš velké pro vytvoření zip souboru.", +"couldn't be determined" => "nelze zjistit", "Application is not enabled" => "Aplikace není povolena", "Authentication error" => "Chyba ověření", "Token expired. Please reload page." => "Token vypršel. Obnovte prosím stránku.", diff --git a/lib/l10n/da.php b/lib/l10n/da.php index a0ab1f17014..8f22be5e823 100644 --- a/lib/l10n/da.php +++ b/lib/l10n/da.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Filer skal downloades en for en.", "Back to Files" => "Tilbage til Filer", "Selected files too large to generate zip file." => "De markerede filer er for store til at generere en ZIP-fil.", +"couldn't be determined" => "kunne ikke fastslås", "Application is not enabled" => "Programmet er ikke aktiveret", "Authentication error" => "Adgangsfejl", "Token expired. Please reload page." => "Adgang er udløbet. Genindlæs siden.", diff --git a/lib/l10n/de.php b/lib/l10n/de.php index 4b77bf7210d..c285a07f63a 100644 --- a/lib/l10n/de.php +++ b/lib/l10n/de.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", "Back to Files" => "Zurück zu \"Dateien\"", "Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.", +"couldn't be determined" => "Konnte nicht festgestellt werden", "Application is not enabled" => "Die Anwendung ist nicht aktiviert", "Authentication error" => "Authentifizierungs-Fehler", "Token expired. Please reload page." => "Token abgelaufen. Bitte lade die Seite neu.", diff --git a/lib/l10n/de_DE.php b/lib/l10n/de_DE.php index e9f0f34a0e1..625ba2ecf20 100644 --- a/lib/l10n/de_DE.php +++ b/lib/l10n/de_DE.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", "Back to Files" => "Zurück zu \"Dateien\"", "Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.", +"couldn't be determined" => "konnte nicht ermittelt werden", "Application is not enabled" => "Die Anwendung ist nicht aktiviert", "Authentication error" => "Authentifizierungs-Fehler", "Token expired. Please reload page." => "Token abgelaufen. Bitte laden Sie die Seite neu.", diff --git a/lib/l10n/el.php b/lib/l10n/el.php index 315b995ecc9..cf0be24b432 100644 --- a/lib/l10n/el.php +++ b/lib/l10n/el.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Τα αρχεία πρέπει να ληφθούν ένα-ένα.", "Back to Files" => "Πίσω στα Αρχεία", "Selected files too large to generate zip file." => "Τα επιλεγμένα αρχεία είναι μεγάλα ώστε να δημιουργηθεί αρχείο zip.", +"couldn't be determined" => "δεν μπορούσε να προσδιορισθεί", "Application is not enabled" => "Δεν ενεργοποιήθηκε η εφαρμογή", "Authentication error" => "Σφάλμα πιστοποίησης", "Token expired. Please reload page." => "Το αναγνωριστικό έληξε. Παρακαλώ φορτώστε ξανά την σελίδα.", diff --git a/lib/l10n/es.php b/lib/l10n/es.php index f843c42dfd3..8bbc8a8f7b4 100644 --- a/lib/l10n/es.php +++ b/lib/l10n/es.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Los archivos deben ser descargados uno por uno.", "Back to Files" => "Volver a Archivos", "Selected files too large to generate zip file." => "Los archivos seleccionados son demasiado grandes para generar el archivo zip.", +"couldn't be determined" => "no pudo ser determinado", "Application is not enabled" => "La aplicación no está habilitada", "Authentication error" => "Error de autenticación", "Token expired. Please reload page." => "Token expirado. Por favor, recarga la página.", diff --git a/lib/l10n/es_AR.php b/lib/l10n/es_AR.php index 2bbffd39e9e..c32017a10f8 100644 --- a/lib/l10n/es_AR.php +++ b/lib/l10n/es_AR.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Los archivos deben ser descargados de a uno.", "Back to Files" => "Volver a archivos", "Selected files too large to generate zip file." => "Los archivos seleccionados son demasiado grandes para generar el archivo zip.", +"couldn't be determined" => "no pudo ser determinado", "Application is not enabled" => "La aplicación no está habilitada", "Authentication error" => "Error de autenticación", "Token expired. Please reload page." => "Token expirado. Por favor, recargá la página.", diff --git a/lib/l10n/eu.php b/lib/l10n/eu.php index 5d47ecbda23..1941551b176 100644 --- a/lib/l10n/eu.php +++ b/lib/l10n/eu.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Fitxategiak banan-banan deskargatu behar dira.", "Back to Files" => "Itzuli fitxategietara", "Selected files too large to generate zip file." => "Hautatuko fitxategiak oso handiak dira zip fitxategia sortzeko.", +"couldn't be determined" => "ezin izan da zehaztu", "Application is not enabled" => "Aplikazioa ez dago gaituta", "Authentication error" => "Autentikazio errorea", "Token expired. Please reload page." => "Tokena iraungitu da. Mesedez birkargatu orria.", diff --git a/lib/l10n/fa.php b/lib/l10n/fa.php index ce7c7c6e970..bbb04290a5c 100644 --- a/lib/l10n/fa.php +++ b/lib/l10n/fa.php @@ -3,16 +3,28 @@ "Personal" => "شخصی", "Settings" => "تنظیمات", "Users" => "کاربران", +"Apps" => " برنامه ها", "Admin" => "مدیر", +"ZIP download is turned off." => "دانلود به صورت فشرده غیر فعال است", +"Files need to be downloaded one by one." => "فایل ها باید به صورت یکی یکی دانلود شوند", +"Back to Files" => "بازگشت به فایل ها", +"Selected files too large to generate zip file." => "فایل های انتخاب شده بزرگتر از آن هستند که بتوان یک فایل فشرده تولید کرد", +"Application is not enabled" => "برنامه فعال نشده است", "Authentication error" => "خطا در اعتبار سنجی", "Files" => "پروندهها", "Text" => "متن", +"Images" => "تصاویر", "seconds ago" => "ثانیهها پیش", "1 minute ago" => "1 دقیقه پیش", "%d minutes ago" => "%d دقیقه پیش", +"1 hour ago" => "1 ساعت پیش", +"%d hours ago" => "%d ساعت پیش", "today" => "امروز", "yesterday" => "دیروز", +"%d days ago" => "%d روز پیش", "last month" => "ماه قبل", +"%d months ago" => "%dماه پیش", "last year" => "سال قبل", -"years ago" => "سالهای قبل" +"years ago" => "سالهای قبل", +"Could not find category \"%s\"" => "دسته بندی %s یافت نشد" ); diff --git a/lib/l10n/fi_FI.php b/lib/l10n/fi_FI.php index 6a5734e978d..b8d4b137431 100644 --- a/lib/l10n/fi_FI.php +++ b/lib/l10n/fi_FI.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Tiedostot on ladattava yksittäin.", "Back to Files" => "Takaisin tiedostoihin", "Selected files too large to generate zip file." => "Valitut tiedostot ovat liian suurikokoisia mahtuakseen zip-tiedostoon.", +"couldn't be determined" => "ei voitu määrittää", "Application is not enabled" => "Sovellusta ei ole otettu käyttöön", "Authentication error" => "Todennusvirhe", "Token expired. Please reload page." => "Valtuutus vanheni. Lataa sivu uudelleen.", diff --git a/lib/l10n/fr.php b/lib/l10n/fr.php index 218c22c1d53..c6bf8f7f9c3 100644 --- a/lib/l10n/fr.php +++ b/lib/l10n/fr.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Les fichiers nécessitent d'être téléchargés un par un.", "Back to Files" => "Retour aux Fichiers", "Selected files too large to generate zip file." => "Les fichiers sélectionnés sont trop volumineux pour être compressés.", +"couldn't be determined" => "impossible à déterminer", "Application is not enabled" => "L'application n'est pas activée", "Authentication error" => "Erreur d'authentification", "Token expired. Please reload page." => "La session a expiré. Veuillez recharger la page.", diff --git a/lib/l10n/gl.php b/lib/l10n/gl.php index 1e897959e41..532b3443b44 100644 --- a/lib/l10n/gl.php +++ b/lib/l10n/gl.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Os ficheiros necesitan seren descargados de un en un.", "Back to Files" => "Volver aos ficheiros", "Selected files too large to generate zip file." => "Os ficheiros seleccionados son demasiado grandes como para xerar un ficheiro zip.", +"couldn't be determined" => "non puido ser determinado", "Application is not enabled" => "O aplicativo non está activado", "Authentication error" => "Produciuse un erro na autenticación", "Token expired. Please reload page." => "Testemuña caducada. Recargue a páxina.", diff --git a/lib/l10n/hu_HU.php b/lib/l10n/hu_HU.php index 3dcf0646d06..e25de3e1ed6 100644 --- a/lib/l10n/hu_HU.php +++ b/lib/l10n/hu_HU.php @@ -5,10 +5,11 @@ "Users" => "Felhasználók", "Apps" => "Alkalmazások", "Admin" => "Admin", -"ZIP download is turned off." => "A ZIP-letöltés nem engedélyezett.", +"ZIP download is turned off." => "A ZIP-letöltés nincs engedélyezve.", "Files need to be downloaded one by one." => "A fájlokat egyenként kell letölteni", "Back to Files" => "Vissza a Fájlokhoz", -"Selected files too large to generate zip file." => "A kiválasztott fájlok túl nagy a zip tömörítéshez.", +"Selected files too large to generate zip file." => "A kiválasztott fájlok túl nagyok a zip tömörítéshez.", +"couldn't be determined" => "nem határozható meg", "Application is not enabled" => "Az alkalmazás nincs engedélyezve", "Authentication error" => "Hitelesítési hiba", "Token expired. Please reload page." => "A token lejárt. Frissítse az oldalt.", diff --git a/lib/l10n/it.php b/lib/l10n/it.php index c0fb0babfb3..eb404db7fb5 100644 --- a/lib/l10n/it.php +++ b/lib/l10n/it.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "I file devono essere scaricati uno alla volta.", "Back to Files" => "Torna ai file", "Selected files too large to generate zip file." => "I file selezionati sono troppo grandi per generare un file zip.", +"couldn't be determined" => "non può essere determinato", "Application is not enabled" => "L'applicazione non è abilitata", "Authentication error" => "Errore di autenticazione", "Token expired. Please reload page." => "Token scaduto. Ricarica la pagina.", diff --git a/lib/l10n/ja_JP.php b/lib/l10n/ja_JP.php index 854734c9764..11cefe900c2 100644 --- a/lib/l10n/ja_JP.php +++ b/lib/l10n/ja_JP.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "ファイルは1つずつダウンロードする必要があります。", "Back to Files" => "ファイルに戻る", "Selected files too large to generate zip file." => "選択したファイルはZIPファイルの生成には大きすぎます。", +"couldn't be determined" => "測定できませんでした", "Application is not enabled" => "アプリケーションは無効です", "Authentication error" => "認証エラー", "Token expired. Please reload page." => "トークンが無効になりました。ページを再読込してください。", diff --git a/lib/l10n/ko.php b/lib/l10n/ko.php index c4716f9f8bd..859657f46b4 100644 --- a/lib/l10n/ko.php +++ b/lib/l10n/ko.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "파일을 개별적으로 다운로드해야 합니다.", "Back to Files" => "파일로 돌아가기", "Selected files too large to generate zip file." => "선택한 파일들은 ZIP 파일을 생성하기에 너무 큽니다.", +"couldn't be determined" => "결정할 수 없음", "Application is not enabled" => "앱이 활성화되지 않았습니다", "Authentication error" => "인증 오류", "Token expired. Please reload page." => "토큰이 만료되었습니다. 페이지를 새로 고치십시오.", diff --git a/lib/l10n/lb.php b/lib/l10n/lb.php index baee630e897..06e8b2ca094 100644 --- a/lib/l10n/lb.php +++ b/lib/l10n/lb.php @@ -1,6 +1,12 @@ <?php $TRANSLATIONS = array( +"Help" => "Hëllef", "Personal" => "Perséinlech", "Settings" => "Astellungen", "Authentication error" => "Authentifikatioun's Fehler", -"Text" => "SMS" +"Files" => "Dateien", +"Text" => "SMS", +"1 hour ago" => "vrun 1 Stonn", +"last month" => "Läschte Mount", +"last year" => "Läscht Joer", +"years ago" => "Joren hier" ); diff --git a/lib/l10n/ms_MY.php b/lib/l10n/ms_MY.php index 86c7e51b486..5afee1cb5a8 100644 --- a/lib/l10n/ms_MY.php +++ b/lib/l10n/ms_MY.php @@ -1,4 +1,5 @@ <?php $TRANSLATIONS = array( +"Help" => "Bantuan", "Personal" => "Peribadi", "Settings" => "Tetapan", "Users" => "Pengguna", diff --git a/lib/l10n/nl.php b/lib/l10n/nl.php index 087cf23a627..7ce134e3621 100644 --- a/lib/l10n/nl.php +++ b/lib/l10n/nl.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Bestanden moeten één voor één worden gedownload.", "Back to Files" => "Terug naar bestanden", "Selected files too large to generate zip file." => "De geselecteerde bestanden zijn te groot om een zip bestand te maken.", +"couldn't be determined" => "kon niet worden vastgesteld", "Application is not enabled" => "De applicatie is niet actief", "Authentication error" => "Authenticatie fout", "Token expired. Please reload page." => "Token verlopen. Herlaad de pagina.", diff --git a/lib/l10n/pl.php b/lib/l10n/pl.php index 6f84a328ed9..6ec35445bc2 100644 --- a/lib/l10n/pl.php +++ b/lib/l10n/pl.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Pliki muszą zostać pobrane pojedynczo.", "Back to Files" => "Wróć do plików", "Selected files too large to generate zip file." => "Wybrane pliki są zbyt duże, aby wygenerować plik zip.", +"couldn't be determined" => "nie może zostać znaleziony", "Application is not enabled" => "Aplikacja nie jest włączona", "Authentication error" => "Błąd uwierzytelniania", "Token expired. Please reload page." => "Token wygasł. Proszę ponownie załadować stronę.", diff --git a/lib/l10n/pt_PT.php b/lib/l10n/pt_PT.php index 84867c4c37c..e35bb489c49 100644 --- a/lib/l10n/pt_PT.php +++ b/lib/l10n/pt_PT.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Os ficheiros precisam de ser descarregados um por um.", "Back to Files" => "Voltar a Ficheiros", "Selected files too large to generate zip file." => "Os ficheiros seleccionados são grandes demais para gerar um ficheiro zip.", +"couldn't be determined" => "Não foi possível determinar", "Application is not enabled" => "A aplicação não está activada", "Authentication error" => "Erro na autenticação", "Token expired. Please reload page." => "O token expirou. Por favor recarregue a página.", diff --git a/lib/l10n/ro.php b/lib/l10n/ro.php index d3ce066c8c1..3f8e59cdac2 100644 --- a/lib/l10n/ro.php +++ b/lib/l10n/ro.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Fișierele trebuie descărcate unul câte unul.", "Back to Files" => "Înapoi la fișiere", "Selected files too large to generate zip file." => "Fișierele selectate sunt prea mari pentru a genera un fișier zip.", +"couldn't be determined" => "nu poate fi determinat", "Application is not enabled" => "Aplicația nu este activată", "Authentication error" => "Eroare la autentificare", "Token expired. Please reload page." => "Token expirat. Te rugăm să reîncarci pagina.", diff --git a/lib/l10n/ru_RU.php b/lib/l10n/ru_RU.php index ba7d39f9eb0..03da09236ea 100644 --- a/lib/l10n/ru_RU.php +++ b/lib/l10n/ru_RU.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Файлы должны быть загружены один за другим.", "Back to Files" => "Обратно к файлам", "Selected files too large to generate zip file." => "Выбранные файлы слишком велики для генерации zip-архива.", +"couldn't be determined" => "не может быть определено", "Application is not enabled" => "Приложение не запущено", "Authentication error" => "Ошибка аутентификации", "Token expired. Please reload page." => "Маркер истек. Пожалуйста, перезагрузите страницу.", diff --git a/lib/l10n/sk_SK.php b/lib/l10n/sk_SK.php index 98a5b5ca677..81f23ffdc50 100644 --- a/lib/l10n/sk_SK.php +++ b/lib/l10n/sk_SK.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Súbory musia byť nahrávané jeden za druhým.", "Back to Files" => "Späť na súbory", "Selected files too large to generate zip file." => "Zvolené súbory sú príliž veľké na vygenerovanie zip súboru.", +"couldn't be determined" => "nedá sa zistiť", "Application is not enabled" => "Aplikácia nie je zapnutá", "Authentication error" => "Chyba autentifikácie", "Token expired. Please reload page." => "Token vypršal. Obnovte, prosím, stránku.", diff --git a/lib/l10n/sr.php b/lib/l10n/sr.php index 2ae7400ba79..1161b0a44b7 100644 --- a/lib/l10n/sr.php +++ b/lib/l10n/sr.php @@ -1,14 +1,15 @@ <?php $TRANSLATIONS = array( "Help" => "Помоћ", "Personal" => "Лично", -"Settings" => "Подешавања", +"Settings" => "Поставке", "Users" => "Корисници", "Apps" => "Апликације", -"Admin" => "Администрација", +"Admin" => "Администратор", "ZIP download is turned off." => "Преузимање ZIP-а је искључено.", "Files need to be downloaded one by one." => "Датотеке морате преузимати једну по једну.", "Back to Files" => "Назад на датотеке", "Selected files too large to generate zip file." => "Изабране датотеке су превелике да бисте направили ZIP датотеку.", +"couldn't be determined" => "није одређено", "Application is not enabled" => "Апликација није омогућена", "Authentication error" => "Грешка при провери идентитета", "Token expired. Please reload page." => "Жетон је истекао. Поново учитајте страницу.", @@ -28,7 +29,7 @@ "last year" => "прошле године", "years ago" => "година раније", "%s is available. Get <a href=\"%s\">more information</a>" => "%s је доступна. Погледајте <a href=\"%s\">више информација</a>.", -"up to date" => "је ажурна.", -"updates check is disabled" => "провера ажурирања је онемогућена.", +"up to date" => "је ажурна", +"updates check is disabled" => "провера ажурирања је онемогућена", "Could not find category \"%s\"" => "Не могу да пронађем категорију „%s“." ); diff --git a/lib/l10n/sv.php b/lib/l10n/sv.php index 5799e2dd1a8..36f00636b2b 100644 --- a/lib/l10n/sv.php +++ b/lib/l10n/sv.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Filer laddas ner en åt gången.", "Back to Files" => "Tillbaka till Filer", "Selected files too large to generate zip file." => "Valda filer är för stora för att skapa zip-fil.", +"couldn't be determined" => "kunde inte bestämmas", "Application is not enabled" => "Applikationen är inte aktiverad", "Authentication error" => "Fel vid autentisering", "Token expired. Please reload page." => "Ogiltig token. Ladda om sidan.", diff --git a/lib/l10n/th_TH.php b/lib/l10n/th_TH.php index 75fa02f84b0..0da607a0589 100644 --- a/lib/l10n/th_TH.php +++ b/lib/l10n/th_TH.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "ไฟล์สามารถดาวน์โหลดได้ทีละครั้งเท่านั้น", "Back to Files" => "กลับไปที่ไฟล์", "Selected files too large to generate zip file." => "ไฟล์ที่เลือกมีขนาดใหญ่เกินกว่าที่จะสร้างเป็นไฟล์ zip", +"couldn't be determined" => "ไม่สามารถกำหนดได้", "Application is not enabled" => "แอพพลิเคชั่นดังกล่าวยังไม่ได้เปิดใช้งาน", "Authentication error" => "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน", "Token expired. Please reload page." => "รหัสยืนยันความถูกต้องหมดอายุแล้ว กรุณาโหลดหน้าเว็บใหม่อีกครั้ง", diff --git a/lib/l10n/tr.php b/lib/l10n/tr.php index 9b7f1815fa3..e55caa15972 100644 --- a/lib/l10n/tr.php +++ b/lib/l10n/tr.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Dosyaların birer birer indirilmesi gerekmektedir.", "Back to Files" => "Dosyalara dön", "Selected files too large to generate zip file." => "Seçilen dosyalar bir zip dosyası oluşturmak için fazla büyüktür.", +"couldn't be determined" => "tespit edilemedi", "Application is not enabled" => "Uygulama etkinleştirilmedi", "Authentication error" => "Kimlik doğrulama hatası", "Token expired. Please reload page." => "Jetonun süresi geçti. Lütfen sayfayı yenileyin.", diff --git a/lib/l10n/uk.php b/lib/l10n/uk.php index f5d52f8682d..053644ddede 100644 --- a/lib/l10n/uk.php +++ b/lib/l10n/uk.php @@ -9,6 +9,7 @@ "Files need to be downloaded one by one." => "Файли повинні бути завантаженні послідовно.", "Back to Files" => "Повернутися до файлів", "Selected files too large to generate zip file." => "Вибрані фали завеликі для генерування zip файлу.", +"couldn't be determined" => "не може бути визначено", "Application is not enabled" => "Додаток не увімкнений", "Authentication error" => "Помилка автентифікації", "Token expired. Please reload page." => "Строк дії токена скінчився. Будь ласка, перезавантажте сторінку.", diff --git a/lib/l10n/zh_TW.php b/lib/l10n/zh_TW.php index 4dbf89c2e0e..62ab8fedd52 100644 --- a/lib/l10n/zh_TW.php +++ b/lib/l10n/zh_TW.php @@ -9,26 +9,27 @@ "Files need to be downloaded one by one." => "檔案需要逐一下載", "Back to Files" => "回到檔案列表", "Selected files too large to generate zip file." => "選擇的檔案太大以致於無法產生壓縮檔", +"couldn't be determined" => "無法判斷", "Application is not enabled" => "應用程式未啟用", "Authentication error" => "認證錯誤", -"Token expired. Please reload page." => "Token 過期. 請重新整理頁面", +"Token expired. Please reload page." => "Token 過期,請重新整理頁面。", "Files" => "檔案", "Text" => "文字", "Images" => "圖片", "seconds ago" => "幾秒前", "1 minute ago" => "1 分鐘前", "%d minutes ago" => "%d 分鐘前", -"1 hour ago" => "1小時之前", -"%d hours ago" => "%d小時之前", +"1 hour ago" => "1 小時之前", +"%d hours ago" => "%d 小時之前", "today" => "今天", "yesterday" => "昨天", "%d days ago" => "%d 天前", "last month" => "上個月", -"%d months ago" => "%d個月之前", +"%d months ago" => "%d 個月之前", "last year" => "去年", "years ago" => "幾年前", -"%s is available. Get <a href=\"%s\">more information</a>" => "%s 已經可用. 取得 <a href=\"%s\">更多資訊</a>", +"%s is available. Get <a href=\"%s\">more information</a>" => "%s 已經可用。取得 <a href=\"%s\">更多資訊</a>", "up to date" => "最新的", "updates check is disabled" => "檢查更新已停用", -"Could not find category \"%s\"" => "找不到分類-\"%s\"" +"Could not find category \"%s\"" => "找不到分類:\"%s\"" ); diff --git a/lib/mail.php b/lib/mail.php index 4683a1b4eee..1bb202ac977 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -38,8 +38,12 @@ class OC_Mail { $SMTPHOST = OC_Config::getValue( 'mail_smtphost', '127.0.0.1' ); $SMTPPORT = OC_Config::getValue( 'mail_smtpport', 25 ); $SMTPAUTH = OC_Config::getValue( 'mail_smtpauth', false ); + $SMTPAUTHTYPE = OC_Config::getValue( 'mail_smtpauthtype', 'LOGIN' ); $SMTPUSERNAME = OC_Config::getValue( 'mail_smtpname', '' ); $SMTPPASSWORD = OC_Config::getValue( 'mail_smtppassword', '' ); + $SMTPDEBUG = OC_Config::getValue( 'mail_smtpdebug', false ); + $SMTPTIMEOUT = OC_Config::getValue( 'mail_smtptimeout', 10 ); + $SMTPSECURE = OC_Config::getValue( 'mail_smtpsecure', '' ); $mailo = new PHPMailer(true); @@ -57,12 +61,16 @@ class OC_Mail { $mailo->Host = $SMTPHOST; $mailo->Port = $SMTPPORT; $mailo->SMTPAuth = $SMTPAUTH; + $mailo->SMTPDebug = $SMTPDEBUG; + $mailo->SMTPSecure = $SMTPSECURE; + $mailo->AuthType = $SMTPAUTHTYPE; $mailo->Username = $SMTPUSERNAME; $mailo->Password = $SMTPPASSWORD; + $mailo->Timeout = $SMTPTIMEOUT; - $mailo->From =$fromaddress; + $mailo->From = $fromaddress; $mailo->FromName = $fromname;; - $mailo->Sender =$fromaddress; + $mailo->Sender = $fromaddress; $a=explode(' ', $toaddress); try { foreach($a as $ad) { diff --git a/lib/mimetypes.list.php b/lib/mimetypes.list.php index 77b97917583..fc87d011ecd 100644 --- a/lib/mimetypes.list.php +++ b/lib/mimetypes.list.php @@ -95,4 +95,6 @@ return array( 'cdr' => 'application/coreldraw', 'impress' => 'text/impress', 'ai' => 'application/illustrator', + 'epub' => 'application/epub+zip', + 'mobi' => 'application/x-mobipocket-ebook', ); diff --git a/lib/ocsclient.php b/lib/ocsclient.php index ca0665da436..30163c1e403 100644 --- a/lib/ocsclient.php +++ b/lib/ocsclient.php @@ -123,6 +123,8 @@ class OC_OCSClient{ $app=array(); $app['id']=(string)$tmp[$i]->id; $app['name']=(string)$tmp[$i]->name; + $app['label']=(string)$tmp[$i]->label; + $app['version']=(string)$tmp[$i]->version; $app['type']=(string)$tmp[$i]->typeid; $app['typename']=(string)$tmp[$i]->typename; $app['personid']=(string)$tmp[$i]->personid; @@ -162,7 +164,9 @@ class OC_OCSClient{ $app=array(); $app['id']=$tmp->id; $app['name']=$tmp->name; + $app['version']=$tmp->version; $app['type']=$tmp->typeid; + $app['label']=$tmp->label; $app['typename']=$tmp->typename; $app['personid']=$tmp->personid; $app['detailpage']=$tmp->detailpage; 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..3c5c2d53782 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 { @@ -410,41 +300,36 @@ class Share { throw new \Exception($message); } // 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)) { - 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, '/') - ) { - // Continue scanning into child folders - array_push($files, $children); - } else { - // 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) - ) { - $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 - self::put($itemType, $name, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder); - } - } - return true; - } - return false; - } else { +// if ($itemType == 'folder') { +// $parentFolder = self::put('folder', $itemSource, $shareType, $shareWith, $uidOwner, $permissions, true); +// 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\Filesystem::getDirectoryContent($name, '/') +// ) { +// // Continue scanning into child folders +// array_push($files, $children); +// } else { +// // 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)) { +// $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 +// self::put($itemType, $name, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder); +// } +// } +// return true; +// } +// return false; +// } else { // Put the item into the database return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions); - } +// } } /** @@ -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,34 +670,29 @@ 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) { if (($itemType == 'file' || $itemType == 'folder') - && $format == \OC_Share_Backend_File::FORMAT_FILE_APP + && $format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT ) { $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `uid_owner`, ' - .'`share_type`, `share_with`, `file_source`, `path`, `file_target`, `permissions`, ' - .'`expiration`, `name`, `ctime`, `mtime`, `mimetype`, `size`, `encrypted`, ' - .'`versioned`, `writable`'; + .'`share_type`, `share_with`, `file_source`, `path`, `file_target`, ' + .'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' + .'`name` `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`'; } 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'])) { @@ -946,13 +758,22 @@ class Share { continue; } } + + // Add display names to result + if ( isset($row['share_with']) && $row['share_with'] != '') { + $row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']); + } + if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
+ $row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']);
+ } + $items[$row['id']] = $row; } if (!empty($items)) { $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 +782,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 +806,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 +840,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 +878,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 +891,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 +913,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 +923,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 +936,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 +952,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 +975,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 +996,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 +1005,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 +1056,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 +1108,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 +1123,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 +1162,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 +1205,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 +1219,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 +1241,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 +1299,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 +1335,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/public/user.php b/lib/public/user.php index 204d8e4c0f1..de52055a4c5 100644 --- a/lib/public/user.php +++ b/lib/public/user.php @@ -51,7 +51,25 @@ class User { public static function getUsers($search = '', $limit = null, $offset = null) { return \OC_USER::getUsers(); } - + + /**
+ * @brief get the user display name of the user currently logged in.
+ * @return string display name
+ */
+ public static function getDisplayName($user=null) {
+ return \OC_USER::getDisplayName($user);
+ } + + /**
+ * @brief Get a list of all display names
+ * @returns array with all display names (value) and the correspondig uids (key)
+ *
+ * Get a list of all display names and user ids.
+ */
+ public static function getDisplayNames($search = '', $limit = null, $offset = null) {
+ return \OC_USER::getDisplayNames($search, $limit, $offset);
+ } + /** * @brief Check if the user is logged in * @returns true/false diff --git a/lib/public/util.php b/lib/public/util.php index 8197482c0dd..a78a52f326e 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -219,6 +219,28 @@ class Util { } /** + * @brief Returns the request uri + * @returns the request uri + * + * Returns the request uri, even if the website uses one or more + * reverse proxies + */ + public static function getRequestUri() { + return(\OC_Request::requestUri()); + } + + /** + * @brief Returns the script name + * @returns the script name + * + * Returns the script name, even if the website uses one or more + * reverse proxies + */ + public static function getScriptName() { + return(\OC_Request::scriptName()); + } + + /** * @brief Creates path to an image * @param string $app app * @param string $image image name @@ -367,4 +389,14 @@ class Util { public static function recursiveArraySearch($haystack, $needle, $index = null) { return(\OC_Helper::recursiveArraySearch($haystack, $needle, $index)); } + + /** + * @brief calculates the maximum upload size respecting system settings, free space and user quota + * + * @param $dir the current folder where the user currently operates + * @return number of bytes representing + */ + public static function maxUploadFilesize($dir) { + return \OC_Helper::maxUploadFilesize($dir); + } } diff --git a/lib/request.php b/lib/request.php index f2f15c21103..1661a1406ca 100755 --- a/lib/request.php +++ b/lib/request.php @@ -8,6 +8,15 @@ class OC_Request { /** + * @brief Check overwrite condition + * @returns true/false + */ + private static function isOverwriteCondition() { + $regex = '/' . OC_Config::getValue('overwritecondaddr', '') . '/'; + return $regex === '//' or preg_match($regex, $_SERVER['REMOTE_ADDR']) === 1; + } + + /** * @brief Returns the server host * @returns the server host * @@ -18,7 +27,7 @@ class OC_Request { if(OC::$CLI) { return 'localhost'; } - if(OC_Config::getValue('overwritehost', '')<>'') { + if(OC_Config::getValue('overwritehost', '')<>'' and self::isOverwriteCondition()) { return OC_Config::getValue('overwritehost'); } if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { @@ -43,7 +52,7 @@ class OC_Request { * Returns the server protocol. It respects reverse proxy servers and load balancers */ public static function serverProtocol() { - if(OC_Config::getValue('overwriteprotocol', '')<>'') { + if(OC_Config::getValue('overwriteprotocol', '')<>'' and self::isOverwriteCondition()) { return OC_Config::getValue('overwriteprotocol'); } if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { @@ -59,6 +68,38 @@ class OC_Request { } /** + * @brief Returns the request uri + * @returns the request uri + * + * Returns the request uri, even if the website uses one or more + * reverse proxies + */ + public static function requestUri() { + $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + if (OC_Config::getValue('overwritewebroot', '') <> '' and self::isOverwriteCondition()) { + $uri = self::scriptName() . substr($uri, strlen($_SERVER['SCRIPT_NAME'])); + } + return $uri; + } + + /** + * @brief Returns the script name + * @returns the script name + * + * Returns the script name, even if the website uses one or more + * reverse proxies + */ + public static function scriptName() { + $name = $_SERVER['SCRIPT_NAME']; + if (OC_Config::getValue('overwritewebroot', '') <> '' and self::isOverwriteCondition()) { + $serverroot = str_replace("\\", '/', substr(__DIR__, 0, -4)); + $suburi = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen($serverroot))); + $name = OC_Config::getValue('overwritewebroot', '') . $suburi; + } + return $name; + } + + /** * @brief get Path info from request * @returns string Path info or false when not found */ diff --git a/lib/search.php b/lib/search.php index 3c3378ad13c..e5a65f7157d 100644 --- a/lib/search.php +++ b/lib/search.php @@ -57,6 +57,22 @@ class OC_Search{ } return $results; } + + /** + * remove an existing search provider + * @param string $provider class name of a OC_Search_Provider + */ + public static function removeProvider($provider) { + self::$registeredProviders = array_filter( + self::$registeredProviders, + function ($element) use ($provider) { + return ($element['class'] != $provider); + } + ); + // force regeneration of providers on next search + self::$providers=array(); + } + /** * create instances of all the registered search providers 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/setup.php b/lib/setup.php index b88bc4b52ce..4dd190b99fb 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -1,5 +1,23 @@ <?php +class DatabaseSetupException extends Exception +{ + private $hint; + + public function __construct($message, $hint, $code = 0, Exception $previous = null) { + $this->hint = $hint; + parent::__construct($message, $code, $previous); + } + + public function __toString() { + return __CLASS__ . ": [{$this->code}]: {$this->message} ({$this->hint})\n"; + } + + public function getHint() { + return $this->hint; + } +} + class OC_Setup { public static function install($options) { $error = array(); @@ -19,9 +37,9 @@ class OC_Setup { if($dbtype=='mysql') $dbprettyname = 'MySQL'; else if($dbtype=='pgsql') - $dbprettyname = 'PostgreSQL'; + $dbprettyname = 'PostgreSQL'; else - $dbprettyname = 'Oracle'; + $dbprettyname = 'Oracle'; if(empty($options['dbuser'])) { @@ -69,10 +87,16 @@ class OC_Setup { try { self::setupMySQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username); + } catch (DatabaseSetupException $e) { + $error[] = array( + 'error' => $e->getMessage(), + 'hint' => $e->getHint() + ); + return($error); } catch (Exception $e) { $error[] = array( - 'error' => 'MySQL username and/or password not valid', - 'hint' => 'You need to enter either an existing account or the administrator.' + 'error' => $e->getMessage(), + 'hint' => '' ); return($error); } @@ -141,7 +165,9 @@ class OC_Setup { if(count($error) == 0) { OC_Appconfig::setValue('core', 'installedat', microtime(true)); OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true)); - + OC_AppConfig::setValue('core', 'remote_core.css', '/core/minimizer.php'); + OC_AppConfig::setValue('core', 'remote_core.js', '/core/minimizer.php'); + OC_Group::createGroup('admin'); OC_Group::addToGroup($username, 'admin'); OC_User::login($username, $password); @@ -166,7 +192,7 @@ class OC_Setup { //check if the database user has admin right $connection = @mysql_connect($dbhost, $dbuser, $dbpass); if(!$connection) { - throw new Exception('MySQL username and/or password not valid'); + throw new DatabaseSetupException('MySQL username and/or password not valid','You need to enter either an existing account or the administrator.'); } $oldUser=OC_Config::getValue('dbuser', false); @@ -229,8 +255,14 @@ class OC_Setup { // the anonymous user would take precedence when there is one. $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; $result = mysql_query($query, $connection); + if (!$result) { + throw new DatabaseSetupException("MySQL user '" . "$name" . "'@'localhost' already exists","Delete this user from MySQL."); + } $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; $result = mysql_query($query, $connection); + if (!$result) { + throw new DatabaseSetupException("MySQL user '" . "$name" . "'@'%' already exists","Delete this user from MySQL."); + } } private static function setupPostgreSQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username) { diff --git a/lib/template.php b/lib/template.php index f7124ebc09c..238d8a8ad0f 100644 --- a/lib/template.php +++ b/lib/template.php @@ -186,9 +186,15 @@ class OC_Template{ $this->l10n = OC_L10N::get($parts[0]); // Some headers to enhance security - header('X-Frame-Options: Sameorigin'); - header('X-XSS-Protection: 1; mode=block'); - header('X-Content-Type-Options: nosniff'); + header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains + header('X-XSS-Protection: 1; mode=block'); // Enforce browser based XSS filters + header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE + + // Content Security Policy + // If you change the standard policy, please also change it in config.sample.php + $policy = OC_Config::getValue('custom_csp_policy', 'default-src \'self\'; script-src \'self\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; frame-src *; img-src *'); + header('Content-Security-Policy:'.$policy); // Standard + header('X-WebKit-CSP:'.$policy); // Older webkit browsers $this->findTemplate($name); } diff --git a/lib/templatelayout.php b/lib/templatelayout.php index 4173e008ba7..37ece91047f 100644 --- a/lib/templatelayout.php +++ b/lib/templatelayout.php @@ -33,18 +33,6 @@ class OC_TemplateLayout extends OC_Template { } else { parent::__construct('core', 'layout.base'); } - - $apps_paths = array(); - foreach(OC_App::getEnabledApps() as $app) { - $apps_paths[$app] = OC_App::getAppWebPath($app); - } - $this->assign( 'apps_paths', str_replace('\\/', '/', json_encode($apps_paths)), false ); // Ugly unescape slashes waiting for better solution - - if (OC_Config::getValue('installed', false) && !OC_AppConfig::getValue('core', 'remote_core.css', false)) { - OC_AppConfig::setValue('core', 'remote_core.css', '/core/minimizer.php'); - OC_AppConfig::setValue('core', 'remote_core.js', '/core/minimizer.php'); - } - // Add the js files $jsfiles = self::findJavascriptFiles(OC_Util::$scripts); $this->assign('jsfiles', array(), false); diff --git a/lib/user.php b/lib/user.php index fd0ed6ecd3a..38259bceea5 100644 --- a/lib/user.php +++ b/lib/user.php @@ -251,6 +251,7 @@ class OC_User { if($uid && $enabled) { session_regenerate_id(true); self::setUserId($uid); + self::setDisplayName($uid); OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password )); return true; } @@ -266,6 +267,48 @@ class OC_User { } /** + * @brief Sets user display name for session + */ + public static function setDisplayName($uid, $displayName = null) { + $result = false; + if ($displayName ) { + foreach(self::$_usedBackends as $backend) { + if($backend->implementsActions(OC_USER_BACKEND_SET_DISPLAYNAME)) { + if($backend->userExists($uid)) { + $success |= $backend->setDisplayName($uid, $displayName); + } + } + } + } else { + $displayName = self::determineDisplayName($uid); + $result = true; + } + if (OC_User::getUser() === $uid) { + $_SESSION['display_name'] = $displayName; + } + return $result; + } + + + /** + * @brief get display name + * @param $uid The username + * @returns string display name or uid if no display name is defined + * + */ + private static function determineDisplayName( $uid ) { + foreach(self::$_usedBackends as $backend) { + if($backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) { + $result=$backend->getDisplayName( $uid ); + if($result) { + return $result; + } + } + } + return $uid; + } + + /** * @brief Logs the current user out and kills all the session data * * Logout, destroys session @@ -321,6 +364,21 @@ class OC_User { } /** + * @brief get the display name of the user currently logged in. + * @return string uid or false + */ + public static function getDisplayName($user=null) { + if ( $user ) { + return self::determineDisplayName($user); + } else if( isset($_SESSION['display_name']) AND $_SESSION['display_name'] ) { + return $_SESSION['display_name']; + } + else{ + return false; + } + } + + /** * @brief Autogenerate a password * @returns string * @@ -383,8 +441,8 @@ class OC_User { /** * @brief Check if the password is correct - * @param $uid The username - * @param $password The password + * @param string $uid The username + * @param string $password The password * @returns string * * returns the path to the users home directory @@ -420,6 +478,24 @@ class OC_User { } /** + * @brief Get a list of all users display name + * @returns associative array with all display names (value) and corresponding uids (key) + * + * Get a list of all display names and user ids. + */ + public static function getDisplayNames($search = '', $limit = null, $offset = null) { + $displayNames = array(); + foreach (self::$_usedBackends as $backend) { + $backendDisplayNames = $backend->getDisplayNames($search, $limit, $offset); + if (is_array($backendDisplayNames)) { + $displayNames = array_merge($displayNames, $backendDisplayNames); + } + } + ksort($displayNames); + return $displayNames; + } + + /** * @brief check if a user exists * @param string $uid the username * @param string $excludingBackend (default none) diff --git a/lib/user/backend.php b/lib/user/backend.php index 2a95db93690..56fa3195978 100644 --- a/lib/user/backend.php +++ b/lib/user/backend.php @@ -35,6 +35,8 @@ define('OC_USER_BACKEND_CREATE_USER', 0x000001); define('OC_USER_BACKEND_SET_PASSWORD', 0x000010); define('OC_USER_BACKEND_CHECK_PASSWORD', 0x000100); define('OC_USER_BACKEND_GET_HOME', 0x001000); +define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x010000); +define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x010000); /** @@ -50,6 +52,8 @@ abstract class OC_User_Backend implements OC_User_Interface { OC_USER_BACKEND_SET_PASSWORD => 'setPassword', OC_USER_BACKEND_CHECK_PASSWORD => 'checkPassword', OC_USER_BACKEND_GET_HOME => 'getHome', + OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName', + OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName', ); /** @@ -120,4 +124,28 @@ abstract class OC_User_Backend implements OC_User_Interface { public function getHome($uid) { return false; } + + /** + * @brief get display name of the user + * @param $uid user ID of the user + * @return display name + */ + public function getDisplayName($uid) { + return $uid; + } + + /**
+ * @brief Get a list of all display names
+ * @returns array with all displayNames (value) and the correspondig uids (key)
+ *
+ * Get a list of all display names and user ids.
+ */
+ public function getDisplayNames($search = '', $limit = null, $offset = null) {
+ $displayNames = array(); + $users = $this->getUsers($search, $limit, $offset); + foreach ( $users as $user) { + $displayNames[$user] = $user; + } + return $displayNames;
+ } } diff --git a/lib/user/database.php b/lib/user/database.php index f33e338e2e4..8dfd9534a96 100644 --- a/lib/user/database.php +++ b/lib/user/database.php @@ -110,7 +110,72 @@ class OC_User_Database extends OC_User_Backend { return false; } } + + /**
+ * @brief Set display name
+ * @param $uid The username
+ * @param $displayName The new display name
+ * @returns true/false
+ *
+ * Change the display name of a user
+ */ + public function setDisplayName( $uid, $displayName ) { + if( $this->userExists($uid) ) {
+ $query = OC_DB::prepare( 'UPDATE `*PREFIX*users` SET `displayname` = ? WHERE `uid` = ?' );
+ $query->execute( array( $displayName, $uid ));
+ return true;
+ }else{
+ return false;
+ }
+ } + /**
+ * @brief get display name of the user
+ * @param $uid user ID of the user
+ * @return display name
+ */
+ public function getDisplayName($uid) {
+ if( $this->userExists($uid) ) { + $query = OC_DB::prepare( 'SELECT displayname FROM `*PREFIX*users` WHERE `uid` = ?' ); + $result = $query->execute( array( $uid ))->fetchAll(); + $displayName = trim($result[0]['displayname'], ' '); + if ( !empty($displayName) ) { + return $displayName; + } else { + return $uid; + } + }
+ } + + /**
+ * @brief Get a list of all display names
+ * @returns array with all displayNames (value) and the correspondig uids (key)
+ *
+ * Get a list of all display names and user ids.
+ */
+ public function getDisplayNames($search = '', $limit = null, $offset = null) { + $displayNames = array(); + $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users` WHERE LOWER(`displayname`) LIKE LOWER(?)', $limit, $offset);
+ $result = $query->execute(array($search.'%')); + $users = array();
+ while ($row = $result->fetchRow()) {
+ $displayNames[$row['uid']] = $row['displayname'];
+ } + + // let's see if we can also find some users who don't have a display name yet + $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users` WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset);
+ $result = $query->execute(array($search.'%')); + while ($row = $result->fetchRow()) {
+ $displayName = trim($row['displayname'], ' '); + if ( empty($displayName) ) {
+ $displayNames[$row['uid']] = $row['uid']; + }
+ } + +
+ return $displayNames;
+ } + /** * @brief Check if the password is correct * @param $uid The username diff --git a/lib/user/interface.php b/lib/user/interface.php index 3d9f4691f24..b4667633b50 100644 --- a/lib/user/interface.php +++ b/lib/user/interface.php @@ -57,4 +57,19 @@ interface OC_User_Interface { */ public function userExists($uid); + /** + * @brief get display name of the user + * @param $uid user ID of the user + * @return display name + */ + public function getDisplayName($uid); + + /** + * @brief Get a list of all display names + * @returns array with all displayNames (value) and the correspondig uids (key) + * + * Get a list of all display names and user ids. + */ + public function getDisplayNames($search = '', $limit = null, $offset = null); + }
\ No newline at end of file diff --git a/lib/util.php b/lib/util.php index 374baa43dbe..91970ab2b96 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, 9); } /** @@ -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 @@ -207,45 +186,20 @@ class OC_Util { in owncloud or disabling the appstore in the config file."); } } - $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - //check for correct file permissions - if(!stristr(PHP_OS, 'WIN')) { - $permissionsModHint="Please change the permissions to 0770 so that the directory cannot be listed by other users."; - $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)), -3); - if(substr($prems, -1)!='0') { - OC_Helper::chmodr($CONFIG_DATADIRECTORY, 0770); - clearstatcache(); - $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)), -3); - if(substr($prems, 2, 1)!='0') { - $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') is readable for other users<br/>', 'hint'=>$permissionsModHint); - } - } - if( OC_Config::getValue( "enablebackup", false )) { - $CONFIG_BACKUPDIRECTORY = OC_Config::getValue( "backupdirectory", OC::$SERVERROOT."/backup" ); - $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)), -3); - if(substr($prems, -1)!='0') { - OC_Helper::chmodr($CONFIG_BACKUPDIRECTORY, 0770); - clearstatcache(); - $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)), -3); - if(substr($prems, 2, 1)!='0') { - $errors[]=array('error'=>'Data directory ('.$CONFIG_BACKUPDIRECTORY.') is readable for other users<br/>', 'hint'=>$permissionsModHint); - } - } - } - }else{ - //TODO: permissions checks for windows hosts - } // Create root dir. if(!is_dir($CONFIG_DATADIRECTORY)) { $success=@mkdir($CONFIG_DATADIRECTORY); - if(!$success) { + if ($success) { + $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); + } else { $errors[]=array('error'=>"Can't create data directory (".$CONFIG_DATADIRECTORY.")", 'hint'=>"You can usually fix this by giving the webserver write access to the ownCloud directory '".OC::$SERVERROOT."' (in a terminal, use the command 'chown -R www-data:www-data /path/to/your/owncloud/install/data' "); } } else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) { $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud<br/>', 'hint'=>$permissionsHint); + } else { + $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); } - // check if all required php modules are present if(!class_exists('ZipArchive')) { $errors[]=array('error'=>'PHP module zip not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.'); @@ -296,6 +250,29 @@ class OC_Util { return $errors; } + /** + * Check for correct file permissions of data directory + * @return array arrays with error messages and hints + */ + public static function checkDataDirectoryPermissions($dataDirectory) { + $errors = array(); + if (stristr(PHP_OS, 'WIN')) { + //TODO: permissions checks for windows hosts + } else { + $permissionsModHint = 'Please change the permissions to 0770 so that the directory cannot be listed by other users.'; + $prems = substr(decoct(@fileperms($dataDirectory)), -3); + if (substr($prems, -1) != '0') { + OC_Helper::chmodr($dataDirectory, 0770); + clearstatcache(); + $prems = substr(decoct(@fileperms($dataDirectory)), -3); + if (substr($prems, 2, 1) != '0') { + $errors[] = array('error' => 'Data directory ('.$dataDirectory.') is readable for other users<br/>', 'hint' => $permissionsModHint); + } + } + } + return $errors; + } + public static function displayLoginPage($errors = array()) { $parameters = array(); foreach( $errors as $key => $value ) { @@ -333,7 +310,7 @@ class OC_Util { public static function checkLoggedIn() { // Check if we are a user if( !OC_User::isLoggedIn()) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', array('redirect_url' => $_SERVER["REQUEST_URI"]))); + header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', array('redirect_url' => OC_Request::requestUri()))); exit(); } } @@ -398,6 +375,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 +393,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 +413,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() { |