parent
3a1994d001
commit
5365ae416e
@ -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; |
||||
} |
||||
|
||||
|
||||
} |
||||
@ -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"; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue