diff options
Diffstat (limited to 'lib')
31 files changed, 701 insertions, 303 deletions
diff --git a/lib/base.php b/lib/base.php index a022b9d005b..882b587a6fd 100644 --- a/lib/base.php +++ b/lib/base.php @@ -284,11 +284,26 @@ class OC { public static function checkUpgrade($showTemplate = true) { if (self::needUpgrade()) { if ($showTemplate && !OC_Config::getValue('maintenance', false)) { + $version = OC_Util::getVersion(); + $oldTheme = OC_Config::getValue('theme'); OC_Config::setValue('theme', ''); OC_Util::addScript('config'); // needed for web root OC_Util::addScript('update'); $tmpl = new OC_Template('', 'update.admin', 'guest'); $tmpl->assign('version', OC_Util::getVersionString()); + + // get third party apps + $apps = OC_App::getEnabledApps(); + $incompatibleApps = array(); + foreach ($apps as $appId) { + $info = OC_App::getAppInfo($appId); + if(!OC_App::isAppCompatible($version, $info)) { + $incompatibleApps[] = $info; + } + } + $tmpl->assign('appList', $incompatibleApps); + $tmpl->assign('productName', 'ownCloud'); // for now + $tmpl->assign('oldTheme', $oldTheme); $tmpl->printPage(); exit(); } else { @@ -637,8 +652,8 @@ class OC { */ 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'); + OC_Hook::connect('OC_Filesystem', 'write', 'OC\Files\Filesystem', 'isBlacklisted'); + OC_Hook::connect('OC_Filesystem', 'rename', 'OC\Files\Filesystem', 'isBlacklisted'); } /** @@ -884,30 +899,24 @@ class OC { if (defined("DEBUG") && DEBUG) { OC_Log::write('core', 'Trying to login from cookie', OC_Log::DEBUG); } - // confirm credentials in cookie - if (isset($_COOKIE['oc_token']) && OC_User::userExists($_COOKIE['oc_username'])) { - // delete outdated cookies + + if(OC_User::userExists($_COOKIE['oc_username'])) { self::cleanupLoginTokens($_COOKIE['oc_username']); - // get stored tokens - $tokens = OC_Preferences::getKeys($_COOKIE['oc_username'], 'login_token'); - // test cookies token against stored tokens - if (in_array($_COOKIE['oc_token'], $tokens, true)) { - // replace successfully used token with a new one - OC_Preferences::deleteKey($_COOKIE['oc_username'], 'login_token', $_COOKIE['oc_token']); - $token = OC_Util::generateRandomBytes(32); - OC_Preferences::setValue($_COOKIE['oc_username'], 'login_token', $token, time()); - OC_User::setMagicInCookie($_COOKIE['oc_username'], $token); - // login - OC_User::setUserId($_COOKIE['oc_username']); + // verify whether the supplied "remember me" token was valid + $granted = OC_User::loginWithCookie( + $_COOKIE['oc_username'], $_COOKIE['oc_token']); + if($granted === true) { OC_Util::redirectToDefaultPage(); // doesn't return } + OC_Log::write('core', 'Authentication cookie rejected for user ' . + $_COOKIE['oc_username'], OC_Log::WARN); // if you reach this point you have changed your password // or you are an attacker // we can not delete tokens here because users may reach // this point multiple times after a password change - OC_Log::write('core', 'Authentication cookie rejected for user ' . $_COOKIE['oc_username'], OC_Log::WARN); } + OC_User::unsetMagicInCookie(); return true; } diff --git a/lib/l10n/ast.php b/lib/l10n/ast.php index c6aa43e9b59..5819cf25639 100644 --- a/lib/l10n/ast.php +++ b/lib/l10n/ast.php @@ -1,15 +1,19 @@ <?php $TRANSLATIONS = array( +"You are accessing the server from an untrusted domain." => "Tas accediendo al sirvidor dende un dominiu non confiáu.", "App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "Nun pue instalase l'aplicación \"%s\" porque nun ye compatible con esta versión d'ownCloud.", "Help" => "Ayuda", "Personal" => "Personal", "Settings" => "Axustes", "Users" => "Usuarios", +"Admin" => "Almin", "Failed to upgrade \"%s\"." => "Fallu al anovar \"%s\".", "Unknown filetype" => "Triba de ficheru desconocida", "Invalid image" => "Imaxe inválida", "web services under your control" => "servicios web baxo'l to control", +"ZIP download is turned off." => "Tan deshabilitaes les descargues de ZIP.", "Files need to be downloaded one by one." => "Los ficheros necesiten descargase ún a ún", +"Selected files too large to generate zip file." => "Los ficheros esbillaos son milenta grandes pa xenerar un ficheru zip.", "App does not provide an info.xml file" => "L'aplicación nun apurre un ficheru info.xml", "App can't be installed because it is not compatible with this version of ownCloud" => "Nun pue instalase l'aplicación porque nun ye compatible con esta versión d'ownCloud.", "Can't create app folder. Please fix permissions. %s" => "Nun pue crease la carpeta de l'aplicación. Por favor, igua los permisos. %s", @@ -23,8 +27,9 @@ $TRANSLATIONS = array( "Oracle connection could not be established" => "Nun pudo afitase la conexón d'Oracle", "Set an admin username." => "Afitar nome d'usuariu p'almin", "Set an admin password." => "Afitar contraseña p'almin", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "El sirvidor web entá nun ta configurado pa permitir la sincronización de ficheros yá que la interface WebDAV paez nun tar funcionando.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "El to sirvidor web entá nun ta configuráu afayadizamente pa permitir la sincronización de ficheros porque la interfaz WebDAV paez tar rota.", "%s shared »%s« with you" => "%s compartió »%s« contigo", +"You need to provide a password to create a public link, only protected links are allowed" => "Necesites apurrir una contraseña pa crear un enllaz públicu, namái tan permitíos los enllaces protexíos", "Share type %s is not valid for %s" => "La triba de compartición %s nun ye válida pa %s", "Sharing backend %s not found" => "Nun s'alcontró'l botón de compartición %s", "Sharing backend for %s not found" => "Nun s'alcontró'l botón de partición pa %s", diff --git a/lib/l10n/el.php b/lib/l10n/el.php index 716b2694d45..546fb6347b5 100644 --- a/lib/l10n/el.php +++ b/lib/l10n/el.php @@ -59,12 +59,14 @@ $TRANSLATIONS = array( "Please double check the <a href='%s'>installation guides</a>." => "Ελέγξτε ξανά τις <a href='%s'>οδηγίες εγκατάστασης</a>.", "%s shared »%s« with you" => "Ο %s διαμοιράστηκε μαζί σας το »%s«", "Sharing %s failed, because the file does not exist" => "Ο διαμοιρασμός του %s απέτυχε, γιατί το αρχείο δεν υπάρχει", +"You are not allowed to share %s" => "Δεν επιτρέπεται να διαμοιράσετε τον πόρο %s", "Sharing %s failed, because the user %s is the item owner" => "Ο διαμοιρασμός του %s απέτυχε, γιατί ο χρήστης %s είναι ο ιδιοκτήτης του αντικειμένου", "Sharing %s failed, because the user %s does not exist" => "Ο διαμοιρασμός του %s απέτυχε, γιατί ο χρήστης %s δεν υπάρχει", "Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" => "Ο διαμοιρασμός του %s απέτυχε, γιατί ο χρήστης %s δεν είναι μέλος καμίας ομάδας στην οποία ο χρήστης %s είναι μέλος", "Sharing %s failed, because this item is already shared with %s" => "Ο διαμοιρασμός του %s απέτυχε, γιατί το αντικείμενο είναι διαμοιρασμένο ήδη με τον χρήστη %s", "Sharing %s failed, because the group %s does not exist" => "Ο διαμοιρασμός του %s απέτυχε, γιατί η ομάδα χρηστών %s δεν υπάρχει", "Sharing %s failed, because %s is not a member of the group %s" => "Ο διαμοιρασμός του %s απέτυχε, γιατί ο χρήστης %s δεν είναι μέλος της ομάδας %s", +"You need to provide a password to create a public link, only protected links are allowed" => "Πρέπει να εισάγετε έναν κωδικό για να δημιουργήσετε έναν δημόσιο σύνδεσμο. Μόνο προστατευμένοι σύνδεσμοι επιτρέπονται", "Sharing %s failed, because sharing with links is not allowed" => "Ο διαμοιρασμός του %s απέτυχε, γιατί δεν επιτρέπεται ο διαμοιρασμός με συνδέσμους", "Share type %s is not valid for %s" => "Ο τύπος διαμοιρασμού %s δεν είναι έγκυρος για το %s", "Setting permissions for %s failed, because the permissions exceed permissions granted to %s" => "Ο ορισμός δικαιωμάτων για το %s απέτυχε, γιατί τα δικαιώματα υπερτερούν αυτά που είναι ορισμένα για το %s", diff --git a/lib/l10n/en_GB.php b/lib/l10n/en_GB.php index 5aa4f0f356e..9a5e9bb831f 100644 --- a/lib/l10n/en_GB.php +++ b/lib/l10n/en_GB.php @@ -59,6 +59,7 @@ $TRANSLATIONS = array( "Please double check the <a href='%s'>installation guides</a>." => "Please double check the <a href='%s'>installation guides</a>.", "%s shared »%s« with you" => "%s shared \"%s\" with you", "Sharing %s failed, because the file does not exist" => "Sharing %s failed, because the file does not exist", +"You are not allowed to share %s" => "You are not allowed to share %s", "Sharing %s failed, because the user %s is the item owner" => "Sharing %s failed, because the user %s is the item owner", "Sharing %s failed, because the user %s does not exist" => "Sharing %s failed, because the user %s does not exist", "Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" => "Sharing %s failed, because the user %s is not a member of any groups that %s is a member of", diff --git a/lib/l10n/et_EE.php b/lib/l10n/et_EE.php index 079ff3ba472..4c18742345c 100644 --- a/lib/l10n/et_EE.php +++ b/lib/l10n/et_EE.php @@ -1,6 +1,7 @@ <?php $TRANSLATIONS = array( "You are accessing the server from an untrusted domain." => "Sa kasutad serverit usalduseta asukohast", +"Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domain\" setting in config/config.php. An example configuration is provided in config/config.sample.php." => "Palun võta ühendust oma saidi administraatoriga. Kui sa oled ise administraator, siis seadista failis config/config.php sätet \"trusted_domain\". Näidis seadistused leiad failist config/config.sample.php.", "App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "Rakendit \"%s\" ei saa paigaldada, kuna see pole ühilduv selle ownCloud versiooniga.", "No app name specified" => "Ühegi rakendi nime pole määratletud", "Help" => "Abiinfo", @@ -58,6 +59,7 @@ $TRANSLATIONS = array( "Please double check the <a href='%s'>installation guides</a>." => "Palun tutvu veelkord <a href='%s'>paigalduse juhenditega</a>.", "%s shared »%s« with you" => "%s jagas sinuga »%s«", "Sharing %s failed, because the file does not exist" => "%s jagamine ebaõnnestus, kuna faili pole olemas", +"You are not allowed to share %s" => "Sul pole lubatud %s jagada", "Sharing %s failed, because the user %s is the item owner" => "%s jagamine ebaõnnestus, kuna kuna kasutaja %s on üksuse omanik", "Sharing %s failed, because the user %s does not exist" => "%s jagamine ebaõnnestus, kuna kasutajat %s pole olemas", "Sharing %s failed, because the user %s is not a member of any groups that %s is a member of" => "%s jagamine ebaõnnestus, kuna kasutaja %s pole ühegi grupi liige, millede liige on %s", diff --git a/lib/private/app.php b/lib/private/app.php index 50065197eb4..ea0453e58ea 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -889,8 +889,14 @@ class OC_App{ * ownCloud version. disable them if not. * This is important if you upgrade ownCloud and have non ported 3rd * party apps installed. + * + * @param array $apps optional app id list to check, uses all enabled apps + * when not specified + * + * @return array containing the list of ids of the disabled apps */ public static function checkAppsRequirements($apps = array()) { + $disabledApps = array(); if (empty($apps)) { $apps = OC_App::getEnabledApps(); } @@ -905,8 +911,10 @@ class OC_App{ OC_Log::ERROR); OC_App::disable( $app ); OC_Hook::emit('update', 'success', 'Disabled '.$info['name'].' app because it is not compatible'); + $disabledApps[] = $app; } } + return $disabledApps; } /** diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php index ee492b8a9e5..61a2333ecee 100644 --- a/lib/private/appframework/dependencyinjection/dicontainer.php +++ b/lib/private/appframework/dependencyinjection/dicontainer.php @@ -83,8 +83,8 @@ class DIContainer extends SimpleContainer implements IAppContainer{ $this['Dispatcher'] = $this->share(function($c) { return new Dispatcher( - $c['Protocol'], - $c['MiddlewareDispatcher'], + $c['Protocol'], + $c['MiddlewareDispatcher'], $c['ControllerMethodReflector'], $c['Request'] ); @@ -97,9 +97,14 @@ class DIContainer extends SimpleContainer implements IAppContainer{ $app = $this; $this['SecurityMiddleware'] = $this->share(function($c) use ($app){ return new SecurityMiddleware( - $app, - $c['Request'], - $c['ControllerMethodReflector'] + $c['Request'], + $c['ControllerMethodReflector'], + $app->getServer()->getNavigationManager(), + $app->getServer()->getURLGenerator(), + $app->getServer()->getLogger(), + $c['AppName'], + $app->isLoggedIn(), + $app->isAdminUser() ); }); diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php index d7e398fe445..5b56210024d 100644 --- a/lib/private/appframework/middleware/security/securitymiddleware.php +++ b/lib/private/appframework/middleware/security/securitymiddleware.php @@ -30,8 +30,10 @@ use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Middleware; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\JSONResponse; -use OCP\AppFramework\IAppContainer; +use OCP\INavigationManager; +use OCP\IURLGenerator; use OCP\IRequest; +use OCP\ILogger; /** @@ -42,31 +44,41 @@ use OCP\IRequest; */ class SecurityMiddleware extends Middleware { - /** - * @var \OCP\AppFramework\IAppContainer - */ - private $app; - - /** - * @var \OCP\IRequest - */ + private $navigationManager; private $request; - - /** - * @var OC\AppFramework\Utility\ControllerMethodReflector - */ private $reflector; + private $appName; + private $urlGenerator; + private $logger; + private $isLoggedIn; + private $isAdminUser; /** - * @param IAppContainer $app * @param IRequest $request * @param ControllerMethodReflector $reflector + * @param INavigationManager $navigationManager + * @param IURLGenerator $urlGenerator + * @param ILogger $logger + * @param string $appName + * @param bool $isLoggedIn + * @param bool $isAdminUser */ - public function __construct(IAppContainer $app, IRequest $request, - ControllerMethodReflector $reflector){ - $this->app = $app; + public function __construct(IRequest $request, + ControllerMethodReflector $reflector, + INavigationManager $navigationManager, + IURLGenerator $urlGenerator, + ILogger $logger, + $appName, + $isLoggedIn, + $isAdminUser){ + $this->navigationManager = $navigationManager; $this->request = $request; $this->reflector = $reflector; + $this->appName = $appName; + $this->urlGenerator = $urlGenerator; + $this->logger = $logger; + $this->isLoggedIn = $isLoggedIn; + $this->isAdminUser = $isAdminUser; } @@ -82,17 +94,17 @@ class SecurityMiddleware extends Middleware { // this will set the current navigation entry of the app, use this only // for normal HTML requests and not for AJAX requests - $this->app->getServer()->getNavigationManager()->setActiveEntry($this->app->getAppName()); + $this->navigationManager->setActiveEntry($this->appName); // security checks $isPublicPage = $this->reflector->hasAnnotation('PublicPage'); if(!$isPublicPage) { - if(!$this->app->isLoggedIn()) { + if(!$this->isLoggedIn) { throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); } if(!$this->reflector->hasAnnotation('NoAdminRequired')) { - if(!$this->app->isAdminUser()) { + if(!$this->isAdminUser) { throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); } } @@ -126,13 +138,13 @@ class SecurityMiddleware extends Middleware { array('message' => $exception->getMessage()), $exception->getCode() ); - $this->app->log($exception->getMessage(), 'debug'); + $this->logger->debug($exception->getMessage()); } else { // TODO: replace with link to route - $url = $this->app->getServer()->getURLGenerator()->getAbsoluteURL('index.php'); + $url = $this->urlGenerator->getAbsoluteURL('index.php'); $response = new RedirectResponse($url); - $this->app->log($exception->getMessage(), 'debug'); + $this->logger->debug($exception->getMessage()); } return $response; diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index ab9d3e47d0e..8a16ba55e7a 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -156,7 +156,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D /** * Returns the size of the node, in bytes * - * @return int + * @return int|float */ public function getSize() { return $this->info->getSize(); diff --git a/lib/private/connector/sabre/server.php b/lib/private/connector/sabre/server.php index 2660b043f46..cf28b11163f 100644 --- a/lib/private/connector/sabre/server.php +++ b/lib/private/connector/sabre/server.php @@ -170,7 +170,7 @@ class OC_Connector_Sabre_Server extends Sabre_DAV_Server { if ($node instanceof Sabre_DAV_IFile) { $size = $node->getSize(); if (!is_null($size)) { - $newProperties[200][$prop] = (int)$node->getSize(); + $newProperties[200][$prop] = 0 + $size; } } break; diff --git a/lib/private/contactsmanager.php b/lib/private/contactsmanager.php index 26264d4e988..338cc048651 100644 --- a/lib/private/contactsmanager.php +++ b/lib/private/contactsmanager.php @@ -34,12 +34,13 @@ namespace OC { * @return array an array of contacts which are arrays of key-value-pairs */ public function search($pattern, $searchProperties = array(), $options = array()) { + $this->loadAddressBooks(); $result = array(); - foreach($this->address_books as $address_book) { - $r = $address_book->search($pattern, $searchProperties, $options); + foreach($this->addressBooks as $addressBook) { + $r = $addressBook->search($pattern, $searchProperties, $options); $contacts = array(); foreach($r as $c){ - $c['addressbook-key'] = $address_book->getKey(); + $c['addressbook-key'] = $addressBook->getKey(); $contacts[] = $c; } $result = array_merge($result, $contacts); @@ -52,18 +53,20 @@ namespace OC { * This function can be used to delete the contact identified by the given id * * @param object $id the unique identifier to a contact - * @param string $address_book_key identifier of the address book in which the contact shall be deleted + * @param string $addressBookKey identifier of the address book in which the contact shall be deleted * @return bool successful or not */ - public function delete($id, $address_book_key) { - if (!array_key_exists($address_book_key, $this->address_books)) + public function delete($id, $addressBookKey) { + $addressBook = $this->getAddressBook($addressBookKey); + if (!$addressBook) { return null; + } - $address_book = $this->address_books[$address_book_key]; - if ($address_book->getPermissions() & \OCP\PERMISSION_DELETE) + if ($addressBook->getPermissions() & \OCP\PERMISSION_DELETE) { return null; + } - return $address_book->delete($id); + return $addressBook->delete($id); } /** @@ -71,19 +74,20 @@ namespace OC { * Otherwise the contact will be updated by replacing the entire data set. * * @param array $properties this array if key-value-pairs defines a contact - * @param string $address_book_key identifier of the address book in which the contact shall be created or updated - * @return array an array representing the contact just created or updated + * @param string $addressBookKey identifier of the address book in which the contact shall be created or updated + * @return array representing the contact just created or updated */ - public function createOrUpdate($properties, $address_book_key) { - - if (!array_key_exists($address_book_key, $this->address_books)) + public function createOrUpdate($properties, $addressBookKey) { + $addressBook = $this->getAddressBook($addressBookKey); + if (!$addressBook) { return null; + } - $address_book = $this->address_books[$address_book_key]; - if ($address_book->getPermissions() & \OCP\PERMISSION_CREATE) + if ($addressBook->getPermissions() & \OCP\PERMISSION_CREATE) { return null; + } - return $address_book->createOrUpdate($properties); + return $addressBook->createOrUpdate($properties); } /** @@ -92,30 +96,31 @@ namespace OC { * @return bool true if enabled, false if not */ public function isEnabled() { - return !empty($this->address_books); + return !empty($this->addressBooks) || !empty($this->addressBookLoaders); } /** - * @param \OCP\IAddressBook $address_book + * @param \OCP\IAddressBook $addressBook */ - public function registerAddressBook(\OCP\IAddressBook $address_book) { - $this->address_books[$address_book->getKey()] = $address_book; + public function registerAddressBook(\OCP\IAddressBook $addressBook) { + $this->addressBooks[$addressBook->getKey()] = $addressBook; } /** - * @param \OCP\IAddressBook $address_book + * @param \OCP\IAddressBook $addressBook */ - public function unregisterAddressBook(\OCP\IAddressBook $address_book) { - unset($this->address_books[$address_book->getKey()]); + public function unregisterAddressBook(\OCP\IAddressBook $addressBook) { + unset($this->addressBooks[$addressBook->getKey()]); } /** * @return array */ public function getAddressBooks() { + $this->loadAddressBooks(); $result = array(); - foreach($this->address_books as $address_book) { - $result[$address_book->getKey()] = $address_book->getDisplayName(); + foreach($this->addressBooks as $addressBook) { + $result[$addressBook->getKey()] = $addressBook->getDisplayName(); } return $result; @@ -125,26 +130,56 @@ namespace OC { * removes all registered address book instances */ public function clear() { - $this->address_books = array(); + $this->addressBooks = array(); + $this->addressBookLoaders = array(); } /** * @var \OCP\IAddressBook[] which holds all registered address books */ - private $address_books = array(); + private $addressBooks = array(); + + /** + * @var \Closure[] to call to load/register address books + */ + private $addressBookLoaders = array(); /** * In order to improve lazy loading a closure can be registered which will be called in case * address books are actually requested * - * @param string $key * @param \Closure $callable */ - function register($key, \Closure $callable) + public function register(\Closure $callable) { - // - //TODO: implement me - // + $this->addressBookLoaders[] = $callable; + } + + /** + * Get (and load when needed) the address book for $key + * + * @param string $addressBookKey + * @return \OCP\IAddressBook + */ + protected function getAddressBook($addressBookKey) + { + $this->loadAddressBooks(); + if (!array_key_exists($addressBookKey, $this->addressBooks)) { + return null; + } + + return $this->addressBooks[$addressBookKey]; + } + + /** + * Load all address books registered with 'register' + */ + protected function loadAddressBooks() + { + foreach($this->addressBookLoaders as $callable) { + $callable($this); + } + $this->addressBookLoaders = array(); } } } diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 3e4f6dfb132..59963f41e3d 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -142,11 +142,11 @@ class Cache { } else { //fix types $data['fileid'] = (int)$data['fileid']; - $data['size'] = (int)$data['size']; + $data['size'] = 0 + $data['size']; $data['mtime'] = (int)$data['mtime']; $data['storage_mtime'] = (int)$data['storage_mtime']; $data['encrypted'] = (bool)$data['encrypted']; - $data['unencrypted_size'] = (int)$data['unencrypted_size']; + $data['unencrypted_size'] = 0 + $data['unencrypted_size']; $data['storage'] = $this->storageId; $data['mimetype'] = $this->getMimetype($data['mimetype']); $data['mimepart'] = $this->getMimetype($data['mimepart']); @@ -532,9 +532,9 @@ class Cache { $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { list($sum, $min, $unencryptedSum) = array_values($row); - $sum = (int)$sum; - $min = (int)$min; - $unencryptedSum = (int)$unencryptedSum; + $sum = 0 + $sum; + $min = 0 + $min; + $unencryptedSum = 0 + $unencryptedSum; if ($min === -1) { $totalSize = $min; } else { diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php index 2326c46e8d0..f61769f0b9b 100644 --- a/lib/private/files/cache/homecache.php +++ b/lib/private/files/cache/homecache.php @@ -36,8 +36,10 @@ class HomeCache extends Cache { $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { list($sum, $unencryptedSum) = array_values($row); - $totalSize = (int)$sum; - $unencryptedSize = (int)$unencryptedSum; + $totalSize = 0 + $sum; + $unencryptedSize = 0 + $unencryptedSum; + $entry['size'] += 0; + $entry['unencrypted_size'] += 0; if ($entry['size'] !== $totalSize) { $this->update($id, array('size' => $totalSize)); } diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index 6dceaf13ec3..b97070fcdf0 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -27,22 +27,22 @@ class Scanner extends BasicEmitter { /** * @var \OC\Files\Storage\Storage $storage */ - private $storage; + protected $storage; /** * @var string $storageId */ - private $storageId; + protected $storageId; /** * @var \OC\Files\Cache\Cache $cache */ - private $cache; + protected $cache; /** * @var \OC\Files\Cache\Permissions $permissionsCache */ - private $permissionsCache; + protected $permissionsCache; /** * @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache diff --git a/lib/private/files/mount/mount.php b/lib/private/files/mount/mount.php index d4a4e186fb9..7c40853ac95 100644 --- a/lib/private/files/mount/mount.php +++ b/lib/private/files/mount/mount.php @@ -161,6 +161,6 @@ class Mount { * @param callable $wrapper */ public function wrapStorage($wrapper) { - $this->storage = $wrapper($this->mountPoint, $this->storage); + $this->storage = $wrapper($this->mountPoint, $this->getStorage()); } } diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index cfca8ca008c..6b11603323a 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -7,6 +7,8 @@ */ namespace OC\Files\Storage; + +use OC\Files\Filesystem; use OC\Files\Cache\Watcher; /** @@ -20,7 +22,6 @@ use OC\Files\Cache\Watcher; * Some \OC\Files\Storage\Common methods call functions which are first defined * in classes which extend it, e.g. $this->stat() . */ - abstract class Common implements \OC\Files\Storage\Storage { protected $cache; protected $scanner; @@ -36,6 +37,22 @@ abstract class Common implements \OC\Files\Storage\Storage { public function __construct($parameters) { } + /** + * Remove a file of folder + * + * @param string $path + * @return bool + */ + protected function remove($path) { + if ($this->is_dir($path)) { + return $this->rmdir($path); + } else if ($this->is_file($path)) { + return $this->unlink($path); + } else { + return false; + } + } + public function is_dir($path) { return $this->filetype($path) == 'dir'; } @@ -137,20 +154,33 @@ abstract class Common implements \OC\Files\Storage\Storage { } public function rename($path1, $path2) { - if ($this->copy($path1, $path2)) { - $this->removeCachedFile($path1); - return $this->unlink($path1); - } else { - return false; - } + $this->remove($path2); + + $this->removeCachedFile($path1); + return $this->copy($path1, $path2) and $this->remove($path1); } public function copy($path1, $path2) { - $source = $this->fopen($path1, 'r'); - $target = $this->fopen($path2, 'w'); - list($count, $result) = \OC_Helper::streamCopy($source, $target); - $this->removeCachedFile($path2); - return $result; + if ($this->is_dir($path1)) { + $this->remove($path2); + $dir = $this->opendir($path1); + $this->mkdir($path2); + while ($file = readdir($dir)) { + if (!Filesystem::isIgnoredDir($file)) { + if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) { + return false; + } + } + } + closedir($dir); + return true; + } else { + $source = $this->fopen($path1, 'r'); + $target = $this->fopen($path2, 'w'); + list(, $result) = \OC_Helper::streamCopy($source, $target); + $this->removeCachedFile($path2); + return $result; + } } public function getMimeType($path) { @@ -382,4 +412,14 @@ abstract class Common implements \OC\Files\Storage\Storage { protected function removeCachedFile($path) { unset($this->cachedFiles[$path]); } + + /** + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class + * + * @param string $class + * @return bool + */ + public function instanceOfStorage($class) { + return is_a($this, $class); + } } diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php index de940fc7cdb..e33747bbd52 100644 --- a/lib/private/files/storage/local.php +++ b/lib/private/files/storage/local.php @@ -89,11 +89,10 @@ if (\OC_Util::runningOnWindows()) { public function stat($path) { $fullPath = $this->datadir . $path; $statResult = stat($fullPath); - - if ($statResult['size'] < 0) { - $size = self::getFileSizeFromOS($fullPath); - $statResult['size'] = $size; - $statResult[7] = $size; + if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) { + $filesize = $this->filesize($path); + $statResult['size'] = $filesize; + $statResult[7] = $filesize; } return $statResult; } @@ -109,15 +108,13 @@ if (\OC_Util::runningOnWindows()) { public function filesize($path) { if ($this->is_dir($path)) { return 0; - } else { - $fullPath = $this->datadir . $path; - $fileSize = filesize($fullPath); - if ($fileSize < 0) { - return self::getFileSizeFromOS($fullPath); - } - - return $fileSize; } + $fullPath = $this->datadir . $path; + if (PHP_INT_SIZE === 4) { + $helper = new \OC\LargeFileHelper; + return $helper->getFilesize($fullPath); + } + return filesize($fullPath); } public function isReadable($path) { @@ -164,7 +161,14 @@ if (\OC_Util::runningOnWindows()) { } public function unlink($path) { - return $this->delTree($path); + if ($this->is_dir($path)) { + return $this->rmdir($path); + } else if ($this->is_file($path)) { + return unlink($this->datadir . $path); + } else { + return false; + } + } public function rename($path1, $path2) { @@ -177,20 +181,21 @@ if (\OC_Util::runningOnWindows()) { return false; } - if ($return = rename($this->datadir . $path1, $this->datadir . $path2)) { + if ($this->is_dir($path2)) { + $this->rmdir($path2); + } else if ($this->is_file($path2)) { + $this->unlink($path2); } - return $return; + + return rename($this->datadir . $path1, $this->datadir . $path2); } public function copy($path1, $path2) { - if ($this->is_dir($path2)) { - if (!$this->file_exists($path2)) { - $this->mkdir($path2); - } - $source = substr($path1, strrpos($path1, '/') + 1); - $path2 .= $source; + if ($this->is_dir($path1)) { + return parent::copy($path1, $path2); + } else { + return copy($this->datadir . $path1, $this->datadir . $path2); } - return copy($this->datadir . $path1, $this->datadir . $path2); } public function fopen($path, $mode) { @@ -212,59 +217,6 @@ if (\OC_Util::runningOnWindows()) { return $return; } - /** - * @param string $dir - */ - private function delTree($dir) { - $dirRelative = $dir; - $dir = $this->datadir . $dir; - if (!file_exists($dir)) return true; - if (!is_dir($dir) || is_link($dir)) return unlink($dir); - foreach (scandir($dir) as $item) { - if ($item == '.' || $item == '..') continue; - if (is_file($dir . '/' . $item)) { - if (unlink($dir . '/' . $item)) { - } - } elseif (is_dir($dir . '/' . $item)) { - if (!$this->delTree($dirRelative . "/" . $item)) { - return false; - }; - } - } - if ($return = rmdir($dir)) { - } - return $return; - } - - /** - * @param string $fullPath - */ - private static function getFileSizeFromOS($fullPath) { - $name = strtolower(php_uname('s')); - // Windows OS: we use COM to access the filesystem - if (strpos($name, 'win') !== false) { - if (class_exists('COM')) { - $fsobj = new \COM("Scripting.FileSystemObject"); - $f = $fsobj->GetFile($fullPath); - return $f->Size; - } - } else if (strpos($name, 'bsd') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); - } - } else if (strpos($name, 'linux') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); - } - } else { - \OC_Log::write('core', - 'Unable to determine file size of "' . $fullPath . '". Unknown OS: ' . $name, - \OC_Log::ERROR); - } - - return 0; - } - public function hash($type, $path, $raw = false) { return hash_file($type, $this->datadir . $path, $raw); } diff --git a/lib/private/files/storage/mappedlocal.php b/lib/private/files/storage/mappedlocal.php index 07691661644..ea4deaa66e8 100644 --- a/lib/private/files/storage/mappedlocal.php +++ b/lib/private/files/storage/mappedlocal.php @@ -10,29 +10,33 @@ namespace OC\Files\Storage; /** * for local filestore, we only have to map the paths */ -class MappedLocal extends \OC\Files\Storage\Common{ +class MappedLocal extends \OC\Files\Storage\Common { protected $datadir; private $mapper; public function __construct($arguments) { - $this->datadir=$arguments['datadir']; - if(substr($this->datadir, -1)!=='/') { - $this->datadir.='/'; + $this->datadir = $arguments['datadir']; + if (substr($this->datadir, -1) !== '/') { + $this->datadir .= '/'; } - $this->mapper= new \OC\Files\Mapper($this->datadir); + $this->mapper = new \OC\Files\Mapper($this->datadir); } + public function __destruct() { if (defined('PHPUNIT_RUN')) { $this->mapper->removePath($this->datadir, true, true); } } - public function getId(){ - return 'local::'.$this->datadir; + + public function getId() { + return 'local::' . $this->datadir; } + public function mkdir($path) { return @mkdir($this->buildPath($path), 0777, true); } + public function rmdir($path) { try { $it = new \RecursiveIteratorIterator( @@ -68,9 +72,10 @@ class MappedLocal extends \OC\Files\Storage\Common{ return false; } } + public function opendir($path) { $files = array('.', '..'); - $physicalPath= $this->buildPath($path); + $physicalPath = $this->buildPath($path); $logicalPath = $this->mapper->physicalToLogic($physicalPath); $dh = opendir($physicalPath); @@ -80,7 +85,7 @@ class MappedLocal extends \OC\Files\Storage\Common{ continue; } - $logicalFilePath = $this->mapper->physicalToLogic($physicalPath.'/'.$file); + $logicalFilePath = $this->mapper->physicalToLogic($physicalPath . '/' . $file); $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath); $file = $this->stripLeading($file); @@ -88,121 +93,151 @@ class MappedLocal extends \OC\Files\Storage\Common{ } } - \OC\Files\Stream\Dir::register('local-win32'.$path, $files); - return opendir('fakedir://local-win32'.$path); + \OC\Files\Stream\Dir::register('local-win32' . $path, $files); + return opendir('fakedir://local-win32' . $path); } + public function is_dir($path) { - if(substr($path, -1)=='/') { - $path=substr($path, 0, -1); + if (substr($path, -1) == '/') { + $path = substr($path, 0, -1); } return is_dir($this->buildPath($path)); } + public function is_file($path) { return is_file($this->buildPath($path)); } + public function stat($path) { $fullPath = $this->buildPath($path); $statResult = stat($fullPath); - - if ($statResult['size'] < 0) { - $size = self::getFileSizeFromOS($fullPath); - $statResult['size'] = $size; - $statResult[7] = $size; + if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) { + $filesize = $this->filesize($path); + $statResult['size'] = $filesize; + $statResult[7] = $filesize; } return $statResult; } + public function filetype($path) { - $filetype=filetype($this->buildPath($path)); - if($filetype=='link') { - $filetype=filetype(realpath($this->buildPath($path))); + $filetype = filetype($this->buildPath($path)); + if ($filetype == 'link') { + $filetype = filetype(realpath($this->buildPath($path))); } return $filetype; } + public function filesize($path) { - if($this->is_dir($path)) { + if ($this->is_dir($path)) { return 0; - }else{ - $fullPath = $this->buildPath($path); - $fileSize = filesize($fullPath); - if ($fileSize < 0) { - return self::getFileSizeFromOS($fullPath); - } - - return $fileSize; } + $fullPath = $this->buildPath($path); + if (PHP_INT_SIZE === 4) { + $helper = new \OC\LargeFileHelper; + return $helper->getFilesize($fullPath); + } + return filesize($fullPath); } + public function isReadable($path) { return is_readable($this->buildPath($path)); } + public function isUpdatable($path) { return is_writable($this->buildPath($path)); } + public function file_exists($path) { return file_exists($this->buildPath($path)); } + public function filemtime($path) { return filemtime($this->buildPath($path)); } - public function touch($path, $mtime=null) { + + public function touch($path, $mtime = null) { // sets the modification time of the file to the given value. // If mtime is nil the current time is set. // note that the access time of the file always changes to the current time. - if(!is_null($mtime)) { - $result=touch( $this->buildPath($path), $mtime ); - }else{ - $result=touch( $this->buildPath($path)); + if (!is_null($mtime)) { + $result = touch($this->buildPath($path), $mtime); + } else { + $result = touch($this->buildPath($path)); } - if( $result ) { - clearstatcache( true, $this->buildPath($path) ); + if ($result) { + clearstatcache(true, $this->buildPath($path)); } return $result; } + public function file_get_contents($path) { return file_get_contents($this->buildPath($path)); } + public function file_put_contents($path, $data) { return file_put_contents($this->buildPath($path), $data); } + public function unlink($path) { return $this->delTree($path); } + 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); + if (!$this->file_exists($path1)) { + \OC_Log::write('core', 'unable to rename, file does not exists : ' . $path1, \OC_Log::ERROR); return false; } + if ($this->is_dir($path2)) { + $this->rmdir($path2); + } else if ($this->is_file($path2)) { + $this->unlink($path2); + } + $physicPath1 = $this->buildPath($path1); $physicPath2 = $this->buildPath($path2); - if($return=rename($physicPath1, $physicPath2)) { + if ($return = rename($physicPath1, $physicPath2)) { // mapper needs to create copies or all children $this->copyMapping($path1, $path2); $this->cleanMapper($physicPath1, false, true); } return $return; } + public function copy($path1, $path2) { - if($this->is_dir($path2)) { - if(!$this->file_exists($path2)) { - $this->mkdir($path2); + if ($this->is_dir($path1)) { + if ($this->is_dir($path2)) { + $this->rmdir($path2); + } else if ($this->is_file($path2)) { + $this->unlink($path2); } - $source=substr($path1, strrpos($path1, '/')+1); - $path2.=$source; - } - if($return=copy($this->buildPath($path1), $this->buildPath($path2))) { - // mapper needs to create copies or all children - $this->copyMapping($path1, $path2); + $dir = $this->opendir($path1); + $this->mkdir($path2); + while ($file = readdir($dir)) { + if (!\OC\Files\Filesystem::isIgnoredDir($file)) { + if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) { + return false; + } + } + } + closedir($dir); + return true; + } else { + if ($return = copy($this->buildPath($path1), $this->buildPath($path2))) { + $this->copyMapping($path1, $path2); + } + return $return; } - return $return; } + public function fopen($path, $mode) { - if($return=fopen($this->buildPath($path), $mode)) { - switch($mode) { + if ($return = fopen($this->buildPath($path), $mode)) { + switch ($mode) { case 'r': break; case 'r+': @@ -223,15 +258,15 @@ class MappedLocal extends \OC\Files\Storage\Common{ * @param string $dir */ private function delTree($dir, $isLogicPath=true) { - $dirRelative=$dir; + $dirRelative = $dir; if ($isLogicPath) { - $dir=$this->buildPath($dir); + $dir = $this->buildPath($dir); } if (!file_exists($dir)) { return true; } if (!is_dir($dir) || is_link($dir)) { - if($return=unlink($dir)) { + if ($return = unlink($dir)) { $this->cleanMapper($dir, false); return $return; } @@ -240,52 +275,23 @@ class MappedLocal extends \OC\Files\Storage\Common{ if ($item == '.' || $item == '..') { continue; } - if(is_file($dir.'/'.$item)) { - if(unlink($dir.'/'.$item)) { - $this->cleanMapper($dir.'/'.$item, false); + if (is_file($dir . '/' . $item)) { + if (unlink($dir . '/' . $item)) { + $this->cleanMapper($dir . '/' . $item, false); } - }elseif(is_dir($dir.'/'.$item)) { - if (!$this->delTree($dir. "/" . $item, false)) { + } elseif (is_dir($dir . '/' . $item)) { + if (!$this->delTree($dir . "/" . $item, false)) { return false; }; } } - if($return=rmdir($dir)) { + if ($return = rmdir($dir)) { $this->cleanMapper($dir, false); } return $return; } - /** - * @param string $fullPath - */ - private static function getFileSizeFromOS($fullPath) { - $name = strtolower(php_uname('s')); - // Windows OS: we use COM to access the filesystem - if (strpos($name, 'win') !== false) { - if (class_exists('COM')) { - $fsobj = new \COM("Scripting.FileSystemObject"); - $f = $fsobj->GetFile($fullPath); - return $f->Size; - } - } else if (strpos($name, 'bsd') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); - } - } else if (strpos($name, 'linux') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); - } - } else { - \OC_Log::write('core', - 'Unable to determine file size of "'.$fullPath.'". Unknown OS: '.$name, - \OC_Log::ERROR); - } - - return 0; - } - - public function hash($type, $path, $raw=false) { + public function hash($type, $path, $raw = false) { return hash_file($type, $this->buildPath($path), $raw); } @@ -296,9 +302,11 @@ class MappedLocal extends \OC\Files\Storage\Common{ public function search($query) { return $this->searchInDir($query); } + public function getLocalFile($path) { return $this->buildPath($path); } + public function getLocalFolder($path) { return $this->buildPath($path); } @@ -306,20 +314,20 @@ class MappedLocal extends \OC\Files\Storage\Common{ /** * @param string $query */ - protected function searchInDir($query, $dir='') { - $files=array(); + protected function searchInDir($query, $dir = '') { + $files = array(); $physicalDir = $this->buildPath($dir); foreach (scandir($physicalDir) as $item) { if ($item == '.' || $item == '..') continue; - $physicalItem = $this->mapper->physicalToLogic($physicalDir.'/'.$item); - $item = substr($physicalItem, strlen($physicalDir)+1); + $physicalItem = $this->mapper->physicalToLogic($physicalDir . '/' . $item); + $item = substr($physicalItem, strlen($physicalDir) + 1); - if(strstr(strtolower($item), strtolower($query)) !== false) { - $files[]=$dir.'/'.$item; + if (strstr(strtolower($item), strtolower($query)) !== false) { + $files[] = $dir . '/' . $item; } - if(is_dir($physicalItem)) { - $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item)); + if (is_dir($physicalItem)) { + $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); } } return $files; @@ -327,30 +335,31 @@ class MappedLocal extends \OC\Files\Storage\Common{ /** * 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->filemtime($path)>$time; + return $this->filemtime($path) > $time; } /** * @param string $path */ - private function buildPath($path, $create=true) { + private function buildPath($path, $create = true) { $path = $this->stripLeading($path); - $fullPath = $this->datadir.$path; + $fullPath = $this->datadir . $path; return $this->mapper->logicToPhysical($fullPath, $create); } /** * @param string $path */ - private function cleanMapper($path, $isLogicPath=true, $recursive=true) { + private function cleanMapper($path, $isLogicPath = true, $recursive=true) { $fullPath = $path; if ($isLogicPath) { - $fullPath = $this->datadir.$path; + $fullPath = $this->datadir . $path; } $this->mapper->removePath($fullPath, $isLogicPath, $recursive); } @@ -363,8 +372,8 @@ class MappedLocal extends \OC\Files\Storage\Common{ $path1 = $this->stripLeading($path1); $path2 = $this->stripLeading($path2); - $fullPath1 = $this->datadir.$path1; - $fullPath2 = $this->datadir.$path2; + $fullPath1 = $this->datadir . $path1; + $fullPath2 = $this->datadir . $path2; $this->mapper->copy($fullPath1, $fullPath2); } @@ -373,10 +382,10 @@ class MappedLocal extends \OC\Files\Storage\Common{ * @param string $path */ private function stripLeading($path) { - if(strpos($path, '/') === 0) { + if (strpos($path, '/') === 0) { $path = substr($path, 1); } - if(strpos($path, '\\') === 0) { + if (strpos($path, '\\') === 0) { $path = substr($path, 1); } if ($path === false) { diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php index 11ea9f71da7..364475a68e0 100644 --- a/lib/private/files/storage/wrapper/wrapper.php +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -440,4 +440,25 @@ class Wrapper implements \OC\Files\Storage\Storage { public function isLocal() { return $this->storage->isLocal(); } + + /** + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class + * + * @param string $class + * @return bool + */ + public function instanceOfStorage($class) { + return is_a($this, $class) or $this->storage->instanceOfStorage($class); + } + + /** + * Pass any methods custom to specific storage implementations to the wrapped storage + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) { + return call_user_func_array(array($this->storage, $method), $args); + } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 940f31fe420..0b8d336f260 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -29,14 +29,13 @@ use OC\Files\Cache\Updater; class View { private $fakeRoot = ''; - private $internal_path_cache = array(); - private $storage_cache = array(); public function __construct($root = '') { $this->fakeRoot = $root; } public function getAbsolutePath($path = '/') { + $this->assertPathLength($path); if ($path === '') { $path = '/'; } @@ -77,6 +76,7 @@ class View { * @return string */ public function getRelativePath($path) { + $this->assertPathLength($path); if ($this->fakeRoot == '') { return $path; } @@ -208,6 +208,7 @@ class View { } public function readfile($path) { + $this->assertPathLength($path); @ob_end_clean(); $handle = $this->fopen($path, 'rb'); if ($handle) { @@ -432,7 +433,7 @@ class View { if ($this->is_dir($path1)) { $result = $this->copy($path1, $path2); if ($result === true) { - $result = $storage1->unlink($internalPath1); + $result = $storage1->rmdir($internalPath1); } } else { $source = $this->fopen($path1 . $postFix1, 'r'); @@ -595,6 +596,7 @@ class View { } public function toTmpFile($path) { + $this->assertPathLength($path); if (Filesystem::isValidPath($path)) { $source = $this->fopen($path, 'r'); if ($source) { @@ -611,7 +613,7 @@ class View { } public function fromTmpFile($tmpFile, $path) { - + $this->assertPathLength($path); if (Filesystem::isValidPath($path)) { // Get directory that the file is going into @@ -640,6 +642,7 @@ class View { } public function getMimeType($path) { + $this->assertPathLength($path); return $this->basicOperation('getMimeType', $path); } @@ -669,6 +672,7 @@ class View { } public function free_space($path = '/') { + $this->assertPathLength($path); return $this->basicOperation('free_space', $path); } @@ -808,6 +812,7 @@ class View { * @return \OC\Files\FileInfo|false */ public function getFileInfo($path, $includeMountPoints = true) { + $this->assertPathLength($path); $data = array(); if (!Filesystem::isValidPath($path)) { return $data; @@ -878,6 +883,7 @@ class View { * @return FileInfo[] */ public function getDirectoryContent($directory, $mimetype_filter = '') { + $this->assertPathLength($directory); $result = array(); if (!Filesystem::isValidPath($directory)) { return $result; @@ -1006,6 +1012,7 @@ class View { * returns the fileid of the updated file */ public function putFileInfo($path, $data) { + $this->assertPathLength($path); if ($data instanceof FileInfo) { $data = $data->getData(); } @@ -1153,4 +1160,12 @@ class View { } return null; } + + private function assertPathLength($path) { + $maxLen = min(PHP_MAXPATHLEN, 4000); + $pathLen = strlen($path); + if ($pathLen > $maxLen) { + throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path"); + } + } } diff --git a/lib/private/largefilehelper.php b/lib/private/largefilehelper.php new file mode 100644 index 00000000000..293e09fe2c9 --- /dev/null +++ b/lib/private/largefilehelper.php @@ -0,0 +1,192 @@ +<?php +/** + * Copyright (c) 2014 Andreas Fischer <bantu@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +/** + * Helper class for large files on 32-bit platforms. + */ +class LargeFileHelper { + /** + * pow(2, 53) as a base-10 string. + * @var string + */ + const POW_2_53 = '9007199254740992'; + + /** + * pow(2, 53) - 1 as a base-10 string. + * @var string + */ + const POW_2_53_MINUS_1 = '9007199254740991'; + + /** + * @brief Checks whether our assumptions hold on the PHP platform we are on. + * + * @throws \RunTimeException if our assumptions do not hold on the current + * PHP platform. + */ + public function __construct() { + $pow_2_53 = floatval(self::POW_2_53_MINUS_1) + 1.0; + if ($this->formatUnsignedInteger($pow_2_53) !== self::POW_2_53) { + throw new \RunTimeException( + 'This class assumes floats to be double precision or "better".' + ); + } + } + + /** + * @brief Formats a signed integer or float as an unsigned integer base-10 + * string. Passed strings will be checked for being base-10. + * + * @param int|float|string $number Number containing unsigned integer data + * + * @throws \UnexpectedValueException if $number is not a float, not an int + * and not a base-10 string. + * + * @return string Unsigned integer base-10 string + */ + public function formatUnsignedInteger($number) { + if (is_float($number)) { + // Undo the effect of the php.ini setting 'precision'. + return number_format($number, 0, '', ''); + } else if (is_string($number) && ctype_digit($number)) { + return $number; + } else if (is_int($number)) { + // Interpret signed integer as unsigned integer. + return sprintf('%u', $number); + } else { + throw new \UnexpectedValueException( + 'Expected int, float or base-10 string' + ); + } + } + + /** + * @brief Tries to get the size of a file via various workarounds that + * even work for large files on 32-bit platforms. + * + * @param string $filename Path to the file. + * + * @return null|int|float Number of bytes as number (float or int) or + * null on failure. + */ + public function getFileSize($filename) { + $fileSize = $this->getFileSizeViaCurl($filename); + if (!is_null($fileSize)) { + return $fileSize; + } + $fileSize = $this->getFileSizeViaCOM($filename); + if (!is_null($fileSize)) { + return $fileSize; + } + $fileSize = $this->getFileSizeViaExec($filename); + if (!is_null($fileSize)) { + return $fileSize; + } + return $this->getFileSizeNative($filename); + } + + /** + * @brief Tries to get the size of a file via a CURL HEAD request. + * + * @param string $filename Path to the file. + * + * @return null|int|float Number of bytes as number (float or int) or + * null on failure. + */ + public function getFileSizeViaCurl($filename) { + if (function_exists('curl_init')) { + $ch = curl_init("file://$filename"); + curl_setopt($ch, CURLOPT_NOBODY, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, true); + $data = curl_exec($ch); + curl_close($ch); + if ($data !== false) { + $matches = array(); + preg_match('/Content-Length: (\d+)/', $data, $matches); + if (isset($matches[1])) { + return 0 + $matches[1]; + } + } + } + return null; + } + + /** + * @brief Tries to get the size of a file via the Windows DOM extension. + * + * @param string $filename Path to the file. + * + * @return null|int|float Number of bytes as number (float or int) or + * null on failure. + */ + public function getFileSizeViaCOM($filename) { + if (class_exists('COM')) { + $fsobj = new \COM("Scripting.FileSystemObject"); + $file = $fsobj->GetFile($filename); + return 0 + $file->Size; + } + return null; + } + + /** + * @brief Tries to get the size of a file via an exec() call. + * + * @param string $filename Path to the file. + * + * @return null|int|float Number of bytes as number (float or int) or + * null on failure. + */ + public function getFileSizeViaExec($filename) { + if (\OC_Helper::is_function_enabled('exec')) { + $os = strtolower(php_uname('s')); + $arg = escapeshellarg($filename); + $result = ''; + if (strpos($os, 'linux') !== false) { + $result = $this->exec("stat -c %s $arg"); + } else if (strpos($os, 'bsd') !== false) { + $result = $this->exec("stat -f %z $arg"); + } else if (strpos($os, 'win') !== false) { + $result = $this->exec("for %F in ($arg) do @echo %~zF"); + if (is_null($result)) { + // PowerShell + $result = $this->exec("(Get-Item $arg).length"); + } + } + return $result; + } + return null; + } + + /** + * @brief Gets the size of a file via a filesize() call and converts + * negative signed int to positive float. As the result of filesize() + * will wrap around after a file size of 2^32 bytes = 4 GiB, this + * should only be used as a last resort. + * + * @param string $filename Path to the file. + * + * @return int|float Number of bytes as number (float or int). + */ + public function getFileSizeNative($filename) { + $result = filesize($filename); + if ($result < 0) { + // For file sizes between 2 GiB and 4 GiB, filesize() will return a + // negative int, as the PHP data type int is signed. Interpret the + // returned int as an unsigned integer and put it into a float. + return (float) sprintf('%u', $result); + } + return $result; + } + + protected function exec($cmd) { + $result = trim(exec($cmd)); + return ctype_digit($result) ? 0 + $result : null; + } +} diff --git a/lib/private/mail.php b/lib/private/mail.php index f9083cc4e64..81bcb3d8deb 100644 --- a/lib/private/mail.php +++ b/lib/private/mail.php @@ -12,8 +12,6 @@ * A class to handle mail sending. */ -require_once 'class.phpmailer.php'; - class OC_Mail { /** diff --git a/lib/private/updater.php b/lib/private/updater.php index d8694ac6ed5..58d3cab73aa 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -134,7 +134,10 @@ class Updater extends BasicEmitter { $this->emit('\OC\Updater', 'failure', array($exception->getMessage())); } \OC_Config::setValue('version', implode('.', \OC_Util::getVersion())); - \OC_App::checkAppsRequirements(); + $disabledApps = \OC_App::checkAppsRequirements(); + if (!empty($disabledApps)) { + $this->emit('\OC\Updater', 'disabledApps', array($disabledApps)); + } // load all apps to also upgrade enabled apps \OC_App::loadApps(); diff --git a/lib/private/user.php b/lib/private/user.php index 9276d7923c9..5d3ebb57c8c 100644 --- a/lib/private/user.php +++ b/lib/private/user.php @@ -236,6 +236,17 @@ class OC_User { } /** + * Try to login a user using the magic cookie (remember login) + * + * @param string $uid The username of the user to log in + * @param string $token + * @return bool + */ + public static function loginWithCookie($uid, $token) { + return self::getUserSession()->loginWithCookie($uid, $token); + } + + /** * Try to login a user, assuming authentication * has already happened (e.g. via Single Sign On). * diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php index 0fcf1ceb6ab..f2964fecca3 100644 --- a/lib/private/user/manager.php +++ b/lib/private/user/manager.php @@ -52,6 +52,12 @@ class Manager extends PublicEmitter { unset($cachedUsers[$i]); } }); + $this->listen('\OC\User', 'postLogin', function ($user) { + $user->updateLastLoginTimestamp(); + }); + $this->listen('\OC\User', 'postRememberedLogin', function ($user) { + $user->updateLastLoginTimestamp(); + }); } /** diff --git a/lib/private/user/session.php b/lib/private/user/session.php index 3d10b134b83..5f0dee607ae 100644 --- a/lib/private/user/session.php +++ b/lib/private/user/session.php @@ -22,7 +22,9 @@ use OC\Hooks\Emitter; * - preCreateUser(string $uid, string $password) * - postCreateUser(\OC\User\User $user) * - preLogin(string $user, string $password) - * - postLogin(\OC\User\User $user) + * - postLogin(\OC\User\User $user, string $password) + * - preRememberedLogin(string $uid) + * - postRememberedLogin(\OC\User\User $user) * - logout() * * @package OC\User @@ -171,6 +173,39 @@ class Session implements Emitter, \OCP\IUserSession { } /** + * perform login using the magic cookie (remember login) + * + * @param string $uid the username + * @param string $currentToken + * @return bool + */ + public function loginWithCookie($uid, $currentToken) { + $this->manager->emit('\OC\User', 'preRememberedLogin', array($uid)); + $user = $this->manager->get($uid); + if(is_null($user)) { + // user does not exist + return false; + } + + // get stored tokens + $tokens = \OC_Preferences::getKeys($uid, 'login_token'); + // test cookies token against stored tokens + if(!in_array($currentToken, $tokens, true)) { + return false; + } + // replace successfully used token with a new one + \OC_Preferences::deleteKey($uid, 'login_token', $currentToken); + $newToken = \OC_Util::generateRandomBytes(32); + \OC_Preferences::setValue($uid, 'login_token', $newToken, time()); + $this->setMagicInCookie($user->getUID(), $newToken); + + //login + $this->setUser($user); + $this->manager->emit('\OC\User', 'postRememberedLogin', array($user)); + return true; + } + + /** * logout the user from the session */ public function logout() { diff --git a/lib/private/user/user.php b/lib/private/user/user.php index bc5c541e521..8aba7188e24 100644 --- a/lib/private/user/user.php +++ b/lib/private/user/user.php @@ -43,6 +43,11 @@ class User { private $home; /** + * @var int $lastLogin + */ + private $lastLogin; + + /** * @var \OC\AllConfig $config */ private $config; @@ -64,6 +69,7 @@ class User { } else { $this->enabled = true; } + $this->lastLogin = \OC_Preferences::getValue($uid, 'login', 'lastLogin', 0); } /** @@ -108,6 +114,25 @@ class User { } /** + * returns the timestamp of the user's last login or 0 if the user did never + * login + * + * @return int + */ + public function getLastLogin() { + return $this->lastLogin; + } + + /** + * updates the timestamp of the most recent login of this user + */ + public function updateLastLoginTimestamp() { + $this->lastLogin = time(); + \OC_Preferences::setValue( + $this->uid, 'login', 'lastLogin', $this->lastLogin); + } + + /** * Delete the user * * @return bool diff --git a/lib/private/util.php b/lib/private/util.php index 23c7053002c..bf7f39ebb20 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -57,7 +57,10 @@ class OC_Util { // set up quota for home storages, even for other users // which can happen when using sharing - if ($storage instanceof \OC\Files\Storage\Home) { + /** + * @var \OC\Files\Storage\Storage $storage + */ + if ($storage->instanceOfStorage('\OC\Files\Storage\Home')) { $user = $storage->getUser()->getUID(); $quota = OC_Util::getUserQuota($user); if ($quota !== \OC\Files\SPACE_UNLIMITED) { diff --git a/lib/public/contacts.php b/lib/public/contacts.php index fb88c13bd1b..5311050d5c3 100644 --- a/lib/public/contacts.php +++ b/lib/public/contacts.php @@ -134,7 +134,7 @@ namespace OCP { */ public static function registerAddressBook(\OCP\IAddressBook $address_book) { $cm = \OC::$server->getContactsManager(); - return $cm->registerAddressBook($address_book); + $cm->registerAddressBook($address_book); } /** @@ -142,7 +142,7 @@ namespace OCP { */ public static function unregisterAddressBook(\OCP\IAddressBook $address_book) { $cm = \OC::$server->getContactsManager(); - return $cm->unregisterAddressBook($address_book); + $cm->unregisterAddressBook($address_book); } /** diff --git a/lib/public/contacts/imanager.php b/lib/public/contacts/imanager.php index 32559220091..5a76585ead9 100644 --- a/lib/public/contacts/imanager.php +++ b/lib/public/contacts/imanager.php @@ -138,11 +138,10 @@ namespace OCP\Contacts { * In order to improve lazy loading a closure can be registered which will be called in case * address books are actually requested * - * @param string $key * @param \Closure $callable * @return void */ - function register($key, \Closure $callable); + function register(\Closure $callable); /** * @return array diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index 5ec8ac6245c..323d20db564 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -327,4 +327,12 @@ interface Storage { * @return bool true if the files are stored locally, false otherwise */ public function isLocal(); + + /** + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class + * + * @param string $class + * @return bool + */ + public function instanceOfStorage($class); } |