2016-12-30 03:59:59 +01:00
|
|
|
<?php
|
2015-07-11 03:59:39 +02:00
|
|
|
|
2015-08-05 16:55:56 +02:00
|
|
|
namespace Amp\File;
|
2015-07-11 03:59:39 +02:00
|
|
|
|
2017-06-17 23:41:57 +02:00
|
|
|
use Amp\Failure;
|
|
|
|
use Amp\Promise;
|
|
|
|
use Amp\Success;
|
2015-07-11 03:59:39 +02:00
|
|
|
|
2018-10-27 17:57:31 +02:00
|
|
|
class BlockingDriver implements Driver
|
|
|
|
{
|
2015-08-13 01:02:41 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function open(string $path, string $mode): Promise
|
|
|
|
{
|
2017-10-30 05:10:35 +01:00
|
|
|
$mode = \str_replace(['b', 't', 'e'], '', $mode);
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$fh = \fopen($path, $mode . 'be')) {
|
2015-08-13 01:02:41 +02:00
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Failed opening file handle"
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Success(new BlockingHandle($fh, $path, $mode));
|
|
|
|
}
|
|
|
|
|
2015-07-11 03:59:39 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function stat(string $path): Promise
|
|
|
|
{
|
2015-08-29 13:34:18 +02:00
|
|
|
if ($stat = StatCache::get($path)) {
|
|
|
|
return new Success($stat);
|
|
|
|
} elseif ($stat = @\stat($path)) {
|
2015-08-08 16:09:07 +02:00
|
|
|
StatCache::set($path, $stat);
|
2015-07-30 15:07:01 +02:00
|
|
|
\clearstatcache(true, $path);
|
2015-07-11 03:59:39 +02:00
|
|
|
} else {
|
|
|
|
$stat = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Success($stat);
|
|
|
|
}
|
|
|
|
|
2015-08-08 16:09:07 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function exists(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if ($exists = @\file_exists($path)) {
|
|
|
|
\clearstatcache(true, $path);
|
|
|
|
}
|
2017-06-17 23:41:57 +02:00
|
|
|
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Success($exists);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2017-03-17 04:39:49 +01:00
|
|
|
* @return \Amp\Promise<int>
|
2015-08-08 16:09:07 +02:00
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function size(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if (!@\file_exists($path)) {
|
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Path does not exist"
|
|
|
|
));
|
2017-06-17 23:41:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!@\is_file($path)) {
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Path is not a regular file"
|
|
|
|
));
|
2017-06-17 23:41:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (($size = @\filesize($path)) === false) {
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
\error_get_last()["message"]
|
|
|
|
));
|
|
|
|
}
|
2017-06-17 23:41:57 +02:00
|
|
|
|
|
|
|
\clearstatcache(true, $path);
|
|
|
|
return new Success($size);
|
2015-08-08 16:09:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2017-03-17 04:39:49 +01:00
|
|
|
* @return \Amp\Promise<bool>
|
2015-08-08 16:09:07 +02:00
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function isdir(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if (!@\file_exists($path)) {
|
|
|
|
return new Success(false);
|
|
|
|
}
|
2017-06-17 23:41:57 +02:00
|
|
|
|
2015-08-08 16:09:07 +02:00
|
|
|
$isDir = @\is_dir($path);
|
2015-10-25 02:50:30 +01:00
|
|
|
\clearstatcache(true, $path);
|
2015-08-08 16:09:07 +02:00
|
|
|
|
|
|
|
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
|
2017-03-17 04:39:49 +01:00
|
|
|
* @return \Amp\Promise<bool>
|
2015-08-08 16:09:07 +02:00
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function isfile(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if (!@\file_exists($path)) {
|
|
|
|
return new Success(false);
|
|
|
|
}
|
2017-06-17 23:41:57 +02:00
|
|
|
|
2015-08-08 16:09:07 +02:00
|
|
|
$isFile = @\is_file($path);
|
2015-10-25 02:50:30 +01:00
|
|
|
\clearstatcache(true, $path);
|
2015-08-08 16:09:07 +02:00
|
|
|
|
|
|
|
return new Success($isFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-06-17 23:41:57 +02:00
|
|
|
* Retrieve the path's last modification time as a unix timestamp.
|
2015-08-08 16:09:07 +02:00
|
|
|
*
|
|
|
|
* @param string $path An absolute file system path
|
2017-03-17 04:39:49 +01:00
|
|
|
* @return \Amp\Promise<int>
|
2015-08-08 16:09:07 +02:00
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function mtime(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if (!@\file_exists($path)) {
|
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Path does not exist"
|
|
|
|
));
|
|
|
|
}
|
2017-06-17 23:41:57 +02:00
|
|
|
|
2015-08-08 16:09:07 +02:00
|
|
|
$mtime = @\filemtime($path);
|
2015-10-25 02:50:30 +01:00
|
|
|
\clearstatcache(true, $path);
|
2015-08-08 16:09:07 +02:00
|
|
|
|
|
|
|
return new Success($mtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-06-17 23:41:57 +02:00
|
|
|
* Retrieve the path's last access time as a unix timestamp.
|
2015-08-08 16:09:07 +02:00
|
|
|
*
|
|
|
|
* @param string $path An absolute file system path
|
2017-03-17 04:39:49 +01:00
|
|
|
* @return \Amp\Promise<int>
|
2015-08-08 16:09:07 +02:00
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function atime(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if (!@\file_exists($path)) {
|
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Path does not exist"
|
|
|
|
));
|
|
|
|
}
|
|
|
|
$atime = @\fileatime($path);
|
2015-10-25 02:50:30 +01:00
|
|
|
\clearstatcache(true, $path);
|
2015-08-08 16:09:07 +02:00
|
|
|
|
|
|
|
return new Success($atime);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-06-17 23:41:57 +02:00
|
|
|
* Retrieve the path's creation time as a unix timestamp.
|
2015-08-08 16:09:07 +02:00
|
|
|
*
|
|
|
|
* @param string $path An absolute file system path
|
2017-03-17 04:39:49 +01:00
|
|
|
* @return \Amp\Promise<int>
|
2015-08-08 16:09:07 +02:00
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function ctime(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if (!@\file_exists($path)) {
|
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Path does not exist"
|
|
|
|
));
|
|
|
|
}
|
2017-06-17 23:41:57 +02:00
|
|
|
|
2015-08-08 16:09:07 +02:00
|
|
|
$ctime = @\filectime($path);
|
2015-10-25 02:50:30 +01:00
|
|
|
\clearstatcache(true, $path);
|
2015-08-08 16:09:07 +02:00
|
|
|
|
|
|
|
return new Success($ctime);
|
|
|
|
}
|
|
|
|
|
2015-07-11 03:59:39 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function lstat(string $path): Promise
|
|
|
|
{
|
2015-07-30 15:07:01 +02:00
|
|
|
if ($stat = @\lstat($path)) {
|
|
|
|
\clearstatcache(true, $path);
|
2015-07-11 03:59:39 +02:00
|
|
|
} else {
|
|
|
|
$stat = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Success($stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function symlink(string $target, string $link): Promise
|
|
|
|
{
|
2016-08-24 06:55:06 +02:00
|
|
|
if (!@\symlink($target, $link)) {
|
|
|
|
return new Failure(new FilesystemException("Could not create symbolic link"));
|
|
|
|
}
|
2017-01-11 14:22:06 +01:00
|
|
|
|
2016-08-24 06:55:06 +02:00
|
|
|
return new Success(true);
|
|
|
|
}
|
2017-01-11 14:22:06 +01:00
|
|
|
|
2016-08-24 06:55:06 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function link(string $target, string $link): Promise
|
|
|
|
{
|
2016-08-24 06:55:06 +02:00
|
|
|
if (!@\link($target, $link)) {
|
|
|
|
return new Failure(new FilesystemException("Could not create hard link"));
|
|
|
|
}
|
2017-01-11 14:22:06 +01:00
|
|
|
|
2016-08-24 06:55:06 +02:00
|
|
|
return new Success(true);
|
|
|
|
}
|
2017-01-11 14:22:06 +01:00
|
|
|
|
2016-08-24 06:55:06 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function readlink(string $path): Promise
|
|
|
|
{
|
2016-08-24 06:55:06 +02:00
|
|
|
if (!($result = @\readlink($path))) {
|
|
|
|
return new Failure(new FilesystemException("Could not read symbolic link"));
|
|
|
|
}
|
2017-01-11 14:22:06 +01:00
|
|
|
|
2016-08-24 06:55:06 +02:00
|
|
|
return new Success($result);
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function rename(string $from, string $to): Promise
|
|
|
|
{
|
2016-08-24 06:55:06 +02:00
|
|
|
if (!@\rename($from, $to)) {
|
|
|
|
return new Failure(new FilesystemException("Could not rename file"));
|
|
|
|
}
|
2017-01-11 14:22:06 +01:00
|
|
|
|
2016-08-24 06:55:06 +02:00
|
|
|
return new Success(true);
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function unlink(string $path): Promise
|
|
|
|
{
|
2015-09-09 15:19:40 +02:00
|
|
|
StatCache::clear($path);
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Success((bool) @\unlink($path));
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise
|
|
|
|
{
|
2016-09-28 12:39:24 +02:00
|
|
|
return new Success((bool) @\mkdir($path, $mode, $recursive));
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function rmdir(string $path): Promise
|
|
|
|
{
|
2015-09-09 15:19:40 +02:00
|
|
|
StatCache::clear($path);
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Success((bool) @\rmdir($path));
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function scandir(string $path): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
if (!@\is_dir($path)) {
|
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Not a directory"
|
|
|
|
));
|
|
|
|
} elseif ($arr = @\scandir($path)) {
|
2017-06-17 23:41:57 +02:00
|
|
|
$arr = \array_values(\array_filter($arr, function ($el) {
|
2015-07-11 03:59:39 +02:00
|
|
|
return !($el === "." || $el === "..");
|
|
|
|
}));
|
2015-07-30 15:07:01 +02:00
|
|
|
\clearstatcache(true, $path);
|
2015-07-11 03:59:39 +02:00
|
|
|
return new Success($arr);
|
|
|
|
}
|
2017-06-17 23:41:57 +02:00
|
|
|
|
|
|
|
return new Failure(new FilesystemException(
|
|
|
|
"Failed reading contents from {$path}"
|
|
|
|
));
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function chmod(string $path, int $mode): Promise
|
|
|
|
{
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Success((bool) @\chmod($path, $mode));
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function chown(string $path, int $uid, int $gid): Promise
|
|
|
|
{
|
2015-12-09 21:45:28 +01:00
|
|
|
if ($uid !== -1 && !@\chown($path, $uid)) {
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Failure(new FilesystemException(
|
2015-07-30 15:07:01 +02:00
|
|
|
\error_get_last()["message"]
|
2015-07-11 03:59:39 +02:00
|
|
|
));
|
2015-12-09 21:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($gid !== -1 && !@\chgrp($path, $gid)) {
|
2015-08-08 16:09:07 +02:00
|
|
|
return new Failure(new FilesystemException(
|
2015-07-30 15:07:01 +02:00
|
|
|
\error_get_last()["message"]
|
2015-07-11 03:59:39 +02:00
|
|
|
));
|
|
|
|
}
|
2015-12-09 21:45:28 +01:00
|
|
|
|
|
|
|
return new Success;
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
2015-07-18 20:53:46 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function touch(string $path, int $time = null, int $atime = null): Promise
|
|
|
|
{
|
2017-11-23 03:55:30 +01:00
|
|
|
$time = $time ?? \time();
|
|
|
|
$atime = $atime ?? $time;
|
|
|
|
return new Success((bool) \touch($path, $time, $atime));
|
2015-07-18 20:53:46 +02:00
|
|
|
}
|
|
|
|
|
2015-07-11 03:59:39 +02:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function get(string $path): Promise
|
|
|
|
{
|
2015-07-30 15:07:01 +02:00
|
|
|
$result = @\file_get_contents($path);
|
2015-07-11 03:59:39 +02:00
|
|
|
return ($result === false)
|
2015-08-08 16:09:07 +02:00
|
|
|
? new Failure(new FilesystemException(\error_get_last()["message"]))
|
2017-06-17 23:41:57 +02:00
|
|
|
: new Success($result);
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-27 17:57:31 +02:00
|
|
|
public function put(string $path, string $contents): Promise
|
|
|
|
{
|
2015-07-30 15:07:01 +02:00
|
|
|
$result = @\file_put_contents($path, $contents);
|
2015-07-11 03:59:39 +02:00
|
|
|
return ($result === false)
|
2015-08-08 16:09:07 +02:00
|
|
|
? new Failure(new FilesystemException(\error_get_last()["message"]))
|
2017-06-17 23:41:57 +02:00
|
|
|
: new Success($result);
|
2015-07-11 03:59:39 +02:00
|
|
|
}
|
|
|
|
}
|