mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-19 21:55:14 +00:00
114 lines
3.3 KiB
C#
114 lines
3.3 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
#nullable enable
|
|
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.PowerShell.Telemetry;
|
|
|
|
namespace System.Management.Automation;
|
|
|
|
/// <summary>
|
|
/// Represents a lazily retrieved <see cref="Stream" /> for transfering bytes
|
|
/// to or from.
|
|
/// </summary>
|
|
internal abstract class BytePipe
|
|
{
|
|
public abstract Task<Stream> GetStream(CancellationToken cancellationToken);
|
|
|
|
internal AsyncByteStreamTransfer Bind(BytePipe bytePipe)
|
|
{
|
|
Debug.Assert(bytePipe is not null);
|
|
return new AsyncByteStreamTransfer(bytePipe, destinationPipe: this);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a <see cref="Stream" /> lazily retrieved from the underlying
|
|
/// <see cref="NativeCommandProcessor" />.
|
|
/// </summary>
|
|
internal sealed class NativeCommandProcessorBytePipe : BytePipe
|
|
{
|
|
private readonly NativeCommandProcessor _nativeCommand;
|
|
|
|
private readonly bool _stdout;
|
|
|
|
internal NativeCommandProcessorBytePipe(
|
|
NativeCommandProcessor nativeCommand,
|
|
bool stdout)
|
|
{
|
|
Debug.Assert(nativeCommand is not null);
|
|
_nativeCommand = nativeCommand;
|
|
_stdout = stdout;
|
|
}
|
|
|
|
public override async Task<Stream> GetStream(CancellationToken cancellationToken)
|
|
{
|
|
// If the native command we're wrapping is the upstream command then
|
|
// NativeCommandProcessor.Prepare will have already been called before
|
|
// the creation of this BytePipe.
|
|
if (_stdout)
|
|
{
|
|
return _nativeCommand.GetStream(stdout: true);
|
|
}
|
|
|
|
await _nativeCommand.WaitForProcessInitializationAsync(cancellationToken);
|
|
return _nativeCommand.GetStream(stdout: false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Provides an byte pipe implementation representing a <see cref="FileStream" />.
|
|
/// </summary>
|
|
internal sealed class FileBytePipe : BytePipe
|
|
{
|
|
private readonly Stream _stream;
|
|
|
|
private FileBytePipe(Stream stream)
|
|
{
|
|
Debug.Assert(stream is not null);
|
|
_stream = stream;
|
|
}
|
|
|
|
internal static FileBytePipe Create(string fileName, bool append)
|
|
{
|
|
FileStream fileStream;
|
|
try
|
|
{
|
|
PathUtils.MasterStreamOpen(
|
|
fileName,
|
|
resolvedEncoding: null,
|
|
defaultEncoding: false,
|
|
append,
|
|
Force: true,
|
|
NoClobber: false,
|
|
out fileStream,
|
|
streamWriter: out _,
|
|
readOnlyFileInfo: out _,
|
|
isLiteralPath: true);
|
|
}
|
|
catch (Exception e) when (e.Data.Contains(typeof(ErrorRecord)))
|
|
{
|
|
// The error record is attached to the exception when thrown to preserve
|
|
// the call stack.
|
|
ErrorRecord? errorRecord = e.Data[typeof(ErrorRecord)] as ErrorRecord;
|
|
if (errorRecord is null)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
e.Data.Remove(typeof(ErrorRecord));
|
|
throw new RuntimeException(null, e, errorRecord);
|
|
}
|
|
|
|
ApplicationInsightsTelemetry.SendExperimentalUseData("PSNativeCommandPreserveBytePipe", "f");
|
|
|
|
return new FileBytePipe(fileStream);
|
|
}
|
|
|
|
public override Task<Stream> GetStream(CancellationToken cancellationToken) => Task.FromResult(_stream);
|
|
}
|