Skip to content

Commit

Permalink
Merge pull request #33 from mathroc/feature/flock
Browse files Browse the repository at this point in the history
Add flock support
  • Loading branch information
michael-donat committed Sep 13, 2014
2 parents d5e33b4 + dfe6ec9 commit ccd513b
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 0 deletions.
59 changes: 59 additions & 0 deletions src/VirtualFileSystem/Structure/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

namespace VirtualFileSystem\Structure;

use SplObjectStorage;

/**
* Object representation of File.
*
Expand All @@ -25,6 +27,27 @@ class File extends Node

protected $data;

/**
* Resource with exclusive lock on this file
* @var resource|null
*/
private $exclusiveLock = null;

/**
* Resources with a shared lock on this file
* @var SplObjectStorage
*/
private $sharedLock;

/**
* @inherit
*/
public function __construct($basename)
{
parent::__construct($basename);
$this->sharedLock = new SplObjectStorage;
}

/**
* Returns contents size.
*
Expand Down Expand Up @@ -55,4 +78,40 @@ public function setData($data)
{
$this->data = $data;
}

public function lock($resource, $operation)
{
if ($this->exclusiveLock === $resource) {
$this->exclusiveLock = null;
} else {
$this->sharedLock->detach($resource);
}

if ($operation & LOCK_NB) {
$operation -= LOCK_NB;
}

$unlock = $operation === LOCK_UN;
$exclusive = $operation === LOCK_EX;

if ($unlock) {
return true;
}

if ($this->exclusiveLock !== null) {
return false;
}

if (!$exclusive) {
$this->sharedLock->attach($resource);
return true;
}

if ($this->sharedLock->count()) {
return false;
}

$this->exclusiveLock = $resource;
return true;
}
}
5 changes: 5 additions & 0 deletions src/VirtualFileSystem/Wrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -768,4 +768,9 @@ public function dir_rewinddir()
{
$this->currentlyOpenedDir->iterator()->rewind();
}

public function stream_lock($operation)
{
return $this->currently_opened->lock($this, $operation);
}
}
5 changes: 5 additions & 0 deletions src/VirtualFileSystem/Wrapper/FileHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,9 @@ public function isOpenedForReading()
{
return (bool) ($this->mode & self::READ_MODE);
}

public function lock($resource, $operation)
{
return $this->file->lock($resource, $operation);
}
}
1 change: 1 addition & 0 deletions tests/VirtualFileSystem/Wrapper/FileHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace VirtualFileSystem\Wrapper;

use VirtualFileSystem\Structure\File;
use stdClass;

class FileHandlerTest extends \PHPUnit_Framework_TestCase
{
Expand Down
91 changes: 91 additions & 0 deletions tests/VirtualFileSystem/WrapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1352,4 +1352,95 @@ public function testIsExecutableReturnsCorrectly()

$this->assertTrue(is_executable($fs->path('/file')));
}

public function testExclusiveLock()
{
$fs = new FileSystem();
$file = $fs->path($fs->createFile('/file')->path());

$fh1 = fopen($file, 'c');
$fh2 = fopen($file, 'c');

$this->assertTrue(flock($fh1, LOCK_EX|LOCK_NB));
$this->assertFalse(flock($fh2, LOCK_EX|LOCK_NB));
}

public function testSharedLock()
{
$fs = new FileSystem();
$file = $fs->path($fs->createFile('/file')->path());

$fh1 = fopen($file, 'c');
$fh2 = fopen($file, 'c');
$fh3 = fopen($file, 'c');

$this->assertTrue(flock($fh1, LOCK_SH|LOCK_NB));
$this->assertTrue(flock($fh2, LOCK_SH|LOCK_NB));
$this->assertFalse(flock($fh3, LOCK_EX|LOCK_NB));
}

public function testUnlockSharedLock()
{
$fs = new FileSystem();
$file = $fs->path($fs->createFile('/file')->path());

$fh1 = fopen($file, 'c');
$fh2 = fopen($file, 'c');

$this->assertTrue(flock($fh1, LOCK_SH|LOCK_NB));
$this->assertTrue(flock($fh1, LOCK_UN|LOCK_NB));
$this->assertTrue(flock($fh2, LOCK_EX|LOCK_NB));
}

public function testUnlockExclusiveLock()
{
$fs = new FileSystem();
$file = $fs->path($fs->createFile('/file')->path());

$fh1 = fopen($file, 'c');
$fh2 = fopen($file, 'c');

$this->assertTrue(flock($fh1, LOCK_EX|LOCK_NB));
$this->assertTrue(flock($fh1, LOCK_UN|LOCK_NB));
$this->assertTrue(flock($fh2, LOCK_EX|LOCK_NB));
}

public function testDowngradeExclusiveLock()
{
$fs = new FileSystem();
$file = $fs->path($fs->createFile('/file')->path());

$fh1 = fopen($file, 'c');
$fh2 = fopen($file, 'c');

$this->assertTrue(flock($fh1, LOCK_EX|LOCK_NB));
$this->assertTrue(flock($fh1, LOCK_SH|LOCK_NB));
$this->assertTrue(flock($fh2, LOCK_SH|LOCK_NB));
}

public function testUpgradeSharedLock()
{
$fs = new FileSystem();
$file = $fs->path($fs->createFile('/file')->path());

$fh1 = fopen($file, 'c');
$fh2 = fopen($file, 'c');

$this->assertTrue(flock($fh1, LOCK_SH|LOCK_NB));
$this->assertTrue(flock($fh1, LOCK_EX|LOCK_NB));
$this->assertFalse(flock($fh2, LOCK_SH|LOCK_NB));
}

public function testUpgradeSharedLockImpossible()
{
$fs = new FileSystem();
$file = $fs->path($fs->createFile('/file')->path());

$fh1 = fopen($file, 'c');
$fh2 = fopen($file, 'c');

$this->assertTrue(flock($fh1, LOCK_SH|LOCK_NB));
$this->assertTrue(flock($fh2, LOCK_SH|LOCK_NB));
$this->assertFalse(flock($fh1, LOCK_EX|LOCK_NB));
}
}

0 comments on commit ccd513b

Please sign in to comment.