diff options
Diffstat (limited to 'lib/private')
68 files changed, 1360 insertions, 584 deletions
diff --git a/lib/private/allconfig.php b/lib/private/allconfig.php index de3ac973637..eb114546010 100644 --- a/lib/private/allconfig.php +++ b/lib/private/allconfig.php @@ -18,11 +18,10 @@ class AllConfig implements \OCP\IConfig { * * @param string $key the key of the value, under which will be saved * @param mixed $value the value that should be stored - * @todo need a use case for this */ -// public function setSystemValue($key, $value) { -// \OCP\Config::setSystemValue($key, $value); -// } + public function setSystemValue($key, $value) { + \OCP\Config::setSystemValue($key, $value); + } /** * Looks up a system wide defined value diff --git a/lib/private/app.php b/lib/private/app.php index 7bf04f11267..70f8980d2c1 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -62,6 +62,9 @@ class OC_App { * if $types is set, only apps of those types will be loaded */ public static function loadApps($types = null) { + if (OC_Config::getValue('maintenance', false)) { + return false; + } // Load the enabled apps here $apps = self::getEnabledApps(); // prevent app.php from printing output @@ -81,10 +84,14 @@ class OC_App { * load a single app * * @param string $app + * @param bool $checkUpgrade whether an upgrade check should be done + * @throws \OC\NeedsUpdateException */ - public static function loadApp($app) { + public static function loadApp($app, $checkUpgrade = true) { if (is_file(self::getAppPath($app) . '/appinfo/app.php')) { - self::checkUpgrade($app); + if ($checkUpgrade and self::shouldUpgrade($app)) { + throw new \OC\NeedsUpdateException(); + } require_once $app . '/appinfo/app.php'; } } @@ -172,6 +179,7 @@ class OC_App { if (!$forceRefresh && !empty(self::$enabledAppsCache)) { return self::$enabledAppsCache; } + $apps = array(); $appConfig = \OC::$server->getAppConfig(); $appStatus = $appConfig->getValues(false, 'enabled'); $user = \OC_User::getUser(); @@ -832,7 +840,8 @@ class OC_App { foreach ($appList as $app) { foreach ($remoteApps AS $key => $remote) { if ($app['name'] === $remote['name'] || - $app['ocsid'] === $remote['id']) { + (isset($app['ocsid']) && + $app['ocsid'] === $remote['id'])) { unset($remoteApps[$key]); } } @@ -955,39 +964,6 @@ class OC_App { } /** - * check if the app needs updating and update when needed - * - * @param string $app - */ - public static function checkUpgrade($app) { - if (in_array($app, self::$checkedApps)) { - return; - } - self::$checkedApps[] = $app; - if (!self::shouldUpgrade($app)) { - return; - } - $versions = self::getAppVersions(); - $installedVersion = $versions[$app]; - $currentVersion = OC_App::getAppVersion($app); - OC_Log::write( - $app, - 'starting app upgrade from ' . $installedVersion . ' to ' . $currentVersion, - OC_Log::DEBUG - ); - $info = self::getAppInfo($app); - try { - OC_App::updateApp($app); - OC_Hook::emit('update', 'success', 'Updated ' . $info['name'] . ' app'); - } catch (Exception $e) { - OC_Hook::emit('update', 'failure', 'Failed to update ' . $info['name'] . ' app: ' . $e->getMessage()); - $l = OC_L10N::get('lib'); - throw new RuntimeException($l->t('Failed to upgrade "%s".', array($app)), 0, $e); - } - OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app)); - } - - /** * check if the current enabled apps are compatible with the current * ownCloud version. disable them if not. * This is important if you upgrade ownCloud and have non ported 3rd @@ -1165,7 +1141,7 @@ class OC_App { */ public static function updateApp($appId) { if (file_exists(self::getAppPath($appId) . '/appinfo/preupdate.php')) { - self::loadApp($appId); + self::loadApp($appId, false); include self::getAppPath($appId) . '/appinfo/preupdate.php'; } if (file_exists(self::getAppPath($appId) . '/appinfo/database.xml')) { @@ -1175,7 +1151,7 @@ class OC_App { return false; } if (file_exists(self::getAppPath($appId) . '/appinfo/update.php')) { - self::loadApp($appId); + self::loadApp($appId, false); include self::getAppPath($appId) . '/appinfo/update.php'; } @@ -1193,6 +1169,9 @@ class OC_App { self::setAppTypes($appId); + $version = \OC_App::getAppVersion($appId); + \OC_Appconfig::setValue($appId, 'installed_version', $version); + return true; } diff --git a/lib/private/appframework/utility/controllermethodreflector.php b/lib/private/appframework/utility/controllermethodreflector.php index d5cf2f52eb2..c49dd80091e 100644 --- a/lib/private/appframework/utility/controllermethodreflector.php +++ b/lib/private/appframework/utility/controllermethodreflector.php @@ -62,6 +62,7 @@ class ControllerMethodReflector { } else { $this->types = array_combine($matches['var'], $matches['type']); } + // get method parameters foreach ($reflection->getParameters() as $param) { if($param->isOptional()) { diff --git a/lib/private/archive.php b/lib/private/archive.php index a62f22cf6d7..562172ddefa 100644 --- a/lib/private/archive.php +++ b/lib/private/archive.php @@ -20,11 +20,8 @@ abstract class OC_Archive{ case '.gz': case '.bz': case '.bz2': - if(strpos($path, '.tar.')) { - return new OC_Archive_TAR($path); - } - break; case '.tgz': + case '.tar': return new OC_Archive_TAR($path); } } diff --git a/lib/private/archive/tar.php b/lib/private/archive/tar.php index 21a995d9e50..31715c4778b 100644 --- a/lib/private/archive/tar.php +++ b/lib/private/archive/tar.php @@ -8,10 +8,10 @@ require_once OC::$THIRDPARTYROOT . '/3rdparty/Archive/Tar.php'; -class OC_Archive_TAR extends OC_Archive{ - const PLAIN=0; - const GZIP=1; - const BZIP=2; +class OC_Archive_TAR extends OC_Archive { + const PLAIN = 0; + const GZIP = 1; + const BZIP = 2; private $fileList; private $cachedHeaders; @@ -19,109 +19,112 @@ class OC_Archive_TAR extends OC_Archive{ /** * @var Archive_Tar tar */ - private $tar=null; + private $tar = null; private $path; /** * @param string $source */ function __construct($source) { - $types=array(null, 'gz', 'bz'); - $this->path=$source; - $this->tar=new Archive_Tar($source, $types[self::getTarType($source)]); + $types = array(null, 'gz', 'bz'); + $this->path = $source; + $this->tar = new Archive_Tar($source, $types[self::getTarType($source)]); } /** * try to detect the type of tar compression + * * @param string $file * @return integer */ static public function getTarType($file) { - if(strpos($file, '.')) { - $extension=substr($file, strrpos($file, '.')); - switch($extension) { - case 'gz': - case 'tgz': + if (strpos($file, '.')) { + $extension = substr($file, strrpos($file, '.')); + switch ($extension) { + case '.gz': + case '.tgz': return self::GZIP; - case 'bz': - case 'bz2': + case '.bz': + case '.bz2': return self::BZIP; + case '.tar': + return self::PLAIN; default: return self::PLAIN; } - }else{ + } else { return self::PLAIN; } } /** * add an empty folder to the archive + * * @param string $path * @return bool */ function addFolder($path) { - $tmpBase=OC_Helper::tmpFolder(); - if(substr($path, -1, 1)!='/') { - $path.='/'; + $tmpBase = OC_Helper::tmpFolder(); + if (substr($path, -1, 1) != '/') { + $path .= '/'; } - if($this->fileExists($path)) { + if ($this->fileExists($path)) { return false; } - $parts=explode('/', $path); - $folder=$tmpBase; - foreach($parts as $part) { - $folder.='/'.$part; - if(!is_dir($folder)) { + $parts = explode('/', $path); + $folder = $tmpBase; + foreach ($parts as $part) { + $folder .= '/' . $part; + if (!is_dir($folder)) { mkdir($folder); } } - $result=$this->tar->addModify(array($tmpBase.$path), '', $tmpBase); - rmdir($tmpBase.$path); - $this->fileList=false; - $this->cachedHeaders=false; + $result = $this->tar->addModify(array($tmpBase . $path), '', $tmpBase); + rmdir($tmpBase . $path); + $this->fileList = false; + $this->cachedHeaders = false; return $result; } + /** * add a file to the archive + * * @param string $path * @param string $source either a local file or string data * @return bool */ - function addFile($path, $source='') { - if($this->fileExists($path)) { + function addFile($path, $source = '') { + if ($this->fileExists($path)) { $this->remove($path); } - if($source and $source[0]=='/' and file_exists($source)) { - $header=array(); - $dummy=''; - $this->tar->_openAppend(); - $result=$this->tar->_addfile($source, $header, $dummy, $dummy, $path); - }else{ - $result=$this->tar->addString($path, $source); + if ($source and $source[0] == '/' and file_exists($source)) { + $source = file_get_contents($source); } - $this->fileList=false; - $this->cachedHeaders=false; + $result = $this->tar->addString($path, $source); + $this->fileList = false; + $this->cachedHeaders = false; return $result; } /** * rename a file or folder in the archive + * * @param string $source * @param string $dest * @return bool */ function rename($source, $dest) { //no proper way to delete, rename entire archive, rename file and remake archive - $tmp=OCP\Files::tmpFolder(); + $tmp = OCP\Files::tmpFolder(); $this->tar->extract($tmp); - rename($tmp.$source, $tmp.$dest); - $this->tar=null; + rename($tmp . $source, $tmp . $dest); + $this->tar = null; unlink($this->path); - $types=array(null, 'gz', 'bz'); - $this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]); - $this->tar->createModify(array($tmp), '', $tmp.'/'); - $this->fileList=false; - $this->cachedHeaders=false; + $types = array(null, 'gz', 'bz'); + $this->tar = new Archive_Tar($this->path, $types[self::getTarType($this->path)]); + $this->tar->createModify(array($tmp), '', $tmp . '/'); + $this->fileList = false; + $this->cachedHeaders = false; return true; } @@ -129,14 +132,15 @@ class OC_Archive_TAR extends OC_Archive{ * @param string $file */ private function getHeader($file) { - if ( ! $this->cachedHeaders ) { + if (!$this->cachedHeaders) { $this->cachedHeaders = $this->tar->listContent(); } - foreach($this->cachedHeaders as $header) { - if( $file == $header['filename'] - or $file.'/' == $header['filename'] - or '/'.$file.'/' == $header['filename'] - or '/'.$file == $header['filename']) { + foreach ($this->cachedHeaders as $header) { + if ($file == $header['filename'] + or $file . '/' == $header['filename'] + or '/' . $file . '/' == $header['filename'] + or '/' . $file == $header['filename'] + ) { return $header; } } @@ -145,186 +149,204 @@ class OC_Archive_TAR extends OC_Archive{ /** * get the uncompressed size of a file in the archive + * * @param string $path * @return int */ function filesize($path) { - $stat=$this->getHeader($path); + $stat = $this->getHeader($path); return $stat['size']; } + /** * get the last modified time of a file in the archive + * * @param string $path * @return int */ function mtime($path) { - $stat=$this->getHeader($path); + $stat = $this->getHeader($path); return $stat['mtime']; } /** * get the files in a folder + * * @param string $path * @return array */ function getFolder($path) { - $files=$this->getFiles(); - $folderContent=array(); - $pathLength=strlen($path); - foreach($files as $file) { - if($file[0]=='/') { - $file=substr($file, 1); + $files = $this->getFiles(); + $folderContent = array(); + $pathLength = strlen($path); + foreach ($files as $file) { + if ($file[0] == '/') { + $file = substr($file, 1); } - if(substr($file, 0, $pathLength)==$path and $file!=$path) { - $result=substr($file, $pathLength); - if($pos=strpos($result, '/')) { - $result=substr($result, 0, $pos+1); + if (substr($file, 0, $pathLength) == $path and $file != $path) { + $result = substr($file, $pathLength); + if ($pos = strpos($result, '/')) { + $result = substr($result, 0, $pos + 1); } - if(array_search($result, $folderContent)===false) { - $folderContent[]=$result; + if (array_search($result, $folderContent) === false) { + $folderContent[] = $result; } } } return $folderContent; } + /** * get all files in the archive + * * @return array */ function getFiles() { - if($this->fileList) { + if ($this->fileList) { return $this->fileList; } - if ( ! $this->cachedHeaders ) { + if (!$this->cachedHeaders) { $this->cachedHeaders = $this->tar->listContent(); } - $files=array(); - foreach($this->cachedHeaders as $header) { - $files[]=$header['filename']; + $files = array(); + foreach ($this->cachedHeaders as $header) { + $files[] = $header['filename']; } - $this->fileList=$files; + $this->fileList = $files; return $files; } + /** * get the content of a file + * * @param string $path * @return string */ function getFile($path) { return $this->tar->extractInString($path); } + /** * extract a single file from the archive + * * @param string $path * @param string $dest * @return bool */ function extractFile($path, $dest) { - $tmp=OCP\Files::tmpFolder(); - if(!$this->fileExists($path)) { + $tmp = OCP\Files::tmpFolder(); + if (!$this->fileExists($path)) { return false; } - if($this->fileExists('/'.$path)) { - $success=$this->tar->extractList(array('/'.$path), $tmp); - }else{ - $success=$this->tar->extractList(array($path), $tmp); + if ($this->fileExists('/' . $path)) { + $success = $this->tar->extractList(array('/' . $path), $tmp); + } else { + $success = $this->tar->extractList(array($path), $tmp); } - if($success) { - rename($tmp.$path, $dest); + if ($success) { + rename($tmp . $path, $dest); } OCP\Files::rmdirr($tmp); return $success; } + /** * extract the archive + * * @param string $dest * @return bool */ function extract($dest) { return $this->tar->extract($dest); } + /** * check if a file or folder exists in the archive + * * @param string $path * @return bool */ function fileExists($path) { - $files=$this->getFiles(); - if((array_search($path, $files)!==false) or (array_search($path.'/', $files)!==false)) { + $files = $this->getFiles(); + if ((array_search($path, $files) !== false) or (array_search($path . '/', $files) !== false)) { return true; - }else{ - $folderPath=$path; - if(substr($folderPath, -1, 1)!='/') { - $folderPath.='/'; + } else { + $folderPath = $path; + if (substr($folderPath, -1, 1) != '/') { + $folderPath .= '/'; } - $pathLength=strlen($folderPath); - foreach($files as $file) { - if(strlen($file)>$pathLength and substr($file, 0, $pathLength)==$folderPath) { + $pathLength = strlen($folderPath); + foreach ($files as $file) { + if (strlen($file) > $pathLength and substr($file, 0, $pathLength) == $folderPath) { return true; } } } - if($path[0]!='/') {//not all programs agree on the use of a leading / - return $this->fileExists('/'.$path); - }else{ + if ($path[0] != '/') { //not all programs agree on the use of a leading / + return $this->fileExists('/' . $path); + } else { return false; } } /** * remove a file or folder from the archive + * * @param string $path * @return bool */ function remove($path) { - if(!$this->fileExists($path)) { + if (!$this->fileExists($path)) { return false; } - $this->fileList=false; - $this->cachedHeaders=false; + $this->fileList = false; + $this->cachedHeaders = false; //no proper way to delete, extract entire archive, delete file and remake archive - $tmp=OCP\Files::tmpFolder(); + $tmp = OCP\Files::tmpFolder(); $this->tar->extract($tmp); - OCP\Files::rmdirr($tmp.$path); - $this->tar=null; + OCP\Files::rmdirr($tmp . $path); + $this->tar = null; unlink($this->path); $this->reopen(); $this->tar->createModify(array($tmp), '', $tmp); return true; } + /** * get a file handler + * * @param string $path * @param string $mode * @return resource */ function getStream($path, $mode) { - if(strrpos($path, '.')!==false) { - $ext=substr($path, strrpos($path, '.')); - }else{ - $ext=''; + if (strrpos($path, '.') !== false) { + $ext = substr($path, strrpos($path, '.')); + } else { + $ext = ''; } - $tmpFile=OCP\Files::tmpFile($ext); - if($this->fileExists($path)) { + $tmpFile = OCP\Files::tmpFile($ext); + if ($this->fileExists($path)) { $this->extractFile($path, $tmpFile); - }elseif($mode=='r' or $mode=='rb') { + } elseif ($mode == 'r' or $mode == 'rb') { return false; } - if($mode=='r' or $mode=='rb') { + if ($mode == 'r' or $mode == 'rb') { return fopen($tmpFile, $mode); - }else{ + } else { \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); + self::$tempFiles[$tmpFile] = $path; + return fopen('close://' . $tmpFile, $mode); } } - private static $tempFiles=array(); + private static $tempFiles = array(); + /** * write back temporary files */ function writeBack($tmpFile) { - if(isset(self::$tempFiles[$tmpFile])) { + if (isset(self::$tempFiles[$tmpFile])) { $this->addFile(self::$tempFiles[$tmpFile], $tmpFile); unlink($tmpFile); } @@ -334,11 +356,11 @@ class OC_Archive_TAR extends OC_Archive{ * reopen the archive to ensure everything is written */ private function reopen() { - if($this->tar) { + if ($this->tar) { $this->tar->_close(); - $this->tar=null; + $this->tar = null; } - $types=array(null, 'gz', 'bz'); - $this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]); + $types = array(null, 'gz', 'bz'); + $this->tar = new Archive_Tar($this->path, $types[self::getTarType($this->path)]); } } diff --git a/lib/private/backgroundjob/joblist.php b/lib/private/backgroundjob/joblist.php index 211d7e9abfc..9d15cd1663a 100644 --- a/lib/private/backgroundjob/joblist.php +++ b/lib/private/backgroundjob/joblist.php @@ -96,7 +96,10 @@ class JobList implements IJobList { $query->execute(); $jobs = array(); while ($row = $query->fetch()) { - $jobs[] = $this->buildJob($row); + $job = $this->buildJob($row); + if ($job) { + $jobs[] = $job; + } } return $jobs; } diff --git a/lib/private/connector/sabre/quotaplugin.php b/lib/private/connector/sabre/quotaplugin.php index cf3c1103f84..ebcc894d744 100644 --- a/lib/private/connector/sabre/quotaplugin.php +++ b/lib/private/connector/sabre/quotaplugin.php @@ -72,7 +72,7 @@ class OC_Connector_Sabre_QuotaPlugin extends \Sabre\DAV\ServerPlugin { $length -= $chunkHandler->getCurrentSize(); } $freeSpace = $this->getFreeSpace($parentUri); - if ($freeSpace !== \OC\Files\SPACE_UNKNOWN && $length > $freeSpace) { + if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN && $length > $freeSpace) { if (isset($chunkHandler)) { $chunkHandler->cleanup(); } diff --git a/lib/private/connector/sabre/server.php b/lib/private/connector/sabre/server.php index aaf4fe85af9..43c3464f1ca 100644 --- a/lib/private/connector/sabre/server.php +++ b/lib/private/connector/sabre/server.php @@ -33,6 +33,11 @@ class OC_Connector_Sabre_Server extends Sabre\DAV\Server { */ private $overLoadedUri = null; + /** + * @var boolean + */ + private $ignoreRangeHeader = false; + public function getRequestUri() { if (!is_null($this->overLoadedUri)) { @@ -59,6 +64,23 @@ class OC_Connector_Sabre_Server extends Sabre\DAV\Server { return $result; } + public function getHTTPRange() { + if ($this->ignoreRangeHeader) { + return null; + } + return parent::getHTTPRange(); + } + + protected function httpGet($uri) { + $range = $this->getHTTPRange(); + + if (OC_App::isEnabled('files_encryption') && $range) { + // encryption does not support range requests + $this->ignoreRangeHeader = true; + } + return parent::httpGet($uri); + } + /** * @see \Sabre\DAV\Server */ diff --git a/lib/private/contacts/localaddressbook.php b/lib/private/contacts/localaddressbook.php new file mode 100644 index 00000000000..483bbee83f8 --- /dev/null +++ b/lib/private/contacts/localaddressbook.php @@ -0,0 +1,104 @@ +<?php + /** + * ownCloud + * + * @author Thomas Müller + * @copyright 2014 Thomas Müller >deepdiver@owncloud.com> + * + */ + +namespace OC\Contacts; + +class LocalAddressBook implements \OCP\IAddressBook { + + /** + * @var \OCP\IUserManager + */ + private $userManager; + + /** + * @param $userManager + */ + public function __construct($userManager) { + $this->userManager = $userManager; + } + + /** + * @return string defining the technical unique key + */ + public function getKey() { + return 'local'; + } + + /** + * In comparison to getKey() this function returns a human readable (maybe translated) name + * + * @return mixed + */ + public function getDisplayName() { + return "Local users"; + } + + /** + * @param string $pattern which should match within the $searchProperties + * @param array $searchProperties defines the properties within the query pattern should match + * @param array $options - for future use. One should always have options! + * @return array an array of contacts which are arrays of key-value-pairs + */ + public function search($pattern, $searchProperties, $options) { + $users = array(); + if($pattern == '') { + // Fetch all contacts + $users = $this->userManager->search(''); + } else { + foreach($searchProperties as $property) { + $result = array(); + if($property === 'FN') { + $result = $this->userManager->searchDisplayName($pattern); + } else if ($property === 'id') { + $result = $this->userManager->search($pattern); + } + if (is_array($result)) { + $users = array_merge($users, $result); + } + } + } + + $contacts = array(); + foreach($users as $user){ + $contact = array( + "id" => $user->getUID(), + "FN" => $user->getDisplayname(), + "EMAIL" => array(), + "IMPP" => array( + "x-owncloud-handle:" . $user->getUID() + ) + ); + $contacts[] = $contact; + } + return $contacts; + } + + /** + * @param array $properties this array if key-value-pairs defines a contact + * @return array an array representing the contact just created or updated + */ + public function createOrUpdate($properties) { + return array(); + } + + /** + * @return int + */ + public function getPermissions() { + return \OCP\PERMISSION_READ; + } + + /** + * @param object $id the unique identifier to a contact + * @return bool successful or not + */ + public function delete($id) { + return false; + } +} diff --git a/lib/private/db/connectionfactory.php b/lib/private/db/connectionfactory.php index 033065bcb77..dbbe58dbef8 100644 --- a/lib/private/db/connectionfactory.php +++ b/lib/private/db/connectionfactory.php @@ -102,6 +102,11 @@ class ConnectionFactory { /** @var $connection \OC\DB\Connection */ $connection->disableQueryStatementCaching(); break; + case 'oci': + // oracle seems to have issues with cached statements which have been closed + /** @var $connection \OC\DB\Connection */ + $connection->disableQueryStatementCaching(); + break; } return $connection; } diff --git a/lib/private/db/mdb2schemamanager.php b/lib/private/db/mdb2schemamanager.php index d3e379c9417..91e590a901a 100644 --- a/lib/private/db/mdb2schemamanager.php +++ b/lib/private/db/mdb2schemamanager.php @@ -59,7 +59,8 @@ class MDB2SchemaManager { public function getMigrator() { $platform = $this->conn->getDatabasePlatform(); if ($platform instanceof SqlitePlatform) { - return new SQLiteMigrator($this->conn); + $config = \OC::$server->getConfig(); + return new SQLiteMigrator($this->conn, $config); } else if ($platform instanceof OraclePlatform) { return new OracleMigrator($this->conn); } else if ($platform instanceof MySqlPlatform) { diff --git a/lib/private/db/sqlitemigrator.php b/lib/private/db/sqlitemigrator.php index f5f78986771..94b421c5562 100644 --- a/lib/private/db/sqlitemigrator.php +++ b/lib/private/db/sqlitemigrator.php @@ -9,8 +9,24 @@ namespace OC\DB; use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Schema\Schema; class SQLiteMigrator extends Migrator { + + /** + * @var \OCP\IConfig + */ + private $config; + + /** + * @param \Doctrine\DBAL\Connection $connection + * @param \OCP\IConfig $config + */ + public function __construct(\Doctrine\DBAL\Connection $connection, \OCP\IConfig $config) { + parent::__construct($connection); + $this->config = $config; + } + /** * @param \Doctrine\DBAL\Schema\Schema $targetSchema * @throws \OC\DB\MigrationException @@ -19,7 +35,7 @@ class SQLiteMigrator extends Migrator { */ public function checkMigrate(\Doctrine\DBAL\Schema\Schema $targetSchema) { $dbFile = $this->connection->getDatabase(); - $tmpFile = \OC_Helper::tmpFile('.db'); + $tmpFile = $this->buildTempDatabase(); copy($dbFile, $tmpFile); $connectionParams = array( @@ -37,4 +53,25 @@ class SQLiteMigrator extends Migrator { throw new MigrationException('', $e->getMessage()); } } + + /** + * @return string + */ + private function buildTempDatabase() { + $dataDir = $this->config->getSystemValue("datadirectory", \OC::$SERVERROOT . '/data'); + $tmpFile = uniqid("oc_"); + return "$dataDir/$tmpFile.db"; + } + + /** + * @param Schema $targetSchema + * @param \Doctrine\DBAL\Connection $connection + * @return \Doctrine\DBAL\Schema\SchemaDiff + */ + protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { + $platform = $connection->getDatabasePlatform(); + $platform->registerDoctrineTypeMapping('tinyint unsigned', 'integer'); + + return parent::getDiff($targetSchema, $connection); + } } diff --git a/lib/private/defaults.php b/lib/private/defaults.php index a439bf0d6db..dfd114cd2fe 100644 --- a/lib/private/defaults.php +++ b/lib/private/defaults.php @@ -18,6 +18,8 @@ class OC_Defaults { private $defaultTitle; private $defaultBaseUrl; private $defaultSyncClientUrl; + private $defaultiOSClientUrl; + private $defaultAndroidClientUrl; private $defaultDocBaseUrl; private $defaultDocVersion; private $defaultSlogan; @@ -28,18 +30,20 @@ class OC_Defaults { $this->l = OC_L10N::get('lib'); $version = OC_Util::getVersion(); - $this->defaultEntity = "ownCloud"; /* e.g. company name, used for footers and copyright notices */ - $this->defaultName = "ownCloud"; /* short name, used when referring to the software */ - $this->defaultTitle = "ownCloud"; /* can be a longer name, for titles */ - $this->defaultBaseUrl = "https://owncloud.org"; - $this->defaultSyncClientUrl = "https://owncloud.org/sync-clients/"; - $this->defaultDocBaseUrl = "http://doc.owncloud.org"; - $this->defaultDocVersion = $version[0] . ".0"; // used to generate doc links - $this->defaultSlogan = $this->l->t("web services under your control"); - $this->defaultLogoClaim = ""; - $this->defaultMailHeaderColor = "#1d2d44"; /* header color of mail notifications */ - - if (class_exists("OC_Theme")) { + $this->defaultEntity = 'ownCloud'; /* e.g. company name, used for footers and copyright notices */ + $this->defaultName = 'ownCloud'; /* short name, used when referring to the software */ + $this->defaultTitle = 'ownCloud'; /* can be a longer name, for titles */ + $this->defaultBaseUrl = 'https://owncloud.org'; + $this->defaultSyncClientUrl = 'https://owncloud.org/sync-clients/'; + $this->defaultiOSClientUrl = 'https://itunes.apple.com/us/app/owncloud/id543672169?mt=8'; + $this->defaultAndroidClientUrl = 'https://play.google.com/store/apps/details?id=com.owncloud.android'; + $this->defaultDocBaseUrl = 'http://doc.owncloud.org'; + $this->defaultDocVersion = $version[0] . '.0'; // used to generate doc links + $this->defaultSlogan = $this->l->t('web services under your control'); + $this->defaultLogoClaim = ''; + $this->defaultMailHeaderColor = '#1d2d44'; /* header color of mail notifications */ + + if (class_exists('OC_Theme')) { $this->theme = new OC_Theme(); } } @@ -79,6 +83,30 @@ class OC_Defaults { } /** + * Returns the URL to the App Store for the iOS Client + * @return string URL + */ + public function getiOSClientUrl() { + if ($this->themeExist('getiOSClientUrl')) { + return $this->theme->getiOSClientUrl(); + } else { + return $this->defaultiOSClientUrl; + } + } + + /** + * Returns the URL to Google Play for the Android Client + * @return string URL + */ + public function getAndroidClientUrl() { + if ($this->themeExist('getAndroidClientUrl')) { + return $this->theme->getAndroidClientUrl(); + } else { + return $this->defaultAndroidClientUrl; + } + } + + /** * Returns the documentation URL * @return string URL */ @@ -158,7 +186,7 @@ class OC_Defaults { if ($this->themeExist('getShortFooter')) { $footer = $this->theme->getShortFooter(); } else { - $footer = "<a href=\"". $this->getBaseUrl() . "\" target=\"_blank\">" .$this->getEntity() . "</a>". + $footer = '<a href="'. $this->getBaseUrl() . '" target="_blank">' .$this->getEntity() . '</a>'. ' – ' . $this->getSlogan(); } diff --git a/lib/private/eventsource.php b/lib/private/eventsource.php index 5a41ddd8b37..192c1446b5a 100644 --- a/lib/private/eventsource.php +++ b/lib/private/eventsource.php @@ -34,6 +34,7 @@ class OC_EventSource{ public function __construct() { OC_Util::obEnd(); header('Cache-Control: no-cache'); + header('X-Accel-Buffering: no'); $this->fallback=isset($_GET['fallback']) and $_GET['fallback']=='true'; if($this->fallback) { $this->fallBackId=$_GET['fallback_id']; @@ -44,6 +45,7 @@ class OC_EventSource{ } if( !OC_Util::isCallRegistered()) { $this->send('error', 'Possible CSRF attack. Connection will be closed.'); + $this->close(); exit(); } flush(); diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index 89fa6b8cc13..2d87871fd89 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -67,7 +67,7 @@ class Scanner extends BasicEmitter { public function getData($path) { if (!$this->storage->isReadable($path)) { //cant read, nothing we can do - \OCP\Util::writeLog('OC\Files\Cache\Scanner', "!!! Path '$path' is not readable !!!", \OCP\Util::DEBUG); + \OCP\Util::writeLog('OC\Files\Cache\Scanner', "!!! Path '$path' is not accessible or present !!!", \OCP\Util::DEBUG); return null; } $data = array(); diff --git a/lib/private/files/cache/storage.php b/lib/private/files/cache/storage.php index 9ad31a272ea..a38656d8499 100644 --- a/lib/private/files/cache/storage.php +++ b/lib/private/files/cache/storage.php @@ -28,9 +28,7 @@ class Storage { } else { $this->storageId = $storage; } - if (strlen($this->storageId) > 64) { - $this->storageId = md5($this->storageId); - } + $this->storageId = self::adjustStorageId($this->storageId); $sql = 'SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'; $result = \OC_DB::executeAudited($sql, array($this->storageId)); @@ -44,6 +42,19 @@ class Storage { } /** + * Adjusts the storage id to use md5 if too long + * @param string $storageId storage id + * @return unchanged $storageId if its length is less than 64 characters, + * else returns the md5 of $storageId + */ + public static function adjustStorageId($storageId) { + if (strlen($storageId) > 64) { + return md5($storageId); + } + return $storageId; + } + + /** * @return string */ public function getNumericId() { @@ -68,9 +79,7 @@ class Storage { * @return string|null */ public static function getNumericStorageId($storageId) { - if (strlen($storageId) > 64) { - $storageId = md5($storageId); - } + $storageId = self::adjustStorageId($storageId); $sql = 'SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'; $result = \OC_DB::executeAudited($sql, array($storageId)); @@ -95,9 +104,7 @@ class Storage { * @param string $storageId */ public static function remove($storageId) { - if (strlen($storageId) > 64) { - $storageId = md5($storageId); - } + $storageId = self::adjustStorageId($storageId); $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'; \OC_DB::executeAudited($sql, array($storageId)); diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index f15c203cd58..0e5e07c587d 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -114,22 +114,23 @@ class Updater { /** * get file owner and path * @param string $filename - * @return string[] with the oweners uid and the owners path + * @return string[] with the owner's uid and the owner's path */ private static function getUidAndFilename($filename) { $uid = \OC\Files\Filesystem::getOwner($filename); \OC\Files\Filesystem::initMountPoints($uid); + $filename = (strpos($filename, '/') !== 0) ? '/' . $filename : $filename; if ($uid != \OCP\User::getUser()) { $info = \OC\Files\Filesystem::getFileInfo($filename); if (!$info) { - return array($uid, '/files/' . $filename); + return array($uid, '/files' . $filename); } $ownerView = new \OC\Files\View('/' . $uid . '/files'); $filename = $ownerView->getPath($info['fileid']); } - return array($uid, '/files/' . $filename); + return array($uid, '/files' . $filename); } /** @@ -139,8 +140,7 @@ class Updater { * @param string $time */ static public function correctFolder($path, $time) { - if ($path !== '' && $path !== '/') { - + if ($path !== '' && $path !== '/' && $path !== '\\') { list($owner, $realPath) = self::getUidAndFilename(dirname($path)); /** @@ -181,6 +181,11 @@ class Updater { $cache = $storage->getCache(); $parentId = $cache->getParentId($internalPath); $parent = dirname($internalPath); + + if ($parent === '.' || $parent === '/' || $parent === '\\') { + $parent = ''; + } + if ($parentId != -1) { $cache->update($parentId, array('storage_mtime' => $storage->filemtime($parent))); } diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index d012c0c5a63..716b7d39402 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -215,7 +215,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { $sid = $this->getStorage()->getId(); if (!is_null($sid)) { $sid = explode(':', $sid); - return ($sid[0] !== 'local' and $sid[0] !== 'home'); + return ($sid[0] !== 'local' and $sid[0] !== 'home' and $sid[0] !== 'shared'); } return false; diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 4774d25ad9e..1dbe66143ac 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -31,11 +31,9 @@ namespace OC\Files; use OC\Files\Storage\Loader; -const SPACE_NOT_COMPUTED = -1; -const SPACE_UNKNOWN = -2; -const SPACE_UNLIMITED = -3; class Filesystem { + /** * @var Mount\Manager $mounts */ diff --git a/lib/private/files/mapper.php b/lib/private/files/mapper.php index 666719da12d..94dda807c2b 100644 --- a/lib/private/files/mapper.php +++ b/lib/private/files/mapper.php @@ -177,14 +177,12 @@ class Mapper /** * @param integer $index */ - public function slugifyPath($path, $index=null) { + public function slugifyPath($path, $index = null) { $path = $this->stripRootFolder($path, $this->unchangedPhysicalRoot); $pathElements = explode('/', $path); $sluggedElements = array(); - - $last= end($pathElements); - + foreach ($pathElements as $pathElement) { // remove empty elements if (empty($pathElement)) { @@ -196,19 +194,18 @@ class Mapper // apply index to file name if ($index !== null) { - $last= array_pop($sluggedElements); + $last = array_pop($sluggedElements); // if filename contains periods - add index number before last period - if (preg_match('~\.[^\.]+$~i',$last,$extension)){ - array_push($sluggedElements, substr($last,0,-(strlen($extension[0]))).'-'.$index.$extension[0]); + if (preg_match('~\.[^\.]+$~i', $last, $extension)) { + array_push($sluggedElements, substr($last, 0, -(strlen($extension[0]))) . '-' . $index . $extension[0]); } else { // if filename doesn't contain periods add index ofter the last char - array_push($sluggedElements, $last.'-'.$index); - } - + array_push($sluggedElements, $last . '-' . $index); + } } - $sluggedPath = $this->unchangedPhysicalRoot.implode('/', $sluggedElements); + $sluggedPath = $this->unchangedPhysicalRoot . implode('/', $sluggedElements); return $this->stripLast($sluggedPath); } @@ -218,8 +215,8 @@ class Mapper * @param string $text * @return string */ - private function slugify($text) - { + private function slugify($text) { + $originalText = $text; // replace non letter or digits or dots by - $text = preg_replace('~[^\\pL\d\.]+~u', '-', $text); @@ -241,7 +238,17 @@ class Mapper $text = preg_replace('~\.+$~', '', $text); if (empty($text)) { - return uniqid(); + /** + * Item slug would be empty. Previously we used uniqid() here. + * However this means that the behaviour is not reproducible, so + * when uploading files into a "empty" folder, the folders name is + * different. + * + * If there would be a md5() hash collision, the deduplicate check + * will spot this and append an index later, so this should not be + * a problem. + */ + return md5($originalText); } return $text; diff --git a/lib/private/files/node/folder.php b/lib/private/files/node/folder.php index 3e23f5c2c94..8c7acc339ae 100644 --- a/lib/private/files/node/folder.php +++ b/lib/private/files/node/folder.php @@ -27,22 +27,19 @@ class Folder extends Node implements \OCP\Files\Folder { /** * @param string $path - * @throws \OCP\Files\NotFoundException * @return string */ public function getRelativePath($path) { if ($this->path === '' or $this->path === '/') { return $this->normalizePath($path); } - if (strpos($path, $this->path) !== 0) { - throw new NotFoundException(); + if ($path === $this->path) { + return '/'; + } else if (strpos($path, $this->path . '/') !== 0) { + return null; } else { $path = substr($path, strlen($this->path)); - if (strlen($path) === 0) { - return '/'; - } else { - return $this->normalizePath($path); - } + return $this->normalizePath($path); } } @@ -295,15 +292,29 @@ class Folder extends Node implements \OCP\Files\Folder { * @return \OC\Files\Node\Node[] */ public function getById($id) { - $nodes = $this->root->getById($id); - $result = array(); - foreach ($nodes as $node) { - $pathPart = substr($node->getPath(), 0, strlen($this->getPath()) + 1); - if ($this->path === '/' or $pathPart === $this->getPath() . '/') { - $result[] = $node; + $mounts = $this->root->getMountsIn($this->path); + $mounts[] = $this->root->getMount($this->path); + // reverse the array so we start with the storage this view is in + // which is the most likely to contain the file we're looking for + $mounts = array_reverse($mounts); + + $nodes = array(); + foreach ($mounts as $mount) { + /** + * @var \OC\Files\Mount\Mount $mount + */ + if ($mount->getStorage()) { + $cache = $mount->getStorage()->getCache(); + $internalPath = $cache->getPathById($id); + if (is_string($internalPath)) { + $fullPath = $mount->getMountPoint() . $internalPath; + if (!is_null($path = $this->getRelativePath($fullPath))) { + $nodes[] = $this->get($path); + } + } } } - return $result; + return $nodes; } public function getFreeSpace() { diff --git a/lib/private/files/node/root.php b/lib/private/files/node/root.php index 70135285b0d..18e7a6b681a 100644 --- a/lib/private/files/node/root.php +++ b/lib/private/files/node/root.php @@ -162,39 +162,13 @@ class Root extends Folder implements Emitter { if ($this->view->file_exists($fullPath)) { return $this->createNode($fullPath); } else { - throw new NotFoundException(); + throw new NotFoundException($path); } } else { throw new NotPermittedException(); } } - /** - * search file by id - * - * An array is returned because in the case where a single storage is mounted in different places the same file - * can exist in different places - * - * @param int $id - * @throws \OCP\Files\NotFoundException - * @return Node[] - */ - public function getById($id) { - $result = Cache::getById($id); - if (is_null($result)) { - throw new NotFoundException(); - } else { - list($storageId, $internalPath) = $result; - $nodes = array(); - $mounts = $this->mountManager->findByStorageId($storageId); - foreach ($mounts as $mount) { - $nodes[] = $this->get($mount->getMountPoint() . $internalPath); - } - return $nodes; - } - - } - //most operations cant be done on the root /** diff --git a/lib/private/files/objectstore/swift.php b/lib/private/files/objectstore/swift.php index 3378fd7b86f..1e8dd6a7401 100644 --- a/lib/private/files/objectstore/swift.php +++ b/lib/private/files/objectstore/swift.php @@ -120,12 +120,11 @@ class Swift implements IObjectStore { $objectContent = $object->getContent(); $objectContent->rewind(); - // directly returning the object stream does not work because the GC seems to collect it, so we need a copy - $tmpStream = fopen('php://temp', 'r+'); - stream_copy_to_stream($objectContent->getStream(), $tmpStream); - rewind($tmpStream); + $stream = $objectContent->getStream(); + // save the object content in the context of the stream to prevent it being gc'd until the stream is closed + stream_context_set_option($stream, 'swift','content', $objectContent); - return $tmpStream; + return $stream; } /** diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 9657b511f15..4799c865142 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -226,6 +226,7 @@ abstract class Common implements \OC\Files\Storage\Storage { $tmpFile = \OC_Helper::tmpFile($extension); $target = fopen($tmpFile, 'w'); \OC_Helper::streamCopy($source, $target); + fclose($target); return $tmpFile; } @@ -397,7 +398,7 @@ abstract class Common implements \OC\Files\Storage\Storage { * @return int */ public function free_space($path) { - return \OC\Files\SPACE_UNKNOWN; + return \OCP\Files\FileInfo::SPACE_UNKNOWN; } /** diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php index 02c3ebd0202..bd7166c9823 100644 --- a/lib/private/files/storage/dav.php +++ b/lib/private/files/storage/dav.php @@ -243,10 +243,10 @@ class DAV extends \OC\Files\Storage\Common { if (isset($response['{DAV:}quota-available-bytes'])) { return (int)$response['{DAV:}quota-available-bytes']; } else { - return \OC\Files\SPACE_UNKNOWN; + return \OCP\Files\FileInfo::SPACE_UNKNOWN; } } catch (\Exception $e) { - return \OC\Files\SPACE_UNKNOWN; + return \OCP\Files\FileInfo::SPACE_UNKNOWN; } } @@ -295,6 +295,7 @@ class DAV extends \OC\Files\Storage\Common { \OCP\Util::writeLog("webdav client", 'curl GET ' . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . ' returned status code ' . $statusCode, \OCP\Util::ERROR); } curl_close($curl); + fclose($source); $this->removeCachedFile($target); } diff --git a/lib/private/files/storage/home.php b/lib/private/files/storage/home.php index 015b1f01885..85b06f8a510 100644 --- a/lib/private/files/storage/home.php +++ b/lib/private/files/storage/home.php @@ -66,4 +66,14 @@ class Home extends Local implements \OCP\Files\IHomeStorage { public function getUser() { return $this->user; } + + /** + * get the owner of a path + * + * @param string $path The path to get the owner + * @return string uid or false + */ + public function getOwner($path) { + return $this->user->getUID(); + } } diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php index 63570d70cff..9df6cdef2af 100644 --- a/lib/private/files/storage/local.php +++ b/lib/private/files/storage/local.php @@ -208,22 +208,7 @@ if (\OC_Util::runningOnWindows()) { } public function fopen($path, $mode) { - if ($return = fopen($this->datadir . $path, $mode)) { - switch ($mode) { - case 'r': - break; - case 'r+': - case 'w+': - case 'x+': - case 'a+': - break; - case 'w': - case 'x': - case 'a': - break; - } - } - return $return; + return fopen($this->datadir . $path, $mode); } public function hash($type, $path, $raw = false) { @@ -233,7 +218,7 @@ if (\OC_Util::runningOnWindows()) { public function free_space($path) { $space = @disk_free_space($this->datadir . $path); if ($space === false || is_null($space)) { - return \OC\Files\SPACE_UNKNOWN; + return \OCP\Files\FileInfo::SPACE_UNKNOWN; } return $space; } diff --git a/lib/private/files/storage/mappedlocal.php b/lib/private/files/storage/mappedlocal.php index c4a8dc1961c..0760d842eaf 100644 --- a/lib/private/files/storage/mappedlocal.php +++ b/lib/private/files/storage/mappedlocal.php @@ -79,7 +79,7 @@ class MappedLocal extends \OC\Files\Storage\Common { $logicalPath = $this->mapper->physicalToLogic($physicalPath); $dh = opendir($physicalPath); - if(is_resource($dh)) { + if (is_resource($dh)) { while (($file = readdir($dh)) !== false) { if ($file === '.' or $file === '..') { continue; @@ -87,9 +87,9 @@ class MappedLocal extends \OC\Files\Storage\Common { $logicalFilePath = $this->mapper->physicalToLogic($physicalPath . '/' . $file); - $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath); + $file = $this->mapper->stripRootFolder($logicalFilePath, $logicalPath); $file = $this->stripLeading($file); - $files[]= $file; + $files[] = $file; } } @@ -245,28 +245,15 @@ class MappedLocal extends \OC\Files\Storage\Common { } public function fopen($path, $mode) { - if ($return = fopen($this->buildPath($path), $mode)) { - switch ($mode) { - case 'r': - break; - case 'r+': - case 'w+': - case 'x+': - case 'a+': - break; - case 'w': - case 'x': - case 'a': - break; - } - } - return $return; + return fopen($this->buildPath($path), $mode); } /** * @param string $dir + * @param bool $isLogicPath + * @return bool */ - private function delTree($dir, $isLogicPath=true) { + private function delTree($dir, $isLogicPath = true) { $dirRelative = $dir; if ($isLogicPath) { $dir = $this->buildPath($dir); @@ -380,7 +367,7 @@ class MappedLocal extends \OC\Files\Storage\Common { /** * @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; diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php index c57c797f87a..bf169e41f13 100644 --- a/lib/private/files/storage/wrapper/quota.php +++ b/lib/private/files/storage/wrapper/quota.php @@ -50,7 +50,7 @@ class Quota extends Wrapper { } return $data['size']; } else { - return \OC\Files\SPACE_NOT_COMPUTED; + return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; } } @@ -66,7 +66,7 @@ class Quota extends Wrapper { } else { $used = $this->getSize($this->sizeRoot); if ($used < 0) { - return \OC\Files\SPACE_NOT_COMPUTED; + return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; } else { $free = $this->storage->free_space($path); $quotaFree = max($this->quota - $used, 0); diff --git a/lib/private/files/view.php b/lib/private/files/view.php index e08cb20f73d..d310a0fa4e1 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -670,6 +670,12 @@ class View { $source = fopen($tmpFile, 'r'); if ($source) { $this->file_put_contents($path, $source); + // $this->file_put_contents() might have already closed + // the resource, so we check it, before trying to close it + // to avoid messages in the error log. + if (is_resource($source)) { + fclose($source); + } unlink($tmpFile); return true; } else { @@ -781,6 +787,9 @@ class View { return false; } $defaultRoot = Filesystem::getRoot(); + if ($defaultRoot === null) { + return false; + } if ($this->fakeRoot === $defaultRoot) { return true; } @@ -957,6 +966,10 @@ class View { $content['permissions'] = $storage->getPermissions($content['path']); $cache->update($content['fileid'], array('permissions' => $content['permissions'])); } + // if sharing was disabled for the user we remove the share permissions + if (\OCP\Util::isSharingDisabledForUser()) { + $content['permissions'] = $content['permissions'] & ~\OCP\PERMISSION_SHARE; + } $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content); } @@ -1005,6 +1018,12 @@ class View { } } $rootEntry['path'] = substr($path . '/' . $rootEntry['name'], strlen($user) + 2); // full path without /$user/ + + // if sharing was disabled for the user we remove the share permissions + if (\OCP\Util::isSharingDisabledForUser()) { + $content['permissions'] = $content['permissions'] & ~\OCP\PERMISSION_SHARE; + } + $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry); } } @@ -1169,6 +1188,7 @@ class View { * @return string|null */ public function getPath($id) { + $id = (int) $id; $manager = Filesystem::getMountManager(); $mounts = $manager->findIn($this->fakeRoot); $mounts[] = $manager->find($this->fakeRoot); diff --git a/lib/private/group/database.php b/lib/private/group/database.php index b7148f38fe3..8d6ea1f50a5 100644 --- a/lib/private/group/database.php +++ b/lib/private/group/database.php @@ -185,7 +185,7 @@ class OC_Group_Database extends OC_Group_Backend { public function groupExists($gid) { $query = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` = ?'); $result = $query->execute(array($gid))->fetchOne(); - if ($result) { + if ($result !== false) { return true; } return false; diff --git a/lib/private/group/manager.php b/lib/private/group/manager.php index 368fa3851d7..bea7ad193bf 100644 --- a/lib/private/group/manager.php +++ b/lib/private/group/manager.php @@ -126,7 +126,7 @@ class Manager extends PublicEmitter implements IGroupManager { * @return \OC\Group\Group */ public function createGroup($gid) { - if (!$gid) { + if ($gid === '' || is_null($gid)) { return false; } else if ($group = $this->get($gid)) { return $group; diff --git a/lib/private/helper.php b/lib/private/helper.php index f90c38d236c..7c1edd1b058 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -183,6 +183,7 @@ class OC_Helper { 'application/x-gzip' => 'package/x-generic', 'application/x-rar-compressed' => 'package/x-generic', 'application/x-tar' => 'package/x-generic', + 'application/vnd.android.package-archive' => 'package/x-generic', 'application/zip' => 'package/x-generic', 'application/msword' => 'x-office/document', @@ -578,8 +579,20 @@ class OC_Helper { public static function tmpFile($postfix = '') { $file = get_temp_dir() . '/' . md5(time() . rand()) . $postfix; $fh = fopen($file, 'w'); - fclose($fh); - self::$tmpFiles[] = $file; + if ($fh!==false){ + fclose($fh); + self::$tmpFiles[] = $file; + } else { + OC_Log::write( + 'OC_Helper', + sprintf( + 'Can not create a temporary file in directory %s. Check it exists and has correct permissions', + get_temp_dir() + ), + OC_Log::WARN + ); + $file = false; + } return $file; } @@ -886,7 +899,7 @@ class OC_Helper { */ public static function freeSpace($dir) { $freeSpace = \OC\Files\Filesystem::free_space($dir); - if ($freeSpace !== \OC\Files\SPACE_UNKNOWN) { + if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN) { $freeSpace = max($freeSpace, 0); return $freeSpace; } else { @@ -959,7 +972,7 @@ class OC_Helper { } if ($includeExtStorage) { $quota = OC_Util::getUserQuota(\OCP\User::getUser()); - if ($quota !== \OC\Files\SPACE_UNLIMITED) { + if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { // always get free space / total space from root + mount points $path = ''; return self::getGlobalStorageInfo(); diff --git a/lib/private/image.php b/lib/private/image.php index 5331c399159..7ddc8dca143 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -603,6 +603,7 @@ class OC_Image { $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14)); // check for bitmap if ($meta['type'] != 19778) { + fclose($fh); trigger_error('imagecreatefrombmp: ' . $fileName . ' is not a bitmap!', E_USER_WARNING); return false; } @@ -626,6 +627,7 @@ class OC_Image { if ($meta['imagesize'] < 1) { $meta['imagesize'] = @filesize($fileName) - $meta['offset']; if ($meta['imagesize'] < 1) { + fclose($fh); trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $fileName . '!', E_USER_WARNING); return false; } @@ -666,6 +668,7 @@ class OC_Image { break; case 16: if (!($part = substr($data, $p, 2))) { + fclose($fh); trigger_error($error, E_USER_WARNING); return $im; } @@ -712,6 +715,7 @@ class OC_Image { $color[1] = $palette[ $color[1] + 1 ]; break; default: + fclose($fh); trigger_error('imagecreatefrombmp: ' . $fileName . ' has ' . $meta['bits'] . ' bits and this is not supported!', E_USER_WARNING); @@ -870,6 +874,14 @@ class OC_Image { imagedestroy($process); return false; } + + // preserve transparency + if($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) { + imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127)); + imagealphablending($process, false); + imagesavealpha($process, true); + } + imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h); if ($process == false) { OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$w.'x'.$h, OC_Log::ERROR); diff --git a/lib/private/installer.php b/lib/private/installer.php index c5a09349629..dc9a3558b75 100644 --- a/lib/private/installer.php +++ b/lib/private/installer.php @@ -532,10 +532,6 @@ class OC_Installer{ */ public static function checkCode($appname, $folder) { $blacklist=array( - 'exec(', - 'eval(', - // more evil pattern will go here later - // classes replaced by the public api 'OC_API::', 'OC_App::', diff --git a/lib/private/largefilehelper.php b/lib/private/largefilehelper.php index 293e09fe2c9..2c35feefc8b 100644 --- a/lib/private/largefilehelper.php +++ b/lib/private/largefilehelper.php @@ -147,7 +147,7 @@ class LargeFileHelper { if (\OC_Helper::is_function_enabled('exec')) { $os = strtolower(php_uname('s')); $arg = escapeshellarg($filename); - $result = ''; + $result = null; if (strpos($os, 'linux') !== false) { $result = $this->exec("stat -c %s $arg"); } else if (strpos($os, 'bsd') !== false) { diff --git a/lib/private/legacy/appconfig.php b/lib/private/legacy/appconfig.php index 4634f2c695d..68f63974e85 100644 --- a/lib/private/legacy/appconfig.php +++ b/lib/private/legacy/appconfig.php @@ -24,6 +24,8 @@ /** * This class provides an easy way for apps to store config values in the * database. + * + * @deprecated use \OC::$server->getAppConfig() to get an \OCP\IAppConfig instance */ class OC_Appconfig { /** diff --git a/lib/private/legacy/config.php b/lib/private/legacy/config.php index 899c19532f0..4d6fefc4e17 100644 --- a/lib/private/legacy/config.php +++ b/lib/private/legacy/config.php @@ -37,6 +37,8 @@ /** * This class is responsible for reading and writing config.php, the very basic * configuration file of ownCloud. + * + * @deprecated use \OC::$server->getConfig() to get an \OCP\Config instance */ class OC_Config { diff --git a/lib/private/legacy/log.php b/lib/private/legacy/log.php index 027cb89e97c..99c9254e90f 100644 --- a/lib/private/legacy/log.php +++ b/lib/private/legacy/log.php @@ -14,6 +14,9 @@ */ OC_Log::$object = new \OC\Log(); +/** + * @deprecated use \OC::$server->getLogger() to get an \OCP\ILogger instance + */ class OC_Log { public static $object; diff --git a/lib/private/legacy/preferences.php b/lib/private/legacy/preferences.php index 060274085fe..4b68b0e69aa 100644 --- a/lib/private/legacy/preferences.php +++ b/lib/private/legacy/preferences.php @@ -21,10 +21,11 @@ * */ +OC_Preferences::$object = new \OC\Preferences(OC_DB::getConnection()); /** * This class provides an easy way for storing user preferences. + * @deprecated use \OC\Preferences instead */ -OC_Preferences::$object = new \OC\Preferences(OC_DB::getConnection()); class OC_Preferences{ public static $object; /** diff --git a/lib/private/legacy/search.php b/lib/private/legacy/search.php index f77b43be2e0..19aba2a8b8c 100644 --- a/lib/private/legacy/search.php +++ b/lib/private/legacy/search.php @@ -22,7 +22,8 @@ /** * provides an interface to all search providers - * @deprecated see lib/search.php + * + * @deprecated use \OCP\ISearch / \OC\Search instead */ class OC_Search { /** diff --git a/lib/private/legacy/search/provider.php b/lib/private/legacy/search/provider.php index b296aeb23d8..b183caf5511 100644 --- a/lib/private/legacy/search/provider.php +++ b/lib/private/legacy/search/provider.php @@ -19,6 +19,7 @@ /** * Class OC_Search_Provider + * * @deprecated use \OCP\Search\Provider instead */ abstract class OC_Search_Provider extends \OCP\Search\Provider { diff --git a/lib/private/legacy/search/provider/file.php b/lib/private/legacy/search/provider/file.php index e610281131d..079ce85bf54 100644 --- a/lib/private/legacy/search/provider/file.php +++ b/lib/private/legacy/search/provider/file.php @@ -17,6 +17,9 @@ * */ +/** + * @deprecated use \OC\Search\Provider\File instead + */ class OC_Search_Provider_File extends \OC\Search\Provider\File { } diff --git a/lib/private/legacy/search/result.php b/lib/private/legacy/search/result.php index f3e6ecbb990..d5aa3391dc8 100644 --- a/lib/private/legacy/search/result.php +++ b/lib/private/legacy/search/result.php @@ -17,8 +17,10 @@ * */ +/** + * @deprecated use \OCP\Search\Result instead + */ class OC_Search_Result extends \OCP\Search\Result { - /** * Create a new search result * @param string $id unique identifier from application: '[app_name]/[item_identifier_in_app]' diff --git a/lib/private/legacy/updater.php b/lib/private/legacy/updater.php index eea7bb129cf..190748066c6 100644 --- a/lib/private/legacy/updater.php +++ b/lib/private/legacy/updater.php @@ -6,6 +6,11 @@ * See the COPYING-README file. */ +/** + * provides an interface to all search providers + * + * @deprecated use \OC\Updater instead + */ class OC_Updater { public static function check() { $updater = new \OC\Updater(); diff --git a/lib/private/mail.php b/lib/private/mail.php index 81bcb3d8deb..691ae1dd33f 100644 --- a/lib/private/mail.php +++ b/lib/private/mail.php @@ -70,20 +70,21 @@ class OC_Mail { $mailo->From = $fromaddress; $mailo->FromName = $fromname;; $mailo->Sender = $fromaddress; + $mailo->XMailer = ' '; try { $toaddress = self::buildAsciiEmail($toaddress); $mailo->AddAddress($toaddress, $toname); - if($ccaddress<>'') $mailo->AddCC($ccaddress, $ccname); - if($bcc<>'') $mailo->AddBCC($bcc); + if($ccaddress != '') $mailo->AddCC($ccaddress, $ccname); + if($bcc != '') $mailo->AddBCC($bcc); $mailo->AddReplyTo($fromaddress, $fromname); - $mailo->WordWrap = 50; - if($html==1) $mailo->IsHTML(true); else $mailo->IsHTML(false); + $mailo->WordWrap = 78; + $mailo->IsHTML($html == 1); $mailo->Subject = $subject; - if($altbody=='') { + if($altbody == '') { $mailo->Body = $mailtext.OC_MAIL::getfooter(); $mailo->AltBody = ''; }else{ diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index d60b157efe2..8e47a8899fc 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -59,7 +59,8 @@ class Factory implements ICacheFactory { * @param string $prefix * @return null|Cache */ - public static function createLowLatency($prefix = '') { + public function createLowLatency($prefix = '') { + $prefix = $this->globalPrefix . '/' . $prefix; if (XCache::isAvailable()) { return new XCache($prefix); } elseif (APCu::isAvailable()) { @@ -76,7 +77,7 @@ class Factory implements ICacheFactory { * * @return bool */ - public static function isAvailableLowLatency() { + public function isAvailableLowLatency() { return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable(); } diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php index d27e9e6348b..a44ec1daa1e 100644 --- a/lib/private/mimetypes.list.php +++ b/lib/private/mimetypes.list.php @@ -28,9 +28,11 @@ * is considered secure. */ return array( + '3gp' => array('video/3gpp', null), '7z' => array('application/x-7z-compressed', null), 'accdb' => array('application/msaccess', null), 'ai' => array('application/illustrator', null), + 'apk' => array('application/vnd.android.package-archive', null), 'avi' => array('video/x-msvideo', null), 'bash' => array('text/x-shellscript', null), 'blend' => array('application/x-blender', null), @@ -137,6 +139,7 @@ return array( 'txt' => array('text/plain', null), 'vcard' => array('text/vcard', null), 'vcf' => array('text/vcard', null), + 'vob' => array('video/dvd', null), 'wav' => array('audio/wav', null), 'webm' => array('video/webm', null), 'woff' => array('application/font-woff', null), diff --git a/lib/private/needsupdateexception.php b/lib/private/needsupdateexception.php new file mode 100644 index 00000000000..bab928dc30f --- /dev/null +++ b/lib/private/needsupdateexception.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright (c) 2014 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; + +class NeedsUpdateException extends ServiceUnavailableException { +} diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php index dc52fc27b5e..e4cce6b2260 100644 --- a/lib/private/ocsclient.php +++ b/lib/private/ocsclient.php @@ -59,7 +59,7 @@ class OC_OCSClient{ /** * Get all the categories from the OCS server - * @return array an array of category ids + * @return array|null an array of category ids or null * @note returns NULL if config value appstoreenabled is set to false * This function returns a list of all the application categories on the OCS server */ @@ -92,7 +92,7 @@ class OC_OCSClient{ /** * Get all the applications from the OCS server - * @return array an array of application data + * @return array|null an array of application data or null * * This function returns a list of all the applications on the OCS server * @param array|string $categories @@ -150,9 +150,9 @@ class OC_OCSClient{ /** * Get an the applications from the OCS server * @param string $id - * @return array an array of application data + * @return array|null an array of application data or null * - * This function returns an applications from the OCS server + * This function returns an applications from the OCS server */ public static function getApplication($id) { if(OC_Config::getValue('appstoreenabled', true)==false) { @@ -162,7 +162,7 @@ class OC_OCSClient{ $xml=OC_OCSClient::getOCSresponse($url); if($xml==false) { - OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); + OC_Log::write('core', 'Unable to parse OCS content for app ' . $id, OC_Log::FATAL); return null; } $loadEntities = libxml_disable_entity_loader(true); @@ -170,6 +170,10 @@ class OC_OCSClient{ libxml_disable_entity_loader($loadEntities); $tmp=$data->data->content; + if (is_null($tmp)) { + OC_Log::write('core', 'Invalid OCS content returned for app ' . $id, OC_Log::FATAL); + return null; + } $app=array(); $app['id']=$tmp->id; $app['name']=$tmp->name; @@ -192,7 +196,7 @@ class OC_OCSClient{ /** * Get the download url for an application from the OCS server - * @return array an array of application data + * @return array|null an array of application data or null * * This function returns an download url for an applications from the OCS server * @param string $id @@ -223,6 +227,4 @@ class OC_OCSClient{ return $app; } - - } diff --git a/lib/private/preview.php b/lib/private/preview.php index 8089379bde5..cc15ab84fe7 100755 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -13,6 +13,7 @@ */ namespace OC; +use OC\Files\Filesystem; use OC\Preview\Provider; require_once 'preview/image.php'; @@ -476,12 +477,15 @@ class Preview { $cached = $this->isCached($fileId); if ($cached) { $stream = $this->userView->fopen($cached, 'r'); - $image = new \OC_Image(); - $image->loadFromFileHandle($stream); - $this->preview = $image->valid() ? $image : null; + $this->preview = null; + if ($stream) { + $image = new \OC_Image(); + $image->loadFromFileHandle($stream); + $this->preview = $image->valid() ? $image : null; - $this->resizeAndCrop(); - fclose($stream); + $this->resizeAndCrop(); + fclose($stream); + } } if (is_null($this->preview)) { @@ -561,9 +565,15 @@ class Preview { $realX = (int)$image->width(); $realY = (int)$image->height(); - // compute $maxY using the aspect of the generated preview + // compute $maxY and $maxX using the aspect of the generated preview if ($this->keepAspect) { - $y = $x / ($realX / $realY); + $ratio = $realX / $realY; + if($x / $ratio < $y) { + // width restricted + $y = $x / $ratio; + } else { + $x = $y * $ratio; + } } if ($x === $realX && $y === $realY) { @@ -726,6 +736,35 @@ class Preview { } /** + * Check if a preview can be generated for a file + * + * @param \OC\Files\FileInfo $file + * @return bool + */ + public static function isAvailable($file) { + if (!\OC_Config::getValue('enable_previews', true)) { + return false; + } + + //check if there are preview backends + if (empty(self::$providers)) { + self::initProviders(); + } + + //remove last element because it has the mimetype * + $providers = array_slice(self::$providers, 0, -1); + foreach ($providers as $supportedMimeType => $provider) { + /** + * @var \OC\Preview\Provider $provider + */ + if (preg_match($supportedMimeType, $file->getMimetype())) { + return $provider->isAvailable($file); + } + } + return false; + } + + /** * @param string $mimeType * @return bool */ diff --git a/lib/private/preview/mp3.php b/lib/private/preview/mp3.php index 21f160fd50f..bb4d3dfce86 100644 --- a/lib/private/preview/mp3.php +++ b/lib/private/preview/mp3.php @@ -14,8 +14,6 @@ class MP3 extends Provider { } public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - require_once('getid3/getid3.php'); - $getID3 = new \getID3(); $tmpPath = $fileview->toTmpFile($path); diff --git a/lib/private/preview/office-cl.php b/lib/private/preview/office-cl.php index 6e4d4321eb7..81e0cf4b6ae 100644 --- a/lib/private/preview/office-cl.php +++ b/lib/private/preview/office-cl.php @@ -29,13 +29,12 @@ if (!\OC_Util::runningOnWindows()) { $tmpDir = get_temp_dir(); - $defaultParameters = ' --headless --nologo --nofirststartwizard --invisible --norestore -convert-to pdf -outdir '; + $defaultParameters = ' -env:UserInstallation=file://' . escapeshellarg($tmpDir) . ' --headless --nologo --nofirststartwizard --invisible --norestore -convert-to pdf -outdir '; $clParameters = \OCP\Config::getSystemValue('preview_office_cl_parameters', $defaultParameters); $exec = $this->cmd . $clParameters . escapeshellarg($tmpDir) . ' ' . escapeshellarg($absPath); - $export = 'export HOME=/' . $tmpDir; - shell_exec($export . "\n" . $exec); + shell_exec($exec); //create imagick object from pdf try{ diff --git a/lib/private/preview/provider.php b/lib/private/preview/provider.php index f769823f6e6..f544c2c4b13 100644 --- a/lib/private/preview/provider.php +++ b/lib/private/preview/provider.php @@ -11,6 +11,16 @@ abstract class Provider { abstract public function getMimeType(); /** + * Check if a preview can be generated for $path + * + * @param string $path + * @return bool + */ + public function isAvailable($path) { + return true; + } + + /** * get thumbnail for file at path $path * @param string $path Path of file * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image diff --git a/lib/private/preview/txt.php b/lib/private/preview/txt.php index 063543c6279..2ac77faf48b 100644 --- a/lib/private/preview/txt.php +++ b/lib/private/preview/txt.php @@ -14,6 +14,16 @@ class TXT extends Provider { } /** + * Check if a preview can be generated for $path + * + * @param \OC\Files\FileInfo $file + * @return bool + */ + public function isAvailable($file) { + return $file->getSize() > 5; + } + + /** * @param string $path * @param int $maxX * @param int $maxY @@ -44,13 +54,20 @@ class TXT extends Provider { $fontFile .= '/../../../core'; $fontFile .= '/fonts/OpenSans-Regular.ttf'; + $canUseTTF = function_exists('imagettftext'); + foreach($lines as $index => $line) { $index = $index + 1; $x = (int) 1; $y = (int) ($index * $lineSize); - imagettftext($image, $fontSize, 0, $x, $y, $textColor, $fontFile, $line); + if ($canUseTTF === true) { + imagettftext($image, $fontSize, 0, $x, $y, $textColor, $fontFile, $line); + } else { + $y -= $fontSize; + imagestring($image, 1, $x, $y, $line, $textColor); + } if(($index * $lineSize) >= $maxY) { break; diff --git a/lib/private/previewmanager.php b/lib/private/previewmanager.php index 23dbee13c7d..85bf609743d 100755 --- a/lib/private/previewmanager.php +++ b/lib/private/previewmanager.php @@ -14,25 +14,35 @@ use OCP\IPreview; class PreviewManager implements IPreview { /** * return a preview of a file + * * @param string $file The path to the file where you want a thumbnail from * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image * @param boolean $scaleUp Scale smaller images up to the thumbnail size or not. Might look ugly * @return \OCP\Image */ - function createPreview($file, $maxX = 100, $maxY = 75, $scaleUp = false) - { + function createPreview($file, $maxX = 100, $maxY = 75, $scaleUp = false) { $preview = new \OC\Preview('', '/', $file, $maxX, $maxY, $scaleUp); return $preview->getPreview(); } /** * returns true if the passed mime type is supported + * * @param string $mimeType * @return boolean */ - function isMimeSupported($mimeType = '*') - { + function isMimeSupported($mimeType = '*') { return \OC\Preview::isMimeSupported($mimeType); } + + /** + * Check if a preview can be generated for a file + * + * @param \OC\Files\FileInfo $file + * @return bool + */ + function isAvailable($file) { + return \OC\Preview::isAvailable($file); + } } diff --git a/lib/private/repair.php b/lib/private/repair.php index e6943c5d057..46b5ae46399 100644 --- a/lib/private/repair.php +++ b/lib/private/repair.php @@ -69,7 +69,8 @@ class Repair extends BasicEmitter { */ public static function getRepairSteps() { return array( - new \OC\Repair\RepairMimeTypes() + new \OC\Repair\RepairMimeTypes(), + new \OC\Repair\RepairLegacyStorages(\OC::$server->getConfig(), \OC_DB::getConnection()), ); } diff --git a/lib/private/repair/repairlegacystorages.php b/lib/private/repair/repairlegacystorages.php new file mode 100644 index 00000000000..ab123afeca6 --- /dev/null +++ b/lib/private/repair/repairlegacystorages.php @@ -0,0 +1,221 @@ +<?php +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Repair; + +use OC\Hooks\BasicEmitter; + +class RepairLegacyStorages extends BasicEmitter { + /** + * @var \OCP\IConfig + */ + protected $config; + + /** + * @var \OC\DB\Connection + */ + protected $connection; + + protected $findStorageInCacheStatement; + protected $renameStorageStatement; + + /** + * @param \OCP\IConfig $config + * @param \OC\DB\Connection $connection + */ + public function __construct($config, $connection) { + $this->connection = $connection; + $this->config = $config; + + $this->findStorageInCacheStatement = $this->connection->prepare( + 'SELECT DISTINCT `storage` FROM `*PREFIX*filecache`' + . ' WHERE `storage` in (?, ?)' + ); + $this->renameStorageStatement = $this->connection->prepare( + 'UPDATE `*PREFIX*storages`' + . ' SET `id` = ?' + . ' WHERE `id` = ?' + ); + } + + public function getName() { + return 'Repair legacy storages'; + } + + /** + * Extracts the user id from a legacy storage id + * + * @param string $storageId legacy storage id in the + * format "local::/path/to/datadir/userid" + * @return string user id extracted from the storage id + */ + private function extractUserId($storageId) { + $storageId = rtrim($storageId, '/'); + $pos = strrpos($storageId, '/'); + return substr($storageId, $pos + 1); + } + + /** + * Fix the given legacy storage by renaming the old id + * to the new id. If the new id already exists, whichever + * storage that has data in the file cache will be used. + * If both have data, nothing will be done and false is + * returned. + * + * @param string $oldId old storage id + * @param int $oldNumericId old storage numeric id + * + * @return bool true if fixed, false otherwise + */ + private function fixLegacyStorage($oldId, $oldNumericId, $userId = null) { + // check whether the new storage already exists + if (is_null($userId)) { + $userId = $this->extractUserId($oldId); + } + $newId = 'home::' . $userId; + + // check if target id already exists + $newNumericId = \OC\Files\Cache\Storage::getNumericStorageId($newId); + if (!is_null($newNumericId)) { + $newNumericId = (int)$newNumericId; + // try and resolve the conflict + // check which one of "local::" or "home::" needs to be kept + $result = $this->findStorageInCacheStatement->execute(array($oldNumericId, $newNumericId)); + $row1 = $this->findStorageInCacheStatement->fetch(); + $row2 = $this->findStorageInCacheStatement->fetch(); + $this->findStorageInCacheStatement->closeCursor(); + if ($row2 !== false) { + // two results means both storages have data, not auto-fixable + throw new \OC\RepairException( + 'Could not automatically fix legacy storage ' + . '"' . $oldId . '" => "' . $newId . '"' + . ' because they both have data.' + ); + } + if ($row1 === false || (int)$row1['storage'] === $oldNumericId) { + // old storage has data, then delete the empty new id + $toDelete = $newId; + } else if ((int)$row1['storage'] === $newNumericId) { + // new storage has data, then delete the empty old id + $toDelete = $oldId; + } else { + // unknown case, do not continue + return false; + } + + // delete storage including file cache + \OC\Files\Cache\Storage::remove($toDelete); + + // if we deleted the old id, the new id will be used + // automatically + if ($toDelete === $oldId) { + // nothing more to do + return true; + } + } + + // rename old id to new id + $newId = \OC\Files\Cache\Storage::adjustStorageId($newId); + $oldId = \OC\Files\Cache\Storage::adjustStorageId($oldId); + $rowCount = $this->renameStorageStatement->execute(array($newId, $oldId)); + $this->renameStorageStatement->closeCursor(); + return ($rowCount === 1); + } + + /** + * Converts legacy home storage ids in the format + * "local::/data/dir/path/userid/" to the new format "home::userid" + */ + public function run() { + // only run once + if ($this->config->getAppValue('core', 'repairlegacystoragesdone') === 'yes') { + return; + } + + $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); + $dataDir = rtrim($dataDir, '/') . '/'; + $dataDirId = 'local::' . $dataDir; + + $count = 0; + + $this->connection->beginTransaction(); + + try { + // note: not doing a direct UPDATE with the REPLACE function + // because regexp search/extract is needed and it is not guaranteed + // to work on all database types + $sql = 'SELECT `id`, `numeric_id` FROM `*PREFIX*storages`' + . ' WHERE `id` LIKE ?' + . ' ORDER BY `id`'; + $result = $this->connection->executeQuery($sql, array($dataDirId . '%')); + while ($row = $result->fetch()) { + $currentId = $row['id']; + // one entry is the datadir itself + if ($currentId === $dataDirId) { + continue; + } + + if ($this->fixLegacyStorage($currentId, (int)$row['numeric_id'])) { + $count++; + } + } + + // check for md5 ids, not in the format "prefix::" + $sql = 'SELECT COUNT(*) AS "c" FROM `*PREFIX*storages`' + . ' WHERE `id` NOT LIKE \'%::%\''; + $result = $this->connection->executeQuery($sql); + $row = $result->fetch(); + // find at least one to make sure it's worth + // querying the user list + if ((int)$row['c'] > 0) { + $userManager = \OC_User::getManager(); + + // use chunks to avoid caching too many users in memory + $limit = 30; + $offset = 0; + + do { + // query the next page of users + $results = $userManager->search('', $limit, $offset); + $storageIds = array(); + $userIds = array(); + foreach ($results as $uid => $userObject) { + $storageId = $dataDirId . $uid . '/'; + if (strlen($storageId) <= 64) { + // skip short storage ids as they were handled in the previous section + continue; + } + $storageIds[$uid] = $storageId; + } + + if (count($storageIds) > 0) { + // update the storages of these users + foreach ($storageIds as $uid => $storageId) { + $numericId = \OC\Files\Cache\Storage::getNumericStorageId($storageId); + if (!is_null($numericId) && $this->fixLegacyStorage($storageId, (int)$numericId)) { + $count++; + } + } + } + $offset += $limit; + } while (count($results) >= $limit); + } + + $this->emit('\OC\Repair', 'info', array('Updated ' . $count . ' legacy home storage ids')); + + $this->connection->commit(); + } + catch (\OC\RepairException $e) { + $this->connection->rollback(); + throw $e; + } + + $this->config->setAppValue('core', 'repairlegacystoragesdone', 'yes'); + } +} diff --git a/lib/private/repairexception.php b/lib/private/repairexception.php new file mode 100644 index 00000000000..642bf90ee40 --- /dev/null +++ b/lib/private/repairexception.php @@ -0,0 +1,16 @@ +<?php +/** + * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +/** + * Exception thrown whenever a database/migration repair + * could not be done. + */ +class RepairException extends \Exception { +} diff --git a/lib/private/server.php b/lib/private/server.php index 22f97429ef5..aab3c82bfeb 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -265,7 +265,11 @@ class Server extends SimpleContainer implements IServerContainer { * @return \OCP\Files\Folder */ function getUserFolder() { - $dir = '/' . $this->getUserSession()->getUser()->getUID(); + $user = $this->getUserSession()->getUser(); + if (!$user) { + return null; + } + $dir = '/' . $user->getUID(); $root = $this->getRootFolder(); $folder = null; diff --git a/lib/private/serviceunavailableexception.php b/lib/private/serviceunavailableexception.php new file mode 100644 index 00000000000..15e4cd5c2fd --- /dev/null +++ b/lib/private/serviceunavailableexception.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright (c) 2014 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; + +class ServiceUnavailableException extends \Exception { +} diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php index cb74dcf8b90..1f4645eed9f 100644 --- a/lib/private/share/mailnotifications.php +++ b/lib/private/share/mailnotifications.php @@ -99,15 +99,20 @@ class MailNotifications { } } + // Link to folder, or root folder if a file + if ($itemType === 'folder') { - $foldername = "/Shared/" . $filename; + $args = array( + 'dir' => $filename, + ); } else { - // if it is a file we can just link to the Shared folder, - // that's the place where the user will find the file - $foldername = "/Shared"; + $args = array( + 'dir' => '/', + 'scrollto' => $filename, + ); } - $link = \OCP\Util::linkToAbsolute('files', 'index.php', array("dir" => $foldername)); + $link = \OCP\Util::linkToAbsolute('files', 'index.php', $args); list($htmlMail, $alttextMail) = $this->createMailBody($filename, $link, $expiration); diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 80389625c61..faa6453d640 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -595,6 +595,7 @@ class Share extends \OC\Share\Constants { $shareWith['group'] = $group; $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner)); } else if ($shareType === self::SHARE_TYPE_LINK) { + $updateExistingShare = false; if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') { // when updating a link share @@ -629,7 +630,7 @@ class Share extends \OC\Share\Constants { throw new \Exception($message_t); } - if (!empty($updateExistingShare) && + if ($updateExistingShare === false && self::isDefaultExpireDateEnabled() && empty($expirationDate)) { $expirationDate = Helper::calcExpireDate(); @@ -820,17 +821,18 @@ class Share extends \OC\Share\Constants { * @param string $itemType * @param string $itemSource * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string $recipient with whom was the file shared * @param boolean $status */ - public static function setSendMailStatus($itemType, $itemSource, $shareType, $status) { + public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) { $status = $status ? 1 : 0; $query = \OC_DB::prepare( 'UPDATE `*PREFIX*share` SET `mail_send` = ? - WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ?'); + WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?'); - $result = $query->execute(array($status, $itemType, $itemSource, $shareType)); + $result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient)); if($result === false) { \OC_Log::write('OCP\Share', 'Couldn\'t set send mail status', \OC_Log::ERROR); @@ -926,19 +928,69 @@ class Share extends \OC\Share\Constants { } /** + * validate expiration date if it meets all constraints + * + * @param string $expireDate well formate date string, e.g. "DD-MM-YYYY" + * @param string $shareTime timestamp when the file was shared + * @param string $itemType + * @param string $itemSource + * @return DateTime validated date + * @throws \Exception + */ + private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) { + $l = \OC_L10N::get('lib'); + $date = new \DateTime($expireDate); + $today = new \DateTime('now'); + + // if the user doesn't provide a share time we need to get it from the database + // fall-back mode to keep API stable, because the $shareTime parameter was added later + $defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced(); + if ($defaultExpireDateEnforced && $shareTime === null) { + $items = self::getItemShared($itemType, $itemSource); + $firstItem = reset($items); + $shareTime = (int)$firstItem['stime']; + } + + if ($defaultExpireDateEnforced) { + // initialize max date with share time + $maxDate = new \DateTime(); + $maxDate->setTimestamp($shareTime); + $maxDays = \OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7'); + $maxDate->add(new \DateInterval('P' . $maxDays . 'D')); + if ($date > $maxDate) { + $warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared'; + $warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays)); + \OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN); + throw new \Exception($warning_t); + } + } + + if ($date < $today) { + $message = 'Cannot set expiration date. Expiration date is in the past'; + $message_t = $l->t('Cannot set expiration date. Expiration date is in the past'); + \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN); + throw new \Exception($message_t); + } + + return $date; + } + + /** * Set expiration date for a share * @param string $itemType * @param string $itemSource * @param string $date expiration date + * @param int $shareTime timestamp from when the file was shared + * @throws \Exception * @return boolean */ - public static function setExpirationDate($itemType, $itemSource, $date) { + public static function setExpirationDate($itemType, $itemSource, $date, $shareTime = null) { $user = \OC_User::getUser(); if ($date == '') { $date = null; } else { - $date = new \DateTime($date); + $date = self::validateExpireDate($date, $shareTime, $itemType, $itemSource); } $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ? AND `uid_owner` = ? AND `share_type` = ?'); $query->bindValue(1, $date, 'datetime'); @@ -955,11 +1007,10 @@ class Share extends \OC\Share\Constants { 'date' => $date, 'uidOwner' => $user )); - + return true; + } - } - /** * Checks whether a share has expired, calls unshareItem() if yes. * @param array $item Share data (usually database row) @@ -969,10 +1020,10 @@ class Share extends \OC\Share\Constants { $result = false; - // only use default expire date for link shares + // only use default expiration date for link shares if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) { - // calculate expire date + // calculate expiration date if (!empty($item['expiration'])) { $userDefinedExpire = new \DateTime($item['expiration']); $expires = $userDefinedExpire->getTimestamp(); @@ -981,7 +1032,7 @@ class Share extends \OC\Share\Constants { } - // get default expire settings + // get default expiration settings $defaultSettings = Helper::getDefaultExpireSetting(); $expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires); @@ -1065,7 +1116,7 @@ class Share extends \OC\Share\Constants { * * Resharing is allowed by default if not configured */ - private static function isResharingAllowed() { + public static function isResharingAllowed() { if (!isset(self::$isResharingAllowed)) { if (\OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') { self::$isResharingAllowed = true; @@ -1339,7 +1390,8 @@ class Share extends \OC\Share\Constants { } if ($mounts[$row['storage']]) { $path = $mounts[$row['storage']]->getMountPoint().$row['path']; - $row['path'] = substr($path, $root); + $relPath = substr($path, $root); // path relative to data/user + $row['path'] = rtrim($relPath, '/'); } } } @@ -1349,7 +1401,7 @@ class Share extends \OC\Share\Constants { } } // Check if resharing is allowed, if not remove share permission - if (isset($row['permissions']) && !self::isResharingAllowed()) { + if (isset($row['permissions']) && (!self::isResharingAllowed() | \OC_Util::isSharingDisabledForUser())) { $row['permissions'] &= ~\OCP\PERMISSION_SHARE; } // Add display names to result diff --git a/lib/private/updater.php b/lib/private/updater.php index d50c2554c75..1d52f9be374 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -7,6 +7,7 @@ */ namespace OC; + use OC\Hooks\BasicEmitter; /** @@ -61,6 +62,7 @@ class Updater extends BasicEmitter { /** * Check if a new version is available + * * @param string $updaterUrl the url to check, i.e. 'http://apps.owncloud.com/updater.php' * @return array|bool */ @@ -161,7 +163,7 @@ class Updater extends BasicEmitter { // create empty file in data dir, so we can later find // out that this is indeed an ownCloud data directory // (in case it didn't exist before) - file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', ''); + file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); /* * START CONFIG CHANGES FOR OLDER VERSIONS @@ -182,22 +184,11 @@ class Updater extends BasicEmitter { // simulate DB upgrade if ($this->simulateStepEnabled) { - // simulate core DB upgrade - \OC_DB::simulateUpdateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); + $this->checkCoreUpgrade(); // simulate apps DB upgrade - $version = \OC_Util::getVersion(); - $apps = \OC_App::getEnabledApps(); - foreach ($apps as $appId) { - $info = \OC_App::getAppInfo($appId); - if (\OC_App::isAppCompatible($version, $info) && \OC_App::shouldUpgrade($appId)) { - if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { - \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); - } - } - } + $this->checkAppUpgrade($currentVersion); - $this->emit('\OC\Updater', 'dbSimulateUpgrade'); } // upgrade from OC6 to OC7 @@ -208,18 +199,14 @@ class Updater extends BasicEmitter { } if ($this->updateStepEnabled) { - // do the real upgrade - \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); - $this->emit('\OC\Updater', 'dbUpgrade'); + $this->doCoreUpgrade(); - // TODO: why not do this at the end ? - \OC_Config::setValue('version', implode('.', \OC_Util::getVersion())); $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(); + + $this->doAppUpgrade(); // post-upgrade repairs $repair = new \OC\Repair(\OC\Repair::getRepairSteps()); @@ -227,6 +214,59 @@ class Updater extends BasicEmitter { //Invalidate update feed \OC_Appconfig::setValue('core', 'lastupdatedat', 0); + + // only set the final version if everything went well + \OC_Config::setValue('version', implode('.', \OC_Util::getVersion())); + } + } + + protected function checkCoreUpgrade() { + // simulate core DB upgrade + \OC_DB::simulateUpdateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); + + $this->emit('\OC\Updater', 'dbSimulateUpgrade'); + } + + protected function doCoreUpgrade() { + // do the real upgrade + \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); + + $this->emit('\OC\Updater', 'dbUpgrade'); + } + + /** + * @param string $version the oc version to check app compatibilty with + */ + protected function checkAppUpgrade($version) { + $apps = \OC_App::getEnabledApps(); + + + foreach ($apps as $appId) { + if ($version) { + $info = \OC_App::getAppInfo($appId); + $compatible = \OC_App::isAppCompatible($version, $info); + } else { + $compatible = true; + } + + if ($compatible && \OC_App::shouldUpgrade($appId)) { + if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { + \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); + } + } + } + + $this->emit('\OC\Updater', 'appUpgradeCheck'); + } + + protected function doAppUpgrade() { + $apps = \OC_App::getEnabledApps(); + + foreach ($apps as $appId) { + if (\OC_App::shouldUpgrade($appId)) { + \OC_App::updateApp($appId); + $this->emit('\OC\Updater', 'appUpgrade', array($appId, \OC_App::getAppVersion($appId))); + } } } } diff --git a/lib/private/user.php b/lib/private/user.php index a8431af97fd..cdef4d8fe65 100644 --- a/lib/private/user.php +++ b/lib/private/user.php @@ -64,7 +64,7 @@ class OC_User { /** * registers backend * @param string $backend name of the backend - * @deprecated Add classes by calling useBackend with a class instance instead + * @deprecated Add classes by calling OC_User::useBackend() with a class instance instead * @return bool * * Makes a list of backends that can be used by other modules @@ -337,7 +337,7 @@ class OC_User { * Checks if the user is logged in */ public static function isLoggedIn() { - if (\OC::$session->get('user_id') && self::$incognitoMode === false) { + if (\OC::$session->get('user_id') !== null && self::$incognitoMode === false) { return self::userExists(\OC::$session->get('user_id')); } return false; diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php index d4d91163003..a54755e71c5 100644 --- a/lib/private/user/manager.php +++ b/lib/private/user/manager.php @@ -164,6 +164,11 @@ class Manager extends PublicEmitter implements IUserManager { } } } + + $remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; + $forwardedFor = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : ''; + + \OC::$server->getLogger()->warning('Login failed: \''. $loginname .'\' (Remote IP: \''. $remoteAddr .'\', X-Forwarded-For: \''. $forwardedFor .'\')', array('app' => 'core')); return false; } diff --git a/lib/private/user/session.php b/lib/private/user/session.php index 8c9b3e264e3..6abf8fb80d2 100644 --- a/lib/private/user/session.php +++ b/lib/private/user/session.php @@ -106,7 +106,7 @@ class Session implements IUserSession, Emitter { return $this->activeUser; } else { $uid = $this->session->get('user_id'); - if ($uid) { + if ($uid !== null) { $this->activeUser = $this->manager->get($uid); return $this->activeUser; } else { diff --git a/lib/private/util.php b/lib/private/util.php index eea194288f9..4307560a928 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -4,29 +4,29 @@ * Class for utility functions * */ - class OC_Util { - public static $scripts=array(); - public static $styles=array(); - public static $headers=array(); - private static $rootMounted=false; - private static $fsSetup=false; + public static $scripts = array(); + public static $styles = array(); + public static $headers = array(); + private static $rootMounted = false; + private static $fsSetup = false; private static function initLocalStorageRootFS() { // mount local file backend as root - $configDataDirectory = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); + $configDataDirectory = OC_Config::getValue("datadirectory", OC::$SERVERROOT . "/data"); //first set up the local "root" storage \OC\Files\Filesystem::initMounts(); - if(!self::$rootMounted) { - \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir'=>$configDataDirectory), '/'); + if (!self::$rootMounted) { + \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir' => $configDataDirectory), '/'); self::$rootMounted = true; } } - + /** * mounting an object storage as the root fs will in essence remove the * necessity of a data folder being present. * TODO make home storage aware of this and use the object storage instead of local disk access + * * @param array $config containing 'class' and optional 'arguments' */ private static function initObjectStoreRootFS($config) { @@ -45,26 +45,27 @@ class OC_Util { // mount object storage as root \OC\Files\Filesystem::initMounts(); - if(!self::$rootMounted) { + if (!self::$rootMounted) { \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/'); self::$rootMounted = true; } } - + /** * Can be set up + * * @param string $user * @return boolean * @description configure the initial filesystem based on the configuration */ - public static function setupFS( $user = '' ) { + public static function setupFS($user = '') { //setting up the filesystem twice can only lead to trouble - if(self::$fsSetup) { + if (self::$fsSetup) { return false; } // If we are not forced to load a specific user we load the one that is logged in - if( $user == "" && OC_User::isLoggedIn()) { + if ($user == "" && OC_User::isLoggedIn()) { $user = OC_User::getUser(); } @@ -75,12 +76,12 @@ class OC_Util { // mark fs setup here to avoid doing the setup from loading // OC_Filesystem if ($user != '') { - self::$fsSetup=true; + self::$fsSetup = true; } //check if we are using an object storage - $objectStore = OC_Config::getValue( 'objectstore' ); - if ( isset( $objectStore ) ) { + $objectStore = OC_Config::getValue('objectstore'); + if (isset($objectStore)) { self::initObjectStoreRootFS($objectStore); } else { self::initLocalStorageRootFS(); @@ -91,8 +92,8 @@ class OC_Util { } //if we aren't logged in, there is no use to set up the filesystem - if( $user != "" ) { - \OC\Files\Filesystem::addStorageWrapper('oc_quota', function($mountPoint, $storage){ + if ($user != "") { + \OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) { // set up quota for home storages, even for other users // which can happen when using sharing @@ -105,7 +106,7 @@ class OC_Util { if (is_object($storage->getUser())) { $user = $storage->getUser()->getUID(); $quota = OC_Util::getUserQuota($user); - if ($quota !== \OC\Files\SPACE_UNLIMITED) { + if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files')); } } @@ -115,16 +116,16 @@ class OC_Util { }); // copy skeleton for local storage only - if ( ! isset( $objectStore ) ) { + if (!isset($objectStore)) { $userRoot = OC_User::getHome($user); $userDirectory = $userRoot . '/files'; - if( !is_dir( $userDirectory )) { - mkdir( $userDirectory, 0755, true ); + if (!is_dir($userDirectory)) { + mkdir($userDirectory, 0755, true); OC_Util::copySkeleton($userDirectory); } } - $userDir = '/'.$user.'/files'; + $userDir = '/' . $user . '/files'; //jail the user into his "home" directory \OC\Files\Filesystem::init($user, $userDir); @@ -139,6 +140,7 @@ class OC_Util { /** * check if a password is required for each public link + * * @return boolean */ public static function isPublicLinkPasswordRequired() { @@ -171,18 +173,35 @@ class OC_Util { } /** + * check if share API enforces a default expire date + * + * @return boolean + */ + public static function isDefaultExpireDateEnforced() { + $isDefaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no'); + $enforceDefaultExpireDate = false; + if ($isDefaultExpireDateEnabled === 'yes') { + $value = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no'); + $enforceDefaultExpireDate = ($value === 'yes') ? true : false; + } + + return $enforceDefaultExpireDate; + } + + /** * Get the quota of a user + * * @param string $user * @return int Quota bytes */ - public static function getUserQuota($user){ + public static function getUserQuota($user) { $config = \OC::$server->getConfig(); $userQuota = $config->getUserValue($user, 'files', 'quota', 'default'); - if($userQuota === 'default') { + if ($userQuota === 'default') { $userQuota = $config->getAppValue('files', 'default_quota', 'none'); } if($userQuota === 'none') { - return \OC\Files\SPACE_UNLIMITED; + return \OCP\Files\FileInfo::SPACE_UNLIMITED; }else{ return OC_Helper::computerFileSize($userQuota); } @@ -190,27 +209,32 @@ class OC_Util { /** * copies the user skeleton files into the fresh user home files + * * @param string $userDirectory */ public static function copySkeleton($userDirectory) { - OC_Util::copyr(\OC::$SERVERROOT.'/core/skeleton' , $userDirectory); + $skeletonDirectory = OC_Config::getValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton'); + if (!empty($skeletonDirectory)) { + OC_Util::copyr($skeletonDirectory, $userDirectory); + } } /** * copies a directory recursively + * * @param string $source * @param string $target * @return void */ - public static function copyr($source,$target) { + public static function copyr($source, $target) { $dir = opendir($source); @mkdir($target); - while(false !== ( $file = readdir($dir)) ) { - if ( !\OC\Files\Filesystem::isIgnoredDir($file) ) { - if ( is_dir($source . '/' . $file) ) { - OC_Util::copyr($source . '/' . $file , $target . '/' . $file); + while (false !== ($file = readdir($dir))) { + if (!\OC\Files\Filesystem::isIgnoredDir($file)) { + if (is_dir($source . '/' . $file)) { + OC_Util::copyr($source . '/' . $file, $target . '/' . $file); } else { - copy($source . '/' . $file,$target . '/' . $file); + copy($source . '/' . $file, $target . '/' . $file); } } } @@ -222,12 +246,13 @@ class OC_Util { */ public static function tearDownFS() { \OC\Files\Filesystem::tearDown(); - self::$fsSetup=false; - self::$rootMounted=false; + self::$fsSetup = false; + self::$rootMounted = false; } /** * get the current installed version of ownCloud + * * @return array */ public static function getVersion() { @@ -237,6 +262,7 @@ class OC_Util { /** * get the current installed version string of ownCloud + * * @return string */ public static function getVersionString() { @@ -277,8 +303,8 @@ class OC_Util { * @description load the version.php into the session as cache */ private static function loadVersion() { - $timestamp = filemtime(OC::$SERVERROOT.'/version.php'); - if(!\OC::$server->getSession()->exists('OC_Version') or OC::$server->getSession()->get('OC_Version_Timestamp') != $timestamp) { + $timestamp = filemtime(OC::$SERVERROOT . '/version.php'); + if (!\OC::$server->getSession()->exists('OC_Version') or OC::$server->getSession()->get('OC_Version_Timestamp') != $timestamp) { require 'version.php'; $session = \OC::$server->getSession(); /** @var $timestamp int */ @@ -303,12 +329,12 @@ class OC_Util { * @param string|null $file filename * @return void */ - public static function addScript( $application, $file = null ) { - if ( is_null( $file )) { + public static function addScript($application, $file = null) { + if (is_null($file)) { $file = $application; $application = ""; } - if ( !empty( $application )) { + if (!empty($application)) { self::$scripts[] = "$application/js/$file"; } else { self::$scripts[] = "js/$file"; @@ -322,12 +348,12 @@ class OC_Util { * @param string|null $file filename * @return void */ - public static function addStyle( $application, $file = null ) { - if ( is_null( $file )) { + public static function addStyle($application, $file = null) { + if (is_null($file)) { $file = $application; $application = ""; } - if ( !empty( $application )) { + if (!empty($application)) { self::$styles[] = "$application/css/$file"; } else { self::$styles[] = "css/$file"; @@ -336,16 +362,17 @@ class OC_Util { /** * Add a custom element to the header + * * @param string $tag tag name of the element * @param array $attributes array of attributes for the element * @param string $text the text content for the element * @return void */ - public static function addHeader( $tag, $attributes, $text='') { + public static function addHeader($tag, $attributes, $text = '') { self::$headers[] = array( - 'tag'=>$tag, - 'attributes'=>$attributes, - 'text'=>$text + 'tag' => $tag, + 'attributes' => $attributes, + 'text' => $text ); } @@ -357,13 +384,13 @@ class OC_Util { * @return string timestamp * @description adjust to clients timezone if we know it */ - public static function formatDate( $timestamp, $dateOnly=false) { - if(\OC::$session->exists('timezone')) { + public static function formatDate($timestamp, $dateOnly = false) { + if (\OC::$session->exists('timezone')) { $systemTimeZone = intval(date('O')); - $systemTimeZone = (round($systemTimeZone/100, 0)*60) + ($systemTimeZone%100); - $clientTimeZone = \OC::$session->get('timezone')*60; + $systemTimeZone = (round($systemTimeZone / 100, 0) * 60) + ($systemTimeZone % 100); + $clientTimeZone = \OC::$session->get('timezone') * 60; $offset = $clientTimeZone - $systemTimeZone; - $timestamp = $timestamp + $offset*60; + $timestamp = $timestamp + $offset * 60; } $l = OC_L10N::get('lib'); return $l->l($dateOnly ? 'date' : 'datetime', $timestamp); @@ -371,6 +398,7 @@ class OC_Util { /** * check if the current server configuration is suitable for ownCloud + * * @return array arrays with error messages and hints */ public static function checkServer() { @@ -384,200 +412,203 @@ class OC_Util { } // Assume that if checkServer() succeeded before in this session, then all is fine. - if(\OC::$session->exists('checkServer_succeeded') && \OC::$session->get('checkServer_succeeded')) { + if (\OC::$session->exists('checkServer_succeeded') && \OC::$session->get('checkServer_succeeded')) { return $errors; } $webServerRestart = false; //check for database drivers - if(!(is_callable('sqlite_open') or class_exists('SQLite3')) + if (!(is_callable('sqlite_open') or class_exists('SQLite3')) and !is_callable('mysql_connect') and !is_callable('pg_connect') - and !is_callable('oci_connect')) { + and !is_callable('oci_connect') + ) { $errors[] = array( - 'error'=> $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'), - 'hint'=>'' //TODO: sane hint + 'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'), + 'hint' => '' //TODO: sane hint ); $webServerRestart = true; } //common hint for all file permissions error messages $permissionsHint = $l->t('Permissions can usually be fixed by ' - .'%sgiving the webserver write access to the root directory%s.', - array('<a href="'.\OC_Helper::linkToDocs('admin-dir_permissions').'" target="_blank">', '</a>')); + . '%sgiving the webserver write access to the root directory%s.', + array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>')); // Check if config folder is writable. - if(!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) { + if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) { $errors[] = array( 'error' => $l->t('Cannot write into "config" directory'), 'hint' => $l->t('This can usually be fixed by ' - .'%sgiving the webserver write access to the config directory%s.', - array('<a href="'.\OC_Helper::linkToDocs('admin-dir_permissions').'" target="_blank">', '</a>')) - ); + . '%sgiving the webserver write access to the config directory%s.', + array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>')) + ); } // Check if there is a writable install folder. - if(OC_Config::getValue('appstoreenabled', true)) { - if( OC_App::getInstallPath() === null + if (OC_Config::getValue('appstoreenabled', true)) { + if (OC_App::getInstallPath() === null || !is_writable(OC_App::getInstallPath()) - || !is_readable(OC_App::getInstallPath()) ) { + || !is_readable(OC_App::getInstallPath()) + ) { $errors[] = array( 'error' => $l->t('Cannot write into "apps" directory'), 'hint' => $l->t('This can usually be fixed by ' - .'%sgiving the webserver write access to the apps directory%s' - .' or disabling the appstore in the config file.', - array('<a href="'.\OC_Helper::linkToDocs('admin-dir_permissions').'" target="_blank">', '</a>')) - ); + . '%sgiving the webserver write access to the apps directory%s' + . ' or disabling the appstore in the config file.', + array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>')) + ); } } // Create root dir. - if(!is_dir($CONFIG_DATADIRECTORY)) { - $success=@mkdir($CONFIG_DATADIRECTORY); + if (!is_dir($CONFIG_DATADIRECTORY)) { + $success = @mkdir($CONFIG_DATADIRECTORY); if ($success) { $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); } else { $errors[] = array( 'error' => $l->t('Cannot create "data" directory (%s)', array($CONFIG_DATADIRECTORY)), 'hint' => $l->t('This can usually be fixed by ' - .'<a href="%s" target="_blank">giving the webserver write access to the root directory</a>.', - array(OC_Helper::linkToDocs('admin-dir_permissions'))) - ); + . '<a href="%s" target="_blank">giving the webserver write access to the root directory</a>.', + array(OC_Helper::linkToDocs('admin-dir_permissions'))) + ); } - } else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) { + } else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) { $errors[] = array( - 'error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud', - 'hint'=>$permissionsHint + 'error' => 'Data directory (' . $CONFIG_DATADIRECTORY . ') not writable by ownCloud', + 'hint' => $permissionsHint ); } else { $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); } - if(!OC_Util::isSetLocaleWorking()) { + if (!OC_Util::isSetLocaleWorking()) { $errors[] = array( 'error' => $l->t('Setting locale to %s failed', - array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/' - .'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')), - 'hint' => $l->t('Please install one of theses locales on your system and restart your webserver.') + array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/' + . 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')), + 'hint' => $l->t('Please install one of these locales on your system and restart your webserver.') ); } $moduleHint = $l->t('Please ask your server administrator to install the module.'); // check if all required php modules are present - if(!class_exists('ZipArchive')) { + if (!class_exists('ZipArchive')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('zip')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('zip')), + 'hint' => $moduleHint ); $webServerRestart = true; } - if(!class_exists('DOMDocument')) { + if (!class_exists('DOMDocument')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('dom')), + 'error' => $l->t('PHP module %s not installed.', array('dom')), 'hint' => $moduleHint ); - $webServerRestart =true; + $webServerRestart = true; } - if(!function_exists('xml_parser_create')) { + if (!function_exists('xml_parser_create')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('libxml')), + 'error' => $l->t('PHP module %s not installed.', array('libxml')), 'hint' => $moduleHint ); $webServerRestart = true; } - if(!function_exists('mb_detect_encoding')) { + if (!function_exists('mb_detect_encoding')) { $errors[] = array( - 'error'=>'PHP module mb multibyte not installed.', - 'hint'=>$moduleHint + 'error' => 'PHP module mb multibyte not installed.', + 'hint' => $moduleHint ); $webServerRestart = true; } - if(!function_exists('ctype_digit')) { + if (!function_exists('ctype_digit')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('ctype')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('ctype')), + 'hint' => $moduleHint ); $webServerRestart = true; } - if(!function_exists('json_encode')) { + if (!function_exists('json_encode')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('JSON')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('JSON')), + 'hint' => $moduleHint ); $webServerRestart = true; } - if(!extension_loaded('gd') || !function_exists('gd_info')) { + if (!extension_loaded('gd') || !function_exists('gd_info')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('GD')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('GD')), + 'hint' => $moduleHint ); $webServerRestart = true; } - if(!function_exists('gzencode')) { + if (!function_exists('gzencode')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('zlib')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('zlib')), + 'hint' => $moduleHint ); $webServerRestart = true; } - if(!function_exists('iconv')) { + if (!function_exists('iconv')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('iconv')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('iconv')), + 'hint' => $moduleHint ); $webServerRestart = true; } - if(!function_exists('simplexml_load_string')) { + if (!function_exists('simplexml_load_string')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('SimpleXML')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('SimpleXML')), + 'hint' => $moduleHint ); $webServerRestart = true; } - if(version_compare(phpversion(), '5.3.3', '<')) { + if (version_compare(phpversion(), '5.3.3', '<')) { $errors[] = array( - 'error'=> $l->t('PHP %s or higher is required.', '5.3.3'), - 'hint'=> $l->t('Please ask your server administrator to update PHP to the latest version.' - .' Your PHP version is no longer supported by ownCloud and the PHP community.') + 'error' => $l->t('PHP %s or higher is required.', '5.3.3'), + 'hint' => $l->t('Please ask your server administrator to update PHP to the latest version.' + . ' Your PHP version is no longer supported by ownCloud and the PHP community.') ); $webServerRestart = true; } - if(!defined('PDO::ATTR_DRIVER_NAME')) { + if (!defined('PDO::ATTR_DRIVER_NAME')) { $errors[] = array( - 'error'=> $l->t('PHP module %s not installed.', array('PDO')), - 'hint'=>$moduleHint + 'error' => $l->t('PHP module %s not installed.', array('PDO')), + 'hint' => $moduleHint ); $webServerRestart = true; } if (((strtolower(@ini_get('safe_mode')) == 'on') || (strtolower(@ini_get('safe_mode')) == 'yes') || (strtolower(@ini_get('safe_mode')) == 'true') - || (ini_get("safe_mode") == 1 ))) { + || (ini_get("safe_mode") == 1)) + ) { $errors[] = array( - 'error'=> $l->t('PHP Safe Mode is enabled. ownCloud requires that it is disabled to work properly.'), - 'hint'=> $l->t('PHP Safe Mode is a deprecated and mostly useless setting that should be disabled. ' - .'Please ask your server administrator to disable it in php.ini or in your webserver config.') + 'error' => $l->t('PHP Safe Mode is enabled. ownCloud requires that it is disabled to work properly.'), + 'hint' => $l->t('PHP Safe Mode is a deprecated and mostly useless setting that should be disabled. ' + . 'Please ask your server administrator to disable it in php.ini or in your webserver config.') ); $webServerRestart = true; } - if (get_magic_quotes_gpc() == 1 ) { + if (get_magic_quotes_gpc() == 1) { $errors[] = array( - 'error'=> $l->t('Magic Quotes is enabled. ownCloud requires that it is disabled to work properly.'), - 'hint'=> $l->t('Magic Quotes is a deprecated and mostly useless setting that should be disabled. ' - .'Please ask your server administrator to disable it in php.ini or in your webserver config.') + 'error' => $l->t('Magic Quotes is enabled. ownCloud requires that it is disabled to work properly.'), + 'hint' => $l->t('Magic Quotes is a deprecated and mostly useless setting that should be disabled. ' + . 'Please ask your server administrator to disable it in php.ini or in your webserver config.') ); $webServerRestart = true; } if (!self::isAnnotationsWorking()) { $errors[] = array( - 'error'=>'PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible.', - 'hint'=>'This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.' + 'error' => 'PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible.', + 'hint' => 'This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.' ); } - if($webServerRestart) { + if ($webServerRestart) { $errors[] = array( - 'error'=> $l->t('PHP modules have been installed, but they are still listed as missing?'), - 'hint'=> $l->t('Please ask your server administrator to restart the web server.') + 'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'), + 'hint' => $l->t('Please ask your server administrator to restart the web server.') ); } @@ -591,6 +622,7 @@ class OC_Util { /** * Check the database version + * * @return array errors array */ public static function checkDatabaseVersion() { @@ -616,7 +648,7 @@ class OC_Util { $errors[] = array( 'error' => $l->t('Error occurred while checking PostgreSQL version'), 'hint' => $l->t('Please make sure you have PostgreSQL >= 9 or' - .' check the logs for more information about the error') + . ' check the logs for more information about the error') ); } } @@ -626,6 +658,7 @@ class OC_Util { /** * check if there are still some encrypted files stored + * * @return boolean */ public static function encryptedFiles() { @@ -647,6 +680,7 @@ class OC_Util { /** * check if a backup from the encryption keys exists + * * @return boolean */ public static function backupKeysExists() { @@ -668,6 +702,7 @@ class OC_Util { /** * Check for correct file permissions of data directory + * * @param string $dataDirectory * @return array arrays with error messages and hints */ @@ -678,7 +713,7 @@ class OC_Util { //TODO: permissions checks for windows hosts } else { $permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory' - .' cannot be listed by other users.'); + . ' cannot be listed by other users.'); $perms = substr(decoct(@fileperms($dataDirectory)), -3); if (substr($perms, -1) != '0') { chmod($dataDirectory, 0770); @@ -705,7 +740,7 @@ class OC_Util { public static function checkDataDirectoryValidity($dataDirectory) { $l = OC_L10N::get('lib'); $errors = array(); - if (!file_exists($dataDirectory.'/.ocdata')) { + if (!file_exists($dataDirectory . '/.ocdata')) { $errors[] = array( 'error' => $l->t('Data directory (%s) is invalid', array($dataDirectory)), 'hint' => $l->t('Please check that the data directory contains a file' . @@ -720,7 +755,7 @@ class OC_Util { */ public static function displayLoginPage($errors = array()) { $parameters = array(); - foreach( $errors as $value ) { + foreach ($errors as $value) { $parameters[$value] = true; } if (!empty($_POST['user'])) { @@ -743,12 +778,13 @@ class OC_Util { /** * Check if the app is enabled, redirects to home if not + * * @param string $app * @return void */ public static function checkAppEnabled($app) { - if( !OC_App::isEnabled($app)) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); + if (!OC_App::isEnabled($app)) { + header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php')); exit(); } } @@ -756,26 +792,28 @@ class OC_Util { /** * Check if the user is logged in, redirects to home if not. With * redirect URL parameter to the request URI. + * * @return void */ public static function checkLoggedIn() { // Check if we are a user - if( !OC_User::isLoggedIn()) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', - array('redirect_url' => OC_Request::requestUri()) - )); + if (!OC_User::isLoggedIn()) { + header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php', + array('redirect_url' => OC_Request::requestUri()) + )); exit(); } } /** * Check if the user is a admin, redirects to home if not + * * @return void */ public static function checkAdminUser() { OC_Util::checkLoggedIn(); - if( !OC_User::isAdminUser(OC_User::getUser())) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); + if (!OC_User::isAdminUser(OC_User::getUser())) { + header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php')); exit(); } } @@ -803,12 +841,13 @@ class OC_Util { /** * Check if the user is a subadmin, redirects to home if not + * * @return null|boolean $groups where the current user is subadmin */ public static function checkSubAdminUser() { OC_Util::checkLoggedIn(); - if(!OC_SubAdmin::isSubAdmin(OC_User::getUser())) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); + if (!OC_SubAdmin::isSubAdmin(OC_User::getUser())) { + header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php')); exit(); } return true; @@ -823,7 +862,7 @@ class OC_Util { */ public static function getDefaultPageUrl() { $urlGenerator = \OC::$server->getURLGenerator(); - if(isset($_REQUEST['redirect_url'])) { + if (isset($_REQUEST['redirect_url'])) { $location = urldecode($_REQUEST['redirect_url']); } else { $defaultPage = OC_Appconfig::getValue('core', 'defaultpage'); @@ -848,21 +887,23 @@ class OC_Util { /** * Redirect to the user default page + * * @return void */ public static function redirectToDefaultPage() { $location = self::getDefaultPageUrl(); - header('Location: '.$location); + header('Location: ' . $location); exit(); } /** * get an id unique for this instance + * * @return string */ public static function getInstanceId() { $id = OC_Config::getValue('instanceid', null); - if(is_null($id)) { + if (is_null($id)) { // We need to guarantee at least one letter in instanceid so it can be used as the session_name $id = 'oc' . self::generateRandomBytes(10); OC_Config::$object->setValue('instanceid', $id); @@ -872,6 +913,7 @@ class OC_Util { /** * Static lifespan (in seconds) when a request token expires. + * * @see OC_Util::callRegister() * @see OC_Util::isCallRegistered() * @description @@ -883,6 +925,7 @@ class OC_Util { /** * Register an get/post call. Important to prevent CSRF attacks. + * * @todo Write howto: CSRF protection guide * @return string Generated token. * @description @@ -895,7 +938,7 @@ class OC_Util { */ public static function callRegister() { // Check if a token exists - if(!\OC::$session->exists('requesttoken')) { + if (!\OC::$session->exists('requesttoken')) { // No valid token found, generate a new one. $requestToken = self::generateRandomBytes(20); \OC::$session->set('requesttoken', $requestToken); @@ -903,11 +946,12 @@ class OC_Util { // Valid token already exists, send it $requestToken = \OC::$session->get('requesttoken'); } - return($requestToken); + return ($requestToken); } /** * 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() @@ -918,11 +962,12 @@ class OC_Util { /** * Check an ajax get/post call if the request token is valid. Exit if not. + * * @todo Write howto * @return void */ public static function callCheck() { - if(!OC_Util::isCallRegistered()) { + if (!OC_Util::isCallRegistered()) { exit(); } } @@ -936,7 +981,7 @@ class OC_Util { * @param string|array &$value * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter. */ - public static function sanitizeHTML( &$value ) { + public static function sanitizeHTML(&$value) { if (is_array($value)) { array_walk_recursive($value, 'OC_Util::sanitizeHTML'); } else { @@ -964,13 +1009,14 @@ class OC_Util { /** * Check if the .htaccess file is working + * * @throws OC\HintException If the testfile can't get written. * @return bool * @description Check if the .htaccess file is working by creating a test * file in the data directory and trying to access via http */ public static function isHtaccessWorking() { - if (!\OC_Config::getValue("check_for_working_htaccess", true)) { + if (!OC::$server->getConfig()->getSystemValue('check_for_working_htaccess', true)) { return true; } @@ -979,39 +1025,37 @@ class OC_Util { $testContent = 'testcontent'; // creating a test file - $testFile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$fileName; + $testFile = OC::$server->getConfig()->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName; - if(file_exists($testFile)) {// already running this test, possible recursive call + if (file_exists($testFile)) {// already running this test, possible recursive call return false; } $fp = @fopen($testFile, 'w'); if (!$fp) { throw new OC\HintException('Can\'t create test file to check for working .htaccess file.', - 'Make sure it is possible for the webserver to write to '.$testFile); + 'Make sure it is possible for the webserver to write to ' . $testFile); } fwrite($fp, $testContent); fclose($fp); // accessing the file via http - $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$fileName); - $fp = @fopen($url, 'r'); - $content=@fread($fp, 2048); - @fclose($fp); + $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT . '/data' . $fileName); + $content = self::getUrlContent($url); // cleanup @unlink($testFile); - // does it work ? - if($content==$testContent) { - return false; - } else { - return true; - } + /* + * If the content is not equal to test content our .htaccess + * is working as required + */ + return $content !== $testContent; } /** * test if webDAV is working properly + * * @return bool * @description * The basic assumption is that if the server returns 401/Not Authenticated for an unauthenticated PROPFIND @@ -1049,7 +1093,7 @@ class OC_Util { } catch (\Sabre\DAV\Exception\NotAuthenticated $e) { $return = true; } catch (\Exception $e) { - OC_Log::write('core', 'isWebDAVWorking: NO - Reason: '.$e->getMessage(). ' ('.get_class($e).')', OC_Log::WARN); + OC_Log::write('core', 'isWebDAVWorking: NO - Reason: ' . $e->getMessage() . ' (' . get_class($e) . ')', OC_Log::WARN); $return = false; } @@ -1059,11 +1103,12 @@ class OC_Util { /** * Check if the setlocal call does not work. This can happen if the right * local packages are not available on the server. + * * @return bool */ public static function isSetLocaleWorking() { // setlocale test is pointless on Windows - if (OC_Util::runningOnWindows() ) { + if (OC_Util::runningOnWindows()) { return true; } @@ -1088,6 +1133,7 @@ class OC_Util { /** * Check if the PHP module fileinfo is loaded. + * * @return bool */ public static function fileInfoLoaded() { @@ -1096,6 +1142,7 @@ class OC_Util { /** * Check if a PHP version older then 5.3.8 is installed. + * * @return bool */ public static function isPHPoutdated() { @@ -1104,6 +1151,7 @@ class OC_Util { /** * Check if the ownCloud server can connect to the internet + * * @return bool */ public static function isInternetConnectionWorking() { @@ -1113,7 +1161,7 @@ class OC_Util { } // in case the connection is via proxy return true to avoid connecting to owncloud.org - if(OC_Config::getValue('proxy', '') != '') { + if (OC_Config::getValue('proxy', '') != '') { return true; } @@ -1136,17 +1184,19 @@ class OC_Util { /** * Check if the connection to the internet is disabled on purpose + * * @return string */ - public static function isInternetConnectionEnabled(){ + public static function isInternetConnectionEnabled() { return \OC_Config::getValue("has_internet_connection", true); } /** * clear all levels of output buffering + * * @return void */ - public static function obEnd(){ + public static function obEnd() { while (ob_get_level()) { ob_end_clean(); } @@ -1155,6 +1205,7 @@ class OC_Util { /** * Generates a cryptographic secure pseudo-random string + * * @param int $length of the random string * @return string * Please also update secureRNGAvailable if you change something here @@ -1163,7 +1214,7 @@ class OC_Util { // Try to use openssl_random_pseudo_bytes if (function_exists('openssl_random_pseudo_bytes')) { $pseudoByte = bin2hex(openssl_random_pseudo_bytes($length, $strong)); - if($strong == true) { + if ($strong == true) { return substr($pseudoByte, 0, $length); // Truncate it to match the length } } @@ -1180,7 +1231,7 @@ class OC_Util { // Fallback to mt_rand() $characters = '0123456789'; $characters .= 'abcdefghijklmnopqrstuvwxyz'; - $charactersLength = strlen($characters)-1; + $charactersLength = strlen($characters) - 1; $pseudoByte = ""; // Select some random characters @@ -1192,13 +1243,14 @@ class OC_Util { /** * Checks if a secure random number generator is available + * * @return bool */ public static function secureRNGAvailable() { // Check openssl_random_pseudo_bytes - if(function_exists('openssl_random_pseudo_bytes')) { + if (function_exists('openssl_random_pseudo_bytes')) { openssl_random_pseudo_bytes(1, $strong); - if($strong == true) { + if ($strong == true) { return true; } } @@ -1217,11 +1269,16 @@ class OC_Util { /** * @Brief Get file content via curl. * @param string $url Url to get content + * @throws Exception If the URL does not start with http:// or https:// * @return string of the response or false on error * This function get the content of a page via curl, if curl is enabled. * If not, file_get_contents is used. */ public static function getUrlContent($url) { + if (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) { + throw new Exception('$url must start with https:// or http://', 1); + } + if (function_exists('curl_init')) { $curl = curl_init(); $max_redirects = 10; @@ -1233,10 +1290,10 @@ class OC_Util { curl_setopt($curl, CURLOPT_USERAGENT, "ownCloud Server Crawler"); - if(OC_Config::getValue('proxy', '') != '') { + if (OC_Config::getValue('proxy', '') != '') { curl_setopt($curl, CURLOPT_PROXY, OC_Config::getValue('proxy')); } - if(OC_Config::getValue('proxyuserpwd', '') != '') { + if (OC_Config::getValue('proxyuserpwd', '') != '') { curl_setopt($curl, CURLOPT_PROXYUSERPWD, OC_Config::getValue('proxyuserpwd')); } @@ -1275,7 +1332,7 @@ class OC_Util { } } - if($mr == 0 && $max_redirects > 0) { + if ($mr == 0 && $max_redirects > 0) { $data = false; } else { $data = curl_exec($curl); @@ -1285,7 +1342,7 @@ class OC_Util { } else { $contextArray = null; - if(OC_Config::getValue('proxy', '') != '') { + if (OC_Config::getValue('proxy', '') != '') { $contextArray = array( 'http' => array( 'timeout' => 10, @@ -1311,6 +1368,7 @@ class OC_Util { /** * Checks whether the server is running on Windows + * * @return bool true if running on Windows, false otherwise */ public static function runningOnWindows() { @@ -1319,6 +1377,7 @@ class OC_Util { /** * Checks whether the server is running on Mac OS X + * * @return bool true if running on Mac OS X, false otherwise */ public static function runningOnMac() { @@ -1328,13 +1387,14 @@ class OC_Util { /** * Handles the case that there may not be a theme, then check if a "default" * theme exists and take that one + * * @return string the theme */ public static function getTheme() { $theme = OC_Config::getValue("theme", ''); - if($theme === '') { - if(is_dir(OC::$SERVERROOT . '/themes/default')) { + if ($theme === '') { + if (is_dir(OC::$SERVERROOT . '/themes/default')) { $theme = 'default'; } } @@ -1346,6 +1406,7 @@ class OC_Util { * Clear the opcode cache if one exists * This is necessary for writing to the config file * in case the opcode cache does not re-validate files + * * @return void */ public static function clearOpcodeCache() { @@ -1373,14 +1434,15 @@ class OC_Util { /** * Normalize a unicode string + * * @param string $value a not normalized string * @return bool|string */ public static function normalizeUnicode($value) { - if(class_exists('Patchwork\PHP\Shim\Normalizer')) { + if (class_exists('Patchwork\PHP\Shim\Normalizer')) { $normalizedValue = \Patchwork\PHP\Shim\Normalizer::normalize($value); - if($normalizedValue === false) { - \OC_Log::write( 'core', 'normalizing failed for "' . $value . '"', \OC_Log::WARN); + if ($normalizedValue === false) { + \OC_Log::write('core', 'normalizing failed for "' . $value . '"', \OC_Log::WARN); } else { $value = $normalizedValue; } @@ -1401,12 +1463,13 @@ class OC_Util { /** * A human readable string is generated based on version, channel and build number + * * @return string */ public static function getHumanVersion() { - $version = OC_Util::getVersionString().' ('.OC_Util::getChannel().')'; + $version = OC_Util::getVersionString() . ' (' . OC_Util::getChannel() . ')'; $build = OC_Util::getBuild(); - if(!empty($build) and OC_Util::getChannel() === 'daily') { + if (!empty($build) and OC_Util::getChannel() === 'daily') { $version .= ' Build:' . $build; } return $version; @@ -1414,6 +1477,7 @@ class OC_Util { /** * Returns whether the given file name is valid + * * @param string $file file name to check * @return bool true if the file name is valid, false otherwise */ @@ -1442,9 +1506,27 @@ class OC_Util { if (OC_Config::getValue('installed', false)) { $installedVersion = OC_Config::getValue('version', '0.0.0'); $currentVersion = implode('.', OC_Util::getVersion()); - return version_compare($currentVersion, $installedVersion, '>'); + if (version_compare($currentVersion, $installedVersion, '>')) { + return true; + } + + // also check for upgrades for apps + $apps = \OC_App::getEnabledApps(); + foreach ($apps as $app) { + if (\OC_App::shouldUpgrade($app)) { + return true; + } + } + return false; } else { return false; } } + + /** + * @return string + */ + public static function isPhpCharSetUtf8() { + return ini_get('default_charset') === 'UTF-8'; + } } |