Skip to content

Commit

Permalink
propagate etags for all user of a share
Browse files Browse the repository at this point in the history
  • Loading branch information
icewind1991 committed Mar 9, 2015
1 parent 7a80ec9 commit 60df28b
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 10 deletions.
138 changes: 138 additions & 0 deletions apps/files_sharing/lib/propagator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <[email protected]>
* 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\Cache\ChangePropagator;
use OC\Files\Filesystem;
use OC\Files\View;
use OC\Share\Share;

class Propagator {
/**
* @var string
*/
protected $userId;

/**
* @var \OC\Files\Cache\ChangePropagator
*/
protected $changePropagator;

/**
* @var \OCP\IConfig
*/
protected $config;

/**
* @param string $userId current user, must match the propagator's
* user
* @param \OC\Files\Cache\ChangePropagator $changePropagator change propagator
* initialized with a view for $user
* @param \OCP\IConfig $config
*/
public function __construct($userId, $changePropagator, $config) {
$this->userId = $userId;
$this->changePropagator = $changePropagator;
$this->config = $config;
}

/**
* Propagate the etag changes for all shares marked as dirty and mark the shares as clean
*
* @param array $shares the shares for the users
* @param int $time
*/
public function propagateDirtyMountPoints(array $shares, $time = null) {
if ($time === null) {
$time = time();
}
$dirtyShares = $this->getDirtyShares($shares);
foreach ($dirtyShares as $share) {
$this->changePropagator->addChange($share['file_target']);
}
$this->config->setUserValue($this->userId, 'files_sharing', 'last_propagate', $time);
if (count($dirtyShares)) {
$this->changePropagator->propagateChanges($time);
}
}

/**
* Get all shares we need to update the etag for
*
* @param array $shares the shares for the users
* @return string[]
*/
protected function getDirtyShares($shares) {
$dirty = [];
$userTime = $this->config->getUserValue($this->userId, 'files_sharing', 'last_propagate', 0);
foreach ($shares as $share) {
$updateTime = $this->config->getAppValue('files_sharing', $share['id'], 0);
if ($updateTime >= $userTime) {
$dirty[] = $share;
}
}
return $dirty;
}

/**
* @param array $share
* @param int $time
*/
public function markDirty($share, $time = null) {
if ($time === null) {
$time = time();
}
$this->config->setAppValue('files_sharing', $share['id'], $time);
}

public static function writeHook($params) {
$path = $params['path'];
$fullPath = Filesystem::getView()->getAbsolutePath($path);
$mount = Filesystem::getView()->getMount($path);
if ($mount instanceof SharedMount) {
self::propagateForOwner($mount->getShare(), $mount->getInternalPath($fullPath), $mount->getOwnerPropagator());
}
}

/**
* @param array $share
* @param string $internalPath
* @param \OC\Files\Cache\ChangePropagator $propagator
*/
private static function propagateForOwner($share, $internalPath, ChangePropagator $propagator) {
// note that we have already set up the filesystem for the owner when mounting the share
$view = new View('/' . $share['uid_owner'] . '/files');

$shareRootPath = $view->getPath($share['item_source']);
if ($shareRootPath) {
$path = $shareRootPath . '/' . $internalPath;
$propagator->addChange($path);
$propagator->propagateChanges();
}
}

/**
* Listen on the propagator for updates made to shares owned by a user
*
* @param \OC\Files\Cache\ChangePropagator $propagator
* @param string $owner
*/
public function attachToPropagator(ChangePropagator $propagator, $owner) {
$shares = Share::getAllSharesForOwner($owner);
$propagator->listen('\OC\Files', 'propagate', function ($path, $entry) use ($shares) {
foreach ($shares as $share) {
if ((int)$share['file_source'] === $entry['fileid']) {
// make sure we also get child entries from group shares
// $sharesForFile = Share::
$this->markDirty($share, time());
}
}
});
}
}
18 changes: 18 additions & 0 deletions apps/files_sharing/lib/sharedmount.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ class SharedMount extends MountPoint implements MoveableMount {
*/
protected $storage = null;

/**
* @var \OC\Files\Cache\ChangePropagator
*/
protected $ownerPropagator;

public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
// first update the mount point before creating the parent
$this->ownerPropagator = $arguments['propagator'];
$newMountPoint = $this->verifyMountPoint($arguments['share'], $arguments['user']);
$absMountPoint = '/' . $arguments['user'] . '/files' . $newMountPoint;
parent::__construct($storage, $absMountPoint, $arguments, $loader);
Expand Down Expand Up @@ -159,4 +165,16 @@ public function removeMount() {

return $result;
}

public function getShare() {
$this->getStorage(); //ensure it exists
return $this->storage->getShare();
}

/**
* @return \OC\Files\Cache\ChangePropagator
*/
public function getOwnerPropagator() {
return $this->ownerPropagator;
}
}
43 changes: 33 additions & 10 deletions apps/files_sharing/lib/sharedstorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
*/

