Skip to content

Commit

Permalink
Merge pull request #11305 from owncloud/ext-updateetagonmount
Browse files Browse the repository at this point in the history
Update etag of parent dir when adding/removing ext storage mount points
  • Loading branch information
Vincent Petry committed Oct 9, 2014
2 parents c82e310 + 26e242a commit 9dea79e
Show file tree
Hide file tree
Showing 7 changed files with 653 additions and 1 deletion.
45 changes: 44 additions & 1 deletion apps/files_external/lib/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,22 @@ public static function initMountPointsHook($data) {
}
$manager->addMount($mount);
}

if ($data['user']) {
$user = \OC::$server->getUserManager()->get($data['user']);
$userView = new \OC\Files\View('/' . $user->getUID() . '/files');
$changePropagator = new \OC\Files\Cache\ChangePropagator($userView);
$etagPropagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, \OC::$server->getConfig());
$etagPropagator->propagateDirtyMountPoints();
\OCP\Util::connectHook(
\OC\Files\Filesystem::CLASSNAME,
\OC\Files\Filesystem::signal_create_mount,
$etagPropagator, 'updateHook');
\OCP\Util::connectHook(
\OC\Files\Filesystem::CLASSNAME,
\OC\Files\Filesystem::signal_delete_mount,
$etagPropagator, 'updateHook');
}
}

/**
Expand Down Expand Up @@ -463,6 +479,7 @@ public static function addMountPoint($mountPoint,
$priority = null) {
$backends = self::getBackends();
$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
$relMountPoint = $mountPoint;
if ($mountPoint === '' || $mountPoint === '/') {
// can't mount at root folder
return false;
Expand Down Expand Up @@ -495,6 +512,10 @@ public static function addMountPoint($mountPoint,
}

$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : NULL);
// who else loves multi-dimensional array ?
$isNew = !isset($mountPoints[$mountType]) ||
!isset($mountPoints[$mountType][$applicable]) ||
!isset($mountPoints[$mountType][$applicable][$mountPoint]);
$mountPoints = self::mergeMountPoints($mountPoints, $mount, $mountType);

// Set default priority if none set
Expand All @@ -510,7 +531,19 @@ public static function addMountPoint($mountPoint,

self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);

return self::getBackendStatus($class, $classOptions, $isPersonal);
$result = self::getBackendStatus($class, $classOptions, $isPersonal);
if ($result && $isNew) {
\OC_Hook::emit(
\OC\Files\Filesystem::CLASSNAME,
\OC\Files\Filesystem::signal_create_mount,
array(
\OC\Files\Filesystem::signal_param_path => $relMountPoint,
\OC\Files\Filesystem::signal_param_mount_type => $mountType,
\OC\Files\Filesystem::signal_param_users => $applicable,
)
);
}
return $result;
}

/**
Expand All @@ -523,6 +556,7 @@ public static function addMountPoint($mountPoint,
*/
public static function removeMountPoint($mountPoint, $mountType, $applicable, $isPersonal = false) {
// Verify that the mount point applies for the current user
$relMountPoints = $mountPoint;
if ($isPersonal) {
if ($applicable != OCP\User::getUser()) {
return false;
Expand All @@ -543,6 +577,15 @@ public static function removeMountPoint($mountPoint, $mountType, $applicable, $i
}
}
self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);
\OC_Hook::emit(
\OC\Files\Filesystem::CLASSNAME,
\OC\Files\Filesystem::signal_delete_mount,
array(
\OC\Files\Filesystem::signal_param_path => $relMountPoints,
\OC\Files\Filesystem::signal_param_mount_type => $mountType,
\OC\Files\Filesystem::signal_param_users => $applicable,
)
);
return true;
}

Expand Down
126 changes: 126 additions & 0 deletions apps/files_external/lib/etagpropagator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?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_External;

use OC\Files\Filesystem;

/**
* Updates the etag of parent folders whenever a new external storage mount
* point has been created or deleted. Updates need to be triggered using
* the updateHook() method.
*
* There are two modes of operation:
* - for personal mount points, the etag is propagated directly
* - for system mount points, a dirty flag is saved in the configuration and
* the etag will be updated the next time propagateDirtyMountPoints() is called
*/
class EtagPropagator {
/**
* @var \OCP\IUser
*/
protected $user;

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

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

/**
* @param \OCP\IUser $user 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($user, $changePropagator, $config) {
$this->user = $user;
$this->changePropagator = $changePropagator;
$this->config = $config;
}

/**
* Propagate the etag changes for all mountpoints marked as dirty and mark the mountpoints as clean
*
* @param int $time
*/
public function propagateDirtyMountPoints($time = null) {
if ($time === null) {
$time = time();
}
$mountPoints = $this->getDirtyMountPoints();
foreach ($mountPoints as $mountPoint) {
$this->changePropagator->addChange($mountPoint);
$this->config->setUserValue($this->user->getUID(), 'files_external', $mountPoint, $time);
}
if (count($mountPoints)) {
$this->changePropagator->propagateChanges($time);
}
}

/**
* Get all mountpoints we need to update the etag for
*
* @return string[]
*/
protected function getDirtyMountPoints() {
$dirty = array();
$mountPoints = $this->config->getAppKeys('files_external');
foreach ($mountPoints as $mountPoint) {
if (substr($mountPoint, 0, 1) === '/') {
$updateTime = $this->config->getAppValue('files_external', $mountPoint);
$userTime = $this->config->getUserValue($this->user->getUID(), 'files_external', $mountPoint);
if ($updateTime > $userTime) {
$dirty[] = $mountPoint;
}
}
}
return $dirty;
}

/**
* @param string $mountPoint
* @param int $time
*/
protected function markDirty($mountPoint, $time = null) {
if ($time === null) {
$time = time();
}
$this->config->setAppValue('files_external', $mountPoint, $time);
}

/**
* Update etags for mount points for known user
* For global or group mount points, updating the etag for every user is not feasible
* instead we mark the mount point as dirty and update the etag when the filesystem is loaded for the user
* For personal mount points, the change is propagated directly
*
* @param array $params hook parameters
* @param int $time update time to use when marking a mount point as dirty
*/
public function updateHook($params, $time = null) {
if ($time === null) {
$time = time();
}
$users = $params[Filesystem::signal_param_users];
$type = $params[Filesystem::signal_param_mount_type];
$mountPoint = $params[Filesystem::signal_param_path];
$mountPoint = Filesystem::normalizePath($mountPoint);
if ($type === \OC_Mount_Config::MOUNT_TYPE_GROUP or $users === 'all') {
$this->markDirty($mountPoint, $time);
} else {
$this->changePropagator->addChange($mountPoint);
$this->changePropagator->propagateChanges($time);
}
}
}
Loading

0 comments on commit 9dea79e

Please sign in to comment.