-
Notifications
You must be signed in to change notification settings - Fork 8.4k
The -Stream parameter now works with directories #13941
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1311,35 +1311,36 @@ protected override void GetItem(string path) | |
| // If we want to retrieve the file streams, retrieve them. | ||
| if (retrieveStreams) | ||
| { | ||
| if (!isContainer) | ||
| foreach (string desiredStream in dynamicParameters.Stream) | ||
| { | ||
| foreach (string desiredStream in dynamicParameters.Stream) | ||
| { | ||
| // See that it matches the name specified | ||
| WildcardPattern p = WildcardPattern.Get(desiredStream, WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant); | ||
| bool foundStream = false; | ||
| // See that it matches the name specified | ||
| WildcardPattern p = WildcardPattern.Get(desiredStream, WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant); | ||
| bool foundStream = false; | ||
|
|
||
| foreach (AlternateStreamData stream in AlternateDataStreamUtilities.GetStreams(result.FullName)) | ||
| foreach (AlternateStreamData stream in AlternateDataStreamUtilities.GetStreams(result.FullName)) | ||
| { | ||
| if (!p.IsMatch(stream.Stream)) | ||
| { | ||
| if (!p.IsMatch(stream.Stream)) { continue; } | ||
|
|
||
| string outputPath = result.FullName + ":" + stream.Stream; | ||
| WriteItemObject(stream, outputPath, isContainer); | ||
| foundStream = true; | ||
| continue; | ||
| } | ||
|
|
||
| if ((!WildcardPattern.ContainsWildcardCharacters(desiredStream)) && (!foundStream)) | ||
| { | ||
| string errorMessage = StringUtil.Format( | ||
| FileSystemProviderStrings.AlternateDataStreamNotFound, desiredStream, result.FullName); | ||
| Exception e = new FileNotFoundException(errorMessage, result.FullName); | ||
|
|
||
| WriteError(new ErrorRecord( | ||
| e, | ||
| "AlternateDataStreamNotFound", | ||
| ErrorCategory.ObjectNotFound, | ||
| path)); | ||
| } | ||
| string outputPath = result.FullName + ":" + stream.Stream; | ||
| // Alternate data streams can never be containers. | ||
| WriteItemObject(stream, outputPath, isContainer: false); | ||
| foundStream = true; | ||
| } | ||
|
|
||
| if ((!WildcardPattern.ContainsWildcardCharacters(desiredStream)) && (!foundStream)) | ||
| { | ||
| string errorMessage = StringUtil.Format( | ||
| FileSystemProviderStrings.AlternateDataStreamNotFound, desiredStream, result.FullName); | ||
| Exception e = new FileNotFoundException(errorMessage, result.FullName); | ||
|
|
||
| WriteError(new ErrorRecord( | ||
| e, | ||
| "AlternateDataStreamNotFound", | ||
| ErrorCategory.ObjectNotFound, | ||
| path)); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -6666,7 +6667,14 @@ public IContentReader GetContentReader(string path) | |
|
|
||
| try | ||
| { | ||
| if (Directory.Exists(path)) | ||
| // Get-Content will write a non-terminating error if the target is a directory. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a few comments here, per Ilya in the V1 PR. Just needed to make sure to explain why the streamName check was here in a !UNIX block. |
||
| // On Windows, the streamName must be null or empty for it to write the error. Otherwise, the | ||
| // alternate data stream is not a directory, even if it's set on a directory. | ||
| if (Directory.Exists(path) | ||
| #if !UNIX | ||
| && string.IsNullOrEmpty(streamName) | ||
| #endif | ||
|
kyanha marked this conversation as resolved.
|
||
| ) | ||
| { | ||
| string errMsg = StringUtil.Format(SessionStateStrings.GetContainerContentException, path); | ||
| ErrorRecord error = new ErrorRecord(new InvalidOperationException(errMsg), "GetContainerContentException", ErrorCategory.InvalidOperation, null); | ||
|
|
@@ -6821,7 +6829,14 @@ public IContentWriter GetContentWriter(string path) | |
|
|
||
| try | ||
| { | ||
| if (Directory.Exists(path)) | ||
| // Add-Content and Set-Content will write a non-terminating error if the target is a directory. | ||
|
kyanha marked this conversation as resolved.
|
||
| // On Windows, the streamName must be null or empty for it to write the error. Otherwise, the | ||
| // alternate data stream is not a directory, even if it's set on a directory. | ||
| if (Directory.Exists(path) | ||
| #if !UNIX | ||
| && string.IsNullOrEmpty(streamName) | ||
| #endif | ||
| ) | ||
| { | ||
| string errMsg = StringUtil.Format(SessionStateStrings.WriteContainerContentException, path); | ||
| ErrorRecord error = new ErrorRecord(new InvalidOperationException(errMsg), "WriteContainerContentException", ErrorCategory.InvalidOperation, null); | ||
|
|
@@ -6899,13 +6914,6 @@ public void ClearContent(string path) | |
|
|
||
| path = NormalizePath(path); | ||
|
|
||
| if (Directory.Exists(path)) | ||
| { | ||
| string errorMsg = StringUtil.Format(SessionStateStrings.ClearDirectoryContent, path); | ||
| WriteError(new ErrorRecord(new NotSupportedException(errorMsg), "ClearDirectoryContent", ErrorCategory.InvalidOperation, path)); | ||
| return; | ||
| } | ||
|
|
||
| try | ||
| { | ||
| #if !UNIX | ||
|
|
@@ -6957,6 +6965,26 @@ public void ClearContent(string path) | |
| clearStream = false; | ||
| } | ||
|
|
||
| #endif | ||
| // On Windows, determine if our argument is a directory only after we determine if | ||
| // we're being asked to work with an alternate data stream, because directories can have | ||
| // alternate data streams on them that are not child items. These alternate data streams | ||
| // must be treated as data streams, even if they're attached to directories. However, | ||
| // if asked to work with a directory without a data stream specified, write a non-terminating | ||
| // error instead of clearing all child items of the directory. (On non-Windows, alternate | ||
| // data streams don't exist, so in that environment always write the error when addressing | ||
| // a directory.) | ||
| if (Directory.Exists(path) | ||
| #if !UNIX | ||
| && !clearStream | ||
| #endif | ||
| ) | ||
| { | ||
| string errorMsg = StringUtil.Format(SessionStateStrings.ClearDirectoryContent, path); | ||
| WriteError(new ErrorRecord(new NotSupportedException(errorMsg), "ClearDirectoryContent", ErrorCategory.InvalidOperation, path)); | ||
| return; | ||
| } | ||
| #if !UNIX | ||
| if (clearStream) | ||
| { | ||
| FileStream fileStream = null; | ||
|
|
@@ -8622,7 +8650,22 @@ internal static List<AlternateStreamData> GetStreams(string path) | |
| SafeFindHandle handle = NativeMethods.FindFirstStreamW( | ||
| path, NativeMethods.StreamInfoLevels.FindStreamInfoStandard, | ||
| findStreamData, 0); | ||
|
kyanha marked this conversation as resolved.
|
||
| if (handle.IsInvalid) throw new Win32Exception(); | ||
|
|
||
| if (handle.IsInvalid) | ||
| { | ||
| int error = Marshal.GetLastWin32Error(); | ||
|
|
||
| // Directories don't normally have alternate streams, so this is not an exceptional state. | ||
| // If a directory has no alternate data streams, FindFirstStreamW returns ERROR_HANDLE_EOF. | ||
| if (error == NativeMethods.ERROR_HANDLE_EOF) | ||
| { | ||
| return alternateStreams; | ||
| } | ||
|
|
||
| // An unexpected error was returned, that we don't know how to interpret. The most helpful | ||
| // thing we can do at this point is simply throw the raw Win32 exception. | ||
| throw new Win32Exception(error); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this isn't a a friendly error message, but I'd rather get functionality in and then gussy it up than fight with it in this PR. (again, an Ilya suggestion.) |
||
| } | ||
|
|
||
| try | ||
| { | ||
|
|
@@ -8757,6 +8800,7 @@ internal static void SetZoneOfOrigin(string path, SecurityZone securityZone) | |
| internal static class NativeMethods | ||
| { | ||
| internal const int ERROR_HANDLE_EOF = 38; | ||
| internal const int ERROR_INVALID_PARAMETER = 87; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is returned when a filesystem doesn't support alternate data streams. |
||
|
|
||
| internal enum StreamInfoLevels { FindStreamInfoStandard = 0 } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed isContainer check, because streams can be retrieved from containers as well.