diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 8bfd0a7845f..0d050e12a95 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -101,11 +101,9 @@ class Hooks { $userView->file_exists('encryption.key') && $encLegacyKey = $userView->file_get_contents('encryption.key') ) { + $plainLegacyKey = Crypt::legacyDecrypt($encLegacyKey, $params['password']); - $plainLegacyKey = Crypt::legacyDecrypt($encLegacyKey, $params['password']); - - $session->setLegacyKey($plainLegacyKey); - + $session->setLegacyKey($plainLegacyKey); } // Encrypt existing user files diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index ef40c18183f..70278234b7c 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -311,7 +311,7 @@ class Proxy extends \OC_FileProxy { \OC_FileProxy::$enabled = false; // get file size - $data['size'] = self::postFileSize($path, $data['size']); + $data['size'] = self::postFileSize($path, $data['size'], $data); // Re-enable the proxy \OC_FileProxy::$enabled = $proxyStatus; @@ -325,7 +325,7 @@ class Proxy extends \OC_FileProxy { * @param $size * @return bool */ - public function postFileSize($path, $size) { + public function postFileSize($path, $size, $fileInfo = null) { $view = new \OC_FilesystemView('/'); @@ -359,9 +359,8 @@ class Proxy extends \OC_FileProxy { return $size; } - $fileInfo = false; // get file info from database/cache if not .part file - if (!Helper::isPartialFilePath($path)) { + if (empty($fileInfo) && !Helper::isPartialFilePath($path)) { $proxyState = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $fileInfo = $view->getFileInfo($path); @@ -369,7 +368,7 @@ class Proxy extends \OC_FileProxy { } // if file is encrypted return real file size - if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { + if (isset($fileInfo['encrypted']) && $fileInfo['encrypted'] === true) { // try to fix unencrypted file size if it doesn't look plausible if ((int)$fileInfo['size'] > 0 && (int)$fileInfo['unencrypted_size'] === 0 ) { $fixSize = $util->getFileSize($path); diff --git a/apps/files_encryption/tests/stream.php b/apps/files_encryption/tests/stream.php index d26cd75648b..8b9dc38a761 100644 --- a/apps/files_encryption/tests/stream.php +++ b/apps/files_encryption/tests/stream.php @@ -136,6 +136,8 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase { // set stream options $this->assertTrue(stream_set_blocking($handle, 1)); + fclose($handle); + // tear down $view->unlink($filename); } @@ -158,6 +160,8 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase { // set stream options $this->assertFalse(stream_set_timeout($handle, 1)); + fclose($handle); + // tear down $view->unlink($filename); } @@ -177,6 +181,8 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase { // set stream options $this->assertEquals(0, stream_set_write_buffer($handle, 1024)); + fclose($handle); + // tear down $view->unlink($filename); } diff --git a/apps/files_encryption/tests/webdav.php b/apps/files_encryption/tests/webdav.php index 8e8b9c53cee..7f728970675 100755 --- a/apps/files_encryption/tests/webdav.php +++ b/apps/files_encryption/tests/webdav.php @@ -48,6 +48,8 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase { public $dataShort; public $stateFilesTrashbin; + private $storage; + public static function setUpBeforeClass() { // reset backend \OC_User::clearBackends(); @@ -77,8 +79,8 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase { $this->pass = \Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1; // init filesystem view - $this->view = new \OC_FilesystemView('/'); - + $this->view = new \OC\Files\View('/'); + list($this->storage, $intPath) = $this->view->resolvePath('/'); // init short data $this->dataShort = 'hats'; @@ -196,6 +198,9 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase { $_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE='; $_SERVER['PATH_INFO'] = '/webdav' . $filename; + // at the beginning the file should exist + $this->assertTrue($this->view->file_exists('/' . $this->userId . '/files' . $filename)); + // handle webdav request $content = $this->handleWebdavRequest(); diff --git a/lib/private/connector/sabre/exception/filelocked.php b/lib/private/connector/sabre/exception/filelocked.php new file mode 100644 index 00000000000..ec200f847e3 --- /dev/null +++ b/lib/private/connector/sabre/exception/filelocked.php @@ -0,0 +1,28 @@ + + * + */ + +class OC_Connector_Sabre_Exception_FileLocked extends Sabre_DAV_Exception { + + public function __construct($message = "", $code = 0, Exception $previous = null) { + if($previous instanceof \OCP\Files\LockNotAcquiredException) { + $message = sprintf('Target file %s is locked by another process.', $previous->path); + } + parent::__construct($message, $code, $previous); + } + + /** + * Returns the HTTP status code for this exception + * + * @return int + */ + public function getHTTPCode() { + + return 503; + } +} diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index d61d97938c7..bc528cde794 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -97,15 +97,24 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D // the path for the file was not valid // TODO: find proper http status code for this case throw new Sabre_DAV_Exception_Forbidden($e->getMessage()); + } catch (\OCP\Files\LockNotAcquiredException $e) { + // the file is currently being written to by another process + throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e); } // rename to correct path - $renameOkay = $fs->rename($partpath, $this->path); - $fileExists = $fs->file_exists($this->path); - if ($renameOkay === false || $fileExists === false) { - \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); - $fs->unlink($partpath); - throw new Sabre_DAV_Exception('Could not rename part file to final file'); + try { + $renameOkay = $fs->rename($partpath, $this->path); + $fileExists = $fs->file_exists($this->path); + if ($renameOkay === false || $fileExists === false) { + \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + $fs->unlink($partpath); + throw new Sabre_DAV_Exception('Could not rename part file to final file'); + } + } + catch (\OCP\Files\LockNotAcquiredException $e) { + // the file is currently being written to by another process + throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e); } // allow sync clients to send the mtime along in a header diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index bbced79524f..0aa5f16ec6d 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -152,8 +152,8 @@ class Filesystem { /** * @param callable $wrapper */ - public static function addStorageWrapper($wrapper) { - self::getLoader()->addStorageWrapper($wrapper); + public static function addStorageWrapper($wrapperName, $wrapper) { + self::getLoader()->addStorageWrapper($wrapperName, $wrapper); $mounts = self::getMountManager()->getAll(); foreach ($mounts as $mount) { diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index dd5cc915dcb..322c2eb9c0d 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -371,6 +371,15 @@ abstract class Common implements \OC\Files\Storage\Storage { } /** + * {@inheritdoc} + */ + public function isLocal() { + // the common implementation returns a temporary file by + // default, which is not local + return false; + } + + /* * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class * * @param string $class diff --git a/lib/private/files/storage/loader.php b/lib/private/files/storage/loader.php index 2572ef443bc..0969596bd8c 100644 --- a/lib/private/files/storage/loader.php +++ b/lib/private/files/storage/loader.php @@ -21,8 +21,8 @@ class Loader { * * @param callable $callback */ - public function addStorageWrapper($callback) { - $this->storageWrappers[] = $callback; + public function addStorageWrapper($wrapperName, $callback) { + $this->storageWrappers[$wrapperName] = $callback; } public function load($mountPoint, $class, $arguments) { diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php index db3c6bfca3a..d698922b4ac 100644 --- a/lib/private/files/storage/local.php +++ b/lib/private/files/storage/local.php @@ -296,7 +296,19 @@ if (\OC_Util::runningOnWindows()) { * @return bool */ public function hasUpdated($path, $time) { - return $this->filemtime($path) > $time; + if ($this->file_exists($path)) { + return $this->filemtime($path) > $time; + } else { + return true; + } } + + /** + * {@inheritdoc} + */ + public function isLocal() { + return true; + } + } } diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php index c731669b1a5..6b2be92143e 100644 --- a/lib/private/files/storage/wrapper/wrapper.php +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -434,6 +434,14 @@ class Wrapper implements \OC\Files\Storage\Storage { } /** + * Returns the wrapped storage's value for isLocal() + * @return bool wrapped storage's isLocal() value + */ + public function isLocal() { + return $this->storage->isLocal(); + } + + /* * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class * * @param string $class diff --git a/lib/private/helper.php b/lib/private/helper.php index f56a2cf6840..cca9d29b4b1 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -903,6 +903,7 @@ class OC_Helper { if ($used < 0) { $used = 0; } + $free = \OC\Files\Filesystem::free_space($path); if ($free >= 0) { $total = $free + $used; diff --git a/lib/private/log/owncloud.php b/lib/private/log/owncloud.php index 3590bbd436d..08d0b7d5f93 100644 --- a/lib/private/log/owncloud.php +++ b/lib/private/log/owncloud.php @@ -28,6 +28,7 @@ class OC_Log_Owncloud { static protected $logFile; + static protected $reqId; /** * Init class data @@ -68,8 +69,20 @@ class OC_Log_Owncloud { $timezone = new DateTimeZone('UTC'); } $time = new DateTime(null, $timezone); - // remove username/passswords from URLs before writing the to the log file - $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=> $time->format($format)); + // remove username/passwords from URLs before writing the to the log file + $time = $time->format($format); + if($minLevel == OC_Log::DEBUG) { + if(empty(self::$reqId)) { + self::$reqId = uniqid(); + } + $reqId = self::$reqId; + $url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '--'; + $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '--'; + $entry = compact('reqId', 'app', 'message', 'level', 'time', 'method', 'url'); + } + else { + $entry = compact('app', 'message', 'level', 'time'); + } $entry = json_encode($entry); $handle = @fopen(self::$logFile, 'a'); @chmod(self::$logFile, 0640); diff --git a/lib/private/util.php b/lib/private/util.php index a88665420fd..5700e98ff3f 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -57,7 +57,7 @@ class OC_Util { //if we aren't logged in, there is no use to set up the filesystem if( $user != "" ) { - \OC\Files\Filesystem::addStorageWrapper(function($mountPoint, $storage){ + \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 diff --git a/lib/public/files/locknotacquiredexception.php b/lib/public/files/locknotacquiredexception.php new file mode 100644 index 00000000000..9fb70e7cbe2 --- /dev/null +++ b/lib/public/files/locknotacquiredexception.php @@ -0,0 +1,47 @@ +. + * + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/LockNotAcquiredException class + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files; + +/** + * Exception for a file that is locked + */ +class LockNotAcquiredException extends \Exception { + /** @var string $path The path that could not be locked */ + public $path; + + /** @var integer $lockType The type of the lock that was attempted */ + public $lockType; + + public function __construct($path, $lockType, $code = 0, \Exception $previous = null) { + $message = \OC_L10N::get('core')->t('Could not obtain lock type %d on "%s".', array($lockType, $path)); + parent::__construct($message, $code, $previous); + } + + // custom string representation of object + public function __toString() { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + } +} \ No newline at end of file diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index 9bed49c5ab8..6ba1b100249 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -317,6 +317,17 @@ interface Storage { public function getETag($path); /** + * Returns whether the storage is local, which means that files + * are stored on the local filesystem instead of remotely. + * Calling getLocalFile() for local storages should always + * return the local files, whereas for non-local storages + * it might return a temporary file. + * + * @return bool true if the files are stored locally, false otherwise + */ + public function isLocal(); + + /* * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class * * @param string $class diff --git a/tests/lib/files/filesystem.php b/tests/lib/files/filesystem.php index 90f1dfe581b..b0ed065571d 100644 --- a/tests/lib/files/filesystem.php +++ b/tests/lib/files/filesystem.php @@ -173,7 +173,7 @@ class Filesystem extends \PHPUnit_Framework_TestCase { $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/'); - $this->assertInstanceOf('\OC\Files\Storage\Local', $homeMount); + $this->assertTrue($homeMount->instanceOfStorage('\OC\Files\Storage\Local')); $this->assertEquals('local::' . $datadir . '/' . $userId . '/', $homeMount->getId()); } @@ -189,7 +189,7 @@ class Filesystem extends \PHPUnit_Framework_TestCase { $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/'); - $this->assertInstanceOf('\OC\Files\Storage\Home', $homeMount); + $this->assertTrue($homeMount->instanceOfStorage('\OC\Files\Storage\Home')); $this->assertEquals('home::' . $userId, $homeMount->getId()); \OC_User::deleteUser($userId); @@ -214,7 +214,7 @@ class Filesystem extends \PHPUnit_Framework_TestCase { $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/'); - $this->assertInstanceOf('\OC\Files\Storage\Home', $homeMount); + $this->assertTrue($homeMount->instanceOfStorage('\OC\Files\Storage\Home')); $this->assertEquals('local::' . $datadir . '/' . $userId . '/', $homeMount->getId()); \OC_User::deleteUser($userId); diff --git a/tests/lib/files/mount/mount.php b/tests/lib/files/mount/mount.php index b057204ad35..c3d33e0870b 100644 --- a/tests/lib/files/mount/mount.php +++ b/tests/lib/files/mount/mount.php @@ -35,7 +35,7 @@ class Mount extends \PHPUnit_Framework_TestCase { }; $loader = new Loader(); - $loader->addStorageWrapper($wrapper); + $loader->addStorageWrapper('test_wrapper', $wrapper); $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') ->disableOriginalConstructor() diff --git a/tests/lib/util.php b/tests/lib/util.php index 852caaeccc3..124fb32ed8b 100644 --- a/tests/lib/util.php +++ b/tests/lib/util.php @@ -128,7 +128,7 @@ class Test_Util extends PHPUnit_Framework_TestCase { $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/'); $this->assertNotNull($userMount); - $this->assertInstanceOf('\OC\Files\Storage\Wrapper\Quota', $userMount->getStorage()); + $this->assertTrue($userMount->getStorage()->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')); // ensure that root wasn't wrapped $rootMount = \OC\Files\Filesystem::getMountManager()->find('/');