PK ?V}\ phpunit.xml.distnu W+A
test
lib
PK ?V#Cz z lib/ParallelDriver.phpnu W+A pool = $pool ?: Worker\pool();
}
/**
* {@inheritdoc}
*/
public function open(string $path, string $mode): Promise {
return call(function () use ($path, $mode) {
$worker = $this->pool->get();
try {
list($id, $size, $mode) = yield $worker->enqueue(new Internal\FileTask("fopen", [$path, $mode]));
} catch (TaskException $exception) {
throw new FilesystemException("Could not open file", $exception);
} catch (WorkerException $exception) {
throw new FilesystemException("Could not send open request to worker", $exception);
}
return new ParallelHandle($worker, $id, $path, $size, $mode);
});
}
private function runFileTask(Internal\FileTask $task): \Generator {
try {
return yield $this->pool->enqueue($task);
} catch (TaskException $exception) {
throw new FilesystemException("The file operation failed", $exception);
} catch (WorkerException $exception) {
throw new FilesystemException("Could not send the file task to worker", $exception);
}
}
/**
* {@inheritdoc}
*/
public function unlink(string $path): Promise {
return call(function () use ($path) {
$result = yield from $this->runFileTask(new Internal\FileTask("unlink", [$path]));
StatCache::clear($path);
return $result;
});
}
/**
* {@inheritdoc}
*/
public function stat(string $path): Promise {
if ($stat = StatCache::get($path)) {
return new Success($stat);
}
return call(function () use ($path) {
$stat = yield from $this->runFileTask(new Internal\FileTask("stat", [$path]));
if (!empty($stat)) {
StatCache::set($path, $stat);
}
return $stat;
});
}
/**
* {@inheritdoc}
*/
public function rename(string $from, string $to): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("rename", [$from, $to])));
}
/**
* {@inheritdoc}
*/
public function isfile(string $path): Promise {
return call(function () use ($path) {
$stat = yield $this->stat($path);
if (empty($stat)) {
return false;
}
if ($stat["mode"] & 0100000) {
return true;
}
return false;
});
}
/**
* {@inheritdoc}
*/
public function isdir(string $path): Promise {
return call(function () use ($path) {
$stat = yield $this->stat($path);
if (empty($stat)) {
return false;
}
if ($stat["mode"] & 0040000) {
return true;
}
return false;
});
}
/**
* {@inheritdoc}
*/
public function link(string $target, string $link): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("link", [$target, $link])));
}
/**
* {@inheritdoc}
*/
public function symlink(string $target, string $link): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("symlink", [$target, $link])));
}
/**
* {@inheritdoc}
*/
public function readlink(string $path): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("readlink", [$path])));
}
/**
* {@inheritdoc}
*/
public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("mkdir", [$path, $mode, $recursive])));
}
/**
* {@inheritdoc}
*/
public function scandir(string $path): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("scandir", [$path])));
}
/**
* {@inheritdoc}
*/
public function rmdir(string $path): Promise {
return call(function () use ($path) {
$result = yield from $this->runFileTask(new Internal\FileTask("rmdir", [$path]));
StatCache::clear($path);
return $result;
});
}
/**
* {@inheritdoc}
*/
public function chmod(string $path, int $mode): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("chmod", [$path, $mode])));
}
/**
* {@inheritdoc}
*/
public function chown(string $path, int $uid, int $gid): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("chown", [$path, $uid, $gid])));
}
/**
* {@inheritdoc}
*/
public function exists(string $path): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("exists", [$path])));
}
/**
* {@inheritdoc}
*/
public function size(string $path): Promise {
return call(function () use ($path) {
$stat = yield $this->stat($path);
if (empty($stat)) {
throw new FilesystemException("Specified path does not exist");
}
if ($stat["mode"] & 0100000) {
return $stat["size"];
}
throw new FilesystemException("Specified path is not a regular file");
});
}
/**
* {@inheritdoc}
*/
public function mtime(string $path): Promise {
return call(function () use ($path) {
$stat = yield $this->stat($path);
if (empty($stat)) {
throw new FilesystemException("Specified path does not exist");
}
return $stat["mtime"];
});
}
/**
* {@inheritdoc}
*/
public function atime(string $path): Promise {
return call(function () use ($path) {
$stat = yield $this->stat($path);
if (empty($stat)) {
throw new FilesystemException("Specified path does not exist");
}
return $stat["atime"];
});
}
/**
* {@inheritdoc}
*/
public function ctime(string $path): Promise {
return call(function () use ($path) {
$stat = yield $this->stat($path);
if (empty($stat)) {
throw new FilesystemException("Specified path does not exist");
}
return $stat["ctime"];
});
}
/**
* {@inheritdoc}
*/
public function lstat(string $path): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("lstat", [$path])));
}
/**
* {@inheritdoc}
*/
public function touch(string $path, int $time = null, int $atime = null): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("touch", [$path, $time, $atime])));
}
/**
* {@inheritdoc}
*/
public function get(string $path): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("get", [$path])));
}
/**
* {@inheritdoc}
*/
public function put(string $path, string $contents): Promise {
return new Coroutine($this->runFileTask(new Internal\FileTask("put", [$path, $contents])));
}
}
PK ?V lib/Driver.phpnu W+A
*/
public function open(string $path, string $mode): Promise;
/**
* Execute a file stat operation.
*
* If the requested path does not exist the resulting Promise will resolve to NULL.
*
* @param string $path The file system path to stat
* @return \Amp\Promise
*/
public function stat(string $path): Promise;
/**
* Does the specified path exist?
*
* This function should never resolve as a failure -- only a successfull bool value
* indicating the existence of the specified path.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function exists(string $path): Promise;
/**
* Retrieve the size in bytes of the file at the specified path.
*
* If the path does not exist or is not a regular file this
* function's returned Promise WILL resolve as a failure.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function size(string $path): Promise;
/**
* Does the specified path exist and is it a directory?
*
* If the path does not exist the returned Promise will resolve
* to FALSE and will not reject with an error.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function isdir(string $path): Promise;
/**
* Does the specified path exist and is it a file?
*
* If the path does not exist the returned Promise will resolve
* to FALSE and will not reject with an error.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function isfile(string $path): Promise;
/**
* Retrieve the path's last modification time as a unix timestamp.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function mtime(string $path): Promise;
/**
* Retrieve the path's last access time as a unix timestamp.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function atime(string $path): Promise;
/**
* Retrieve the path's creation time as a unix timestamp.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function ctime(string $path): Promise;
/**
* Same as stat() except if the path is a link then the link's data is returned.
*
* @param string $path The file system path to stat
* @return \Amp\Promise A promise resolving to an associative array upon successful resolution
*/
public function lstat(string $path): Promise;
/**
* Create a symlink $link pointing to the file/directory located at $target.
*
* @param string $target
* @param string $link
* @return \Amp\Promise
*/
public function symlink(string $target, string $link): Promise;
/**
* Create a hard link $link pointing to the file/directory located at $target.
*
* @param string $target
* @param string $link
* @return \Amp\Promise
*/
public function link(string $target, string $link): Promise;
/**
* Read the symlink at $path.
*
* @param string $target
* @return \Amp\Promise
*/
public function readlink(string $target): Promise;
/**
* Rename a file or directory.
*
* @param string $from
* @param string $to
* @return \Amp\Promise
*/
public function rename(string $from, string $to): Promise;
/**
* Delete a file.
*
* @param string $path
* @return \Amp\Promise
*/
public function unlink(string $path): Promise;
/**
* Create a director.
*
* @param string $path
* @param int $mode
* @param bool $recursive
* @return \Amp\Promise
*/
public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise;
/**
* Delete a directory.
*
* @param string $path
* @return \Amp\Promise
*/
public function rmdir(string $path): Promise;
/**
* Retrieve an array of files and directories inside the specified path.
*
* Dot entries are not included in the resulting array (i.e. "." and "..").
*
* @param string $path
* @return \Amp\Promise
*/
public function scandir(string $path): Promise;
/**
* chmod a file or directory.
*
* @param string $path
* @param int $mode
* @return \Amp\Promise
*/
public function chmod(string $path, int $mode): Promise;
/**
* chown a file or directory.
*
* @param string $path
* @param int $uid
* @param int $gid
* @return \Amp\Promise
*/
public function chown(string $path, int $uid, int $gid): Promise;
/**
* Update the access and modification time of the specified path.
*
* If the file does not exist it will be created automatically.
*
* @param string $path
* @param int $time The touch time. If $time is not supplied, the current system time is used.
* @param int $atime The access time. If $atime is not supplied, value passed to the $time parameter is used.
* @return \Amp\Promise
*/
public function touch(string $path, int $time = null, int $atime = null): Promise;
/**
* Buffer the specified file's contents.
*
* @param string $path The file path from which to buffer contents
* @return \Amp\Promise A promise resolving to a string upon successful resolution
*/
public function get(string $path): Promise;
/**
* Write the contents string to the specified path.
*
* @param string $path The file path to which to $contents should be written
* @param string $contents The data to write to the specified $path
* @return \Amp\Promise A promise resolving to the integer length written upon success
*/
public function put(string $path, string $contents): Promise;
}
PK ?VX/ lib/Handle.phpnu W+A
*/
public function read(int $length = self::DEFAULT_READ_LENGTH): Promise;
/**
* Write $data to the open file handle starting at $offset.
*
* @param string $data
* @return \Amp\Promise
*/
public function write(string $data): Promise;
/**
* Write $data to the open file handle and close the handle once the write completes.
*
* @param string $data
*
* @return \Amp\Promise
*/
public function end(string $data = ""): Promise;
/**
* Close the file handle.
*
* Applications are not required to manually close handles -- they will
* be unloaded automatically when the object is garbage collected.
*
* @return \Amp\Promise
*/
public function close(): Promise;
/**
* Set the handle's internal pointer position.
*
* $whence values:
*
* SEEK_SET - Set position equal to offset bytes.
* SEEK_CUR - Set position to current location plus offset.
* SEEK_END - Set position to end-of-file plus offset.
*
* @param int $position
* @param int $whence
* @return \Amp\Promise New offset position.
*/
public function seek(int $position, int $whence = \SEEK_SET): Promise;
/**
* Return the current internal offset position of the file handle.
*
* @return int
*/
public function tell(): int;
/**
* Test for "end-of-file" on the file handle.
*
* @return bool
*/
public function eof(): bool;
/**
* Retrieve the path used when opening the file handle.
*
* @return string
*/
public function path(): string;
/**
* Retrieve the mode used when opening the file handle.
*
* @return string
*/
public function mode(): string;
}
PK ?V lib/Internal/EioPoll.phpnu W+A onDone = $this->callableFromInstanceMethod("done");
if (!self::$stream) {
\eio_init();
self::$stream = \eio_get_event_stream();
}
$this->watcher = Loop::onReadable(self::$stream, static function () {
while (\eio_npending()) {
\eio_poll();
}
});
Loop::disable($this->watcher);
Loop::setState(self::class, new class($this->watcher) {
private $watcher;
public function __construct(string $watcher) {
$this->watcher = $watcher;
}
public function __destruct() {
Loop::cancel($this->watcher);
// Ensure there are no active operations anymore. This is a safe-guard as some operations might not be
// finished on loop exit due to not being yielded. This also ensures a clean shutdown for these if PHP
// exists.
\eio_event_loop();
}
});
}
public function listen(Promise $promise) {
if ($this->requests++ === 0) {
Loop::enable($this->watcher);
}
$promise->onResolve($this->onDone);
}
private function done() {
if (--$this->requests === 0) {
Loop::disable($this->watcher);
}
\assert($this->requests >= 0);
}
}
PK ?V/' lib/Internal/UvPoll.phpnu W+A onDone = $this->callableFromInstanceMethod("done");
$this->watcher = Loop::repeat(\PHP_INT_MAX / 2, function () {
// do nothing, it's a dummy watcher
});
Loop::disable($this->watcher);
Loop::setState(self::class, new class($this->watcher) {
private $watcher;
public function __construct(string $watcher) {
$this->watcher = $watcher;
}
public function __destruct() {
Loop::cancel($this->watcher);
}
});
}
public function listen(Promise $promise) {
if ($this->requests++ === 0) {
Loop::enable($this->watcher);
}
$promise->onResolve($this->onDone);
}
private function done() {
if (--$this->requests === 0) {
Loop::disable($this->watcher);
}
\assert($this->requests >= 0);
}
}
PK ?V._l lib/Internal/FileTask.phpnu W+A operation = $operation;
$this->args = $args;
$this->id = $id;
}
/**
* {@inheritdoc}
*
* @throws \Amp\File\FilesystemException
* @throws \Error
*/
public function run(Environment $environment) {
if ('f' === $this->operation[0]) {
if ("fopen" === $this->operation) {
$path = $this->args[0];
$mode = \str_replace(['b', 't', 'e'], '', $this->args[1]);
switch ($mode) {
case "r":
case "r+":
case "w":
case "w+":
case "a":
case "a+":
case "x":
case "x+":
case "c":
case "c+":
break;
default:
throw new \Error("Invalid file mode");
}
$handle = @\fopen($path, $mode . 'be');
if (!$handle) {
$message = 'Could not open the file.';
if ($error = \error_get_last()) {
$message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]);
}
throw new FilesystemException($message);
}
$file = new BlockingHandle($handle, $path, $mode);
$id = (int) $handle;
$size = \fstat($handle)["size"];
$environment->set(self::makeId($id), $file);
return [$id, $size, $mode];
}
if ($this->id === null) {
throw new FilesystemException("No file ID provided");
}
$id = self::makeId($this->id);
if (!$environment->exists($id)) {
throw new FilesystemException(\sprintf("No file handle with the ID %d has been opened on the worker", $this->id));
}
/** @var \Amp\File\BlockingHandle $file */
if (!($file = $environment->get($id)) instanceof BlockingHandle) {
throw new FilesystemException("File storage found in inconsistent state");
}
switch ($this->operation) {
case "fread":
case "fwrite":
case "fseek":
return ([$file, \substr($this->operation, 1)])(...$this->args);
case "fclose":
$environment->delete($id);
$file->close();
return;
default:
throw new \Error('Invalid operation');
}
}
StatCache::clear();
switch ($this->operation) {
case "stat":
case "unlink":
case "rename":
case "link":
case "symlink":
case "readlink":
case "lstat":
case "exists":
case "mkdir":
case "scandir":
case "rmdir":
case "chmod":
case "chown":
case "touch":
case "get":
case "put":
return ([new BlockingDriver, $this->operation])(...$this->args);
default:
throw new \Error("Invalid operation");
}
}
/**
* @param int $id
*
* @return string
*/
private static function makeId(int $id): string {
return self::ENV_PREFIX . $id;
}
}
PK ?V5BB lib/ParallelHandle.phpnu W+A worker = $worker;
$this->id = $id;
$this->path = $path;
$this->size = $size;
$this->mode = $mode;
$this->position = $this->mode[0] === 'a' ? $this->size : 0;
}
public function __destruct() {
if ($this->id !== null) {
$this->close();
}
}
/**
* {@inheritdoc}
*/
public function path(): string {
return $this->path;
}
/**
* {@inheritdoc}
*/
public function close(): Promise {
if ($this->closing) {
return $this->closing;
}
$this->writable = false;
if ($this->worker->isRunning()) {
$this->closing = $this->worker->enqueue(new Internal\FileTask('fclose', [], $this->id));
$this->id = null;
} else {
$this->closing = new Success;
}
return $this->closing;
}
/**
* {@inheritdoc}
*/
public function eof(): bool {
return $this->pendingWrites === 0 && $this->size <= $this->position;
}
public function read(int $length = self::DEFAULT_READ_LENGTH): Promise {
if ($this->id === null) {
throw new ClosedException("The file has been closed");
}
if ($this->busy) {
throw new PendingOperationError;
}
return new Coroutine($this->doRead($length));
}
private function doRead(int $length): \Generator {
$this->busy = true;
try {
$data = yield $this->worker->enqueue(new Internal\FileTask('fread', [$length], $this->id));
$this->position += \strlen($data);
return $data;
} catch (TaskException $exception) {
throw new StreamException("Reading from the file failed", 0, $exception);
} catch (WorkerException $exception) {
throw new StreamException("Sending the task to the worker failed", 0, $exception);
} finally {
$this->busy = false;
}
}
/**
* {@inheritdoc}
*/
public function write(string $data): Promise {
if ($this->id === null) {
throw new ClosedException("The file has been closed");
}
if ($this->busy && $this->pendingWrites === 0) {
throw new PendingOperationError;
}
if (!$this->writable) {
throw new ClosedException("The file is no longer writable");
}
return new Coroutine($this->doWrite($data));
}
/**
* {@inheritdoc}
*/
public function end(string $data = ""): Promise {
return call(function () use ($data) {
$promise = $this->write($data);
$this->writable = false;
// ignore any errors
yield Promise\any([$this->close()]);
return $promise;
});
}
private function doWrite(string $data): \Generator {
++$this->pendingWrites;
$this->busy = true;
try {
$length = yield $this->worker->enqueue(new Internal\FileTask('fwrite', [$data], $this->id));
} catch (TaskException $exception) {
throw new StreamException("Writing to the file failed", 0, $exception);
} catch (WorkerException $exception) {
throw new StreamException("Sending the task to the worker failed", 0, $exception);
} finally {
if (--$this->pendingWrites === 0) {
$this->busy = false;
}
}
$this->position += $length;
return $length;
}
/**
* {@inheritdoc}
*/
public function seek(int $offset, int $whence = SEEK_SET): Promise {
if ($this->id === null) {
throw new ClosedException("The file has been closed");
}
if ($this->busy) {
throw new PendingOperationError;
}
return new Coroutine($this->doSeek($offset, $whence));
}
private function doSeek(int $offset, int $whence) {
switch ($whence) {
case \SEEK_SET:
case \SEEK_CUR:
case \SEEK_END:
try {
$this->position = yield $this->worker->enqueue(
new Internal\FileTask('fseek', [$offset, $whence], $this->id)
);
if ($this->position > $this->size) {
$this->size = $this->position;
}
return $this->position;
} catch (TaskException $exception) {
throw new StreamException('Seeking in the file failed.', 0, $exception);
} catch (WorkerException $exception) {
throw new StreamException("Sending the task to the worker failed", 0, $exception);
}
default:
throw new \Error('Invalid whence value. Use SEEK_SET, SEEK_CUR, or SEEK_END.');
}
}
/**
* {@inheritdoc}
*/
public function tell(): int {
return $this->position;
}
/**
* {@inheritdoc}
*/
public function size(): int {
return $this->size;
}
/**
* {@inheritdoc}
*/
public function mode(): string {
return $this->mode;
}
}
PK ?Vpb lib/UvHandle.phpnu W+A poll = $poll;
$this->fh = $fh;
$this->path = $path;
$this->mode = $mode;
$this->size = $size;
$this->loop = $driver->getHandle();
$this->position = ($mode[0] === "a") ? $size : 0;
$this->queue = new \SplQueue;
}
public function read(int $length = self::DEFAULT_READ_LENGTH): Promise {
if ($this->isActive) {
throw new PendingOperationError;
}
$deferred = new Deferred;
$this->poll->listen($deferred->promise());
$this->isActive = true;
$onRead = function ($fh, $result, $buffer) use ($deferred) {
$this->isActive = false;
if ($result < 0) {
$error = \uv_strerror($result);
if ($error === "bad file descriptor") {
$deferred->fail(new ClosedException("Reading from the file failed due to a closed handle"));
} else {
$deferred->fail(new StreamException("Reading from the file failed: " . $error));
}
} else {
$length = strlen($buffer);
$this->position = $this->position + $length;
$deferred->resolve($length ? $buffer : null);
}
};
\uv_fs_read($this->loop, $this->fh, $this->position, $length, $onRead);
return $deferred->promise();
}
/**
* {@inheritdoc}
*/
public function write(string $data): Promise {
if ($this->isActive && $this->queue->isEmpty()) {
throw new PendingOperationError;
}
if (!$this->writable) {
throw new ClosedException("The file is no longer writable");
}
$this->isActive = true;
if ($this->queue->isEmpty()) {
$promise = $this->push($data);
} else {
$promise = $this->queue->top();
$promise = call(function () use ($promise, $data) {
yield $promise;
return yield $this->push($data);
});
}
$this->queue->push($promise);
return $promise;
}
/**
* {@inheritdoc}
*/
public function end(string $data = ""): Promise {
return call(function () use ($data) {
$promise = $this->write($data);
$this->writable = false;
// ignore any errors
yield Promise\any([$this->close()]);
return $promise;
});
}
private function push(string $data): Promise {
$length = \strlen($data);
$deferred = new Deferred;
$this->poll->listen($deferred->promise());
$onWrite = function ($fh, $result) use ($deferred, $length) {
if ($this->queue->isEmpty()) {
$deferred->fail(new ClosedException('No pending write, the file may have been closed'));
}
$this->queue->shift();
if ($this->queue->isEmpty()) {
$this->isActive = false;
}
if ($result < 0) {
$error = \uv_strerror($result);
if ($error === "bad file descriptor") {
$deferred->fail(new ClosedException("Writing to the file failed due to a closed handle"));
} else {
$deferred->fail(new StreamException("Writing to the file failed: " . $error));
}
} else {
StatCache::clear($this->path);
$newPosition = $this->position + $length;
$delta = $newPosition - $this->position;
$this->position = ($this->mode[0] === "a") ? $this->position : $newPosition;
$this->size += $delta;
$deferred->resolve($length);
}
};
\uv_fs_write($this->loop, $this->fh, $data, $this->position, $onWrite);
return $deferred->promise();
}
/**
* {@inheritdoc}
*/
public function seek(int $offset, int $whence = \SEEK_SET): Promise {
if ($this->isActive) {
throw new PendingOperationError;
}
$offset = (int) $offset;
switch ($whence) {
case \SEEK_SET:
$this->position = $offset;
break;
case \SEEK_CUR:
$this->position = $this->position + $offset;
break;
case \SEEK_END:
$this->position = $this->size + $offset;
break;
default:
throw new \Error(
"Invalid whence parameter; SEEK_SET, SEEK_CUR or SEEK_END expected"
);
}
return new Success($this->position);
}
/**
* {@inheritdoc}
*/
public function tell(): int {
return $this->position;
}
/**
* {@inheritdoc}
*/
public function eof(): bool {
return !$this->queue->isEmpty() ? false : ($this->size <= $this->position);
}
/**
* {@inheritdoc}
*/
public function path(): string {
return $this->path;
}
/**
* {@inheritdoc}
*/
public function mode(): string {
return $this->mode;
}
/**
* {@inheritdoc}
*/
public function close(): Promise {
if ($this->closing) {
return $this->closing;
}
$deferred = new Deferred;
$this->poll->listen($this->closing = $deferred->promise());
\uv_fs_close($this->loop, $this->fh, function ($fh) use ($deferred) {
// Ignore errors when closing file, as the handle will become invalid anyway.
$deferred->resolve();
});
return $deferred->promise();
}
}
PK ?V쓗# # lib/BlockingDriver.phpnu W+A
*/
public function size(string $path): Promise {
if (!@\file_exists($path)) {
return new Failure(new FilesystemException(
"Path does not exist"
));
}
if (!@\is_file($path)) {
return new Failure(new FilesystemException(
"Path is not a regular file"
));
}
if (($size = @\filesize($path)) === false) {
return new Failure(new FilesystemException(
\error_get_last()["message"]
));
}
\clearstatcache(true, $path);
return new Success($size);
}
/**
* Does the specified path exist and is it a directory?
*
* If the path does not exist the returned Promise will resolve
* to FALSE. It will NOT reject with an error.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function isdir(string $path): Promise {
if (!@\file_exists($path)) {
return new Success(false);
}
$isDir = @\is_dir($path);
\clearstatcache(true, $path);
return new Success($isDir);
}
/**
* Does the specified path exist and is it a file?
*
* If the path does not exist the returned Promise will resolve
* to FALSE. It will NOT reject with an error.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function isfile(string $path): Promise {
if (!@\file_exists($path)) {
return new Success(false);
}
$isFile = @\is_file($path);
\clearstatcache(true, $path);
return new Success($isFile);
}
/**
* Retrieve the path's last modification time as a unix timestamp.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function mtime(string $path): Promise {
if (!@\file_exists($path)) {
return new Failure(new FilesystemException(
"Path does not exist"
));
}
$mtime = @\filemtime($path);
\clearstatcache(true, $path);
return new Success($mtime);
}
/**
* Retrieve the path's last access time as a unix timestamp.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function atime(string $path): Promise {
if (!@\file_exists($path)) {
return new Failure(new FilesystemException(
"Path does not exist"
));
}
$atime = @\fileatime($path);
\clearstatcache(true, $path);
return new Success($atime);
}
/**
* Retrieve the path's creation time as a unix timestamp.
*
* @param string $path An absolute file system path
* @return \Amp\Promise
*/
public function ctime(string $path): Promise {
if (!@\file_exists($path)) {
return new Failure(new FilesystemException(
"Path does not exist"
));
}
$ctime = @\filectime($path);
\clearstatcache(true, $path);
return new Success($ctime);
}
/**
* {@inheritdoc}
*/
public function lstat(string $path): Promise {
if ($stat = @\lstat($path)) {
\clearstatcache(true, $path);
} else {
$stat = null;
}
return new Success($stat);
}
/**
* {@inheritdoc}
*/
public function symlink(string $target, string $link): Promise {
if (!@\symlink($target, $link)) {
return new Failure(new FilesystemException("Could not create symbolic link"));
}
return new Success(true);
}
/**
* {@inheritdoc}
*/
public function link(string $target, string $link): Promise {
if (!@\link($target, $link)) {
return new Failure(new FilesystemException("Could not create hard link"));
}
return new Success(true);
}
/**
* {@inheritdoc}
*/
public function readlink(string $path): Promise {
if (!($result = @\readlink($path))) {
return new Failure(new FilesystemException("Could not read symbolic link"));
}
return new Success($result);
}
/**
* {@inheritdoc}
*/
public function rename(string $from, string $to): Promise {
if (!@\rename($from, $to)) {
return new Failure(new FilesystemException("Could not rename file"));
}
return new Success(true);
}
/**
* {@inheritdoc}
*/
public function unlink(string $path): Promise {
StatCache::clear($path);
return new Success((bool) @\unlink($path));
}
/**
* {@inheritdoc}
*/
public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise {
return new Success((bool) @\mkdir($path, $mode, $recursive));
}
/**
* {@inheritdoc}
*/
public function rmdir(string $path): Promise {
StatCache::clear($path);
return new Success((bool) @\rmdir($path));
}
/**
* {@inheritdoc}
*/
public function scandir(string $path): Promise {
if (!@\is_dir($path)) {
return new Failure(new FilesystemException(
"Not a directory"
));
} elseif ($arr = @\scandir($path)) {
$arr = \array_values(\array_filter($arr, function ($el) {
return !($el === "." || $el === "..");
}));
\clearstatcache(true, $path);
return new Success($arr);
}
return new Failure(new FilesystemException(
"Failed reading contents from {$path}"
));
}
/**
* {@inheritdoc}
*/
public function chmod(string $path, int $mode): Promise {
return new Success((bool) @\chmod($path, $mode));
}
/**
* {@inheritdoc}
*/
public function chown(string $path, int $uid, int $gid): Promise {
if ($uid !== -1 && !@\chown($path, $uid)) {
return new Failure(new FilesystemException(
\error_get_last()["message"]
));
}
if ($gid !== -1 && !@\chgrp($path, $gid)) {
return new Failure(new FilesystemException(
\error_get_last()["message"]
));
}
return new Success;
}
/**
* {@inheritdoc}
*/
public function touch(string $path, int $time = null, int $atime = null): Promise {
$time = $time ?? \time();
$atime = $atime ?? $time;
return new Success((bool) \touch($path, $time, $atime));
}
/**
* {@inheritdoc}
*/
public function get(string $path): Promise {
$result = @\file_get_contents($path);
return ($result === false)
? new Failure(new FilesystemException(\error_get_last()["message"]))
: new Success($result);
}
/**
* {@inheritdoc}
*/
public function put(string $path, string $contents): Promise {
$result = @\file_put_contents($path, $contents);
return ($result === false)
? new Failure(new FilesystemException(\error_get_last()["message"]))
: new Success($result);
}
}
PK ?V