namespace OC\Files\Storage;

use OC\Files\Cache\ChangePropagator;
use OC\Files\Filesystem;
use OC\Files\View;
use OCA\Files_Sharing\ISharedStorage;
use OCA\Files_Sharing\Propagator;
use OCA\Files_Sharing\SharedMount;

/**
Expand All @@ -40,6 +44,7 @@ public function __construct($arguments) {

/**
* get id of the mount point
*
* @return string
*/
public function getId() {
Expand All @@ -48,14 +53,16 @@ public function getId() {

/**
* get file cache of the shared item source
*
* @return int
*/
public function getSourceId() {
return (int) $this->share['file_source'];
return (int)$this->share['file_source'];
}

/**
* Get the source file path, permissions, and owner for a shared file
*
* @param string $target Shared target file path
* @return Returns array with the keys path, permissions, and owner or false if not found
*/
Expand All @@ -79,6 +86,7 @@ public function getFile($target) {

/**
* Get the source file path for a shared file
*
* @param string $target Shared target file path
* @return string|false source file path or false if not found
*/
Expand All @@ -102,6 +110,7 @@ public function getSourcePath($target) {

/**
* Get the permissions granted for a shared file
*
* @param string $target Shared target file path
* @return int CRUDS permissions granted
*/
Expand Down Expand Up @@ -131,13 +140,14 @@ public function mkdir($path) {

/**
* 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)) {
if (empty($path)) {
return false;
}

Expand Down Expand Up @@ -270,6 +280,7 @@ public function file_put_contents($path, $data) {

/**
* Delete the file if DELETE permission is granted
*
* @param string $path
* @return boolean
*/
Expand Down Expand Up @@ -400,25 +411,33 @@ public static function setup($options) {
$shares = \OCP\Share::getItemsSharedWithUser('file', $options['user']);
$manager = Filesystem::getMountManager();
$loader = Filesystem::getLoader();
$view = Filesystem::getView();
$propagator = new Propagator($options['user'], new ChangePropagator($view), \OC::$server->getConfig());
if (!\OCP\User::isLoggedIn() || \OCP\User::getUser() != $options['user']
|| $shares
) {
$propagator->propagateDirtyMountPoints($shares);
foreach ($shares as $share) {
// don't mount shares where we have no permissions
if ($share['permissions'] > 0) {
$ownerPropagator = new ChangePropagator(new View('/' . $share['uid_owner'] . '/files'));
$mount = new SharedMount(
'\OC\Files\Storage\Shared',
$options['user_dir'] . '/' . $share['file_target'],
array(
'share' => $share,
'user' => $options['user']
),
$loader
);
'\OC\Files\Storage\Shared',
$options['user_dir'] . '/' . $share['file_target'],
array(
'propagator' => $ownerPropagator,
'share' => $share,
'user' => $options['user']
),
$loader
);
$propagator->attachToPropagator($ownerPropagator, $share['uid_owner']);
$manager->addMount($mount);
}
}
}
$propagator->attachToPropagator($view->getUpdater()->getPropagator(), $options['user']);
\OC_Hook::connect('OC_Filesystem', 'write', '\OCA\Files_Sharing\Propagator', 'writeHook');
}

/**
Expand All @@ -440,6 +459,7 @@ public function getShareType() {

/**
* does the group share already has a user specific unique name
*
* @return bool
*/
public function uniqueNameSet() {
Expand All @@ -457,6 +477,7 @@ public function setUniqueName() {

/**
* get share ID
*
* @return integer unique share ID
*/
public function getShareId() {
Expand All @@ -465,6 +486,7 @@ public function getShareId() {

/**
* get the user who shared the file
*
* @return string
*/
public function getSharedFrom() {
Expand All @@ -480,6 +502,7 @@ public function getShare() {

/**
* return share type, can be "file" or "folder"
*
* @return string
*/
public function getItemType() {
Expand Down

0 comments on commit 60df28b

Please sign in to comment.