Page MenuHomePhabricator

D11688.id28129.diff
No OneTemporary

D11688.id28129.diff

diff --git a/src/filesystem/TempFile.php b/src/filesystem/TempFile.php
--- a/src/filesystem/TempFile.php
+++ b/src/filesystem/TempFile.php
@@ -20,6 +20,7 @@
private $file;
private $preserve;
private $destroyed = false;
+ private $maskUnlinkFailure = false;
/* -( Creating a Temporary File )------------------------------------------ */
@@ -64,6 +65,20 @@
return $this;
}
+ /**
+ * Sets whether or not any errors during unlinking should be masked. This
+ * is useful if an external process may still have a lock on the file (under
+ * Windows).
+ *
+ * @param bool True to mask any errors occurring during unlinking.
+ * @return this
+ * @task config
+ */
+ public function setMaskUnlinkFailure($mask) {
+ $this->maskUnlinkFailure = $mask;
+ return $this;
+ }
+
/* -( Internals )---------------------------------------------------------- */
@@ -95,13 +110,27 @@
return;
}
- Filesystem::remove($this->dir);
+ if ($this->maskUnlinkFailure) {
+ try {
+ @Filesystem::remove($this->dir);
+ } catch (FilesystemException $ex) {
+ }
+ } else {
+ Filesystem::remove($this->dir);
+ }
// NOTE: tempnam() doesn't guarantee it will return a file inside the
// directory you passed to the function, so we make sure to nuke the file
// explicitly.
- Filesystem::remove($this->file);
+ if ($this->maskUnlinkFailure) {
+ try {
+ @Filesystem::remove($this->file);
+ } catch (FilesystemException $ex) {
+ }
+ } else {
+ Filesystem::remove($this->file);
+ }
$this->file = null;
$this->dir = null;
diff --git a/src/future/exec/ExecFuture.php b/src/future/exec/ExecFuture.php
--- a/src/future/exec/ExecFuture.php
+++ b/src/future/exec/ExecFuture.php
@@ -564,6 +564,23 @@
}
do {
+ $real_length = $length;
+
+ // On Windows, we must check to see if we can read without blocking
+ // from the stream, and even then we must read only 1 byte at a time.
+ if (phutil_is_windows()) {
+ $r = array($stream);
+ $w = array();
+ $e = array();
+ if (false === stream_select($r, $w, $e, 0)) {
+ throw new Exception('stream_select() failed');
+ }
+ $real_length = 0;
+ if (in_array($stream, $r)) {
+ $real_length = 1;
+ }
+ }
+
$data = fread($stream, min($length, 64 * 1024));
if (false === $data) {
throw new Exception('Failed to read from '.$description);
@@ -662,13 +679,38 @@
} else {
$trap = null;
}
+
+ $stdout_target = null;
+ $stderr_target = null;
+
+ $spec = self::$descriptorSpec;
+ if (phutil_is_windows()) {
+ $stdout_target = id(new TempFile())->setMaskUnlinkFailure(true);
+ $stderr_target = id(new TempFile())->setMaskUnlinkFailure(true);
+
+ $spec = array(
+ 0 => self::$descriptorSpec[0], // stdin
+ 1 => fopen($stdout_target, 'wb'), // stdout
+ 2 => fopen($stderr_target, 'wb'), // stderr
+ );
+ }
$proc = @proc_open(
$unmasked_command,
- self::$descriptorSpec,
+ $spec,
$pipes,
$cwd,
$env);
+
+ if (phutil_is_windows()) {
+ fclose($spec[1]);
+ fclose($spec[2]);
+ $pipes = array(
+ 0 => head($pipes), // stdin
+ 1 => fopen($stdout_target, 'rb'), // stdout
+ 2 => fopen($stderr_target, 'rb'), // stderr
+ );
+ }
if ($trap) {
$err = $trap->getErrorsAsString();
@@ -685,12 +727,12 @@
$this->proc = $proc;
list($stdin, $stdout, $stderr) = $pipes;
-
+
if (!phutil_is_windows()) {
- // On Windows, there's no such thing as nonblocking interprocess I/O.
- // Just leave the sockets blocking and hope for the best. Some features
- // will not work.
+ // On Windows, we redirect process standard output and standard error
+ // through temporary files, and then use stream_select to determine
+ // if there's more data to read.
if ((!stream_set_blocking($stdout, false)) ||
(!stream_set_blocking($stderr, false)) ||
@@ -732,14 +774,14 @@
$status = $this->procGetStatus();
$read_buffer_size = $this->readBufferSize;
-
+
$max_stdout_read_bytes = PHP_INT_MAX;
$max_stderr_read_bytes = PHP_INT_MAX;
if ($read_buffer_size !== null) {
$max_stdout_read_bytes = $read_buffer_size - strlen($this->stdout);
$max_stderr_read_bytes = $read_buffer_size - strlen($this->stderr);
}
-
+
if ($max_stdout_read_bytes > 0) {
$this->stdout .= $this->readAndDiscard(
$stdout,
@@ -755,8 +797,13 @@
'stderr',
$max_stderr_read_bytes);
}
-
+
if (!$status['running']) {
+ if (phutil_is_windows()) {
+ fclose($stdout);
+ fclose($stderr);
+ }
+
$this->result = array(
$status['exitcode'],
$this->stdout,

File Metadata

Mime Type
text/plain
Expires
Mon, May 13, 12:59 PM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6292854
Default Alt Text
D11688.id28129.diff (4 KB)

Event Timeline