Add a path for checking ZoneInformation without throwing an exception (#8025)
This commit is contained in:
parent
05e9f78bcb
commit
3e4fa87901
|
@ -8242,24 +8242,54 @@ namespace System.Management.Automation.Internal
|
|||
/// <returns>A FileStream that can be used to interact with the file.</returns>
|
||||
internal static FileStream CreateFileStream(string path, string streamName, FileMode mode, FileAccess access, FileShare share)
|
||||
{
|
||||
if (path == null) throw new ArgumentNullException("path");
|
||||
if (streamName == null) throw new ArgumentNullException("streamName");
|
||||
if (!TryCreateFileStream(path, streamName, mode, access, share, out var stream))
|
||||
{
|
||||
string errorMessage = StringUtil.Format(
|
||||
FileSystemProviderStrings.AlternateDataStreamNotFound, streamName, path);
|
||||
throw new FileNotFoundException(errorMessage, $"{path}:{streamName}");
|
||||
}
|
||||
|
||||
string adjustedStreamName = streamName.Trim();
|
||||
adjustedStreamName = ":" + adjustedStreamName;
|
||||
string resultPath = path + adjustedStreamName;
|
||||
return stream;
|
||||
}
|
||||
|
||||
if (mode == FileMode.Append) mode = FileMode.OpenOrCreate;
|
||||
/// <summary>
|
||||
/// Tries to create a file stream on a file.
|
||||
/// </summary>
|
||||
/// <param name="path">The fully-qualified path to the file.</param>
|
||||
/// <param name="streamName">The name of the alternate data stream to open.</param>
|
||||
/// <param name="mode">The FileMode of the file.</param>
|
||||
/// <param name="access">The FileAccess of the file.</param>
|
||||
/// <param name="share">The FileShare of the file.</param>
|
||||
/// <param name="stream">A FileStream that can be used to interact with the file.</param>
|
||||
/// <returns>true if the stream was successfully created, otherwise false.</returns>
|
||||
internal static bool TryCreateFileStream(string path, string streamName, FileMode mode, FileAccess access, FileShare share, out FileStream stream)
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
if (streamName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(streamName));
|
||||
}
|
||||
|
||||
if (mode == FileMode.Append)
|
||||
{
|
||||
mode = FileMode.OpenOrCreate;
|
||||
}
|
||||
|
||||
var resultPath = $"{path}:{streamName}";
|
||||
SafeFileHandle handle = NativeMethods.CreateFile(resultPath, access, share, IntPtr.Zero, mode, 0, IntPtr.Zero);
|
||||
|
||||
if (handle.IsInvalid)
|
||||
{
|
||||
string errorMessage = StringUtil.Format(
|
||||
FileSystemProviderStrings.AlternateDataStreamNotFound, streamName, path);
|
||||
throw new FileNotFoundException(errorMessage, resultPath);
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return new FileStream(handle, access);
|
||||
stream = new FileStream(handle, access);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -224,57 +224,50 @@ namespace System.Management.Automation
|
|||
/// </summary>
|
||||
private static SecurityZone ReadFromZoneIdentifierDataStream(string filePath)
|
||||
{
|
||||
try
|
||||
if (!AlternateDataStreamUtilities.TryCreateFileStream(filePath, "Zone.Identifier", FileMode.Open, FileAccess.Read, FileShare.Read, out var zoneDataStream))
|
||||
{
|
||||
FileStream zoneDataSteam = AlternateDataStreamUtilities.CreateFileStream(
|
||||
filePath, "Zone.Identifier", FileMode.Open,
|
||||
FileAccess.Read, FileShare.Read);
|
||||
return SecurityZone.NoZone;
|
||||
}
|
||||
|
||||
// If we successfully get the zone data stream, try to read the ZoneId information
|
||||
using (StreamReader zoneDataReader = new StreamReader(zoneDataSteam, GetDefaultEncoding()))
|
||||
// If we successfully get the zone data stream, try to read the ZoneId information
|
||||
using (StreamReader zoneDataReader = new StreamReader(zoneDataStream, GetDefaultEncoding()))
|
||||
{
|
||||
string line = null;
|
||||
bool zoneTransferMatched = false;
|
||||
|
||||
// After a lot experiments with Zone.CreateFromUrl/Zone.SecurityZone, the way it handles the alternate
|
||||
// data stream 'Zone.Identifier' is observed as follows:
|
||||
// 1. Read content of the data stream line by line. Each line is trimmed.
|
||||
// 2. Try to match the current line with '^\[ZoneTransfer\]'.
|
||||
// - if matching, then do step #3 starting from the next line
|
||||
// - if not matching, then continue to do step #2 with the next line.
|
||||
// 3. Try to match the current line with '^ZoneId\s*=\s*(.*)'
|
||||
// - if matching, check if the ZoneId is valid. Then return the corresponding SecurityZone if valid, or 'NoZone' if invalid.
|
||||
// - if not matching, then continue to do step #3 with the next line.
|
||||
// 4. Reach EOF, then return 'NoZone'.
|
||||
while ((line = zoneDataReader.ReadLine()) != null)
|
||||
{
|
||||
string line = null;
|
||||
bool zoneTransferMatched = false;
|
||||
|
||||
// After a lot experiments with Zone.CreateFromUrl/Zone.SecurityZone, the way it handles the alternate
|
||||
// data stream 'Zone.Identifier' is observed as follows:
|
||||
// 1. Read content of the data stream line by line. Each line is trimmed.
|
||||
// 2. Try to match the current line with '^\[ZoneTransfer\]'.
|
||||
// - if matching, then do step #3 starting from the next line
|
||||
// - if not matching, then continue to do step #2 with the next line.
|
||||
// 3. Try to match the current line with '^ZoneId\s*=\s*(.*)'
|
||||
// - if matching, check if the ZoneId is valid. Then return the corresponding SecurityZone if valid, or 'NoZone' if invalid.
|
||||
// - if not matching, then continue to do step #3 with the next line.
|
||||
// 4. Reach EOF, then return 'NoZone'.
|
||||
while ((line = zoneDataReader.ReadLine()) != null)
|
||||
line = line.Trim();
|
||||
if (!zoneTransferMatched)
|
||||
{
|
||||
line = line.Trim();
|
||||
if (!zoneTransferMatched)
|
||||
{
|
||||
zoneTransferMatched = Regex.IsMatch(line, @"^\[ZoneTransfer\]", RegexOptions.IgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
Match match = Regex.Match(line, @"^ZoneId\s*=\s*(.*)", RegexOptions.IgnoreCase);
|
||||
if (!match.Success) { continue; }
|
||||
zoneTransferMatched = Regex.IsMatch(line, @"^\[ZoneTransfer\]", RegexOptions.IgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
Match match = Regex.Match(line, @"^ZoneId\s*=\s*(.*)", RegexOptions.IgnoreCase);
|
||||
if (!match.Success) { continue; }
|
||||
|
||||
// Match found. Validate ZoneId value.
|
||||
string zoneIdRawValue = match.Groups[1].Value;
|
||||
match = Regex.Match(zoneIdRawValue, @"^[+-]?\d+", RegexOptions.IgnoreCase);
|
||||
if (!match.Success) { return SecurityZone.NoZone; }
|
||||
// Match found. Validate ZoneId value.
|
||||
string zoneIdRawValue = match.Groups[1].Value;
|
||||
match = Regex.Match(zoneIdRawValue, @"^[+-]?\d+", RegexOptions.IgnoreCase);
|
||||
if (!match.Success) { return SecurityZone.NoZone; }
|
||||
|
||||
string zoneId = match.Groups[0].Value;
|
||||
SecurityZone result;
|
||||
return LanguagePrimitives.TryConvertTo(zoneId, out result) ? result : SecurityZone.NoZone;
|
||||
}
|
||||
string zoneId = match.Groups[0].Value;
|
||||
SecurityZone result;
|
||||
return LanguagePrimitives.TryConvertTo(zoneId, out result) ? result : SecurityZone.NoZone;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// FileNotFoundException may be thrown by AlternateDataStreamUtilities.CreateFileStream when the data stream 'Zone.Identifier'
|
||||
// does not exist, or when the underlying file system doesn't support alternate data stream.
|
||||
}
|
||||
|
||||
return SecurityZone.NoZone;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue