Add option to set file modes

This commit is contained in:
Robin Appelman 2014-08-03 14:28:20 +02:00
commit 3888ae6b43
9 changed files with 235 additions and 89 deletions

View file

@ -19,6 +19,7 @@ class FileInfo implements IFileInfo {
const MODE_VOLUME_ID = 0x08;
const MODE_DIRECTORY = 0x10;
const MODE_ARCHIVE = 0x20;
const MODE_NORMAL = 0x80;
/**
* @var string
@ -108,4 +109,18 @@ class FileInfo implements IFileInfo {
public function isHidden() {
return (bool)($this->mode & self::MODE_HIDDEN);
}
/**
* @return bool
*/
public function isSystem() {
return (bool)($this->mode & self::MODE_SYSTEM);
}
/**
* @return bool
*/
public function isArchived() {
return (bool)($this->mode & self::MODE_ARCHIVE);
}
}

View file

@ -42,4 +42,14 @@ interface IFileInfo {
* @return bool
*/
public function isHidden();
/**
* @return bool
*/
public function isSystem();
/**
* @return bool
*/
public function isArchived();
}

View file

@ -87,16 +87,6 @@ interface IShare {
/**
* List the content of a remote folder
*
* Returns a nested array in the format of
* [
* $name => [
* 'size' => $size,
* 'type' => $type,
* 'time' => $mtime
* ],
* ...
* ]
*
* @param $path
* @return \Icewind\SMB\IFileInfo[]
*
@ -105,6 +95,14 @@ interface IShare {
*/
public function dir($path);
/**
* @param string $path
* @return \Icewind\SMB\IFileInfo
*
* @throws \Icewind\SMB\NotFoundException
*/
public function stat($path);
/**
* Create a folder on the share
*
@ -126,4 +124,11 @@ interface IShare {
* @throws \Icewind\SMB\InvalidTypeException
*/
public function rmdir($path);
/**
* @param string $path
* @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL
* @return mixed
*/
public function setMode($path, $mode);
}

View file

@ -65,7 +65,7 @@ class NativeFileInfo implements IFileInfo {
*/
protected function stat() {
if (!$this->statCache) {
$this->statCache = $this->share->stat($this->getPath());
$this->statCache = $this->share->getStat($this->getPath());
}
return $this->statCache;
}
@ -119,4 +119,20 @@ class NativeFileInfo implements IFileInfo {
$mode = $this->getMode();
return (bool)($mode & FileInfo::MODE_HIDDEN);
}
/**
* @return bool
*/
public function isSystem() {
$mode = $this->getMode();
return (bool)($mode & FileInfo::MODE_SYSTEM);
}
/**
* @return bool
*/
public function isArchived() {
$mode = $this->getMode();
return (bool)($mode & FileInfo::MODE_ARCHIVE);
}
}

View file

@ -96,7 +96,15 @@ class NativeShare implements IShare {
return $files;
}
/**
* @param string $path
* @return \Icewind\SMB\IFileInfo[]
*/
public function stat($path) {
return new NativeFileInfo($this, $path, basename($path));
}
public function getStat($path) {
$this->connect();
return $this->state->stat($this->buildUrl($path));
}
@ -250,6 +258,33 @@ class NativeShare implements IShare {
return $result;
}
/**
* Get extended attributes for the path
*
* @param string $path
* @param string $attribute attribute to get the info
* @param mixed $value
* @return string the attribute value
*/
public function setAttribute($path, $attribute, $value) {
$this->connect();
if ($attribute === 'system.dos_attr.mode' and is_int($value)) {
$value = '0x' . dechex($value);
}
return $this->state->setxattr($this->buildUrl($path), $attribute, $value);
}
/**
* @param string $path
* @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL
* @return mixed
*/
public function setMode($path, $mode) {
return $this->setAttribute($path, 'system.dos_attr.mode', $mode);
}
public function __destruct() {
unset($this->state);
}

View file

