Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 87 additions & 3 deletions apps/files_sharing/lib/MountProvider.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -75,16 +75,20 @@ public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
});

$mounts = [];
foreach ($shares as $share) {
$superShares = $this->buildSuperShares($shares, $user);

$mounts = [];
foreach ($superShares as $share) {
try {
$mounts[] = new SharedMount(
'\OC\Files\Storage\Shared',
$mounts,
[
'user' => $user->getUID(),
'newShare' => $share,
// parent share
'superShare' => $share[0],
// children/component of the superShare
'groupedShares' => $share[1],
],
$storageFactory
);
Expand All@@ -97,4 +101,84 @@ public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
// array_filter removes the null values from the array
return array_filter($mounts);
}

/**
* Groups shares by path (nodeId) and target path
*
* @param \OCP\Share\IShare[] $shares
* @return \OCP\Share\IShare[][] array of grouped shares, each element in the
* array is a group which itself is an array of shares
*/
private function groupShares(array $shares) {
$tmp = [];

foreach ($shares as $share) {
if (!isset($tmp[$share->getNodeId()])) {
$tmp[$share->getNodeId()] = [];
}
$tmp[$share->getNodeId()][] = $share;
}

$result = [];
// sort by stime, the super share will be based on the least recent share
foreach ($tmp as &$tmp2) {
@usort($tmp2, function($a, $b) {
if ($a->getShareTime() < $b->getShareTime()) {
return -1;
}
return 1;
});
$result[] = $tmp2;
}

return array_values($result);
}

/**
* Build super shares (virtual share) by grouping them by node id and target,
* then for each group compute the super share and return it along with the matching
* grouped shares. The most permissive permissions are used based on the permissions
* of all shares within the group.
*
* @param \OCP\Share\IShare[] $allShares
* @param \OCP\IUser $user user
* @return array Tuple of [superShare, groupedShares]
*/
private function buildSuperShares(array $allShares, \OCP\IUser $user) {
$result = [];

$groupedShares = $this->groupShares($allShares);

/** @var \OCP\Share\IShare[] $shares */
foreach ($groupedShares as $shares) {
if (count($shares) === 0) {
continue;
}

$superShare = $this->shareManager->newShare();

// compute super share based on first entry of the group
$superShare->setId($shares[0]->getId())
->setShareOwner($shares[0]->getShareOwner())
->setNodeId($shares[0]->getNodeId())
->setTarget($shares[0]->getTarget());

// use most permissive permissions
$permissions = 0;
foreach ($shares as $share) {
$permissions |= $share->getPermissions();
if ($share->getTarget() !== $superShare->getTarget()) {
// adjust target, for database consistency
$share->setTarget($superShare->getTarget());
$this->shareManager->moveShare($share, $user->getUID());
}
}

$superShare->setPermissions($permissions);

$result[] = [$superShare, $shares];
}

return $result;
}
}
24 changes: 17 additions & 7 deletions apps/files_sharing/lib/SharedMount.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -52,7 +52,10 @@ class SharedMount extends MountPoint implements MoveableMount {
private $user;

/** @var \OCP\Share\IShare */
private $share;
private $superShare;

/** @var \OCP\Share\IShare[] */
private $groupedShares;

/**
* @param string $storage
Expand All@@ -63,10 +66,13 @@ class SharedMount extends MountPoint implements MoveableMount {
public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) {
$this->user = $arguments['user'];
$this->recipientView = new View('/' . $this->user . '/files');
$this->share = $arguments['newShare'];
$newMountPoint = $this->verifyMountPoint($this->share, $mountpoints);

$this->superShare = $arguments['superShare'];
$this->groupedShares = $arguments['groupedShares'];

$newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints);
$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
$arguments['ownerView'] = new View('/' . $this->share->getShareOwner() . '/files');
$arguments['ownerView'] = new View('/' . $this->superShare->getShareOwner() . '/files');
parent::__construct($storage, $absMountPoint, $arguments, $loader);
}

Expand DownExpand Up@@ -108,7 +114,11 @@ private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints)
*/
private function updateFileTarget($newPath, &$share) {
$share->setTarget($newPath);
\OC::$server->getShareManager()->moveShare($share, $this->user);

foreach ($this->groupedShares as $share) {
$share->setTarget($newPath);
\OC::$server->getShareManager()->moveShare($share, $this->user);
}
}


Expand DownExpand Up@@ -214,7 +224,7 @@ public function removeMount() {
* @return \OCP\Share\IShare
*/
public function getShare() {
return $this->share;
return $this->superShare;
}

/**
Expand All@@ -223,6 +233,6 @@ public function getShare() {
* @return int
*/
public function getStorageRootId() {
return $this->share->getNodeId();
return $this->getShare()->getNodeId();
}
}
77 changes: 34 additions & 43 deletions apps/files_sharing/lib/sharedstorage.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,11 +43,11 @@
* Convert target path to source path and pass the function call to the correct storage provider
*/
class Shared extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage {

private $share; // the shared resource

/** @var \OCP\Share\IShare */
private $newShare;
private $superShare;

/** @var \OCP\Share\IShare[] */
private $groupedShares;

/**
* @var \OC\Files\View
Expand DownExpand Up@@ -77,11 +77,14 @@ class Shared extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage {
public function __construct($arguments) {
$this->ownerView = $arguments['ownerView'];
$this->logger = \OC::$server->getLogger();
$this->newShare = $arguments['newShare'];

$this->superShare = $arguments['superShare'];
$this->groupedShares = $arguments['groupedShares'];

$this->user = $arguments['user'];

Filesystem::initMountPoints($this->newShare->getShareOwner());
$sourcePath = $this->ownerView->getPath($this->newShare->getNodeId());
Filesystem::initMountPoints($this->superShare->getShareOwner());
$sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
list($storage, $internalPath) = $this->ownerView->resolvePath($sourcePath);

parent::__construct([
Expand All@@ -96,15 +99,22 @@ private function init() {
}
$this->initialized = true;
try {
Filesystem::initMountPoints($this->newShare->getShareOwner());
$sourcePath = $this->ownerView->getPath($this->newShare->getNodeId());
Filesystem::initMountPoints($this->superShare->getShareOwner());
$sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
list($this->sourceStorage, $sourceInternalPath) = $this->ownerView->resolvePath($sourcePath);
$this->sourceRootInfo = $this->sourceStorage->getCache()->get($sourceInternalPath);
} catch (\Exception $e) {
$this->logger->logException($e);
}
}

/**
* @return string
*/
public function getShareId() {
return $this->superShare->getId();
}

private function isValid() {
$this->init();
return $this->sourceRootInfo && ($this->sourceRootInfo->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
Expand All@@ -119,15 +129,6 @@ public function getId() {
return 'shared::' . $this->getMountPoint();
}

/**
* get file cache of the shared item source
*
* @return int
*/
public function getSourceId() {
return $this->newShare->getNodeId();
}

/**
* Get the permissions granted for a shared file
*
Expand All@@ -138,7 +139,7 @@ public function getPermissions($target = '') {
if (!$this->isValid()) {
return 0;
}
$permissions = $this->newShare->getPermissions();
$permissions = $this->superShare->getPermissions();
// part files and the mount point always have delete permissions
if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
$permissions |= \OCP\Constants::PERMISSION_DELETE;
Expand DownExpand Up@@ -260,30 +261,18 @@ public function rename($path1, $path2) {
* @return string
*/
public function getMountPoint() {
return $this->newShare->getTarget();
return $this->superShare->getTarget();
}

/**
* @param string $path
*/
public function setMountPoint($path) {
$this->newShare->setTarget($path);
}

/**
* @return int
*/
public function getShareType() {
return $this->newShare->getShareType();
}
$this->superShare->setTarget($path);

/**
* get share ID
*
* @return integer unique share ID
*/
public function getShareId() {
return $this->newShare->getId();
foreach ($this->groupedShares as $share) {
$share->setTarget($path);
}
}

/**
Expand All@@ -292,14 +281,14 @@ public function getShareId() {
* @return string
*/
public function getSharedFrom() {
return $this->newShare->getShareOwner();
return $this->superShare->getShareOwner();
}

/**
* @return \OCP\Share\IShare
*/
public function getShare() {
return $this->newShare;
return $this->superShare;
}

/**
Expand All@@ -308,7 +297,7 @@ public function getShare() {
* @return string
*/
public function getItemType() {
return $this->newShare->getNodeType();
return $this->superShare->getNodeType();
}

public function getCache($path = '', $storage = null) {
Expand DownExpand Up@@ -337,7 +326,7 @@ public function getPropagator($storage = null) {
}

public function getOwner($path) {
return $this->newShare->getShareOwner();
return $this->superShare->getShareOwner();
}

/**
Expand All@@ -346,7 +335,9 @@ public function getOwner($path) {
* @return bool
*/
public function unshareStorage() {
\OC::$server->getShareManager()->deleteFromSelf($this->newShare, $this->user);
foreach ($this->groupedShares as $share) {
\OC::$server->getShareManager()->deleteFromSelf($share, $this->user);
}
return true;
}

Expand All@@ -362,7 +353,7 @@ public function acquireLock($path, $type, ILockingProvider $provider) {
$targetStorage->acquireLock($targetInternalPath, $type, $provider);
// lock the parent folders of the owner when locking the share as recipient
if ($path === '') {
$sourcePath = $this->ownerView->getPath($this->newShare->getNodeId());
$sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
$this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
}
}
Expand All@@ -378,7 +369,7 @@ public function releaseLock($path, $type, ILockingProvider $provider) {
$targetStorage->releaseLock($targetInternalPath, $type, $provider);
// unlock the parent folders of the owner when unlocking the share as recipient
if ($path === '') {
$sourcePath = $this->ownerView->getPath($this->newShare->getNodeId());
$sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
$this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
}
}
Expand Down
Loading