summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
m---------3rdparty0
-rw-r--r--apps/dav/lib/connector/sabre/quotaplugin.php17
-rw-r--r--apps/dav/tests/unit/connector/sabre/quotaplugin.php109
-rw-r--r--apps/files/ajax/upload.php8
-rw-r--r--apps/files/js/file-upload.js43
-rw-r--r--apps/files_external/appinfo/database.xml9
-rw-r--r--apps/files_external/service/storagesservice.php7
-rw-r--r--apps/files_sharing/api/share20ocs.php32
-rw-r--r--apps/files_sharing/lib/external/storage.php3
-rw-r--r--apps/files_sharing/lib/helper.php58
-rw-r--r--apps/files_sharing/tests/api/share20ocstest.php331
-rw-r--r--apps/files_trashbin/lib/trashbin.php102
-rw-r--r--apps/files_versions/lib/storage.php71
-rw-r--r--core/ajax/share.php2
-rw-r--r--lib/private/db/mdb2schemareader.php11
-rw-r--r--lib/private/files/filesystem.php4
-rw-r--r--lib/private/files/node/root.php2
-rw-r--r--lib/private/files/storage/common.php7
-rw-r--r--lib/private/files/storage/wrapper/quota.php27
-rw-r--r--lib/private/server.php12
-rw-r--r--lib/private/util.php4
-rw-r--r--lib/public/appframework/http/redirectresponse.php2
-rw-r--r--settings/js/apps.js9
-rw-r--r--settings/templates/apps.php4
-rw-r--r--tests/lib/appframework/http/RedirectResponseTest.php2
-rw-r--r--version.php4
26 files changed, 750 insertions, 130 deletions
diff --git a/3rdparty b/3rdparty
-Subproject b65fc869803ac93e2441f53d8c91bd29fbcd82c
+Subproject fc0c1159f4e275186b45f8454aaa89f90718b89
diff --git a/apps/dav/lib/connector/sabre/quotaplugin.php b/apps/dav/lib/connector/sabre/quotaplugin.php
index a02827da499..b1c3bbfbbb9 100644
--- a/apps/dav/lib/connector/sabre/quotaplugin.php
+++ b/apps/dav/lib/connector/sabre/quotaplugin.php
@@ -95,12 +95,14 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
$req = $this->server->httpRequest;
if ($req->getHeader('OC-Chunked')) {
$info = \OC_FileChunking::decodeName($newName);
- $chunkHandler = new \OC_FileChunking($info);
+ $chunkHandler = $this->getFileChunking($info);
// subtract the already uploaded size to see whether
// there is still enough space for the remaining chunks
$length -= $chunkHandler->getCurrentSize();
+ // use target file name for free space check in case of shared files
+ $uri = rtrim($parentUri, '/') . '/' . $info['name'];
}
- $freeSpace = $this->getFreeSpace($parentUri);
+ $freeSpace = $this->getFreeSpace($uri);
if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN && $length > $freeSpace) {
if (isset($chunkHandler)) {
$chunkHandler->cleanup();
@@ -111,6 +113,11 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
return true;
}
+ public function getFileChunking($info) {
+ // FIXME: need a factory for better mocking support
+ return new \OC_FileChunking($info);
+ }
+
public function getLength() {
$req = $this->server->httpRequest;
$length = $req->getHeader('X-Expected-Entity-Length');
@@ -127,12 +134,12 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
}
/**
- * @param string $parentUri
+ * @param string $uri
* @return mixed
*/
- public function getFreeSpace($parentUri) {
+ public function getFreeSpace($uri) {
try {
- $freeSpace = $this->view->free_space($parentUri);
+ $freeSpace = $this->view->free_space(ltrim($uri, '/'));
return $freeSpace;
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
diff --git a/apps/dav/tests/unit/connector/sabre/quotaplugin.php b/apps/dav/tests/unit/connector/sabre/quotaplugin.php
index cc4339ecc1a..b5a8bfef31c 100644
--- a/apps/dav/tests/unit/connector/sabre/quotaplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/quotaplugin.php
@@ -39,10 +39,13 @@ class QuotaPlugin extends \Test\TestCase {
*/
private $plugin;
- private function init($quota) {
- $view = $this->buildFileViewMock($quota);
+ private function init($quota, $checkedPath = '') {
+ $view = $this->buildFileViewMock($quota, $checkedPath);
$this->server = new \Sabre\DAV\Server();
- $this->plugin = new \OCA\DAV\Connector\Sabre\QuotaPlugin($view);
+ $this->plugin = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\QuotaPlugin')
+ ->setConstructorArgs([$view])
+ ->setMethods(['getFileChunking'])
+ ->getMock();
$this->plugin->initialize($this->server);
}
@@ -51,6 +54,8 @@ class QuotaPlugin extends \Test\TestCase {
*/
public function testLength($expected, $headers) {
$this->init(0);
+ $this->plugin->expects($this->never())
+ ->method('getFileChunking');
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
$length = $this->plugin->getLength();
$this->assertEquals($expected, $length);
@@ -61,6 +66,8 @@ class QuotaPlugin extends \Test\TestCase {
*/
public function testCheckQuota($quota, $headers) {
$this->init($quota);
+ $this->plugin->expects($this->never())
+ ->method('getFileChunking');
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
$result = $this->plugin->checkQuota('');
@@ -73,11 +80,26 @@ class QuotaPlugin extends \Test\TestCase {
*/
public function testCheckExceededQuota($quota, $headers) {
$this->init($quota);
+ $this->plugin->expects($this->never())
+ ->method('getFileChunking');
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
$this->plugin->checkQuota('');
}
+ /**
+ * @dataProvider quotaOkayProvider
+ */
+ public function testCheckQuotaOnPath($quota, $headers) {
+ $this->init($quota, 'sub/test.txt');
+ $this->plugin->expects($this->never())
+ ->method('getFileChunking');
+
+ $this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
+ $result = $this->plugin->checkQuota('/sub/test.txt');
+ $this->assertTrue($result);
+ }
+
public function quotaOkayProvider() {
return array(
array(1024, array()),
@@ -110,12 +132,89 @@ class QuotaPlugin extends \Test\TestCase {
);
}
- private function buildFileViewMock($quota) {
+ public function quotaChunkedOkProvider() {
+ return array(
+ array(1024, 0, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(1024, 0, array('CONTENT-LENGTH' => '512')),
+ array(1024, 0, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
+ // with existing chunks (allowed size = total length - chunk total size)
+ array(400, 128, array('X-EXPECTED-ENTITY-LENGTH' => '512')),
+ array(400, 128, array('CONTENT-LENGTH' => '512')),
+ array(400, 128, array('OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500')),
+ // \OCP\Files\FileInfo::SPACE-UNKNOWN = -2
+ array(-2, 0, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(-2, 0, array('CONTENT-LENGTH' => '512')),
+ array(-2, 0, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
+ array(-2, 128, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(-2, 128, array('CONTENT-LENGTH' => '512')),
+ array(-2, 128, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
+ );
+ }
+
+ /**
+ * @dataProvider quotaChunkedOkProvider
+ */
+ public function testCheckQuotaChunkedOk($quota, $chunkTotalSize, $headers) {
+ $this->init($quota, 'sub/test.txt');
+
+ $mockChunking = $this->getMockBuilder('\OC_FileChunking')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mockChunking->expects($this->once())
+ ->method('getCurrentSize')
+ ->will($this->returnValue($chunkTotalSize));
+
+ $this->plugin->expects($this->once())
+ ->method('getFileChunking')
+ ->will($this->returnValue($mockChunking));
+
+ $headers['OC-CHUNKED'] = 1;
+ $this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
+ $result = $this->plugin->checkQuota('/sub/test.txt-chunking-12345-3-1');
+ $this->assertTrue($result);
+ }
+
+ public function quotaChunkedFailProvider() {
+ return array(
+ array(400, 0, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(400, 0, array('CONTENT-LENGTH' => '512')),
+ array(400, 0, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
+ // with existing chunks (allowed size = total length - chunk total size)
+ array(380, 128, array('X-EXPECTED-ENTITY-LENGTH' => '512')),
+ array(380, 128, array('CONTENT-LENGTH' => '512')),
+ array(380, 128, array('OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500')),
+ );
+ }
+
+ /**
+ * @dataProvider quotaChunkedFailProvider
+ * @expectedException \Sabre\DAV\Exception\InsufficientStorage
+ */
+ public function testCheckQuotaChunkedFail($quota, $chunkTotalSize, $headers) {
+ $this->init($quota, 'sub/test.txt');
+
+ $mockChunking = $this->getMockBuilder('\OC_FileChunking')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mockChunking->expects($this->once())
+ ->method('getCurrentSize')
+ ->will($this->returnValue($chunkTotalSize));
+
+ $this->plugin->expects($this->once())
+ ->method('getFileChunking')
+ ->will($this->returnValue($mockChunking));
+
+ $headers['OC-CHUNKED'] = 1;
+ $this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
+ $this->plugin->checkQuota('/sub/test.txt-chunking-12345-3-1');
+ }
+
+ private function buildFileViewMock($quota, $checkedPath) {
// mock filesysten
$view = $this->getMock('\OC\Files\View', array('free_space'), array(), '', false);
$view->expects($this->any())
->method('free_space')
- ->with($this->identicalTo(''))
+ ->with($this->identicalTo($checkedPath))
->will($this->returnValue($quota));
return $view;
diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index 5bf69d3e304..36aaed5ad9e 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -136,8 +136,12 @@ $maxUploadFileSize = $storageStats['uploadMaxFilesize'];
$maxHumanFileSize = OCP\Util::humanFileSize($maxUploadFileSize);
$totalSize = 0;
-foreach ($files['size'] as $size) {
- $totalSize += $size;
+$isReceivedShare = \OC::$server->getRequest()->getParam('isReceivedShare', false) === 'true';
+// defer quota check for received shares
+if (!$isReceivedShare) {
+ foreach ($files['size'] as $size) {
+ $totalSize += $size;
+ }
}
if ($maxUploadFileSize >= 0 and $totalSize > $maxUploadFileSize) {
OCP\JSON::error(array('data' => array('message' => $l->t('Not enough storage available'),
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index d419cb3a2c0..8ba294e2a7f 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -251,7 +251,26 @@ OC.Upload = {
$('#file_upload_start').trigger(new $.Event('resized'));
},
+ /**
+ * Returns whether the given file is known to be a received shared file
+ *
+ * @param {Object} file file
+ * @return {bool} true if the file is a shared file
+ */
+ _isReceivedSharedFile: function(file) {
+ if (!window.FileList) {
+ return false;
+ }
+ var $tr = window.FileList.findFileEl(file.name);
+ if (!$tr.length) {
+ return false;
+ }
+
+ return ($tr.attr('data-mounttype') === 'shared-root' && $tr.attr('data-mime') !== 'httpd/unix-directory');
+ },
+
init: function() {
+ var self = this;
if ( $('#file_upload_start').exists() ) {
var file_upload_param = {
dropZone: $('#content'), // restrict dropZone to content div
@@ -341,10 +360,15 @@ OC.Upload = {
}
}
- // add size
- selection.totalBytes += file.size;
- // update size of biggest file
- selection.biggestFileBytes = Math.max(selection.biggestFileBytes, file.size);
+ // only count if we're not overwriting an existing shared file
+ if (self._isReceivedSharedFile(file)) {
+ file.isReceivedShare = true;
+ } else {
+ // add size
+ selection.totalBytes += file.size;
+ // update size of biggest file
+ selection.biggestFileBytes = Math.max(selection.biggestFileBytes, file.size);
+ }
// check PHP upload limit against biggest file
if (selection.biggestFileBytes > $('#upload_limit').val()) {
@@ -430,11 +454,16 @@ OC.Upload = {
fileDirectory = data.files[0].relativePath;
}
- addFormData(data.formData, {
+ var params = {
requesttoken: oc_requesttoken,
dir: data.targetDir || FileList.getCurrentDirectory(),
- file_directory: fileDirectory
- });
+ file_directory: fileDirectory,
+ };
+ if (data.files[0].isReceivedShare) {
+ params.isReceivedShare = true;
+ }
+
+ addFormData(data.formData, params);
},
fail: function(e, data) {
OC.Upload.log('fail', e, data);
diff --git a/apps/files_external/appinfo/database.xml b/apps/files_external/appinfo/database.xml
index 2c3615a4d4c..54ee642ead6 100644
--- a/apps/files_external/appinfo/database.xml
+++ b/apps/files_external/appinfo/database.xml
@@ -79,13 +79,16 @@
<type>text</type>
<length>64</length>
</field>
+
<index>
+ <name>applicable_mount</name>
<field>
<name>mount_id</name>
<sorting>ascending</sorting>
</field>
</index>
<index>
+ <name>applicable_type_value</name>
<field>
<name>type</name>
<sorting>ascending</sorting>
@@ -96,6 +99,7 @@
</field>
</index>
<index>
+ <name>applicable_type_value_mount</name>
<unique>true</unique>
<field>
<name>type</name>
@@ -112,6 +116,7 @@
</index>
</declaration>
</table>
+
<table>
<name>*dbprefix*external_config</name>
<declaration>
@@ -144,12 +149,14 @@
</field>
<index>
+ <name>config_mount</name>
<field>
<name>mount_id</name>
<sorting>ascending</sorting>
</field>
</index>
<index>
+ <name>config_mount_key</name>
<unique>true</unique>
<field>
<name>mount_id</name>
@@ -162,6 +169,7 @@
</index>
</declaration>
</table>
+
<table>
<name>*dbprefix*external_options</name>
<declaration>
@@ -194,6 +202,7 @@
</field>
<index>
+ <name>option_mount</name>
<field>
<name>mount_id</name>
<sorting>ascending</sorting>
diff --git a/apps/files_external/service/storagesservice.php b/apps/files_external/service/storagesservice.php
index 678b91c0109..0a4c00c66ad 100644
--- a/apps/files_external/service/storagesservice.php
+++ b/apps/files_external/service/storagesservice.php
@@ -104,6 +104,13 @@ abstract class StoragesService {
\OCP\Util::ERROR
);
return null;
+ } catch (\InvalidArgumentException $e) {
+ \OCP\Util::writeLog(
+ 'files_external',
+ 'Could not load storage: "' . $e->getMessage() . '"',
+ \OCP\Util::ERROR
+ );
+ return null;
}
}
diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php
index 688ed5b3ee5..309e1159fff 100644
--- a/apps/files_sharing/api/share20ocs.php
+++ b/apps/files_sharing/api/share20ocs.php
@@ -20,6 +20,7 @@
*/
namespace OCA\Files_Sharing\API;
+use OCP\Files\NotFoundException;
use OCP\IGroupManager;
use OCP\IUserManager;
use OCP\IRequest;
@@ -83,6 +84,7 @@ class Share20OCS {
*
* @param \OCP\Share\IShare $share
* @return array
+ * @throws NotFoundException In case the node can't be resolved.
*/
protected function formatShare(\OCP\Share\IShare $share) {
$sharedBy = $this->userManager->get($share->getSharedBy());
@@ -177,11 +179,15 @@ class Share20OCS {
}
if ($this->canAccessShare($share)) {
- $share = $this->formatShare($share);
- return new \OC_OCS_Result([$share]);
- } else {
- return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
+ try {
+ $share = $this->formatShare($share);
+ return new \OC_OCS_Result([$share]);
+ } catch (NotFoundException $e) {
+ //Fall trough
+ }
}
+
+ return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
}
/**
@@ -368,7 +374,11 @@ class Share20OCS {
$formatted = [];
foreach ($shares as $share) {
if ($this->canAccessShare($share)) {
- $formatted[] = $this->formatShare($share);
+ try {
+ $formatted[] = $this->formatShare($share);
+ } catch (NotFoundException $e) {
+ // Ignore this share
+ }
}
}
@@ -398,7 +408,11 @@ class Share20OCS {
$formatted = [];
foreach ($shares as $share) {
- $formatted[] = $this->formatShare($share);
+ try {
+ $formatted[] = $this->formatShare($share);
+ } catch (NotFoundException $e) {
+ //Ignore this share
+ }
}
return new \OC_OCS_Result($formatted);
@@ -458,7 +472,11 @@ class Share20OCS {
$formatted = [];
foreach ($shares as $share) {
- $formatted[] = $this->formatShare($share);
+ try {
+ $formatted[] = $this->formatShare($share);
+ } catch (NotFoundException $e) {
+ //Ignore share
+ }
}
return new \OC_OCS_Result($formatted);
diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php
index 783eea43c62..ba7fba654a9 100644
--- a/apps/files_sharing/lib/external/storage.php
+++ b/apps/files_sharing/lib/external/storage.php
@@ -252,6 +252,9 @@ class Storage extends DAV implements ISharedStorage {
if ($e->getCode() === 401 || $e->getCode() === 403) {
throw new ForbiddenException();
}
+ if ($e->getCode() === 404) {
+ throw new NotFoundException();
+ }
// throw this to be on the safe side: the share will still be visible
// in the UI in case the failure is intermittent, and the user will
// be able to decide whether to remove it if it's really gone
diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php
index cffdc8887ec..e857974ae74 100644
--- a/apps/files_sharing/lib/helper.php
+++ b/apps/files_sharing/lib/helper.php
@@ -29,7 +29,9 @@
namespace OCA\Files_Sharing;
use OC\Files\Filesystem;
+use OC\Files\View;
use OCP\Files\NotFoundException;
+use OCP\User;
class Helper {
@@ -78,7 +80,7 @@ class Helper {
}
try {
- $path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
+ $path = Filesystem::getPath($linkItem['file_source']);
} catch (NotFoundException $e) {
\OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
\OC_Response::setStatus(404);
@@ -103,8 +105,8 @@ class Helper {
$basePath = $path;
- if ($relativePath !== null && \OC\Files\Filesystem::isReadable($basePath . $relativePath)) {
- $path .= \OC\Files\Filesystem::normalizePath($relativePath);
+ if ($relativePath !== null && Filesystem::isReadable($basePath . $relativePath)) {
+ $path .= Filesystem::normalizePath($relativePath);
}
return array(
@@ -168,11 +170,11 @@ class Helper {
public static function getSharesFromItem($target) {
$result = array();
- $owner = \OC\Files\Filesystem::getOwner($target);
- \OC\Files\Filesystem::initMountPoints($owner);
- $info = \OC\Files\Filesystem::getFileInfo($target);
- $ownerView = new \OC\Files\View('/'.$owner.'/files');
- if ( $owner != \OCP\User::getUser() ) {
+ $owner = Filesystem::getOwner($target);
+ Filesystem::initMountPoints($owner);
+ $info = Filesystem::getFileInfo($target);
+ $ownerView = new View('/'.$owner.'/files');
+ if ( $owner != User::getUser() ) {
$path = $ownerView->getPath($info['fileid']);
} else {
$path = $target;
@@ -205,8 +207,34 @@ class Helper {
return $result;
}
+ /**
+ * get the UID of the owner of the file and the path to the file relative to
+ * owners files folder
+ *
+ * @param $filename
+ * @return array
+ * @throws \OC\User\NoUserException
+ */
public static function getUidAndFilename($filename) {
- return Filesystem::getView()->getUidAndFilename($filename);
+ $uid = Filesystem::getOwner($filename);
+ $userManager = \OC::$server->getUserManager();
+ // if the user with the UID doesn't exists, e.g. because the UID points
+ // to a remote user with a federated cloud ID we use the current logged-in
+ // user. We need a valid local user to create the share
+ if (!$userManager->userExists($uid)) {
+ $uid = User::getUser();
+ }
+ Filesystem::initMountPoints($uid);
+ if ( $uid != User::getUser() ) {
+ $info = Filesystem::getFileInfo($filename);
+ $ownerView = new View('/'.$uid.'/files');
+ try {
+ $filename = $ownerView->getPath($info['fileid']);
+ } catch (NotFoundException $e) {
+ $filename = null;
+ }
+ }
+ return [$uid, $filename];
}
/**
@@ -234,7 +262,7 @@ class Helper {
*
* @param string $path
* @param array $excludeList
- * @param \OC\Files\View $view
+ * @param View $view
* @return string $path
*/
public static function generateUniqueTarget($path, $excludeList, $view) {
@@ -244,7 +272,7 @@ class Helper {
$dir = $pathinfo['dirname'];
$i = 2;
while ($view->file_exists($path) || in_array($path, $excludeList)) {
- $path = \OC\Files\Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
+ $path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
$i++;
}
@@ -278,15 +306,15 @@ class Helper {
*/
public static function getShareFolder() {
$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
- $shareFolder = \OC\Files\Filesystem::normalizePath($shareFolder);
+ $shareFolder = Filesystem::normalizePath($shareFolder);
- if (!\OC\Files\Filesystem::file_exists($shareFolder)) {
+ if (!Filesystem::file_exists($shareFolder)) {
$dir = '';
$subdirs = explode('/', $shareFolder);
foreach ($subdirs as $subdir) {
$dir = $dir . '/' . $subdir;
- if (!\OC\Files\Filesystem::is_dir($dir)) {
- \OC\Files\Filesystem::mkdir($dir);
+ if (!Filesystem::is_dir($dir)) {
+ Filesystem::mkdir($dir);
}
}
}
diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php
index a1094ce4b22..44d94868a32 100644
--- a/apps/files_sharing/tests/api/share20ocstest.php
+++ b/apps/files_sharing/tests/api/share20ocstest.php
@@ -21,6 +21,7 @@
namespace OCA\Files_Sharing\Tests\API;
use OCA\Files_Sharing\API\Share20OCS;
+use OCP\Files\NotFoundException;
use OCP\IGroupManager;
use OCP\IUserManager;
use OCP\IRequest;
@@ -28,6 +29,12 @@ use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Files\IRootFolder;
+/**
+ * Class Share20OCSTest
+ *
+ * @package OCA\Files_Sharing\Tests\API
+ * @group DB
+ */
class Share20OCSTest extends \Test\TestCase {
/** @var \OC\Share20\Manager | \PHPUnit_Framework_MockObject_MockObject */
@@ -398,6 +405,22 @@ class Share20OCSTest extends \Test\TestCase {
$this->assertEquals($expected->getData(), $ocs->getShare($share->getId())->getData());
}
+ public function testGetShareInvalidNode() {
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setSharedBy('initiator')
+ ->setSharedWith('recipient')
+ ->setShareOwner('owner');
+
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareById')
+ ->with('ocinternal:42')
+ ->willReturn($share);
+
+ $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.');
+ $this->assertEquals($expected->getMeta(), $this->ocs->getShare(42)->getMeta());
+ }
+
public function testCanAccessShare() {
$share = $this->getMock('OCP\Share\IShare');
$share->method('getShareOwner')->willReturn($this->currentUser->getUID());
@@ -1361,4 +1384,312 @@ class Share20OCSTest extends \Test\TestCase {
$this->assertEquals($expected->getMeta(), $result->getMeta());
$this->assertEquals($expected->getData(), $result->getData());
}
+
+ public function dataFormatShare() {
+ $file = $this->getMock('\OCP\Files\File');
+ $folder = $this->getMock('\OCP\Files\Folder');
+ $parent = $this->getMock('\OCP\Files\Folder');
+
+ $file->method('getPath')->willReturn('file');
+ $folder->method('getPath')->willReturn('folder');
+
+ $parent->method('getId')->willReturn(1);
+ $folder->method('getId')->willReturn(2);
+ $file->method('getId')->willReturn(3);
+
+ $file->method('getParent')->willReturn($parent);
+ $folder->method('getParent')->willReturn($parent);
+
+ $cache = $this->getMock('OCP\Files\Cache\ICache');
+ $cache->method('getNumericStorageId')->willReturn(100);
+ $storage = $this->getMock('\OCP\Files\Storage');
+ $storage->method('getId')->willReturn('storageId');
+ $storage->method('getCache')->willReturn($cache);
+
+ $file->method('getStorage')->willReturn($storage);
+ $folder->method('getStorage')->willReturn($storage);
+
+ $owner = $this->getMock('\OCP\IUser');
+ $owner->method('getDisplayName')->willReturn('ownerDN');
+ $initiator = $this->getMock('\OCP\IUser');
+ $initiator->method('getDisplayName')->willReturn('initiatorDN');
+ $recipient = $this->getMock('\OCP\IUser');
+ $recipient->method('getDisplayName')->willReturn('recipientDN');
+
+ $result = [];
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('recipient')
+ ->setSharedBy('initiator')
+ ->setShareOwner('owner')
+ ->setPermissions(\OCP\Constants::PERMISSION_READ)
+ ->setNode($file)
+ ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
+ ->setTarget('myTarget')
+ ->setId(42);
+
+ /* User backend down */
+ $result[] = [
+ [
+ 'id' => 42,
+ 'share_type' => \OCP\Share::SHARE_TYPE_USER,
+ 'uid_owner' => 'initiator',
+ 'displayname_owner' => 'initiator',
+ 'permissions' => 1,
+ 'stime' => 946684862,
+ 'parent' => null,
+ 'expiration' => null,
+ 'token' => null,
+ 'uid_file_owner' => 'owner',
+ 'displayname_file_owner' => 'owner',
+ 'path' => 'file',
+ 'item_type' => 'file',
+ 'storage_id' => 'storageId',
+ 'storage' => 100,
+ 'item_source' => 3,
+ 'file_source' => 3,
+ 'file_parent' => 1,
+ 'file_target' => 'myTarget',
+ 'share_with' => 'recipient',
+ 'share_with_displayname' => 'recipient',
+ 'mail_send' => 0,
+ ], $share, [], false
+ ];
+
+ /* User backend up */
+ $result[] = [
+ [
+ 'id' => 42,
+ 'share_type' => \OCP\Share::SHARE_TYPE_USER,
+ 'uid_owner' => 'initiator',
+ 'displayname_owner' => 'initiatorDN',
+ 'permissions' => 1,
+ 'stime' => 946684862,
+ 'parent' => null,
+ 'expiration' => null,
+ 'token' => null,
+ 'uid_file_owner' => 'owner',
+ 'displayname_file_owner' => 'ownerDN',
+ 'path' => 'file',
+ 'item_type' => 'file',
+ 'storage_id' => 'storageId',
+ 'storage' => 100,
+ 'item_source' => 3,
+ 'file_source' => 3,
+ 'file_parent' => 1,
+ 'file_target' => 'myTarget',
+ 'share_with' => 'recipient',
+ 'share_with_displayname' => 'recipientDN',
+ 'mail_send' => 0,
+ ], $share, [
+ ['owner', $owner],
+ ['initiator', $initiator],
+ ['recipient', $recipient],
+ ], false
+ ];
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedWith('recipient')
+ ->setSharedBy('initiator')
+ ->setShareOwner('owner')
+ ->setPermissions(\OCP\Constants::PERMISSION_READ)
+ ->setNode($file)
+ ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
+ ->setTarget('myTarget')
+ ->setId(42);
+
+ /* User backend down */
+ $result[] = [
+ [
+ 'id' => 42,
+ 'share_type' => \OCP\Share::SHARE_TYPE_USER,
+ 'uid_owner' => 'initiator',
+ 'displayname_owner' => 'initiator',
+ 'permissions' => 1,
+ 'stime' => 946684862,
+ 'parent' => null,
+ 'expiration' => null,
+ 'token' => null,
+ 'uid_file_owner' => 'owner',
+ 'displayname_file_owner' => 'owner',
+ 'path' => 'file',
+ 'item_type' => 'file',
+ 'storage_id' => 'storageId',
+ 'storage' => 100,
+ 'item_source' => 3,
+ 'file_source' => 3,
+ 'file_parent' => 1,
+ 'file_target' => 'myTarget',
+ 'share_with' => 'recipient',
+ 'share_with_displayname' => 'recipient',
+ 'mail_send' => 0,
+ ], $share, [], false
+ ];
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_GROUP)
+ ->setSharedWith('recipient')
+ ->setSharedBy('initiator')
+ ->setShareOwner('owner')
+ ->setPermissions(\OCP\Constants::PERMISSION_READ)
+ ->setNode($file)
+ ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
+ ->setTarget('myTarget')
+ ->setId(42);
+
+ $result[] = [
+ [
+ 'id' => 42,
+ 'share_type' => \OCP\Share::SHARE_TYPE_GROUP,
+ 'uid_owner' => 'initiator',
+ 'displayname_owner' => 'initiator',
+ 'permissions' => 1,
+ 'stime' => 946684862,
+ 'parent' => null,
+ 'expiration' => null,
+ 'token' => null,
+ 'uid_file_owner' => 'owner',
+ 'displayname_file_owner' => 'owner',
+ 'path' => 'file',
+ 'item_type' => 'file',
+ 'storage_id' => 'storageId',
+ 'storage' => 100,
+ 'item_source' => 3,
+ 'file_source' => 3,
+ 'file_parent' => 1,
+ 'file_target' => 'myTarget',
+ 'share_with' => 'recipient',
+ 'share_with_displayname' => 'recipient',
+ 'mail_send' => 0,
+ ], $share, [], false
+ ];
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_LINK)
+ ->setSharedBy('initiator')
+ ->setShareOwner('owner')
+ ->setPermissions(\OCP\Constants::PERMISSION_READ)
+ ->setNode($file)
+ ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
+ ->setTarget('myTarget')
+ ->setPassword('mypassword')
+ ->setExpirationDate(new \DateTime('2001-01-02T00:00:00'))
+ ->setToken('myToken')
+ ->setId(42);
+
+ $result[] = [
+ [
+ 'id' => 42,
+ 'share_type' => \OCP\Share::SHARE_TYPE_LINK,
+ 'uid_owner' => 'initiator',
+ 'displayname_owner' => 'initiator',
+ 'permissions' => 1,
+ 'stime' => 946684862,
+ 'parent' => null,
+ 'expiration' => '2001-01-02 00:00:00',
+ 'token' => 'myToken',
+ 'uid_file_owner' => 'owner',
+ 'displayname_file_owner' => 'owner',
+ 'path' => 'file',
+ 'item_type' => 'file',
+ 'storage_id' => 'storageId',
+ 'storage' => 100,
+ 'item_source' => 3,
+ 'file_source' => 3,
+ 'file_parent' => 1,
+ 'file_target' => 'myTarget',
+ 'share_with' => 'mypassword',
+ 'share_with_displayname' => 'mypassword',
+ 'mail_send' => 0,
+ 'url' => 'myLink'
+ ], $share, [], false
+ ];
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_REMOTE)
+ ->setSharedBy('initiator')
+ ->setSharedWith('user@server.com')
+ ->setShareOwner('owner')
+ ->setPermissions(\OCP\Constants::PERMISSION_READ)
+ ->setNode($folder)
+ ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
+ ->setTarget('myTarget')
+ ->setId(42);
+
+ $result[] = [
+ [
+ 'id' => 42,
+ 'share_type' => \OCP\Share::SHARE_TYPE_REMOTE,
+ 'uid_owner' => 'initiator',
+ 'displayname_owner' => 'initiator',
+ 'permissions' => 1,
+ 'stime' => 946684862,
+ 'parent' => null,
+ 'expiration' => null,
+ 'token' => null,
+ 'uid_file_owner' => 'owner',
+ 'displayname_file_owner' => 'owner',
+ 'path' => 'folder',
+ 'item_type' => 'folder',
+ 'storage_id' => 'storageId',
+ 'storage' => 100,
+ 'item_source' => 2,
+ 'file_source' => 2,
+ 'file_parent' => 1,
+ 'file_target' => 'myTarget',
+ 'share_with' => 'user@server.com',
+ 'share_with_displayname' => 'user@server.com',
+ 'mail_send' => 0,
+ ], $share, [], false
+ ];
+
+ $share = \OC::$server->getShareManager()->newShare();
+ $share->setShareType(\OCP\Share::SHARE_TYPE_USER)
+ ->setSharedBy('initiator')
+ ->setSharedWith('recipient')
+ ->setShareOwner('owner')
+ ->setPermissions(\OCP\Constants::PERMISSION_READ)
+ ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
+ ->setTarget('myTarget')
+ ->setId(42);
+
+ $result[] = [
+ [], $share, [], true
+ ];
+
+
+
+ return $result;
+ }
+
+ /**
+ * @dataProvider dataFormatShare
+ *
+ * @param array $expects
+ * @param \OCP\Share\IShare $share
+ * @param array $users
+ * @param $exception
+ */
+ public function testFormatShare(array $expects, \OCP\Share\IShare $share, array $users, $exception) {
+ $this->userManager->method('get')->will($this->returnValueMap($users));
+ $this->urlGenerator->method('linkToRouteAbsolute')
+ ->with('files_sharing.sharecontroller.showShare', ['token' => 'myToken'])
+ ->willReturn('myLink');
+
+
+ $this->rootFolder->method('getUserFolder')->with($share->getShareOwner())->will($this->returnSelf());
+ $this->rootFolder->method('getRelativePath')->will($this->returnArgument(0));
+
+ try {
+ $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
+ $this->assertFalse($exception);
+ $this->assertEquals($expects, $result);
+ } catch (NotFoundException $e) {
+ $this->assertTrue($exception);
+ }
+
+
+ }
}
diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php
index 62d70d7356a..3b386b0abd8 100644
--- a/apps/files_trashbin/lib/trashbin.php
+++ b/apps/files_trashbin/lib/trashbin.php
@@ -43,6 +43,7 @@ use OC\Files\View;
use OCA\Files_Trashbin\AppInfo\Application;
use OCA\Files_Trashbin\Command\Expire;
use OCP\Files\NotFoundException;
+use OCP\User;
class Trashbin {
@@ -71,12 +72,33 @@ class Trashbin {
}
/**
+ * get the UID of the owner of the file and the path to the file relative to
+ * owners files folder
+ *
* @param string $filename
* @return array
* @throws \OC\User\NoUserException
*/
public static function getUidAndFilename($filename) {
- return Filesystem::getView()->getUidAndFilename($filename);
+ $uid = Filesystem::getOwner($filename);
+ $userManager = \OC::$server->getUserManager();
+ // if the user with the UID doesn't exists, e.g. because the UID points
+ // to a remote user with a federated cloud ID we use the current logged-in
+ // user. We need a valid local user to move the file to the right trash bin
+ if (!$userManager->userExists($uid)) {
+ $uid = User::getUser();
+ }
+ Filesystem::initMountPoints($uid);
+ if ($uid != User::getUser()) {
+ $info = Filesystem::getFileInfo($filename);
+ $ownerView = new View('/' . $uid . '/files');
+ try {
+ $filename = $ownerView->getPath($info['fileid']);
+ } catch (NotFoundException $e) {
+ $filename = null;
+ }
+ }
+ return [$uid, $filename];
}
/**
@@ -120,7 +142,7 @@ class Trashbin {
}
private static function setUpTrash($user) {
- $view = new \OC\Files\View('/' . $user);
+ $view = new View('/' . $user);
if (!$view->is_dir('files_trashbin')) {
$view->mkdir('files_trashbin');
}
@@ -153,7 +175,7 @@ class Trashbin {
$sourceFilename = basename($sourcePath);
- $view = new \OC\Files\View('/');
+ $view = new View('/');
$target = $user . '/files_trashbin/files/' . $targetFilename . '.d' . $timestamp;
$source = $owner . '/files_trashbin/files/' . $sourceFilename . '.d' . $timestamp;
@@ -182,7 +204,7 @@ class Trashbin {
list(, $user) = explode('/', $root);
list($owner, $ownerPath) = self::getUidAndFilename($file_path);
- $ownerView = new \OC\Files\View('/' . $owner);
+ $ownerView = new View('/' . $owner);
// file has been deleted in between
if (!$ownerView->file_exists('/files/' . $ownerPath)) {
return true;
@@ -234,8 +256,8 @@ class Trashbin {
if (!$result) {
\OCP\Util::writeLog('files_trashbin', 'trash bin database couldn\'t be updated', \OCP\Util::ERROR);
}
- \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', array('filePath' => \OC\Files\Filesystem::normalizePath($file_path),
- 'trashPath' => \OC\Files\Filesystem::normalizePath($filename . '.d' . $timestamp)));
+ \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', array('filePath' => Filesystem::normalizePath($file_path),
+ 'trashPath' => Filesystem::normalizePath($filename . '.d' . $timestamp)));
self::retainVersions($filename, $owner, $ownerPath, $timestamp);
@@ -266,8 +288,8 @@ class Trashbin {
private static function retainVersions($filename, $owner, $ownerPath, $timestamp) {
if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) {
- $user = \OCP\User::getUser();
- $rootView = new \OC\Files\View('/');
+ $user = User::getUser();
+ $rootView = new View('/');
if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
if ($owner !== $user) {
@@ -341,8 +363,8 @@ class Trashbin {
* @return bool true on success, false otherwise
*/
public static function restore($file, $filename, $timestamp) {
- $user = \OCP\User::getUser();
- $view = new \OC\Files\View('/' . $user);
+ $user = User::getUser();
+ $view = new View('/' . $user);
$location = '';
if ($timestamp) {
@@ -363,8 +385,8 @@ class Trashbin {
// we need a extension in case a file/dir with the same name already exists
$uniqueFilename = self::getUniqueFilename($location, $filename, $view);
- $source = \OC\Files\Filesystem::normalizePath('files_trashbin/files/' . $file);
- $target = \OC\Files\Filesystem::normalizePath('files/' . $location . '/' . $uniqueFilename);
+ $source = Filesystem::normalizePath('files_trashbin/files/' . $file);
+ $target = Filesystem::normalizePath('files/' . $location . '/' . $uniqueFilename);
if (!$view->file_exists($source)) {
return false;
}
@@ -379,8 +401,8 @@ class Trashbin {
$view->chroot('/' . $user . '/files');
$view->touch('/' . $location . '/' . $uniqueFilename, $mtime);
$view->chroot($fakeRoot);
- \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', array('filePath' => \OC\Files\Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename),
- 'trashPath' => \OC\Files\Filesystem::normalizePath($file)));
+ \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', array('filePath' => Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename),
+ 'trashPath' => Filesystem::normalizePath($file)));
self::restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp);
@@ -398,7 +420,7 @@ class Trashbin {
/**
* restore versions from trash bin
*
- * @param \OC\Files\View $view file view
+ * @param View $view file view
* @param string $file complete path to file
* @param string $filename name of file once it was deleted
* @param string $uniqueFilename new file name to restore the file without overwriting existing files
@@ -406,14 +428,14 @@ class Trashbin {
* @param int $timestamp deletion time
* @return false|null
*/
- private static function restoreVersions(\OC\Files\View $view, $file, $filename, $uniqueFilename, $location, $timestamp) {
+ private static function restoreVersions(View $view, $file, $filename, $uniqueFilename, $location, $timestamp) {
if (\OCP\App::isEnabled('files_versions')) {
- $user = \OCP\User::getUser();
- $rootView = new \OC\Files\View('/');
+ $user = User::getUser();
+ $rootView = new View('/');
- $target = \OC\Files\Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename);
+ $target = Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename);
list($owner, $ownerPath) = self::getUidAndFilename($target);
@@ -429,7 +451,7 @@ class Trashbin {
}
if ($view->is_dir('/files_trashbin/versions/' . $file)) {
- $rootView->rename(\OC\Files\Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
+ $rootView->rename(Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp, $user)) {
foreach ($versions as $v) {
if ($timestamp) {
@@ -446,8 +468,8 @@ class Trashbin {
* delete all files from the trash
*/
public static function deleteAll() {
- $user = \OCP\User::getUser();
- $view = new \OC\Files\View('/' . $user);
+ $user = User::getUser();
+ $view = new View('/' . $user);
$view->deleteAll('files_trashbin');
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
$query->execute(array($user));
@@ -467,7 +489,7 @@ class Trashbin {
* @return int size of deleted files
*/
public static function delete($filename, $user, $timestamp = null) {
- $view = new \OC\Files\View('/' . $user);
+ $view = new View('/' . $user);
$size = 0;
if ($timestamp) {
@@ -481,7 +503,7 @@ class Trashbin {
$size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
if ($view->is_dir('/files_trashbin/files/' . $file)) {
- $size += self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin/files/' . $file));
+ $size += self::calculateSize(new View('/' . $user . '/files_trashbin/files/' . $file));
} else {
$size += $view->filesize('/files_trashbin/files/' . $file);
}
@@ -493,18 +515,18 @@ class Trashbin {
}
/**
- * @param \OC\Files\View $view
+ * @param View $view
* @param string $file
* @param string $filename
* @param integer|null $timestamp
* @param string $user
* @return int
*/
- private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
+ private static function deleteVersions(View $view, $file, $filename, $timestamp, $user) {
$size = 0;
if (\OCP\App::isEnabled('files_versions')) {
if ($view->is_dir('files_trashbin/versions/' . $file)) {
- $size += self::calculateSize(new \OC\Files\view('/' . $user . '/files_trashbin/versions/' . $file));
+ $size += self::calculateSize(new View('/' . $user . '/files_trashbin/versions/' . $file));
$view->unlink('files_trashbin/versions/' . $file);
} else if ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
foreach ($versions as $v) {
@@ -529,8 +551,8 @@ class Trashbin {
* @return bool true if file exists, otherwise false
*/
public static function file_exists($filename, $timestamp = null) {
- $user = \OCP\User::getUser();
- $view = new \OC\Files\View('/' . $user);
+ $user = User::getUser();
+ $view = new View('/' . $user);
if ($timestamp) {
$filename = $filename . '.d' . $timestamp;
@@ -538,7 +560,7 @@ class Trashbin {
$filename = $filename;
}
- $target = \OC\Files\Filesystem::normalizePath('files_trashbin/files/' . $filename);
+ $target = Filesystem::normalizePath('files_trashbin/files/' . $filename);
return $view->file_exists($target);
}
@@ -568,7 +590,7 @@ class Trashbin {
}
$quota = $userObject->getQuota();
if ($quota === null || $quota === 'none') {
- $quota = \OC\Files\Filesystem::free_space('/');
+ $quota = Filesystem::free_space('/');
$softQuota = false;
// inf or unknown free space
if ($quota < 0) {
@@ -710,11 +732,11 @@ class Trashbin {
*
* @param string $source source path, relative to the users files directory
* @param string $destination destination path relative to the users root directoy
- * @param \OC\Files\View $view file view for the users root directory
+ * @param View $view file view for the users root directory
* @return int
* @throws Exceptions\CopyRecursiveException
*/
- private static function copy_recursive($source, $destination, \OC\Files\View $view) {
+ private static function copy_recursive($source, $destination, View $view) {
$size = 0;
if ($view->is_dir($source)) {
$view->mkdir($destination);
@@ -751,7 +773,7 @@ class Trashbin {
* @return array
*/
private static function getVersionsFromTrash($filename, $timestamp, $user) {
- $view = new \OC\Files\View('/' . $user . '/files_trashbin/versions');
+ $view = new View('/' . $user . '/files_trashbin/versions');
$versions = array();
//force rescan of versions, local storage may not have updated the cache
@@ -789,10 +811,10 @@ class Trashbin {
*
* @param string $location where the file should be restored
* @param string $filename name of the file
- * @param \OC\Files\View $view filesystem view relative to users root directory
+ * @param View $view filesystem view relative to users root directory
* @return string with unique extension
*/
- private static function getUniqueFilename($location, $filename, \OC\Files\View $view) {
+ private static function getUniqueFilename($location, $filename, View $view) {
$ext = pathinfo($filename, PATHINFO_EXTENSION);
$name = pathinfo($filename, PATHINFO_FILENAME);
$l = \OC::$server->getL10N('files_trashbin');
@@ -821,7 +843,7 @@ class Trashbin {
/**
* get the size from a given root folder
*
- * @param \OC\Files\View $view file view on the root folder
+ * @param View $view file view on the root folder
* @return integer size of the folder
*/
private static function calculateSize($view) {
@@ -856,7 +878,7 @@ class Trashbin {
* @return integer trash bin size
*/
private static function getTrashbinSize($user) {
- $view = new \OC\Files\View('/' . $user);
+ $view = new View('/' . $user);
$fileInfo = $view->getFileInfo('/files_trashbin');
return isset($fileInfo['size']) ? $fileInfo['size'] : 0;
}
@@ -885,10 +907,10 @@ class Trashbin {
*/
public static function isEmpty($user) {
- $view = new \OC\Files\View('/' . $user . '/files_trashbin');
+ $view = new View('/' . $user . '/files_trashbin');
if ($view->is_dir('/files') && $dh = $view->opendir('/files')) {
while ($file = readdir($dh)) {
- if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
+ if (!Filesystem::isIgnoredDir($file)) {
return false;
}
}
diff --git a/apps/files_versions/lib/storage.php b/apps/files_versions/lib/storage.php
index d5e21959698..da736c868fc 100644
--- a/apps/files_versions/lib/storage.php
+++ b/apps/files_versions/lib/storage.php
@@ -42,9 +42,11 @@
namespace OCA\Files_Versions;
use OC\Files\Filesystem;
+use OC\Files\View;
use OCA\Files_Versions\AppInfo\Application;
use OCA\Files_Versions\Command\Expire;
use OCP\Lock\ILockingProvider;
+use OCP\User;
class Storage {
@@ -80,12 +82,33 @@ class Storage {
private static $application;
/**
+ * get the UID of the owner of the file and the path to the file relative to
+ * owners files folder
+ *
* @param string $filename
* @return array
* @throws \OC\User\NoUserException
*/
public static function getUidAndFilename($filename) {
- return Filesystem::getView()->getUidAndFilename($filename);
+ $uid = Filesystem::getOwner($filename);
+ $userManager = \OC::$server->getUserManager();
+ // if the user with the UID doesn't exists, e.g. because the UID points
+ // to a remote user with a federated cloud ID we use the current logged-in
+ // user. We need a valid local user to create the versions
+ if (!$userManager->userExists($uid)) {
+ $uid = User::getUser();
+ }
+ Filesystem::initMountPoints($uid);
+ if ( $uid != User::getUser() ) {
+ $info = Filesystem::getFileInfo($filename);
+ $ownerView = new View('/'.$uid.'/files');
+ try {
+ $filename = $ownerView->getPath($info['fileid']);
+ } catch (NotFoundException $e) {
+ $filename = null;
+ }
+ }
+ return [$uid, $filename];
}
/**
@@ -123,7 +146,7 @@ class Storage {
* @return int versions size
*/
private static function getVersionsSize($user) {
- $view = new \OC\Files\View('/' . $user);
+ $view = new View('/' . $user);
$fileInfo = $view->getFileInfo('/files_versions');
return isset($fileInfo['size']) ? $fileInfo['size'] : 0;
}
@@ -148,8 +171,8 @@ class Storage {
list($uid, $filename) = self::getUidAndFilename($filename);
- $files_view = new \OC\Files\View('/'.$uid .'/files');
- $users_view = new \OC\Files\View('/'.$uid);
+ $files_view = new View('/'.$uid .'/files');
+ $users_view = new View('/'.$uid);
// no use making versions for empty files
if ($files_view->filesize($filename) === 0) {
@@ -189,7 +212,7 @@ class Storage {
/**
* delete the version from the storage and cache
*
- * @param \OC\Files\View $view
+ * @param View $view
* @param string $path
*/
protected static function deleteVersion($view, $path) {
@@ -212,9 +235,9 @@ class Storage {
$uid = $deletedFile['uid'];
$filename = $deletedFile['filename'];
- if (!\OC\Files\Filesystem::file_exists($path)) {
+ if (!Filesystem::file_exists($path)) {
- $view = new \OC\Files\View('/' . $uid . '/files_versions');
+ $view = new View('/' . $uid . '/files_versions');
$versions = self::getVersions($uid, $filename);
if (!empty($versions)) {
@@ -252,14 +275,14 @@ class Storage {
$sourcePath = ltrim($sourcePath, '/');
$targetPath = ltrim($targetPath, '/');
- $rootView = new \OC\Files\View('');
+ $rootView = new View('');
// did we move a directory ?
if ($rootView->is_dir('/' . $targetOwner . '/files/' . $targetPath)) {
// does the directory exists for versions too ?
if ($rootView->is_dir('/' . $sourceOwner . '/files_versions/' . $sourcePath)) {
// create missing dirs if necessary
- self::createMissingDirectories($targetPath, new \OC\Files\View('/'. $targetOwner));
+ self::createMissingDirectories($targetPath, new View('/'. $targetOwner));
// move the directory containing the versions
$rootView->$operation(
@@ -269,7 +292,7 @@ class Storage {
}
} else if ($versions = Storage::getVersions($sourceOwner, '/' . $sourcePath)) {
// create missing dirs if necessary
- self::createMissingDirectories($targetPath, new \OC\Files\View('/'. $targetOwner));
+ self::createMissingDirectories($targetPath, new View('/'. $targetOwner));
foreach ($versions as $v) {
// move each version one by one to the target directory
@@ -299,8 +322,8 @@ class Storage {
// add expected leading slash
$file = '/' . ltrim($file, '/');
list($uid, $filename) = self::getUidAndFilename($file);
- $users_view = new \OC\Files\View('/'.$uid);
- $files_view = new \OC\Files\View('/'.\OCP\User::getUser().'/files');
+ $users_view = new View('/'.$uid);
+ $files_view = new View('/'. User::getUser().'/files');
$versionCreated = false;
//first create a new version
@@ -332,7 +355,7 @@ class Storage {
/**
* Stream copy file contents from $path1 to $path2
*
- * @param \OC\Files\View $view view to use for copying
+ * @param View $view view to use for copying
* @param string $path1 source file to copy
* @param string $path2 target file
*
@@ -381,12 +404,12 @@ class Storage {
return $versions;
}
// fetch for old versions
- $view = new \OC\Files\View('/' . $uid . '/');
+ $view = new View('/' . $uid . '/');
$pathinfo = pathinfo($filename);
$versionedFile = $pathinfo['basename'];
- $dir = \OC\Files\Filesystem::normalizePath(self::VERSIONS_ROOT . '/' . $pathinfo['dirname']);
+ $dir = Filesystem::normalizePath(self::VERSIONS_ROOT . '/' . $pathinfo['dirname']);
$dirContent = false;
if ($view->is_dir($dir)) {
@@ -399,7 +422,7 @@ class Storage {
if (is_resource($dirContent)) {
while (($entryName = readdir($dirContent)) !== false) {
- if (!\OC\Files\Filesystem::isIgnoredDir($entryName)) {
+ if (!Filesystem::isIgnoredDir($entryName)) {
$pathparts = pathinfo($entryName);
$filename = $pathparts['filename'];
if ($filename === $versionedFile) {
@@ -414,7 +437,7 @@ class Storage {
} else {
$versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $userFullPath, 'version' => $timestamp));
}
- $versions[$key]['path'] = \OC\Files\Filesystem::normalizePath($pathinfo['dirname'] . '/' . $filename);
+ $versions[$key]['path'] = Filesystem::normalizePath($pathinfo['dirname'] . '/' . $filename);
$versions[$key]['name'] = $versionedFile;
$versions[$key]['size'] = $view->filesize($dir . '/' . $entryName);
}
@@ -451,7 +474,7 @@ class Storage {
}
}
- $view = new \OC\Files\View('/' . $uid . '/files_versions');
+ $view = new View('/' . $uid . '/files_versions');
if (!empty($toDelete)) {
foreach ($toDelete as $version) {
\OC_Hook::emit('\OCP\Versions', 'preDelete', array('path' => $version['path'].'.v'.$version['version'], 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT));
@@ -494,7 +517,7 @@ class Storage {
* @return array with contains two arrays 'all' which contains all versions sorted by age and 'by_file' which contains all versions sorted by filename
*/
private static function getAllVersions($uid) {
- $view = new \OC\Files\View('/' . $uid . '/');
+ $view = new View('/' . $uid . '/');
$dirs = array(self::VERSIONS_ROOT);
$versions = array();
@@ -655,14 +678,14 @@ class Storage {
// file maybe renamed or deleted
return false;
}
- $versionsFileview = new \OC\Files\View('/'.$uid.'/files_versions');
+ $versionsFileview = new View('/'.$uid.'/files_versions');
// get available disk space for user
$user = \OC::$server->getUserManager()->get($uid);
$softQuota = true;
$quota = $user->getQuota();
if ( $quota === null || $quota === 'none' ) {
- $quota = \OC\Files\Filesystem::free_space('/');
+ $quota = Filesystem::free_space('/');
$softQuota = false;
} else {
$quota = \OCP\Util::computerFileSize($quota);
@@ -675,7 +698,7 @@ class Storage {
// subtract size of files and current versions size from quota
if ($quota >= 0) {
if ($softQuota) {
- $files_view = new \OC\Files\View('/' . $uid . '/files');
+ $files_view = new View('/' . $uid . '/files');
$rootInfo = $files_view->getFileInfo('/', false);
$free = $quota - $rootInfo['size']; // remaining free space for user
if ($free > 0) {
@@ -752,10 +775,10 @@ class Storage {
*
* @param string $filename $path to a file, relative to the user's
* "files" folder
- * @param \OC\Files\View $view view on data/user/
+ * @param View $view view on data/user/
*/
private static function createMissingDirectories($filename, $view) {
- $dirname = \OC\Files\Filesystem::normalizePath(dirname($filename));
+ $dirname = Filesystem::normalizePath(dirname($filename));
$dirParts = explode('/', $dirname);
$dir = "/files_versions";
foreach ($dirParts as $part) {
diff --git a/core/ajax/share.php b/core/ajax/share.php
index 987b637cc97..93a7e911c42 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -254,7 +254,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
if (isset($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP]) &&
is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])) {
- $sharedGroups = isset($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP]);
+ $sharedGroups = $_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP];
}
}
diff --git a/lib/private/db/mdb2schemareader.php b/lib/private/db/mdb2schemareader.php
index 6f99206e5c8..94c48d61f06 100644
--- a/lib/private/db/mdb2schemareader.php
+++ b/lib/private/db/mdb2schemareader.php
@@ -30,6 +30,7 @@
namespace OC\DB;
use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\DBAL\Schema\SchemaConfig;
use OCP\IConfig;
class MDB2SchemaReader {
@@ -48,6 +49,9 @@ class MDB2SchemaReader {
*/
protected $platform;
+ /** @var \Doctrine\DBAL\Schema\SchemaConfig $schemaConfig */
+ protected $schemaConfig;
+
/**
* @param \OCP\IConfig $config
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
@@ -56,6 +60,12 @@ class MDB2SchemaReader {
$this->platform = $platform;
$this->DBNAME = $config->getSystemValue('dbname', 'owncloud');
$this->DBTABLEPREFIX = $config->getSystemValue('dbtableprefix', 'oc_');
+
+ // Oracle does not support longer index names then 30 characters.
+ // We use this limit for all DBs to make sure it does not cause a
+ // problem.
+ $this->schemaConfig = new SchemaConfig();
+ $this->schemaConfig->setMaxIdentifierLength(30);
}
/**
@@ -107,6 +117,7 @@ class MDB2SchemaReader {
$name = $this->platform->quoteIdentifier($name);
$table = $schema->createTable($name);
$table->addOption('collate', 'utf8_bin');
+ $table->setSchemaConfig($this->schemaConfig);
break;
case 'create':
case 'overwrite':
diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php
index 9d4a2c0aa05..d6fc9648c1e 100644
--- a/lib/private/files/filesystem.php
+++ b/lib/private/files/filesystem.php
@@ -237,9 +237,9 @@ class Filesystem {
*
* @return \OC\Files\Mount\Manager
*/
- public static function getMountManager() {
+ public static function getMountManager($user = '') {
if (!self::$mounts) {
- \OC_Util::setupFS();
+ \OC_Util::setupFS($user);
}
return self::$mounts;
}
diff --git a/lib/private/files/node/root.php b/lib/private/files/node/root.php
index 40ed531d5df..a9343e72220 100644
--- a/lib/private/files/node/root.php
+++ b/lib/private/files/node/root.php
@@ -71,7 +71,7 @@ class Root extends Folder implements IRootFolder {
/**
* @param \OC\Files\Mount\Manager $manager
* @param \OC\Files\View $view
- * @param \OC\User\User $user
+ * @param \OC\User\User|null $user
*/
public function __construct($manager, $view, $user) {
parent::__construct($this, $view, '');
diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php
index 3d5898dcd80..edc570c967d 100644
--- a/lib/private/files/storage/common.php
+++ b/lib/private/files/storage/common.php
@@ -72,6 +72,7 @@ abstract class Common implements Storage, ILockingStorage {
protected $updater;
protected $mountOptions = [];
+ protected $owner = null;
public function __construct($parameters) {
}
@@ -383,7 +384,11 @@ abstract class Common implements Storage, ILockingStorage {
* @return string|false uid or false
*/
public function getOwner($path) {
- return \OC_User::getUser();
+ if ($this->owner === null) {
+ $this->owner = \OC_User::getUser();
+ }
+
+ return $this->owner;
}
/**
diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php
index 844505679df..500677b092e 100644
--- a/lib/private/files/storage/wrapper/quota.php
+++ b/lib/private/files/storage/wrapper/quota.php
@@ -141,17 +141,34 @@ class Quota extends Wrapper {
*/
public function fopen($path, $mode) {
$source = $this->storage->fopen($path, $mode);
- $free = $this->free_space('');
- if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
- // only apply quota for files, not metadata, trash or others
- if (strpos(ltrim($path, '/'), 'files/') === 0) {
- return \OC\Files\Stream\Quota::wrap($source, $free);
+
+ // don't apply quota for part files
+ if (!$this->isPartFile($path)) {
+ $free = $this->free_space('');
+ if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
+ // only apply quota for files, not metadata, trash or others
+ if (strpos(ltrim($path, '/'), 'files/') === 0) {
+ return \OC\Files\Stream\Quota::wrap($source, $free);
+ }
}
}
return $source;
}
/**
+ * Checks whether the given path is a part file
+ *
+ * @param string $path Path that may identify a .part file
+ * @return string File path without .part extension
+ * @note this is needed for reusing keys
+ */
+ private function isPartFile($path) {
+ $extension = pathinfo($path, PATHINFO_EXTENSION);
+
+ return ($extension === 'part');
+ }
+
+ /**
* @param \OCP\Files\Storage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
diff --git a/lib/private/server.php b/lib/private/server.php
index ef4764d07cf..7c8ecce71a5 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -40,7 +40,6 @@ namespace OC;
use bantu\IniGetWrapper\IniGetWrapper;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Db\Db;
-use OC\AppFramework\Utility\SimpleContainer;
use OC\AppFramework\Utility\TimeFactory;
use OC\Command\AsyncBus;
use OC\Diagnostics\EventLogger;
@@ -164,15 +163,10 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('SystemTagObjectMapper', function (Server $c) {
return $c->query('SystemTagManagerFactory')->getObjectMapper();
});
- $this->registerService('RootFolder', function (Server $c) {
- // TODO: get user and user manager from container as well
- $user = \OC_User::getUser();
- /** @var $c SimpleContainer */
- $userManager = $c->query('UserManager');
- $user = $userManager->get($user);
- $manager = \OC\Files\Filesystem::getMountManager();
+ $this->registerService('RootFolder', function () {
+ $manager = \OC\Files\Filesystem::getMountManager(null);
$view = new View();
- $root = new Root($manager, $view, $user);
+ $root = new Root($manager, $view, null);
$connector = new HookConnector($root, $view);
$connector->viewToNode();
return $root;
diff --git a/lib/private/util.php b/lib/private/util.php
index 6ad668dedaa..35ae3e3090b 100644
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -128,7 +128,9 @@ class OC_Util {
\OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
// 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 === null) {
+ $user = '';
+ } else if ($user == "" && OC_User::isLoggedIn()) {
$user = OC_User::getUser();
}
diff --git a/lib/public/appframework/http/redirectresponse.php b/lib/public/appframework/http/redirectresponse.php
index 7208012295f..bb0c8843715 100644
--- a/lib/public/appframework/http/redirectresponse.php
+++ b/lib/public/appframework/http/redirectresponse.php
@@ -44,7 +44,7 @@ class RedirectResponse extends Response {
*/
public function __construct($redirectURL) {
$this->redirectURL = $redirectURL;
- $this->setStatus(Http::STATUS_TEMPORARY_REDIRECT);
+ $this->setStatus(Http::STATUS_SEE_OTHER);
$this->addHeader('Location', $redirectURL);
}
diff --git a/settings/js/apps.js b/settings/js/apps.js
index b6f6363a992..a99df65e3c1 100644
--- a/settings/js/apps.js
+++ b/settings/js/apps.js
@@ -124,6 +124,7 @@ OC.Settings.Apps = OC.Settings.Apps || {
$('.app-level .experimental').tipsy({fallback: t('settings', 'This app is not checked for security issues and is new or known to be unstable. Install at your own risk.')});
},
complete: function() {
+ var availableUpdates = 0;
$('#apps-list').removeClass('icon-loading');
$.ajax(OC.generateUrl('settings/apps/list?category={categoryId}&includeUpdateInfo=1', {
categoryId: categoryId
@@ -135,8 +136,14 @@ OC.Settings.Apps = OC.Settings.Apps || {
var $update = $('#app-' + app.id + ' .update');
$update.removeClass('hidden');
$update.val(t('settings', 'Update to %s').replace(/%s/g, app.update));
+ availableUpdates++;
+ OC.Settings.Apps.State.apps[app.id].update = true;
}
- })
+ });
+
+ if (availableUpdates > 0) {
+ OC.Notification.show(n('settings', 'You have %n app update pending', 'You have %n app updates pending', availableUpdates));
+ }
}
});
}
diff --git a/settings/templates/apps.php b/settings/templates/apps.php
index 489062d5191..ef89a5393cd 100644
--- a/settings/templates/apps.php
+++ b/settings/templates/apps.php
@@ -97,6 +97,10 @@ script(
<div class="app-description-toggle-show"><?php p($l->t("Show description …"));?></div>
<div class="app-description-toggle-hide hidden"><?php p($l->t("Hide description …"));?></div>
+ <div class="app-dependencies update hidden">
+ <p><?php p($l->t('This app has an update available.')); ?></p>
+ </div>
+
{{#if missingMinOwnCloudVersion}}
<div class="app-dependencies">
<p><?php p($l->t('This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later.')); ?></p>
diff --git a/tests/lib/appframework/http/RedirectResponseTest.php b/tests/lib/appframework/http/RedirectResponseTest.php
index 17db0c0be6c..723f6600c55 100644
--- a/tests/lib/appframework/http/RedirectResponseTest.php
+++ b/tests/lib/appframework/http/RedirectResponseTest.php
@@ -43,7 +43,7 @@ class RedirectResponseTest extends \Test\TestCase {
public function testHeaders() {
$headers = $this->response->getHeaders();
$this->assertEquals('/url', $headers['Location']);
- $this->assertEquals(Http::STATUS_TEMPORARY_REDIRECT,
+ $this->assertEquals(Http::STATUS_SEE_OTHER,
$this->response->getStatus());
}
diff --git a/version.php b/version.php
index 240a92cc0b7..dfe5d68300c 100644
--- a/version.php
+++ b/version.php
@@ -25,10 +25,10 @@
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
-$OC_Version = array(9, 0, 0, 11);
+$OC_Version = array(9, 0, 0, 12);
// The human readable string
-$OC_VersionString = '9.0 beta 1';
+$OC_VersionString = '9.0.0 beta 2';
$OC_VersionCanBeUpgradedFrom = array(8, 2);