@ -32,13 +32,7 @@ class NativeState {
return;
}
$this->handlerSet = true;
$state = $this;
set_error_handler(function ($errorNumber, $errorString) use ($state) {
/**
* @var \Icewind\SMB\NativeState $state
*/
$state->handleError($errorString);
});
set_error_handler(array($this, 'handleError'));
}
protected function restoreErrorHandler() {
@ -49,7 +43,7 @@ class NativeState {
restore_error_handler();
}
protected function handleError($errorString = '') {
protected function handleError($errorNumber = 0, $errorString = '') {
$error = smbclient_state_errno($this->state);
switch ($error) {
// see error.h
@ -343,60 +337,6 @@ class NativeState {
return $result;
}
/**
* @param string $uri
* @param string $mode
* @return bool
*/
public function chmod($uri, $mode) {
$this->setErrorHandler();
$result = smbclient_chmod($this->state, $uri, $mode);
$this->restoreErrorHandler();
if ($result === false) {
$this->handleError();
}
return $result;
}
/**
* @param string $uri
* @param int $mtime
* @param int $atime
* @return bool
*/
public function utimes($uri, $mtime = null, $atime = null) {
if ($mtime = null) {
$mtime = time();
}
if ($atime = null) {
$atime = $mtime;
}
$this->setErrorHandler();
$result = smbclient_utimes($this->state, $uri, $mtime, $atime);
$this->restoreErrorHandler();
if ($result === false) {
$this->handleError();
}
return $result;
}
/**
* @param string $uri
* @return array
*/
public function listxattr($uri) {
$this->setErrorHandler();
$result = smbclient_listxattr($this->state, $uri);
$this->restoreErrorHandler();
if ($result === false) {
$this->handleError();
}
return $result;
}
/**
* @param string $uri
* @param string $key
@ -431,22 +371,6 @@ class NativeState {
return $result;
}
/**
* @param string $uri
* @param string $key
* @return bool
*/
public function removexattr($uri, $key) {
$this->setErrorHandler();
$result = smbclient_removexattr($this->state, $uri, $key);
$this->restoreErrorHandler();
if ($result === false) {
$this->handleError();
}
return $result;
}
public function __destruct() {
if ($this->connected) {
smbclient_state_free($this->state);

View file

@ -112,6 +112,34 @@ class Share implements IShare {
return $content;
}
/**
* @param string $path
* @return \Icewind\SMB\IFileInfo[]
*/
public function stat($path) {
$escapedPath = $this->escapePath($path);
$output = $this->execute('allinfo ' . $escapedPath);
if (count($output) < 3) {
$this->parseOutput($output);
}
$mtime = 0;
$mode = 0;
$size = 0;
foreach ($output as $line) {
list($name, $value) = explode(':', $line, 2);
$value = trim($value);
if ($name === 'write_time') {
$mtime = $value;
} else if ($name === 'attributes') {
$mode = $this->parseMode($value);
} else if ($name === 'stream') {
list(, $size,) = explode(' ', $value);
$size = intval($size);
}
}
return new FileInfo($path, basename($path), $size, $mtime, $mode);
}
/**
* Create a folder on the share
*
@ -271,6 +299,37 @@ class Share implements IShare {
});
}
/**
* @param string $path
* @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL
* @return mixed
*/
public function setMode($path, $mode) {
$modeString = '';
if ($mode & FileInfo::MODE_READONLY) {
$modeString .= 'r';
}
if ($mode & FileInfo::MODE_HIDDEN) {
$modeString .= 'h';
}
if ($mode & FileInfo::MODE_ARCHIVE) {
$modeString .= 'a';
}
if ($mode & FileInfo::MODE_SYSTEM) {
$modeString .= 's';
}
$path = $this->escapePath($path);
// first reset the mode to normal
$cmd = 'setmode ' . $path . ' -rsha';
$output = $this->execute($cmd);
// then set the modes we want
$cmd = 'setmode ' . $path . ' ' . $modeString;
$output = $this->execute($cmd);
return $this->parseOutput($output);
}
/**
* @param string $mode
* @return string