diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs
index 1c918ea8c2..141b7803c9 100644
--- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs
+++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs
@@ -8242,24 +8242,54 @@ namespace System.Management.Automation.Internal
/// A FileStream that can be used to interact with the file.
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;
+ ///
+ /// Tries to create a file stream on a file.
+ ///
+ /// The fully-qualified path to the file.
+ /// The name of the alternate data stream to open.
+ /// The FileMode of the file.
+ /// The FileAccess of the file.
+ /// The FileShare of the file.
+ /// A FileStream that can be used to interact with the file.
+ /// true if the stream was successfully created, otherwise false.
+ 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;
}
///
diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs
index 144844c3b4..02ecae8f6a 100644
--- a/src/System.Management.Automation/utils/ClrFacade.cs
+++ b/src/System.Management.Automation/utils/ClrFacade.cs
@@ -224,57 +224,50 @@ namespace System.Management.Automation
///
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;
}