summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authoricewind1991 <robin@icewind.nl>2014-06-06 11:57:43 +0200
committericewind1991 <robin@icewind.nl>2014-06-06 11:57:43 +0200
commitc47d4ebbac7885ad91cf56355bd6aa09318ff8e8 (patch)
tree22a78530feb3c582cf5624b4089bd79c8e9b2afd /apps
parent0661d737e6f529b7d921ada441453f2b314c3445 (diff)
parent46f70aabfd399e1bc5517b2192ac2489189f9d94 (diff)
downloadnextcloud-server-c47d4ebbac7885ad91cf56355bd6aa09318ff8e8.tar.gz
nextcloud-server-c47d4ebbac7885ad91cf56355bd6aa09318ff8e8.zip
Merge pull request #8666 from owncloud/mount-remove
Support for (re)moving mountpoints
Diffstat (limited to 'apps')
-rw-r--r--apps/files/lib/helper.php2
-rw-r--r--apps/files/tests/ajax_rename.php2
-rw-r--r--apps/files/tests/helper.php2
-rw-r--r--apps/files_encryption/hooks/hooks.php55
-rwxr-xr-xapps/files_encryption/lib/helper.php2
-rw-r--r--apps/files_encryption/tests/hooks.php6
-rwxr-xr-xapps/files_external/lib/config.php36
-rw-r--r--apps/files_external/lib/personalmount.php40
-rw-r--r--apps/files_sharing/appinfo/update.php38
-rw-r--r--apps/files_sharing/appinfo/version2
-rw-r--r--apps/files_sharing/js/share.js9
-rw-r--r--apps/files_sharing/lib/cache.php7
-rw-r--r--apps/files_sharing/lib/sharedmount.php161
-rw-r--r--apps/files_sharing/lib/sharedstorage.php230
-rw-r--r--apps/files_sharing/tests/api.php10
-rw-r--r--apps/files_sharing/tests/permissions.php5
-rw-r--r--apps/files_sharing/tests/share.php173
-rw-r--r--apps/files_sharing/tests/sharedmount.php197
-rw-r--r--apps/files_sharing/tests/update.php233
-rw-r--r--apps/files_sharing/tests/updater.php125
20 files changed, 1040 insertions, 295 deletions
diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php
index 7d8906e2251..b84b6c06d30 100644
--- a/apps/files/lib/helper.php
+++ b/apps/files/lib/helper.php
@@ -113,7 +113,7 @@ class Helper
if (\OC::$server->getPreviewManager()->isMimeSupported($i['mimetype'])) {
$entry['isPreviewAvailable'] = true;
}
- $entry['name'] = $i['name'];
+ $entry['name'] = $i->getName();
$entry['permissions'] = $i['permissions'];
$entry['mimetype'] = $i['mimetype'];
$entry['size'] = $i['size'];
diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php
index 9928053e501..fed366aa8eb 100644
--- a/apps/files/tests/ajax_rename.php
+++ b/apps/files/tests/ajax_rename.php
@@ -81,7 +81,7 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
$this->viewMock->expects($this->any())
->method('getFileInfo')
->will($this->returnValue(new \OC\Files\FileInfo(
- '/',
+ '/new_name',
new \OC\Files\Storage\Local(array('datadir' => '/')),
'/',
array(
diff --git a/apps/files/tests/helper.php b/apps/files/tests/helper.php
index 9b3603cd563..f269cc70ed5 100644
--- a/apps/files/tests/helper.php
+++ b/apps/files/tests/helper.php
@@ -17,7 +17,7 @@ class Test_Files_Helper extends \PHPUnit_Framework_TestCase {
private function makeFileInfo($name, $size, $mtime, $isDir = false) {
return new \OC\Files\FileInfo(
- '/',
+ '/' . $name,
null,
'/',
array(
diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php
index 66e2bccd59f..f546ef72373 100644
--- a/apps/files_encryption/hooks/hooks.php
+++ b/apps/files_encryption/hooks/hooks.php
@@ -34,6 +34,8 @@ class Hooks {
private static $renamedFiles = array();
// file for which we want to delete the keys after the delete operation was successful
private static $deleteFiles = array();
+ // file for which we want to delete the keys after the delete operation was successful
+ private static $umountedFiles = array();
/**
* Startup encryption backend upon user login
@@ -610,4 +612,57 @@ class Hooks {
'path' => $ownerPath);
}
+ /**
+ * remember files/folders which get unmounted
+ */
+ public static function preUmount($params) {
+ $path = $params[\OC\Files\Filesystem::signal_param_path];
+ $user = \OCP\USER::getUser();
+
+ $view = new \OC\Files\View();
+ $itemType = $view->is_dir('/' . $user . '/files' . $path) ? 'folder' : 'file';
+
+ $util = new Util($view, $user);
+ list($owner, $ownerPath) = $util->getUidAndFilename($path);
+
+ self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]] = array(
+ 'uid' => $owner,
+ 'path' => $ownerPath,
+ 'itemType' => $itemType);
+ }
+
+ public static function postUmount($params) {
+
+ if (!isset(self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]])) {
+ return true;
+ }
+
+ $umountedFile = self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]];
+ $path = $umountedFile['path'];
+ $user = $umountedFile['uid'];
+ $itemType = $umountedFile['itemType'];
+
+ $view = new \OC\Files\View();
+ $util = new Util($view, $user);
+
+ // we don't need to remember the file any longer
+ unset(self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]]);
+
+ // if we unshare a folder we need a list of all (sub-)files
+ if ($itemType === 'folder') {
+ $allFiles = $util->getAllFiles($path);
+ } else {
+ $allFiles = array($path);
+ }
+
+ foreach ($allFiles as $path) {
+
+ // check if the user still has access to the file, otherwise delete share key
+ $sharingUsers = \OCP\Share::getUsersSharingFile($path, $user);
+ if (!in_array(\OCP\User::getUser(), $sharingUsers['users'])) {
+ Keymanager::delShareKey($view, array(\OCP\User::getUser()), $path);
+ }
+ }
+ }
+
}
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
index 564e97e0592..2684bf7be33 100755
--- a/apps/files_encryption/lib/helper.php
+++ b/apps/files_encryption/lib/helper.php
@@ -65,6 +65,8 @@ class Helper {
\OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
\OCP\Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete');
\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete');
+ \OCP\Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Encryption\Hooks', 'postUmount');
+ \OCP\Util::connectHook('OC_Filesystem', 'umount', 'OCA\Encryption\Hooks', 'preUmount');
}
/**
diff --git a/apps/files_encryption/tests/hooks.php b/apps/files_encryption/tests/hooks.php
index 95f5996bb8e..a2e3ea30f04 100644
--- a/apps/files_encryption/tests/hooks.php
+++ b/apps/files_encryption/tests/hooks.php
@@ -257,14 +257,14 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
$this->assertTrue($result);
- // now keys from user1s home should be gone
- $this->assertFalse($this->rootView->file_exists(
+ // share key for user2 from user1s home should be gone, all other keys should still exists
+ $this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertFalse($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
- $this->assertFalse($this->rootView->file_exists(
+ $this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// cleanup
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 28e28ffcde6..6f78e569b64 100755
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -104,8 +104,15 @@ class OC_Mount_Config {
*/
public static function initMountPointsHook($data) {
$mountPoints = self::getAbsoluteMountPoints($data['user']);
+ $loader = \OC\Files\Filesystem::getLoader();
+ $manager = \OC\Files\Filesystem::getMountManager();
foreach ($mountPoints as $mountPoint => $options) {
- \OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint);
+ if ($options['personal']){
+ $mount = new \OCA\Files_External\PersonalMount($options['class'], $mountPoint, $options['options'], $loader);
+ } else{
+ $mount = new \OC\Files\Mount\Mount($options['class'], $mountPoint, $options['options'], $loader);
+ }
+ $manager->addMount($mount);
}
}
@@ -135,6 +142,7 @@ class OC_Mount_Config {
// Global mount points (is this redundant?)
if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
+ $options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority'];
@@ -178,6 +186,7 @@ class OC_Mount_Config {
foreach ($options as &$option) {
$option = self::setUserVars($user, $option);
}
+ $options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority'];
@@ -203,6 +212,7 @@ class OC_Mount_Config {
foreach ($options as &$option) {
$option = self::setUserVars($user, $option);
}
+ $options['personal'] = false;
$options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['priority'])) {
$options['priority'] = $backends[$options['class']]['priority'];
@@ -224,6 +234,7 @@ class OC_Mount_Config {
$mountConfig = self::readData($user);
if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
+ $options['personal'] = true;
$options['options'] = self::decryptPasswords($options['options']);
// Always override previous config
@@ -506,6 +517,7 @@ class OC_Mount_Config {
} else {
$mountPoint = '/$user/files/'.ltrim($mountPoint, '/');
}
+ $mountPoint = \OC\Files\Filesystem::normalizePath($mountPoint);
$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : NULL);
// Remove mount point
unset($mountPoints[$mountType][$applicable][$mountPoint]);
@@ -521,6 +533,28 @@ class OC_Mount_Config {
}
/**
+ *
+ * @param string $mountPoint Mount point
+ * @param string $target The new mount point
+ * @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
+ * @return bool
+ */
+ public static function movePersonalMountPoint($mountPoint, $target, $mountType) {
+ $mountPoint = rtrim($mountPoint, '/');
+ $user = OCP\User::getUser();
+ $mountPoints = self::readData($user);
+ if (!isset($mountPoints[$mountType][$user][$mountPoint])) {
+ return false;
+ }
+ $mountPoints[$mountType][$user][$target] = $mountPoints[$mountType][$user][$mountPoint];
+ // Remove old mount point
+ unset($mountPoints[$mountType][$user][$mountPoint]);
+
+ self::writeData($user, $mountPoints);
+ return true;
+ }
+
+ /**
* Read the mount points in the config file into an array
* @param string|null $user If not null, personal for $user, otherwise system
* @return array
diff --git a/apps/files_external/lib/personalmount.php b/apps/files_external/lib/personalmount.php
new file mode 100644
index 00000000000..708128d644a
--- /dev/null
+++ b/apps/files_external/lib/personalmount.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_External;
+
+use OC\Files\Mount\Mount;
+use OC\Files\Mount\MoveableMount;
+
+/**
+ * Person mount points can be moved by the user
+ */
+class PersonalMount extends Mount implements MoveableMount {
+ /**
+ * Move the mount point to $target
+ *
+ * @param string $target the target mount point
+ * @return bool
+ */
+ public function moveMount($target) {
+ $result = \OC_Mount_Config::movePersonalMountPoint($this->getMountPoint(), $target, \OC_Mount_Config::MOUNT_TYPE_USER);
+ $this->setMountPoint($target);
+ return $result;
+ }
+
+ /**
+ * Remove the mount points
+ *
+ * @return bool
+ */
+ public function removeMount() {
+ $user = \OCP\User::getUser();
+ $relativeMountPoint = substr($this->getMountPoint(), strlen('/' . $user . '/files/'));
+ return \OC_Mount_Config::removeMountPoint($relativeMountPoint, \OC_Mount_Config::MOUNT_TYPE_USER, $user , true);
+ }
+}
diff --git a/apps/files_sharing/appinfo/update.php b/apps/files_sharing/appinfo/update.php
index bc8cda42313..fc547ba349d 100644
--- a/apps/files_sharing/appinfo/update.php
+++ b/apps/files_sharing/appinfo/update.php
@@ -1,6 +1,11 @@
<?php
$installedVersion = OCP\Config::getAppValue('files_sharing', 'installed_version');
+
+if (version_compare($installedVersion, '0.5', '<')) {
+ updateFilePermissions();
+}
+
if (version_compare($installedVersion, '0.4', '<')) {
removeSharedFolder();
}
@@ -12,6 +17,39 @@ if (version_compare($installedVersion, '0.3.5.6', '<')) {
/**
+ * it is no longer possible to share single files with delete permissions. User
+ * should only be able to unshare single files but never to delete them.
+ */
+function updateFilePermissions($chunkSize = 99) {
+ $query = OCP\DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `item_type` = ?');
+ $result = $query->execute(array('file'));
+
+ $updatedRows = array();
+
+ while ($row = $result->fetchRow()) {
+ if ($row['permissions'] & \OCP\PERMISSION_DELETE) {
+ $updatedRows[$row['id']] = (int)$row['permissions'] & ~\OCP\PERMISSION_DELETE;
+ }
+ }
+
+ $chunkedPermissionList = array_chunk($updatedRows, $chunkSize, true);
+
+ foreach ($chunkedPermissionList as $subList) {
+ $statement = "UPDATE `*PREFIX*share` SET `permissions` = CASE `id` ";
+ //update share table
+ $ids = implode(',', array_keys($subList));
+ foreach ($subList as $id => $permission) {
+ $statement .= "WHEN " . $id . " THEN " . $permission . " ";
+ }
+ $statement .= ' END WHERE `id` IN (' . $ids . ')';
+
+ $query = OCP\DB::prepare($statement);
+ $query->execute();
+ }
+
+}
+
+/**
* update script for the removal of the logical "Shared" folder, we create physical "Shared" folder and
* update the users file_target so that it doesn't make any difference for the user
* @note parameters are just for testing, please ignore them
diff --git a/apps/files_sharing/appinfo/version b/apps/files_sharing/appinfo/version
index 267577d47e4..2eb3c4fe4ee 100644
--- a/apps/files_sharing/appinfo/version
+++ b/apps/files_sharing/appinfo/version
@@ -1 +1 @@
-0.4.1
+0.5
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index d63a590fb8e..47fe0bd2c57 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -18,12 +18,17 @@
var oldCreateRow = OCA.Files.FileList.prototype._createRow;
OCA.Files.FileList.prototype._createRow = function(fileData) {
var tr = oldCreateRow.apply(this, arguments);
+ var sharePermissions = fileData.permissions;
+ if (fileData.type === 'file') {
+ // files can't be shared with delete permissions
+ sharePermissions = sharePermissions & ~OC.PERMISSION_DELETE;
+ }
+ tr.attr('data-share-permissions', sharePermissions);
if (fileData.shareOwner) {
tr.attr('data-share-owner', fileData.shareOwner);
// user should always be able to rename a mount point
if (fileData.isShareMountPoint) {
tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
- tr.attr('data-reshare-permissions', fileData.permissions);
}
}
if (fileData.recipientsDisplayName) {
@@ -94,7 +99,7 @@
if ($tr.data('type') === 'dir') {
itemType = 'folder';
}
- var possiblePermissions = $tr.data('reshare-permissions');
+ var possiblePermissions = $tr.data('share-permissions');
if (_.isUndefined(possiblePermissions)) {
possiblePermissions = $tr.data('permissions');
}
diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php
index f6c42e930d1..b2594aa0b4d 100644
--- a/apps/files_sharing/lib/cache.php
+++ b/apps/files_sharing/lib/cache.php
@@ -94,6 +94,11 @@ class Shared_Cache extends Cache {
$data['is_share_mount_point'] = true;
}
$data['uid_owner'] = $this->storage->getOwner($file);
+ if (isset($data['permissions'])) {
+ $data['permissions'] = $data['permissions'] & $this->storage->getPermissions('');
+ } else {
+ $data['permissions'] = $this->storage->getPermissions('');
+ }
return $data;
}
} else {
@@ -130,6 +135,7 @@ class Shared_Cache extends Cache {
$data['name'] = basename($this->storage->getMountPoint());
$data['is_share_mount_point'] = true;
}
+ $data['permissions'] = $data['permissions'] & $this->storage->getPermissions('');
return $data;
}
return false;
@@ -157,6 +163,7 @@ class Shared_Cache extends Cache {
$sourceFolderContent[$key]['path'] = $dir . $c['name'];
$sourceFolderContent[$key]['uid_owner'] = $parent['uid_owner'];
$sourceFolderContent[$key]['displayname_owner'] = $parent['uid_owner'];
+ $sourceFolderContent[$key]['permissions'] = $sourceFolderContent[$key]['permissions'] & $this->storage->getPermissions('');
}
return $sourceFolderContent;
diff --git a/apps/files_sharing/lib/sharedmount.php b/apps/files_sharing/lib/sharedmount.php
new file mode 100644
index 00000000000..8d0ecbc6789
--- /dev/null
+++ b/apps/files_sharing/lib/sharedmount.php
@@ -0,0 +1,161 @@
+<?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 OCA\Files_Sharing;
+
+use OC\Files\Filesystem;
+use OC\Files\Mount\Mount;
+use OC\Files\Mount\MoveableMount;
+use OC\Files\Storage\Shared;
+
+/**
+ * Shared mount points can be moved by the user
+ */
+class SharedMount extends Mount implements MoveableMount {
+ /**
+ * @var \OC\Files\Storage\Shared $storage
+ */
+ protected $storage = null;
+
+ public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
+ // first update the mount point before creating the parent
+ $newMountPoint = self::verifyMountPoint($arguments['share']);
+ $absMountPoint = '/' . \OCP\User::getUser() . '/files' . $newMountPoint;
+ parent::__construct($storage, $absMountPoint, $arguments, $loader);
+ }
+
+ /**
+ * check if the parent folder exists otherwise move the mount point up
+ */
+ private static function verifyMountPoint(&$share) {
+
+ $mountPoint = basename($share['file_target']);
+ $parent = dirname($share['file_target']);
+
+ while (!\OC\Files\Filesystem::is_dir($parent)) {
+ $parent = dirname($parent);
+ }
+
+ $newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
+ \OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
+ array(),
+ new \OC\Files\View('/' . \OCP\User::getUser() . '/files')
+ );
+
+ if($newMountPoint !== $share['file_target']) {
+ self::updateFileTarget($newMountPoint, $share);
+ $share['file_target'] = $newMountPoint;
+ $share['unique_name'] = true;
+ }
+
+ return $newMountPoint;
+ }
+
+ /**
+ * update fileTarget in the database if the mount point changed
+ * @param string $newPath
+ * @param array $share reference to the share which should be modified
+ * @return type
+ */
+ private static function updateFileTarget($newPath, &$share) {
+ // if the user renames a mount point from a group share we need to create a new db entry
+ // for the unique name
+ if ($share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP && empty($share['unique_name'])) {
+ $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`,'
+ .' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
+ .' `file_target`, `token`, `parent`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
+ $arguments = array($share['item_type'], $share['item_source'], $share['item_target'],
+ 2, \OCP\User::getUser(), $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
+ $newPath, $share['token'], $share['id']);
+ } else {
+ // rename mount point
+ $query = \OC_DB::prepare(
+ 'Update `*PREFIX*share`
+ SET `file_target` = ?
+ WHERE `id` = ?'
+ );
+ $arguments = array($newPath, $share['id']);
+ }
+
+ $result = $query->execute($arguments);
+
+ return $result === 1 ? true : false;
+ }
+
+ /**
+ * Format a path to be relative to the /user/files/ directory
+ *
+ * @param string $path the absolute path
+ * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
+ */
+ private function stripUserFilesPath($path) {
+ $trimmed = ltrim($path, '/');
+ $split = explode('/', $trimmed);
+
+ // it is not a file relative to data/user/files
+ if (count($split) < 3 || $split[1] !== 'files') {
+ \OCP\Util::writeLog('file sharing',
+ 'Can not strip userid and "files/" from path: ' . $path,
+ \OCP\Util::DEBUG);
+ return false;
+ }
+
+ // skip 'user' and 'files'
+ $sliced = array_slice($split, 2);
+ $relPath = implode('/', $sliced);
+
+ return '/' . $relPath;
+ }
+
+ /**
+ * Move the mount point to $target
+ *
+ * @param string $target the target mount point
+ * @return bool
+ */
+ public function moveMount($target) {
+ // it shouldn't be possible to move a Shared storage into another one
+ list($targetStorage,) = Filesystem::resolvePath($target);
+ if ($targetStorage instanceof Shared) {
+ \OCP\Util::writeLog('file sharing',
+ 'It is not allowed to move one mount point into another one',
+ \OCP\Util::DEBUG);
+ return false;
+ }
+
+ $relTargetPath = $this->stripUserFilesPath($target);
+ $share = $this->storage->getShare();
+
+ $result = $this->updateFileTarget($relTargetPath, $share);
+
+ if ($result) {
+ $this->setMountPoint($target);
+ $this->storage->setUniqueName();
+ $this->storage->setMountPoint($relTargetPath);
+
+ } else {
+ \OCP\Util::writeLog('file sharing',
+ 'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
+ \OCP\Util::ERROR);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Remove the mount points
+ *
+ * @return bool
+ */
+ public function removeMount() {
+ $storage = $this->getStorage();
+ $result = \OCP\Share::unshareFromSelf($storage->getItemType(), $storage->getMountPoint());
+
+ return $result;
+ }
+}
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index f93982ee857..59de2dfa4c4 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -22,6 +22,8 @@
*/
namespace OC\Files\Storage;
+use OC\Files\Filesystem;
+use OCA\Files_Sharing\SharedMount;
/**
* Convert target path to source path and pass the function call to the correct storage provider
@@ -104,8 +106,8 @@ class Shared extends \OC\Files\Storage\Common {
*/
public function getPermissions($target = '') {
$permissions = $this->share['permissions'];
- // part file are always have delete permissions
- if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
+ // part files and the mount point always have delete permissions
+ if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
$permissions |= \OCP\PERMISSION_DELETE;
}
@@ -126,7 +128,18 @@ class Shared extends \OC\Files\Storage\Common {
return false;
}
+ /**
+ * Delete the directory if DELETE permission is granted
+ * @param string $path
+ * @return boolean
+ */
public function rmdir($path) {
+
+ // never delete a share mount point
+ if(empty($path)) {
+ return false;
+ }
+
if (($source = $this->getSourcePath($path)) && $this->isDeletable($path)) {
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
return $storage->rmdir($internalPath);
@@ -254,9 +267,17 @@ class Shared extends \OC\Files\Storage\Common {
return false;
}
+ /**
+ * Delete the file if DELETE permission is granted
+ * @param string $path
+ * @return boolean
+ */
public function unlink($path) {
- // Delete the file if DELETE permission is granted
- $path = ($path === false) ? '' : $path;
+
+ // never delete a share mount point
+ if (empty($path)) {
+ return false;
+ }
if ($source = $this->getSourcePath($path)) {
if ($this->isDeletable($path)) {
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
@@ -266,124 +287,14 @@ class Shared extends \OC\Files\Storage\Common {
return false;
}
- /**
- * Format a path to be relative to the /user/files/ directory
- * @param string $path the absolute path
- * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
- */
- private static function stripUserFilesPath($path) {
- $trimmed = ltrim($path, '/');
- $split = explode('/', $trimmed);
-
- // it is not a file relative to data/user/files
- if (count($split) < 3 || $split[1] !== 'files') {
- \OCP\Util::writeLog('file sharing',
- 'Can not strip userid and "files/" from path: ' . $path,
- \OCP\Util::DEBUG);
- return false;
- }
-
- // skip 'user' and 'files'
- $sliced = array_slice($split, 2);
- $relPath = implode('/', $sliced);
-
- return '/' . $relPath;
- }
-
- /**
- * rename a shared folder/file
- * @param string $sourcePath
- * @param string $targetPath
- * @return bool
- */
- private function renameMountPoint($sourcePath, $targetPath) {
-
- // it shouldn't be possible to move a Shared storage into another one
- list($targetStorage, ) = \OC\Files\Filesystem::resolvePath($targetPath);
- if ($targetStorage->instanceOfStorage('\OC\Files\Storage\Shared')) {
- \OCP\Util::writeLog('file sharing',
- 'It is not allowed to move one mount point into another one',
- \OCP\Util::DEBUG);
- return false;
- }
-
- $relTargetPath = $this->stripUserFilesPath($targetPath);
-
- if ($relTargetPath === false) {
- \OCP\Util::writeLog('file sharing', 'Wrong target path given: ' . $targetPath, \OCP\Util::ERROR);
- return false;
- }
-
- $result = self::updateFileTarget($relTargetPath, $this->share);
-
- if ($result) {
- // update the mount manager with the new paths
- $mountManager = \OC\Files\Filesystem::getMountManager();
- $mount = $mountManager->find($sourcePath);
- $mount->setMountPoint($targetPath . '/');
- $mountManager->addMount($mount);
- $mountManager->removeMount($sourcePath . '/');
- $this->setUniqueName();
- $this->setMountPoint($relTargetPath);
-
- } else {
- \OCP\Util::writeLog('file sharing',
- 'Could not rename mount point for shared folder "' . $sourcePath . '" to "' . $targetPath . '"',
- \OCP\Util::ERROR);
- }
-
- return (bool)$result;
- }
-
- /**
- * @update fileTarget in the database if the mount point changed
- * @param string $newPath
- * @param array $share reference to the share which should be modified
- * @return type
- */
- private static function updateFileTarget($newPath, &$share) {
- // if the user renames a mount point from a group share we need to create a new db entry
- // for the unique name
- if ($share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP &&
- (isset($share['unique_name']) && $share['unique_name'])) {
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`,'
- .' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
- .' `file_target`, `token`, `parent`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
- $arguments = array($share['item_type'], $share['item_source'], $share['item_target'],
- 2, \OCP\User::getUser(), $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
- $newPath, $share['token'], $share['id']);
-
- } else {
- // rename mount point
- $query = \OC_DB::prepare(
- 'Update `*PREFIX*share`
- SET `file_target` = ?
- WHERE `id` = ?'
- );
- $arguments = array($newPath, $share['id']);
- }
-
- return $query->execute($arguments);
- }
-
public function rename($path1, $path2) {
- $sourceMountPoint = \OC\Files\Filesystem::getMountPoint($path1);
- $targetMountPoint = \OC\Files\Filesystem::getMountPoint($path2);
- $relPath1 = \OCA\Files_Sharing\Helper::stripUserFilesPath($path1);
- $relPath2 = \OCA\Files_Sharing\Helper::stripUserFilesPath($path2);
-
- // if we renamed the mount point we need to adjust the file_target in the
- // database
- if (\OC\Files\Filesystem::normalizePath($sourceMountPoint) === \OC\Files\Filesystem::normalizePath($path1)) {
- return $this->renameMountPoint($path1, $path2);
- }
+ // we need the paths relative to data/user/files
+ $relPath1 = $this->getMountPoint() . '/' . $path1;
+ $relPath2 = $this->getMountPoint() . '/' . $path2;
-
- if ( // Within the same mount point, we only need UPDATE permissions
- ($sourceMountPoint === $targetMountPoint && $this->isUpdatable($sourceMountPoint)) ||
- // otherwise DELETE and CREATE permissions required
- ($this->isDeletable($path1) && $this->isCreatable(dirname($path2)))) {
+ // check for update permissions on the share
+ if ($this->isUpdatable('')) {
$pathinfo = pathinfo($relPath1);
// for part files we need to ask for the owner and path from the parent directory because
@@ -486,48 +397,29 @@ class Shared extends \OC\Files\Storage\Common {
public static function setup($options) {
$shares = \OCP\Share::getItemsSharedWith('file');
+ $manager = Filesystem::getMountManager();
+ $loader = Filesystem::getLoader();
if (!\OCP\User::isLoggedIn() || \OCP\User::getUser() != $options['user']
|| $shares
) {
foreach ($shares as $share) {
- self::verifyMountPoint($share);
- \OC\Files\Filesystem::mount('\OC\Files\Storage\Shared',
- array(
- 'share' => $share,
- ),
- $options['user_dir'] . '/' . $share['file_target']);
+ // don't mount shares where we have no permissions
+ if ($share['permissions'] > 0) {
+ $mount = new SharedMount(
+ '\OC\Files\Storage\Shared',
+ $options['user_dir'] . '/' . $share['file_target'],
+ array(
+ 'share' => $share,
+ ),
+ $loader
+ );
+ $manager->addMount($mount);
+ }
}
}
}
/**
- * check if the parent folder exists otherwise move the mount point up
- *
- * @param array $share reference to the share we want to check
- */
- private static function verifyMountPoint(&$share) {
- $mountPoint = basename($share['file_target']);
- $parent = dirname($share['file_target']);
-
- while (!\OC\Files\Filesystem::is_dir($parent)) {
- $parent = dirname($parent);
- }
-
- $newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
- \OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
- array(),
- new \OC\Files\View('/' . \OCP\User::getUser() . '/files')
- );
-
- if($newMountPoint !== $share['file_target']) {
-
- self::updateFileTarget($newMountPoint, $share);
- $share['file_target'] = $newMountPoint;
-
- }
- }
-
- /**
* return mount point of share, relative to data/user/files
*
* @return string
@@ -536,22 +428,41 @@ class Shared extends \OC\Files\Storage\Common {
return $this->share['file_target'];
}
- private function setMountPoint($path) {
+ public function setMountPoint($path) {
$this->share['file_target'] = $path;
}
+ public function getShareType() {
+ return $this->share['share_type'];
+ }
+
+ /**
+ * does the group share already has a user specific unique name
+ * @return bool
+ */
+ public function uniqueNameSet() {
+ return (isset($this->share['unique_name']) && $this->share['unique_name']);
+ }
+
/**
* the share now uses a unique name of this user
*
* @brief the share now uses a unique name of this user
*/
- private function setUniqueName() {
+ public function setUniqueName() {
$this->share['unique_name'] = true;
}
/**
- * @brief get the user who shared the file
- *
+ * get share ID
+ * @return integer unique share ID
+ */
+ public function getShareId() {
+ return $this->share['id'];
+ }
+
+ /**
+ * get the user who shared the file
* @return string
*/
public function getSharedFrom() {
@@ -559,6 +470,13 @@ class Shared extends \OC\Files\Storage\Common {
}
/**
+ * @return array
+ */
+ public function getShare() {
+ return $this->share;
+ }
+
+ /**
* return share type, can be "file" or "folder"
* @return string
*/
diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php
index 6d0ed434ef2..3c683afacb4 100644
--- a/apps/files_sharing/tests/api.php
+++ b/apps/files_sharing/tests/api.php
@@ -784,7 +784,7 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
$fileInfo = $this->view->getFileInfo($this->filename);
$result = \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
- \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
+ \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL);
// share was successful?
$this->assertTrue($result);
@@ -816,9 +816,11 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
$this->assertTrue(is_array($linkShare));
$this->assertTrue(is_array($userShare));
- // update permissions
+ // check if share have expected permissions, single shared files never have
+ // delete permissions
+ $this->assertEquals(\OCP\PERMISSION_ALL & ~\OCP\PERMISSION_DELETE, $userShare['permissions']);
- $this->assertEquals('31', $userShare['permissions']);
+ // update permissions
$params = array();
$params['id'] = $userShare['id'];
@@ -893,7 +895,7 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
$items = \OCP\Share::getItemShared('file', null);
// make sure that we found a link share and a user share
- $this->assertEquals(count($items), 1);
+ $this->assertEquals(1, count($items));
$linkShare = null;
diff --git a/apps/files_sharing/tests/permissions.php b/apps/files_sharing/tests/permissions.php
index 5ac251b0527..0a222b08512 100644
--- a/apps/files_sharing/tests/permissions.php
+++ b/apps/files_sharing/tests/permissions.php
@@ -111,5 +111,10 @@ class Test_Files_Sharing_Permissions extends Test_Files_Sharing_Base {
$this->assertEquals(7, $contents[0]['permissions']);
$this->assertEquals('textfile1.txt', $contents[1]['name']);
$this->assertEquals(7, $contents[1]['permissions']);
+
+ // the share mount point should always have delete permissions to allow the user
+ // to unmount it
+ $restrictedShare = $this->secondView->getFileInfo('files/shareddirrestricted');
+ $this->assertEquals(7 | \OCP\PERMISSION_DELETE, $restrictedShare['permissions']);
}
}
diff --git a/apps/files_sharing/tests/share.php b/apps/files_sharing/tests/share.php
new file mode 100644
index 00000000000..d3ca1816c75
--- /dev/null
+++ b/apps/files_sharing/tests/share.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once __DIR__ . '/base.php';
+
+use OCA\Files\Share;
+
+/**
+ * Class Test_Files_Sharing
+ */
+class Test_Files_Sharing extends Test_Files_Sharing_Base {
+
+ const TEST_FOLDER_NAME = '/folder_share_api_test';
+
+ private static $tempStorage;
+
+ function setUp() {
+ parent::setUp();
+
+ $this->folder = self::TEST_FOLDER_NAME;
+ $this->subfolder = '/subfolder_share_api_test';
+ $this->subsubfolder = '/subsubfolder_share_api_test';
+
+ $this->filename = '/share-api-test.txt';
+
+ // save file with content
+ $this->view->file_put_contents($this->filename, $this->data);
+ $this->view->mkdir($this->folder);
+ $this->view->mkdir($this->folder . $this->subfolder);
+ $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder);
+ $this->view->file_put_contents($this->folder.$this->filename, $this->data);
+ $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data);
+ }
+
+ function tearDown() {
+ $this->view->unlink($this->filename);
+ $this->view->deleteAll($this->folder);
+
+ self::$tempStorage = null;
+
+ parent::tearDown();
+ }
+
+ function testUnshareFromSelf() {
+
+ \OC_Group::createGroup('testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+ $fileinfo = $this->view->getFileInfo($this->filename);
+
+ $pathinfo = pathinfo($this->filename);
+
+ $duplicate = '/' . $pathinfo['filename'] . ' (2).' . $pathinfo['extension'];
+
+ $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, 31);
+
+ $this->assertTrue($result);
+
+ $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
+ 'testGroup', 31);
+
+ $this->assertTrue($result);
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($duplicate));
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ \OC\Files\Filesystem::unlink($this->filename);
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($duplicate));
+
+ // for user3 nothing should change
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ \OC\Files\Filesystem::unlink($duplicate);
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+ // for user3 nothing should change
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+ //cleanup
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
+ 'testGroup');
+ \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ self::TEST_FILES_SHARING_API_USER2);
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::deleteGroup('testGroup');
+
+
+ }
+
+ /**
+ * shared files should never have delete permissions
+ * @dataProvider DataProviderTestFileSharePermissions
+ */
+ function testFileSharePermissions($permission, $expectedPermissions) {
+
+ $fileinfo = $this->view->getFileInfo($this->filename);
+
+ $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, $permission);
+
+ $this->assertTrue($result);
+
+ $result = \OCP\Share::getItemShared('file', null);
+
+ $this->assertTrue(is_array($result));
+
+ // test should return exactly one shares created from testCreateShare()
+ $this->assertTrue(count($result) === 1);
+
+ $share = reset($result);
+ $this->assertSame($expectedPermissions, $share['permissions']);
+
+ \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2);
+ }
+
+ function DataProviderTestFileSharePermissions() {
+ $permission1 = \OCP\PERMISSION_ALL;
+ $permission2 = \OCP\PERMISSION_DELETE;
+ $permission3 = \OCP\PERMISSION_READ;
+ $permission4 = \OCP\PERMISSION_READ | \OCP\PERMISSION_UPDATE;
+ $permission5 = \OCP\PERMISSION_READ | \OCP\PERMISSION_DELETE;
+ $permission6 = \OCP\PERMISSION_READ | \OCP\PERMISSION_UPDATE | \OCP\PERMISSION_DELETE;
+
+ return array(
+ array($permission1, \OCP\PERMISSION_ALL & ~\OCP\PERMISSION_DELETE),
+ array($permission2, 0),
+ array($permission3, $permission3),
+ array($permission4, $permission4),
+ array($permission5, $permission3),
+ array($permission6, $permission4),
+ );
+ }
+
+}
diff --git a/apps/files_sharing/tests/sharedmount.php b/apps/files_sharing/tests/sharedmount.php
new file mode 100644
index 00000000000..f8c65734184
--- /dev/null
+++ b/apps/files_sharing/tests/sharedmount.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once __DIR__ . '/base.php';
+
+/**
+ * Class Test_Files_Sharing_Api
+ */
+class Test_Files_Sharing_Mount extends Test_Files_Sharing_Base {
+
+ function setUp() {
+ parent::setUp();
+
+ $this->folder = '/folder_share_storage_test';
+
+ $this->filename = '/share-api-storage.txt';
+
+
+ $this->view->mkdir($this->folder);
+
+ // save file with content
+ $this->view->file_put_contents($this->filename, "root file");
+ $this->view->file_put_contents($this->folder . $this->filename, "file in subfolder");
+ }
+
+ function tearDown() {
+ $this->view->unlink($this->folder);
+ $this->view->unlink($this->filename);
+
+ parent::tearDown();
+ }
+
+ /**
+ * test if the mount point moves up if the parent folder no longer exists
+ */
+ function testShareMountLoseParentFolder() {
+
+ // share to user
+ $fileinfo = $this->view->getFileInfo($this->folder);
+ $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ self::TEST_FILES_SHARING_API_USER2, 31);
+
+ $statement = "UPDATE `*PREFIX*share` SET `file_target` = ? where `share_with` = ?";
+ $query = \OC_DB::prepare($statement);
+ $arguments = array('/foo/bar' . $this->folder, self::TEST_FILES_SHARING_API_USER2);
+ $query->execute($arguments);
+
+ $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+ $result = $query->execute();
+
+ $shares = $result->fetchAll();
+
+ $this->assertSame(1, count($shares));
+
+ $share = reset($shares);
+ $this->assertSame('/foo/bar' . $this->folder, $share['file_target']);
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+ // share should have moved up
+
+ $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+ $result = $query->execute();
+
+ $shares = $result->fetchAll();
+
+ $this->assertSame(1, count($shares));
+
+ $share = reset($shares);
+ $this->assertSame($this->folder, $share['file_target']);
+
+ //cleanup
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
+ $this->view->unlink($this->folder);
+ }
+
+ /**
+ * @medium
+ */
+ function testDeleteParentOfMountPoint() {
+
+ // share to user
+ $fileinfo = $this->view->getFileInfo($this->folder);
+ $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ self::TEST_FILES_SHARING_API_USER2, 31);
+
+ $this->assertTrue($result);
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
+ $this->assertTrue($user2View->file_exists($this->folder));
+
+ // create a local folder
+ $result = $user2View->mkdir('localfolder');
+ $this->assertTrue($result);
+
+ // move mount point to local folder
+ $result = $user2View->rename($this->folder, '/localfolder/' . $this->folder);
+ $this->assertTrue($result);
+
+ // mount point in the root folder should no longer exist
+ $this->assertFalse($user2View->is_dir($this->folder));
+
+ // delete the local folder
+ $result = $user2View->unlink('/localfolder');
+ $this->assertTrue($result);
+
+ //enforce reload of the mount points
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+ //mount point should be back at the root
+ $this->assertTrue($user2View->is_dir($this->folder));
+
+ //cleanup
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ $this->view->unlink($this->folder);
+ }
+
+ function testMoveSharedFile() {
+ $fileinfo = $this->view->getFileInfo($this->filename);
+ $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+ self::TEST_FILES_SHARING_API_USER2, 31);
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+ \OC\Files\Filesystem::rename($this->filename, "newFileName");
+
+ $this->assertTrue(\OC\Files\Filesystem::file_exists('newFileName'));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName"));
+
+ //cleanup
+ \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
+ }
+
+ /**
+ * share file with a group if a user renames the file the filename should not change
+ * for the other users
+ */
+ function testMoveGroupShare () {
+ \OC_Group::createGroup('testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+ $fileinfo = $this->view->getFileInfo($this->filename);
+ $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
+ "testGroup", 31);
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+
+ \OC\Files\Filesystem::rename($this->filename, "newFileName");
+
+ $this->assertTrue(\OC\Files\Filesystem::file_exists('newFileName'));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName"));
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+ $this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName"));
+
+ //cleanup
+ \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+ \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+ }
+
+}
diff --git a/apps/files_sharing/tests/update.php b/apps/files_sharing/tests/update.php
new file mode 100644
index 00000000000..b0215d68176
--- /dev/null
+++ b/apps/files_sharing/tests/update.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Morris Jobke, Bjoern Schiessle
+ * @copyright 2014 Morris Jobke <morris.jobke@gmail.com>
+ * 2014 Bjoern Schiessle <schiessle@ownlcoud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once __DIR__ . '/../appinfo/update.php';
+require_once __DIR__ . '/base.php';
+
+/**
+ * Class Test_Files_Sharing_Update
+ */
+class Test_Files_Sharing_Update_Routine extends Test_Files_Sharing_Base {
+
+ const TEST_FOLDER_NAME = '/folder_share_api_test';
+
+ function setUp() {
+ parent::setUp();
+
+ $this->folder = self::TEST_FOLDER_NAME;
+
+ $this->filename = '/share-api-test.txt';
+
+ // save file with content
+ $this->view->file_put_contents($this->filename, $this->data);
+ $this->view->mkdir($this->folder);
+ $this->view->file_put_contents($this->folder . '/' . $this->filename, $this->data);
+ }
+
+ function tearDown() {
+ $this->view->unlink($this->filename);
+ $this->view->deleteAll($this->folder);
+
+ $removeShares = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
+ $removeShares->execute();
+ $removeItems = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache`');
+ $removeItems->execute();
+
+ parent::tearDown();
+ }
+
+ /**
+ * test update of file permission. The update should remove from all shared
+ * files the delete permission
+ */
+ function testUpdateFilePermissions() {
+
+ self::prepareDBUpdateFilePermissions();
+ // run the update routine to update the share permission
+ updateFilePermissions(2);
+
+ // verify results
+ $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+ $result = $query->execute(array());
+
+ while ($row = $result->fetchRow()) {
+ if ($row['item_type'] === 'file') {
+ // for all files the delete permission should be removed
+ $this->assertSame(0, (int)$row['permissions'] & \OCP\PERMISSION_DELETE);
+ } else {
+ // for all other the permission shouldn't change
+ $this->assertSame(31, (int)$row['permissions'] & \OCP\PERMISSION_ALL);
+ }
+ }
+
+ // cleanup
+ $this->cleanupSharedTable();
+ }
+
+ /**
+ * @medium
+ */
+ function testRemoveBrokenShares() {
+
+ $this->prepareFileCache();
+
+ // check if there are just 3 shares (see setUp - precondition: empty table)
+ $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
+ $result = $countShares->execute()->fetchOne();
+ $this->assertEquals(3, $result);
+
+ // check if there are just 2 items (see setUp - precondition: empty table)
+ $countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
+ $result = $countItems->execute()->fetchOne();
+ $this->assertEquals(2, $result);
+
+ // execute actual code which should be tested
+ \OC\Files\Cache\Shared_Updater::fixBrokenSharesOnAppUpdate();
+
+ // check if there are just 2 shares (one gets killed by the code as there is no filecache entry for this)
+ $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
+ $result = $countShares->execute()->fetchOne();
+ $this->assertEquals(2, $result);
+
+ // check if the share of file '200' is removed as there is no entry for this in filecache table
+ $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share` WHERE `file_source` = 200');
+ $result = $countShares->execute()->fetchOne();
+ $this->assertEquals(0, $result);
+
+ // check if there are just 2 items
+ $countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
+ $result = $countItems->execute()->fetchOne();
+ $this->assertEquals(2, $result);
+ }
+
+ /**
+ * test update for the removal of the logical "Shared" folder. It should update
+ * the file_target for every share and create a physical "Shared" folder for each user
+ */
+ function testRemoveSharedFolder() {
+ self::prepareDB();
+ // run the update routine to remove the shared folder and replace it with a real folder
+ removeSharedFolder(false, 2);
+
+ // verify results
+ $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+ $result = $query->execute(array());
+
+ $newDBContent = $result->fetchAll();
+
+ foreach ($newDBContent as $row) {
+ if ((int)$row['share_type'] === \OCP\Share::SHARE_TYPE_USER) {
+ $this->assertSame('/Shared', substr($row['file_target'], 0, strlen('/Shared')));
+ } else {
+ $this->assertSame('/ShouldNotChange', $row['file_target']);
+ }
+ }
+
+ // cleanup
+ $this->cleanupSharedTable();
+
+ }
+
+ private function cleanupSharedTable() {
+ $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
+ $query->execute();
+ }
+
+ /**
+ * prepare sharing table for testRemoveSharedFolder()
+ */
+ private function prepareDB() {
+ $this->cleanupSharedTable();
+ // add items except one - because this is the test case for the broken share table
+ $addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`share_type`, `item_type`, ' .
+ '`share_with`, `uid_owner` , `file_target`) ' .
+ 'VALUES (?, ?, ?, ?, ?)');
+ $items = array(
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo'),
+ array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user2', 'admin', '/foo2'),
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user3', 'admin', '/foo3'),
+ array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', '/foo4'),
+ array(\OCP\Share::SHARE_TYPE_LINK, 'file', 'user1', 'admin', '/ShouldNotChange'),
+ array(\OCP\Share::SHARE_TYPE_CONTACT, 'contact', 'admin', 'user1', '/ShouldNotChange'),
+
+ );
+ foreach($items as $item) {
+ // the number is used as path_hash
+ $addItems->execute($item);
+ }
+ }
+
+ /**
+ * prepare sharing table for testUpdateFilePermissions()
+ */
+ private function prepareDBUpdateFilePermissions() {
+ $this->cleanupSharedTable();
+ // add items except one - because this is the test case for the broken share table
+ $addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`share_type`, `item_type`, ' .
+ '`share_with`, `uid_owner` , `file_target`, `permissions`) ' .
+ 'VALUES (?, ?, ?, ?, ?, ?)');
+ $items = array(
+ array(\OCP\Share::SHARE_TYPE_LINK, 'file', 'user1', 'admin', '/foo', \OCP\PERMISSION_ALL),
+ array(\OCP\Share::SHARE_TYPE_CONTACT, 'contact', 'admin', 'user1', '/foo', \OCP\PERMISSION_ALL),
+ array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', '/foo', \OCP\PERMISSION_ALL),
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user3', 'admin', '/foo3', \OCP\PERMISSION_ALL),
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_DELETE),
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_READ & \OCP\PERMISSION_DELETE),
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_SHARE & \OCP\PERMISSION_UPDATE),
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_ALL),
+ array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_SHARE & \OCP\PERMISSION_READ & \OCP\PERMISSION_DELETE),
+ );
+ foreach($items as $item) {
+ // the number is used as path_hash
+ $addItems->execute($item);
+ }
+ }
+
+ /**
+ * prepare file cache for testRemoveBrokenShares()
+ */
+ private function prepareFileCache() {
+ // some previous tests didn't clean up and therefore this has to be done here
+ // FIXME: DIRTY HACK - TODO: find tests, that don't clean up and fix it there
+ $this->tearDown();
+
+ // add items except one - because this is the test case for the broken share table
+ $addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` (`storage`, `path_hash`, ' .
+ '`parent`, `mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`) ' .
+ 'VALUES (1, ?, 1, 1, 1, 1, 1, 1)');
+ $items = array(1, 3);
+ $fileIds = array();
+ foreach($items as $item) {
+ // the number is used as path_hash
+ $addItems->execute(array($item));
+ $fileIds[] = \OC_DB::insertId('*PREFIX*filecache');
+ }
+
+ $addShares = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`file_source`, `item_type`, `uid_owner`) VALUES (?, \'file\', 1)');
+ // the number is used as item_source
+ $addShares->execute(array($fileIds[0]));
+ $addShares->execute(array(200)); // id of "deleted" file
+ $addShares->execute(array($fileIds[1]));
+ }
+
+}
diff --git a/apps/files_sharing/tests/updater.php b/apps/files_sharing/tests/updater.php
index 1b851cccf6c..8183e7067a4 100644
--- a/apps/files_sharing/tests/updater.php
+++ b/apps/files_sharing/tests/updater.php
@@ -47,11 +47,6 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
$this->view->unlink($this->filename);
$this->view->deleteAll($this->folder);
- $removeShares = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
- $removeShares->execute();
- $removeItems = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache`');
- $removeItems->execute();
-
parent::tearDown();
}
@@ -111,124 +106,4 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
}
}
- /**
- * @medium
- */
- function testRemoveBrokenShares() {
-
- $this->prepareFileCache();
-
- // check if there are just 3 shares (see setUp - precondition: empty table)
- $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
- $result = $countShares->execute()->fetchOne();
- $this->assertEquals(3, $result);
-
- // check if there are just 2 items (see setUp - precondition: empty table)
- $countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
- $result = $countItems->execute()->fetchOne();
- $this->assertEquals(2, $result);
-
- // execute actual code which should be tested
- \OC\Files\Cache\Shared_Updater::fixBrokenSharesOnAppUpdate();
-
- // check if there are just 2 shares (one gets killed by the code as there is no filecache entry for this)
- $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
- $result = $countShares->execute()->fetchOne();
- $this->assertEquals(2, $result);
-
- // check if the share of file '200' is removed as there is no entry for this in filecache table
- $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share` WHERE `file_source` = 200');
- $result = $countShares->execute()->fetchOne();
- $this->assertEquals(0, $result);
-
- // check if there are just 2 items
- $countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
- $result = $countItems->execute()->fetchOne();
- $this->assertEquals(2, $result);
- }
-
- /**
- * test update for the removal of the logical "Shared" folder. It should update
- * the file_target for every share and create a physical "Shared" folder for each user
- */
- function testRemoveSharedFolder() {
- self::prepareDB();
- // run the update routine to remove the shared folder and replace it with a real folder
- removeSharedFolder(false, 2);
-
- // verify results
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
- $result = $query->execute(array());
-
- $newDBContent = $result->fetchAll();
-
- foreach ($newDBContent as $row) {
- if ((int)$row['share_type'] === \OCP\Share::SHARE_TYPE_USER) {
- $this->assertSame('/Shared', substr($row['file_target'], 0, strlen('/Shared')));
- } else {
- $this->assertSame('/ShouldNotChange', $row['file_target']);
- }
- }
-
- // cleanup
- $this->cleanupSharedTable();
-
- }
-
- private function cleanupSharedTable() {
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
- $query->execute();
- }
-
- /**
- * prepare sharing table for testRemoveSharedFolder()
- */
- private function prepareDB() {
- $this->cleanupSharedTable();
- // add items except one - because this is the test case for the broken share table
- $addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`share_type`, `item_type`, ' .
- '`share_with`, `uid_owner` , `file_target`) ' .
- 'VALUES (?, ?, ?, ?, ?)');
- $items = array(
- array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo'),
- array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user2', 'admin', '/foo2'),
- array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user3', 'admin', '/foo3'),
- array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', '/foo4'),
- array(\OCP\Share::SHARE_TYPE_LINK, 'file', 'user1', 'admin', '/ShouldNotChange'),
- array(\OCP\Share::SHARE_TYPE_CONTACT, 'contact', 'admin', 'user1', '/ShouldNotChange'),
-
- );
- foreach($items as $item) {
- // the number is used as path_hash
- $addItems->execute($item);
- }
- }
-
- /**
- * prepare file cache for testRemoveBrokenShares()
- */
- private function prepareFileCache() {
- // some previous tests didn't clean up and therefore this has to be done here
- // FIXME: DIRTY HACK - TODO: find tests, that don't clean up and fix it there
- $this->tearDown();
-
- // add items except one - because this is the test case for the broken share table
- $addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` (`storage`, `path_hash`, ' .
- '`parent`, `mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`) ' .
- 'VALUES (1, ?, 1, 1, 1, 1, 1, 1)');
- $items = array(1, 3);
- $fileIds = array();
- foreach($items as $item) {
- // the number is used as path_hash
- $addItems->execute(array($item));
- $fileIds[] = \OC_DB::insertId('*PREFIX*filecache');
- }
-
- $addShares = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`file_source`, `item_type`, `uid_owner`) VALUES (?, \'file\', 1)');
- // the number is used as item_source
- $addShares->execute(array($fileIds[0]));
- $addShares->execute(array(200)); // id of "deleted" file
- $addShares->execute(array($fileIds[1]));
- }
-
}