flock changes. Work in progress.
This commit is contained in:
parent
3a1994d001
commit
5365ae416e
|
@ -103,5 +103,4 @@ abstract class StreamWrapper extends Common {
|
||||||
public function stat($path) {
|
public function stat($path) {
|
||||||
return stat($this->constructUrl($path));
|
return stat($this->constructUrl($path));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,5 +279,19 @@ if (\OC_Util::runningOnWindows()) {
|
||||||
public function isLocal() {
|
public function isLocal() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a lock on a file
|
||||||
|
*/
|
||||||
|
public function getLock($path, $lockType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release an existing lock
|
||||||
|
*/
|
||||||
|
public function releaseLock($path) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2013 ownCloud, Inc.
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OC\Files\Storage\Wrapper;
|
||||||
|
|
||||||
|
use OC\Files\Filesystem;
|
||||||
|
use OCP\Files\LockNotAcquiredException;
|
||||||
|
use OCP\Files\Lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class LockingWrapper
|
||||||
|
* A Storage Wrapper used to lock files at the system level
|
||||||
|
* @package OC\Files\Storage\Wrapper
|
||||||
|
*
|
||||||
|
* Notes: Does the $locks array need to be global to all LockingWrapper instances, such as in the case of two paths
|
||||||
|
* that point to the same physical file? Otherwise accessing the file from a different path the second time would show
|
||||||
|
* the file as locked, even though this process is the one locking it.
|
||||||
|
*/
|
||||||
|
class LockingWrapper extends Wrapper {
|
||||||
|
|
||||||
|
/** @var array $locks Holds an array of lock instances indexed by path for this storage */
|
||||||
|
protected $locks = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a lock on a file
|
||||||
|
* @param string $path Path to file, relative to this storage
|
||||||
|
* @param integer $lockType A Lock class constant, Lock::READ/Lock::WRITE
|
||||||
|
* @return bool|\OCP\Files\Lock Lock instance on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function getLock($path, $lockType){
|
||||||
|
$path = Filesystem::normalizePath($path);
|
||||||
|
if(!isset($this->locks[$path])) {
|
||||||
|
$this->locks[$path] = new Lock($path);
|
||||||
|
}
|
||||||
|
$this->locks[$path]->addLock($lockType);
|
||||||
|
return $this->locks[$path];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release an existing lock
|
||||||
|
* @param string $path Path to file, relative to this storage
|
||||||
|
* @return bool true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function releaseLock($path, $lockType, $releaseAll = false){
|
||||||
|
$path = Filesystem::normalizePath($path);
|
||||||
|
if(isset($this->locks[$path])) {
|
||||||
|
if($releaseAll) {
|
||||||
|
return $this->locks[$path]->releaseAll();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $this->locks[$path]->release($lockType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see http://php.net/manual/en/function.file_get_contents.php
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function file_get_contents($path) {
|
||||||
|
try {
|
||||||
|
if (!$this->getLock($path, Lock::READ)) {
|
||||||
|
throw new LockNotAcquiredException($path, Lock::READ);
|
||||||
|
}
|
||||||
|
$result = $this->storage->file_get_contents($path);
|
||||||
|
}
|
||||||
|
catch(\Exception $originalException) {
|
||||||
|
// Need to release the lock before more operations happen in upstream exception handlers
|
||||||
|
$this->releaseLock($path, Lock::READ);
|
||||||
|
throw $originalException;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function file_put_contents($path, $data) {
|
||||||
|
try {
|
||||||
|
if (!$this->getLock($path, Lock::WRITE)) {
|
||||||
|
throw new LockNotAcquiredException($path, Lock::WRITE);
|
||||||
|
}
|
||||||
|
$result = $this->storage->file_put_contents($path, $data);
|
||||||
|
}
|
||||||
|
catch(\Exception $originalException) {
|
||||||
|
// Release lock, throw original exception
|
||||||
|
$this->releaseLock($path, Lock::WRITE);
|
||||||
|
throw $originalException;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function copy($path1, $path2) {
|
||||||
|
try {
|
||||||
|
if (!$this->getLock($path1, Lock::READ)) {
|
||||||
|
throw new LockNotAcquiredException($path1, Lock::READ);
|
||||||
|
}
|
||||||
|
if (!$this->getLock($path2, Lock::WRITE)) {
|
||||||
|
throw new LockNotAcquiredException($path2, Lock::WRITE);
|
||||||
|
}
|
||||||
|
$result = $this->storage->copy($path1, $path2);
|
||||||
|
}
|
||||||
|
catch(\Exception $originalException) {
|
||||||
|
// Release locks, throw original exception
|
||||||
|
$this->releaseLock($path1, Lock::READ);
|
||||||
|
$this->releaseLock($path2, Lock::WRITE);
|
||||||
|
throw $originalException;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rename($path1, $path2) {
|
||||||
|
try {
|
||||||
|
if (!$this->getLock($path1, Lock::READ)) {
|
||||||
|
throw new LockNotAcquiredException($path1, Lock::READ);
|
||||||
|
}
|
||||||
|
if (!$this->getLock($path2, Lock::WRITE)) {
|
||||||
|
throw new LockNotAcquiredException($path2, Lock::WRITE);
|
||||||
|
}
|
||||||
|
$result = $this->storage->rename($path1, $path2);
|
||||||
|
}
|
||||||
|
catch(\Exception $originalException) {
|
||||||
|
// Release locks, throw original exception
|
||||||
|
$this->releaseLock($path1, Lock::READ);
|
||||||
|
$this->releaseLock($path2, Lock::WRITE);
|
||||||
|
throw $originalException;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -71,6 +71,16 @@ class OC_Util {
|
||||||
return $storage;
|
return $storage;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set up flock
|
||||||
|
\OC\Files\Filesystem::addStorageWrapper(function($mountPoint, /** @var \OC\Files\Storage\Storage|null $storage */ $storage){
|
||||||
|
// lock files on all local storage
|
||||||
|
if ($storage instanceof \OC\Files\Storage\Storage && $storage->isLocal()) {
|
||||||
|
return new \OC\Files\Storage\Wrapper\LockingWrapper(array('storage' => $storage));
|
||||||
|
} else {
|
||||||
|
return $storage;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$userDir = '/'.$user.'/files';
|
$userDir = '/'.$user.'/files';
|
||||||
$userRoot = OC_User::getHome($user);
|
$userRoot = OC_User::getHome($user);
|
||||||
$userDirectory = $userRoot . '/files';
|
$userDirectory = $userRoot . '/files';
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCP\Files;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Lock
|
||||||
|
* @package OC\Files
|
||||||
|
*/
|
||||||
|
class Lock {
|
||||||
|
const READ = 1;
|
||||||
|
const WRITE = 2;
|
||||||
|
|
||||||
|
/** @var string $path Filename of the file as represented in storage */
|
||||||
|
protected $path;
|
||||||
|
|
||||||
|
public function __construct($path) {
|
||||||
|
$this->path = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addLock($lockType) {
|
||||||
|
// This class is a stub/base for classes that implement locks
|
||||||
|
// We don't actually care what kind of lock we're queuing here
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release locks on handles and files
|
||||||
|
*/
|
||||||
|
public function release($lockType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public interface of ownCloud for apps to use.
|
||||||
|
* Files/LockNotAcquiredException class
|
||||||
|
*/
|
||||||
|
|
||||||
|
// use OCP namespace for all classes that are considered public.
|
||||||
|
// This means that they should be used by apps instead of the internal ownCloud classes
|
||||||
|
namespace OCP\Files;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for a file that is locked
|
||||||
|
*/
|
||||||
|
class LockNotAcquiredException extends \Exception {
|
||||||
|
/** @var string $path The path that could not be locked */
|
||||||
|
public $path;
|
||||||
|
|
||||||
|
/** @var integer $lockType The type of the lock that was attempted */
|
||||||
|
public $lockType;
|
||||||
|
|
||||||
|
public function __construct($path, $lockType, $code = 0, \Exception $previous = null) {
|
||||||
|
$message = \OC_L10N::get('core')->t('Could not obtain lock type %d on "%s".', array($lockType, $path));
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom string representation of object
|
||||||
|
public function __toString() {
|
||||||
|
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ namespace OCP\Files;
|
||||||
* All paths passed to the storage are relative to the storage and should NOT have a leading slash.
|
* All paths passed to the storage are relative to the storage and should NOT have a leading slash.
|
||||||
*/
|
*/
|
||||||
interface Storage {
|
interface Storage {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $parameters is a free form array with the configuration options needed to construct the storage
|
* $parameters is a free form array with the configuration options needed to construct the storage
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue