Skip to content

Commit

Permalink
Merge pull request #5 from thornag/0.3
Browse files Browse the repository at this point in the history
0.3.2 - file permissions support
  • Loading branch information
michael-donat committed Nov 8, 2013
2 parents 84f13f9 + ddde644 commit 155b948
Show file tree
Hide file tree
Showing 8 changed files with 574 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
vendor
build
tmp
2 changes: 1 addition & 1 deletion src/VirtualFileSystem/Structure/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
abstract class Node
{
const S_IFMT = 0160000;
const DEF_MODE = 0000;
const DEF_MODE = 0755;

protected $basename;
protected $parent;
Expand Down
45 changes: 42 additions & 3 deletions src/VirtualFileSystem/Wrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use VirtualFileSystem\Structure\File;
use VirtualFileSystem\Wrapper\FileHandler;
use VirtualFileSystem\Wrapper\DirectoryHandler;
use VirtualFileSystem\Wrapper\PermissionHelper;

/**
* Stream wrapper class. This is the class that PHP uses as the stream operations handler.
Expand Down Expand Up @@ -145,29 +146,60 @@ public function stream_open($path, $mode, $options, &$opened_path)
return false;
}
$parent = $container->fileAt(dirname($path));
$ph = new PermissionHelper($parent);
if (!$ph->isWritable()) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('%s: failed to open stream: Permission denied', $path), E_USER_WARNING);
}
return false;
}
$parent->addFile($container->factory()->getFile(basename($path)));
}

$file = $container->fileAt($path);

if (($extended || $writeMode) && $file instanceof Directory) {
if (($extended || $writeMode || $appendMode) && $file instanceof Directory) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('fopen(%s): failed to open stream: Is a directory', $path), E_USER_WARNING);
}
return false;
}

if ($file instanceof Directory) {
$dir = $file;
$file = $container->factory()->getFile('tmp');
$file->chmod($dir->mode());
$file->chown($dir->user());
$file->chgrp($dir->group());
}

$permissionHelper = new PermissionHelper($file);

$this->currently_opened = new FileHandler();
$this->currently_opened->setFile($file);
if ($extended) {
if (!$permissionHelper->isReadable() or !$permissionHelper->isWritable()) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('fopen(%s): failed to open stream: Permission denied', $path), E_USER_WARNING);
}
return false;
}
$this->currently_opened->setReadWriteMode();
} elseif ($readMode) {
if (!$permissionHelper->isReadable()) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('fopen(%s): failed to open stream: Permission denied', $path), E_USER_WARNING);
}
return false;
}
$this->currently_opened->setReadOnlyMode();
} else { // a or w are for write only
if (!$permissionHelper->isWritable()) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('fopen(%s): failed to open stream: Permission denied', $path), E_USER_WARNING);
}
return false;
}
$this->currently_opened->setWriteOnlyMode();
}

Expand All @@ -193,7 +225,7 @@ public function stream_open($path, $mode, $options, &$opened_path)
*/
public function stream_write($data)
{
if (!$this->currently_opened->isWritable()) {
if (!$this->currently_opened->isOpenedForWriting()) {
return false;
}
//file access time changes so stat cache needs to be cleared
Expand Down Expand Up @@ -253,7 +285,7 @@ public function url_stat($path, $flags)
*/
public function stream_read($bytes)
{
if (!$this->currently_opened->isReadable()) {
if (!$this->currently_opened->isOpenedForReading()) {
return null;
}
$data = $this->currently_opened->read($bytes);
Expand Down Expand Up @@ -542,6 +574,13 @@ public function dir_opendir($path, $options)
return false;
}

$permissionHelper = new PermissionHelper($dir);

if (!$permissionHelper->isReadable()) {
trigger_error(sprintf('opendir(%s): failed to open dir: Permission denied', $path), E_USER_WARNING);
return false;
}

$this->currently_opened = new DirectoryHandler();
$this->currently_opened->setDirectory($dir);

Expand Down
4 changes: 2 additions & 2 deletions src/VirtualFileSystem/Wrapper/FileHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public function setWriteOnlyMode()
*
* @return bool
*/
public function isWritable()
public function isOpenedForWriting()
{
return (bool)($this->mode & self::WRITE_MODE);
}
Expand All @@ -183,7 +183,7 @@ public function isWritable()
*
* @return bool
*/
public function isReadable()
public function isOpenedForReading()
{
return (bool)($this->mode & self::READ_MODE);
}
Expand Down
136 changes: 136 additions & 0 deletions src/VirtualFileSystem/Wrapper/PermissionHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

namespace VirtualFileSystem\Wrapper;


use VirtualFileSystem\Structure\Node;

class PermissionHelper
{
const MODE_USER_READ = 0400;
const MODE_USER_WRITE = 0200;

const MODE_GROUP_READ = 0040;
const MODE_GROUP_WRITE = 0020;

const MODE_WORLD_READ = 0004;
const MODE_WORLD_WRITE = 0002;

/**
* @var Node
*/
protected $node;

protected $userid;
protected $groupid;

/**
* @param Node $node
*/
public function __construct(Node $node)
{
$this->node = $node;
$this->userid = posix_getuid();
$this->groupid = posix_getgid();
}

/**
* Checks whether user_id on file is the same as executing user
*
* @return bool
*/
public function userIsOwner()
{
return (bool)($this->userid == $this->node->user());
}

/**
* Checks whether file is readable for user
*
* @return bool
*/
public function userCanRead()
{
return $this->userIsOwner() && ($this->node->mode() & self::MODE_USER_READ);
}

/**
* Checks whether file is writable for user
*
* @return bool
*/
public function userCanWrite()
{
return $this->userIsOwner() && ($this->node->mode() & self::MODE_USER_WRITE);
}

/**
* Checks whether group_id on file is the same as executing user
*
* @return bool
*/
public function groupIsOwner()
{
return (bool)($this->groupid == $this->node->group());
}

/**
* Checks whether file is readable for group
*
* @return bool
*/
public function groupCanRead()
{
return $this->groupIsOwner() && ($this->node->mode() & self::MODE_GROUP_READ);
}

/**
* Checks whether file is writable for group
*
* @return bool
*/
public function groupCanWrite()
{
return $this->groupIsOwner() && ($this->node->mode() & self::MODE_GROUP_WRITE);
}

/**
* Checks whether file is readable for world
*
* @return bool
*/
public function worldCanRead()
{
return (bool)($this->node->mode() & self::MODE_WORLD_READ);
}

/**
* Checks whether file is writable for world
*
* @return bool
*/
public function worldCanWrite()
{
return (bool)($this->node->mode() & self::MODE_WORLD_WRITE);
}

/**
* Checks whether file is readable (by user, group or world)
*
* @return bool
*/
public function isReadable()
{
return $this->userCanRead() || $this->groupCanRead() || $this->worldCanRead();
}

/**
* Checks whether file is writable (by user, group or world)
*
* @return bool
*/
public function isWritable()
{
return $this->userCanWrite() || $this->groupCanWrite() || $this->worldCanWrite();
}
}
2 changes: 1 addition & 1 deletion tests/VirtualFileSystem/Structure/NodeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function testChmod()
{
$file = new File('file');

$this->assertEquals(0000 | File::S_IFTYPE, $file->mode());
$this->assertEquals(Node::DEF_MODE | File::S_IFTYPE, $file->mode());

$file->chmod(0200);
$this->assertEquals(0200 | File::S_IFTYPE, $file->mode());
Expand Down
Loading

0 comments on commit 155b948

Please sign in to comment.