1
0
mirror of https://github.com/danog/file.git synced 2024-11-30 04:19:39 +01:00
file/lib/Internal/FileTask.php

164 lines
4.3 KiB
PHP
Raw Permalink Normal View History

2016-08-30 21:05:14 +02:00
<?php
2016-08-30 21:05:14 +02:00
namespace Amp\File\Internal;
2017-06-17 23:41:57 +02:00
use Amp\File\BlockingDriver;
use Amp\File\BlockingHandle;
use Amp\File\FilesystemException;
2017-07-18 07:37:07 +02:00
use Amp\File\StatCache;
2017-06-17 23:41:57 +02:00
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Task;
2016-08-30 21:05:14 +02:00
/**
* @codeCoverageIgnore
*
* @internal
*/
class FileTask implements Task
{
2017-12-15 05:36:16 +01:00
const ENV_PREFIX = "amp/file#";
2017-06-17 23:41:57 +02:00
2016-08-30 21:05:14 +02:00
/** @var string */
private $operation;
/** @var mixed[] */
private $args;
/** @var string|null */
private $id;
/**
* @param string $operation
* @param array $args
* @param int $id File ID.
*
* @throws \Error
*/
public function __construct(string $operation, array $args = [], int $id = null)
{
2016-08-30 21:05:14 +02:00
if (!\strlen($operation)) {
throw new \Error('Operation must be a non-empty string');
}
$this->operation = $operation;
$this->args = $args;
2017-06-22 17:16:33 +02:00
$this->id = $id;
2016-08-30 21:05:14 +02:00
}
/**
* {@inheritdoc}
*
* @throws \Amp\File\FilesystemException
* @throws \Error
*/
public function run(Environment $environment)
{
2016-08-30 21:05:14 +02:00
if ('f' === $this->operation[0]) {
if ("fopen" === $this->operation) {
$path = $this->args[0];
2017-10-30 04:58:08 +01:00
$mode = \str_replace(['b', 't', 'e'], '', $this->args[1]);
2017-06-17 23:41:57 +02:00
2016-08-30 21:05:14 +02:00
switch ($mode) {
case "r":
case "r+":
case "w":
case "w+":
case "a":
case "a+":
case "x":
case "x+":
case "c":
case "c+":
break;
2017-06-17 23:41:57 +02:00
2016-08-30 21:05:14 +02:00
default:
throw new \Error("Invalid file mode");
2016-08-30 21:05:14 +02:00
}
2017-06-17 23:41:57 +02:00
$handle = @\fopen($path, $mode . 'be');
2017-06-17 23:41:57 +02:00
2016-08-30 21:05:14 +02:00
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);
}
2017-06-17 23:41:57 +02:00
2016-08-30 21:05:14 +02:00
$file = new BlockingHandle($handle, $path, $mode);
$id = (int) $handle;
$size = \fstat($handle)["size"];
2017-06-22 17:16:33 +02:00
$environment->set(self::makeId($id), $file);
2017-06-17 23:41:57 +02:00
2016-08-30 21:05:14 +02:00
return [$id, $size, $mode];
}
2017-06-22 17:16:33 +02:00
if ($this->id === null) {
2016-08-30 21:05:14 +02:00
throw new FilesystemException("No file ID provided");
}
2017-06-22 17:16:33 +02:00
$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));
2016-08-30 21:05:14 +02:00
}
/** @var \Amp\File\BlockingHandle $file */
2017-06-22 17:16:33 +02:00
if (!($file = $environment->get($id)) instanceof BlockingHandle) {
2016-08-30 21:05:14 +02:00
throw new FilesystemException("File storage found in inconsistent state");
}
switch ($this->operation) {
case "fread":
case "fwrite":
case "fseek":
case "ftruncate":
return ([$file, \substr($this->operation, 1)])(...$this->args);
2016-08-30 21:05:14 +02:00
case "fclose":
2017-12-15 05:36:16 +01:00
$environment->delete($id);
$file->close();
return;
2016-08-30 21:05:14 +02:00
default:
throw new \Error('Invalid operation');
}
}
2017-07-18 07:37:07 +02:00
StatCache::clear();
2016-08-30 21:05:14 +02:00
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);
2016-08-30 21:05:14 +02:00
default:
throw new \Error("Invalid operation");
}
}
/**
* @param int $id
*
* @return string
*/
private static function makeId(int $id): string
{
2016-08-30 21:05:14 +02:00
return self::ENV_PREFIX . $id;
}
}