diff options
author | Marek Safar <marek.safar@gmail.com> | 2017-06-20 14:21:00 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2017-06-20 14:21:00 +0300 |
commit | b177aba3ac6d685d48dce5359707be91a213fe0c (patch) | |
tree | 573e9c2160f3d38c4471b36d38263d1ac33187fa /src/System.IO.FileSystem | |
parent | 8cf292c487d12ed451fe8c0d05acc509eb85fa70 (diff) | |
parent | cf4b42457249f6d874141b43231bb727c60a0e20 (diff) |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'src/System.IO.FileSystem')
24 files changed, 427 insertions, 1580 deletions
diff --git a/src/System.IO.FileSystem/src/PinvokeAnalyzerExceptionList.analyzerdata b/src/System.IO.FileSystem/src/PinvokeAnalyzerExceptionList.analyzerdata deleted file mode 100644 index 4b690b7504..0000000000 --- a/src/System.IO.FileSystem/src/PinvokeAnalyzerExceptionList.analyzerdata +++ /dev/null @@ -1,6 +0,0 @@ -kernel32.dll!CopyFileExW -kernel32.dll!CreateFileW -kernel32.dll!DeleteVolumeMountPointW -kernel32.dll!GetLogicalDrives -kernel32.dll!SetThreadErrorMode - diff --git a/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj b/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj index 1036cfbf78..c604f2f0af 100644 --- a/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj +++ b/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj @@ -63,6 +63,7 @@ </ItemGroup> <!-- Windows --> <ItemGroup Condition="'$(TargetsWindows)' == 'true'"> + <Compile Include="System\IO\DisableMediaInsertionPrompt.cs" /> <Compile Include="Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" /> <Compile Include="System\IO\DirectoryInfo.Windows.cs" /> <Compile Include="System\IO\FileInfo.Windows.cs" /> @@ -235,9 +236,7 @@ <Compile Include="System\IO\FileSystemInfo.WinRT.cs" /> <Compile Include="System\IO\MultiplexingWin32WinRTFileSystem.cs" /> <Compile Include="System\IO\WinRTIOExtensions.cs" /> - <Compile Include="System\IO\WinRTFileStream.cs" /> <Compile Include="System\IO\WinRTFileSystem.cs" /> - <Compile Include="System\IO\WinRTFileSystemObject.cs" /> <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.CopyFile2.cs"> <Link>Common\Interop\Windows\Interop.CopyFile2.cs</Link> </Compile> diff --git a/src/System.IO.FileSystem/src/System/IO/Directory.cs b/src/System.IO.FileSystem/src/System/IO/Directory.cs index cd7ada9dd2..8039cc6a83 100644 --- a/src/System.IO.FileSystem/src/System/IO/Directory.cs +++ b/src/System.IO.FileSystem/src/System/IO/Directory.cs @@ -2,25 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections; using System.Collections.Generic; -using System.Security; -using Microsoft.Win32; -using Microsoft.Win32.SafeHandles; -using System.Text; -using System.Runtime.InteropServices; -using System.Globalization; -using System.Runtime.Versioning; using System.Diagnostics; using System.Diagnostics.Contracts; -using System.Threading; +using System.Security; namespace System.IO { public static partial class Directory { - public static DirectoryInfo GetParent(String path) + public static DirectoryInfo GetParent(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -29,16 +20,16 @@ namespace System.IO throw new ArgumentException(SR.Argument_PathEmpty, nameof(path)); Contract.EndContractBlock(); - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); - String s = Path.GetDirectoryName(fullPath); + string s = Path.GetDirectoryName(fullPath); if (s == null) return null; return new DirectoryInfo(s); } [System.Security.SecuritySafeCritical] - public static DirectoryInfo CreateDirectory(String path) + public static DirectoryInfo CreateDirectory(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -46,7 +37,7 @@ namespace System.IO throw new ArgumentException(SR.Argument_PathEmpty, nameof(path)); Contract.EndContractBlock(); - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.CreateDirectory(fullPath); @@ -55,9 +46,9 @@ namespace System.IO // Input to this method should already be fullpath. This method will ensure that we append // the trailing slash only when appropriate. - internal static String EnsureTrailingDirectorySeparator(string fullPath) + internal static string EnsureTrailingDirectorySeparator(string fullPath) { - String fullPathWithTrailingDirectorySeparator; + string fullPathWithTrailingDirectorySeparator; if (!PathHelpers.EndsInDirectorySeparator(fullPath)) fullPathWithTrailingDirectorySeparator = fullPath + PathHelpers.DirectorySeparatorCharAsString; @@ -74,7 +65,7 @@ namespace System.IO // contents. // [System.Security.SecuritySafeCritical] // auto-generated - public static bool Exists(String path) + public static bool Exists(string path) { try { @@ -83,7 +74,7 @@ namespace System.IO if (path.Length == 0) return false; - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.DirectoryExists(fullPath); } @@ -96,78 +87,78 @@ namespace System.IO return false; } - public static void SetCreationTime(String path, DateTime creationTime) + public static void SetCreationTime(string path, DateTime creationTime) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetCreationTime(fullPath, creationTime, asDirectory: true); } - public static void SetCreationTimeUtc(String path, DateTime creationTimeUtc) + public static void SetCreationTimeUtc(string path, DateTime creationTimeUtc) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetCreationTime(fullPath, File.GetUtcDateTimeOffset(creationTimeUtc), asDirectory: true); } - public static DateTime GetCreationTime(String path) + public static DateTime GetCreationTime(string path) { return File.GetCreationTime(path); } - public static DateTime GetCreationTimeUtc(String path) + public static DateTime GetCreationTimeUtc(string path) { return File.GetCreationTimeUtc(path); } - public static void SetLastWriteTime(String path, DateTime lastWriteTime) + public static void SetLastWriteTime(string path, DateTime lastWriteTime) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastWriteTime(fullPath, lastWriteTime, asDirectory: true); } - public static void SetLastWriteTimeUtc(String path, DateTime lastWriteTimeUtc) + public static void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastWriteTime(fullPath, File.GetUtcDateTimeOffset(lastWriteTimeUtc), asDirectory: true); } - public static DateTime GetLastWriteTime(String path) + public static DateTime GetLastWriteTime(string path) { return File.GetLastWriteTime(path); } - public static DateTime GetLastWriteTimeUtc(String path) + public static DateTime GetLastWriteTimeUtc(string path) { return File.GetLastWriteTimeUtc(path); } - public static void SetLastAccessTime(String path, DateTime lastAccessTime) + public static void SetLastAccessTime(string path, DateTime lastAccessTime) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastAccessTime(fullPath, lastAccessTime, asDirectory: true); } - public static void SetLastAccessTimeUtc(String path, DateTime lastAccessTimeUtc) + public static void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastAccessTime(fullPath, File.GetUtcDateTimeOffset(lastAccessTimeUtc), asDirectory: true); } - public static DateTime GetLastAccessTime(String path) + public static DateTime GetLastAccessTime(string path) { return File.GetLastAccessTime(path); } - public static DateTime GetLastAccessTimeUtc(String path) + public static DateTime GetLastAccessTimeUtc(string path) { return File.GetLastAccessTimeUtc(path); } // Returns an array of filenames in the DirectoryInfo specified by path - public static String[] GetFiles(String path) + public static string[] GetFiles(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetFiles(path, "*", SearchOption.TopDirectoryOnly); @@ -175,13 +166,13 @@ namespace System.IO // Returns an array of Files in the current DirectoryInfo matching the // given search pattern (i.e. "*.txt"). - public static String[] GetFiles(String path, String searchPattern) + public static string[] GetFiles(string path, string searchPattern) { if (path == null) throw new ArgumentNullException(nameof(path)); if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetFiles(path, searchPattern, SearchOption.TopDirectoryOnly); @@ -189,7 +180,7 @@ namespace System.IO // Returns an array of Files in the current DirectoryInfo matching the // given search pattern (i.e. "*.txt") and search option - public static String[] GetFiles(String path, String searchPattern, SearchOption searchOption) + public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -197,7 +188,7 @@ namespace System.IO throw new ArgumentNullException(nameof(searchPattern)); if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories)) throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetFiles(path, searchPattern, searchOption); @@ -205,7 +196,7 @@ namespace System.IO // Returns an array of Files in the current DirectoryInfo matching the // given search pattern (i.e. "*.txt") and search option - private static String[] InternalGetFiles(String path, String searchPattern, SearchOption searchOption) + private static string[] InternalGetFiles(string path, string searchPattern, SearchOption searchOption) { Debug.Assert(path != null); Debug.Assert(searchPattern != null); @@ -215,11 +206,11 @@ namespace System.IO } // Returns an array of Directories in the current directory. - public static String[] GetDirectories(String path) + public static string[] GetDirectories(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetDirectories(path, "*", SearchOption.TopDirectoryOnly); @@ -227,13 +218,13 @@ namespace System.IO // Returns an array of Directories in the current DirectoryInfo matching the // given search criteria (i.e. "*.txt"). - public static String[] GetDirectories(String path, String searchPattern) + public static string[] GetDirectories(string path, string searchPattern) { if (path == null) throw new ArgumentNullException(nameof(path)); if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly); @@ -241,7 +232,7 @@ namespace System.IO // Returns an array of Directories in the current DirectoryInfo matching the // given search criteria (i.e. "*.txt"). - public static String[] GetDirectories(String path, String searchPattern, SearchOption searchOption) + public static string[] GetDirectories(string path, string searchPattern, SearchOption searchOption) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -249,7 +240,7 @@ namespace System.IO throw new ArgumentNullException(nameof(searchPattern)); if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories)) throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetDirectories(path, searchPattern, searchOption); @@ -257,22 +248,22 @@ namespace System.IO // Returns an array of Directories in the current DirectoryInfo matching the // given search criteria (i.e. "*.txt"). - private static String[] InternalGetDirectories(String path, String searchPattern, SearchOption searchOption) + private static string[] InternalGetDirectories(string path, string searchPattern, SearchOption searchOption) { Debug.Assert(path != null); Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); return InternalGetFileDirectoryNames(path, path, searchPattern, false, true, searchOption); } // Returns an array of strongly typed FileSystemInfo entries in the path - public static String[] GetFileSystemEntries(String path) + public static string[] GetFileSystemEntries(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly); @@ -280,13 +271,13 @@ namespace System.IO // Returns an array of strongly typed FileSystemInfo entries in the path with the // given search criteria (i.e. "*.txt"). We disallow .. as a part of the search criteria - public static String[] GetFileSystemEntries(String path, String searchPattern) + public static string[] GetFileSystemEntries(string path, string searchPattern) { if (path == null) throw new ArgumentNullException(nameof(path)); if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly); @@ -294,7 +285,7 @@ namespace System.IO // Returns an array of strongly typed FileSystemInfo entries in the path with the // given search criteria (i.e. "*.txt"). We disallow .. as a part of the search criteria - public static String[] GetFileSystemEntries(String path, String searchPattern, SearchOption searchOption) + public static string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -302,13 +293,13 @@ namespace System.IO throw new ArgumentNullException(nameof(searchPattern)); if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories)) throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum); - Contract.Ensures(Contract.Result<String[]>() != null); + Contract.Ensures(Contract.Result<string[]>() != null); Contract.EndContractBlock(); return InternalGetFileSystemEntries(path, searchPattern, searchOption); } - private static String[] InternalGetFileSystemEntries(String path, String searchPattern, SearchOption searchOption) + private static string[] InternalGetFileSystemEntries(string path, string searchPattern, SearchOption searchOption) { Debug.Assert(path != null); Debug.Assert(searchPattern != null); @@ -322,19 +313,19 @@ namespace System.IO // the given search criteria against every dir. // For all the dirs/files returned, it will then demand path discovery permission for // their parent folders (it will avoid duplicate permission checks) - internal static String[] InternalGetFileDirectoryNames(String path, String userPathOriginal, String searchPattern, bool includeFiles, bool includeDirs, SearchOption searchOption) + internal static string[] InternalGetFileDirectoryNames(string path, string userPathOriginal, string searchPattern, bool includeFiles, bool includeDirs, SearchOption searchOption) { Debug.Assert(path != null); Debug.Assert(userPathOriginal != null); Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); - IEnumerable<String> enumerable = FileSystem.Current.EnumeratePaths(path, searchPattern, searchOption, + IEnumerable<string> enumerable = FileSystem.Current.EnumeratePaths(path, searchPattern, searchOption, (includeFiles ? SearchTarget.Files : 0) | (includeDirs ? SearchTarget.Directories : 0)); return EnumerableHelpers.ToArray(enumerable); } - public static IEnumerable<String> EnumerateDirectories(String path) + public static IEnumerable<string> EnumerateDirectories(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -343,7 +334,7 @@ namespace System.IO return InternalEnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly); } - public static IEnumerable<String> EnumerateDirectories(String path, String searchPattern) + public static IEnumerable<string> EnumerateDirectories(string path, string searchPattern) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -354,7 +345,7 @@ namespace System.IO return InternalEnumerateDirectories(path, searchPattern, SearchOption.TopDirectoryOnly); } - public static IEnumerable<String> EnumerateDirectories(String path, String searchPattern, SearchOption searchOption) + public static IEnumerable<string> EnumerateDirectories(string path, string searchPattern, SearchOption searchOption) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -367,7 +358,7 @@ namespace System.IO return InternalEnumerateDirectories(path, searchPattern, searchOption); } - private static IEnumerable<String> InternalEnumerateDirectories(String path, String searchPattern, SearchOption searchOption) + private static IEnumerable<string> InternalEnumerateDirectories(string path, string searchPattern, SearchOption searchOption) { Debug.Assert(path != null); Debug.Assert(searchPattern != null); @@ -376,29 +367,29 @@ namespace System.IO return EnumerateFileSystemNames(path, searchPattern, searchOption, false, true); } - public static IEnumerable<String> EnumerateFiles(String path) + public static IEnumerable<string> EnumerateFiles(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); Contract.EndContractBlock(); return InternalEnumerateFiles(path, "*", SearchOption.TopDirectoryOnly); } - public static IEnumerable<String> EnumerateFiles(String path, String searchPattern) + public static IEnumerable<string> EnumerateFiles(string path, string searchPattern) { if (path == null) throw new ArgumentNullException(nameof(path)); if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); Contract.EndContractBlock(); return InternalEnumerateFiles(path, searchPattern, SearchOption.TopDirectoryOnly); } - public static IEnumerable<String> EnumerateFiles(String path, String searchPattern, SearchOption searchOption) + public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOption) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -406,45 +397,45 @@ namespace System.IO throw new ArgumentNullException(nameof(searchPattern)); if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories)) throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); Contract.EndContractBlock(); return InternalEnumerateFiles(path, searchPattern, searchOption); } - private static IEnumerable<String> InternalEnumerateFiles(String path, String searchPattern, SearchOption searchOption) + private static IEnumerable<string> InternalEnumerateFiles(string path, string searchPattern, SearchOption searchOption) { Debug.Assert(path != null); Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); return EnumerateFileSystemNames(path, searchPattern, searchOption, true, false); } - public static IEnumerable<String> EnumerateFileSystemEntries(String path) + public static IEnumerable<string> EnumerateFileSystemEntries(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); Contract.EndContractBlock(); return InternalEnumerateFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly); } - public static IEnumerable<String> EnumerateFileSystemEntries(String path, String searchPattern) + public static IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern) { if (path == null) throw new ArgumentNullException(nameof(path)); if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); Contract.EndContractBlock(); return InternalEnumerateFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly); } - public static IEnumerable<String> EnumerateFileSystemEntries(String path, String searchPattern, SearchOption searchOption) + public static IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, SearchOption searchOption) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -452,48 +443,48 @@ namespace System.IO throw new ArgumentNullException(nameof(searchPattern)); if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories)) throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); Contract.EndContractBlock(); return InternalEnumerateFileSystemEntries(path, searchPattern, searchOption); } - private static IEnumerable<String> InternalEnumerateFileSystemEntries(String path, String searchPattern, SearchOption searchOption) + private static IEnumerable<string> InternalEnumerateFileSystemEntries(string path, string searchPattern, SearchOption searchOption) { Debug.Assert(path != null); Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); return EnumerateFileSystemNames(path, searchPattern, searchOption, true, true); } - private static IEnumerable<String> EnumerateFileSystemNames(String path, String searchPattern, SearchOption searchOption, + private static IEnumerable<string> EnumerateFileSystemNames(string path, string searchPattern, SearchOption searchOption, bool includeFiles, bool includeDirs) { Debug.Assert(path != null); Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); - Contract.Ensures(Contract.Result<IEnumerable<String>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<string>>() != null); return FileSystem.Current.EnumeratePaths(path, searchPattern, searchOption, (includeFiles ? SearchTarget.Files : 0) | (includeDirs ? SearchTarget.Directories : 0)); } [System.Security.SecuritySafeCritical] - public static String GetDirectoryRoot(String path) + public static string GetDirectoryRoot(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); Contract.EndContractBlock(); - String fullPath = Path.GetFullPath(path); - String root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath)); + string fullPath = Path.GetFullPath(path); + string root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath)); return root; } - internal static String InternalGetDirectoryRoot(String path) + internal static string InternalGetDirectoryRoot(string path) { if (path == null) return null; return path.Substring(0, PathInternal.GetRootLength(path)); @@ -507,14 +498,14 @@ namespace System.IO **Exceptions: ==============================================================================*/ [System.Security.SecuritySafeCritical] - public static String GetCurrentDirectory() + public static string GetCurrentDirectory() { return FileSystem.Current.GetCurrentDirectory(); } [System.Security.SecurityCritical] // auto-generated - public static void SetCurrentDirectory(String path) + public static void SetCurrentDirectory(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -524,13 +515,13 @@ namespace System.IO if (PathInternal.IsPathTooLong(path)) throw new PathTooLongException(SR.IO_PathTooLong); - String fulldestDirName = Path.GetFullPath(path); + string fulldestDirName = Path.GetFullPath(path); FileSystem.Current.SetCurrentDirectory(fulldestDirName); } [System.Security.SecuritySafeCritical] - public static void Move(String sourceDirName, String destDirName) + public static void Move(string sourceDirName, string destDirName) { if (sourceDirName == null) throw new ArgumentNullException(nameof(sourceDirName)); @@ -543,25 +534,25 @@ namespace System.IO throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destDirName)); Contract.EndContractBlock(); - String fullsourceDirName = Path.GetFullPath(sourceDirName); - String sourcePath = EnsureTrailingDirectorySeparator(fullsourceDirName); + string fullsourceDirName = Path.GetFullPath(sourceDirName); + string sourcePath = EnsureTrailingDirectorySeparator(fullsourceDirName); if (PathInternal.IsDirectoryTooLong(sourcePath)) throw new PathTooLongException(SR.IO_PathTooLong); - String fulldestDirName = Path.GetFullPath(destDirName); - String destPath = EnsureTrailingDirectorySeparator(fulldestDirName); + string fulldestDirName = Path.GetFullPath(destDirName); + string destPath = EnsureTrailingDirectorySeparator(fulldestDirName); if (PathInternal.IsDirectoryTooLong(destPath)) throw new PathTooLongException(SR.IO_PathTooLong); StringComparison pathComparison = PathInternal.StringComparison; - if (String.Equals(sourcePath, destPath, pathComparison)) + if (string.Equals(sourcePath, destPath, pathComparison)) throw new IOException(SR.IO_SourceDestMustBeDifferent); - String sourceRoot = Path.GetPathRoot(sourcePath); - String destinationRoot = Path.GetPathRoot(destPath); - if (!String.Equals(sourceRoot, destinationRoot, pathComparison)) + string sourceRoot = Path.GetPathRoot(sourcePath); + string destinationRoot = Path.GetPathRoot(destPath); + if (!string.Equals(sourceRoot, destinationRoot, pathComparison)) throw new IOException(SR.IO_SourceDestMustHaveSameRoot); // Windows will throw if the source file/directory doesn't exist, we preemptively check @@ -576,16 +567,16 @@ namespace System.IO } [System.Security.SecuritySafeCritical] - public static void Delete(String path) + public static void Delete(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.RemoveDirectory(fullPath, false); } [System.Security.SecuritySafeCritical] - public static void Delete(String path, bool recursive) + public static void Delete(string path, bool recursive) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.RemoveDirectory(fullPath, recursive); } diff --git a/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs b/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs index 4b4a274997..9842c70f87 100644 --- a/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs +++ b/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Security; -using System.Runtime.Serialization; namespace System.IO { @@ -14,7 +13,7 @@ namespace System.IO public sealed partial class DirectoryInfo : FileSystemInfo { [System.Security.SecuritySafeCritical] - public DirectoryInfo(String path) + public DirectoryInfo(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -26,7 +25,7 @@ namespace System.IO } [System.Security.SecuritySafeCritical] - internal DirectoryInfo(String fullPath, String originalPath) + internal DirectoryInfo(string fullPath, string originalPath) { Debug.Assert(Path.IsPathRooted(fullPath), "fullPath must be fully qualified!"); @@ -36,7 +35,7 @@ namespace System.IO DisplayPath = GetDisplayName(OriginalPath); } - public override String Name + public override string Name { get { @@ -68,7 +67,7 @@ namespace System.IO [System.Security.SecuritySafeCritical] - public DirectoryInfo CreateSubdirectory(String path) + public DirectoryInfo CreateSubdirectory(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -78,16 +77,16 @@ namespace System.IO } [System.Security.SecurityCritical] // auto-generated - private DirectoryInfo CreateSubdirectoryHelper(String path) + private DirectoryInfo CreateSubdirectoryHelper(string path) { Debug.Assert(path != null); PathHelpers.ThrowIfEmptyOrRootedPath(path); - String newDirs = Path.Combine(FullPath, path); - String fullPath = Path.GetFullPath(newDirs); + string newDirs = Path.Combine(FullPath, path); + string fullPath = Path.GetFullPath(newDirs); - if (0 != String.Compare(FullPath, 0, fullPath, 0, FullPath.Length, PathInternal.StringComparison)) + if (0 != string.Compare(FullPath, 0, fullPath, 0, FullPath.Length, PathInternal.StringComparison)) { throw new ArgumentException(SR.Format(SR.Argument_InvalidSubPath, path, DisplayPath), nameof(path)); } @@ -128,7 +127,7 @@ namespace System.IO // Returns an array of Files in the current DirectoryInfo matching the // given search criteria (i.e. "*.txt"). [SecurityCritical] - public FileInfo[] GetFiles(String searchPattern) + public FileInfo[] GetFiles(string searchPattern) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -139,7 +138,7 @@ namespace System.IO // Returns an array of Files in the current DirectoryInfo matching the // given search criteria (i.e. "*.txt"). - public FileInfo[] GetFiles(String searchPattern, SearchOption searchOption) + public FileInfo[] GetFiles(string searchPattern, SearchOption searchOption) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -152,7 +151,7 @@ namespace System.IO // Returns an array of Files in the current DirectoryInfo matching the // given search criteria (i.e. "*.txt"). - private FileInfo[] InternalGetFiles(String searchPattern, SearchOption searchOption) + private FileInfo[] InternalGetFiles(string searchPattern, SearchOption searchOption) { Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); @@ -175,7 +174,7 @@ namespace System.IO // Returns an array of strongly typed FileSystemInfo entries in the path with the // given search criteria (i.e. "*.txt"). - public FileSystemInfo[] GetFileSystemInfos(String searchPattern) + public FileSystemInfo[] GetFileSystemInfos(string searchPattern) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -186,7 +185,7 @@ namespace System.IO // Returns an array of strongly typed FileSystemInfo entries in the path with the // given search criteria (i.e. "*.txt"). - public FileSystemInfo[] GetFileSystemInfos(String searchPattern, SearchOption searchOption) + public FileSystemInfo[] GetFileSystemInfos(string searchPattern, SearchOption searchOption) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -199,7 +198,7 @@ namespace System.IO // Returns an array of strongly typed FileSystemInfo entries in the path with the // given search criteria (i.e. "*.txt"). - private FileSystemInfo[] InternalGetFileSystemInfos(String searchPattern, SearchOption searchOption) + private FileSystemInfo[] InternalGetFileSystemInfos(string searchPattern, SearchOption searchOption) { Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); @@ -218,7 +217,7 @@ namespace System.IO // Returns an array of Directories in the current DirectoryInfo matching the // given search criteria (i.e. "System*" could match the System & System32 // directories). - public DirectoryInfo[] GetDirectories(String searchPattern) + public DirectoryInfo[] GetDirectories(string searchPattern) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -230,7 +229,7 @@ namespace System.IO // Returns an array of Directories in the current DirectoryInfo matching the // given search criteria (i.e. "System*" could match the System & System32 // directories). - public DirectoryInfo[] GetDirectories(String searchPattern, SearchOption searchOption) + public DirectoryInfo[] GetDirectories(string searchPattern, SearchOption searchOption) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -244,7 +243,7 @@ namespace System.IO // Returns an array of Directories in the current DirectoryInfo matching the // given search criteria (i.e. "System*" could match the System & System32 // directories). - private DirectoryInfo[] InternalGetDirectories(String searchPattern, SearchOption searchOption) + private DirectoryInfo[] InternalGetDirectories(string searchPattern, SearchOption searchOption) { Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); @@ -258,7 +257,7 @@ namespace System.IO return InternalEnumerateDirectories("*", SearchOption.TopDirectoryOnly); } - public IEnumerable<DirectoryInfo> EnumerateDirectories(String searchPattern) + public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -267,7 +266,7 @@ namespace System.IO return InternalEnumerateDirectories(searchPattern, SearchOption.TopDirectoryOnly); } - public IEnumerable<DirectoryInfo> EnumerateDirectories(String searchPattern, SearchOption searchOption) + public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern, SearchOption searchOption) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -278,7 +277,7 @@ namespace System.IO return InternalEnumerateDirectories(searchPattern, searchOption); } - private IEnumerable<DirectoryInfo> InternalEnumerateDirectories(String searchPattern, SearchOption searchOption) + private IEnumerable<DirectoryInfo> InternalEnumerateDirectories(string searchPattern, SearchOption searchOption) { Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); @@ -291,7 +290,7 @@ namespace System.IO return InternalEnumerateFiles("*", SearchOption.TopDirectoryOnly); } - public IEnumerable<FileInfo> EnumerateFiles(String searchPattern) + public IEnumerable<FileInfo> EnumerateFiles(string searchPattern) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -300,7 +299,7 @@ namespace System.IO return InternalEnumerateFiles(searchPattern, SearchOption.TopDirectoryOnly); } - public IEnumerable<FileInfo> EnumerateFiles(String searchPattern, SearchOption searchOption) + public IEnumerable<FileInfo> EnumerateFiles(string searchPattern, SearchOption searchOption) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -311,7 +310,7 @@ namespace System.IO return InternalEnumerateFiles(searchPattern, searchOption); } - private IEnumerable<FileInfo> InternalEnumerateFiles(String searchPattern, SearchOption searchOption) + private IEnumerable<FileInfo> InternalEnumerateFiles(string searchPattern, SearchOption searchOption) { Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); @@ -324,7 +323,7 @@ namespace System.IO return InternalEnumerateFileSystemInfos("*", SearchOption.TopDirectoryOnly); } - public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(String searchPattern) + public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -333,7 +332,7 @@ namespace System.IO return InternalEnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly); } - public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(String searchPattern, SearchOption searchOption) + public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern, SearchOption searchOption) { if (searchPattern == null) throw new ArgumentNullException(nameof(searchPattern)); @@ -344,7 +343,7 @@ namespace System.IO return InternalEnumerateFileSystemInfos(searchPattern, searchOption); } - private IEnumerable<FileSystemInfo> InternalEnumerateFileSystemInfos(String searchPattern, SearchOption searchOption) + private IEnumerable<FileSystemInfo> InternalEnumerateFileSystemInfos(string searchPattern, SearchOption searchOption) { Debug.Assert(searchPattern != null); Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); @@ -367,7 +366,7 @@ namespace System.IO [System.Security.SecuritySafeCritical] get { - String rootPath = Path.GetPathRoot(FullPath); + string rootPath = Path.GetPathRoot(FullPath); return new DirectoryInfo(rootPath); } @@ -442,12 +441,12 @@ namespace System.IO /// <summary> /// Returns the original path. Use FullPath or Name properties for the path / directory name. /// </summary> - public override String ToString() + public override string ToString() { return DisplayPath; } - private static String GetDisplayName(String originalPath) + private static string GetDisplayName(string originalPath) { Debug.Assert(originalPath != null); @@ -458,7 +457,7 @@ namespace System.IO originalPath; } - private static String GetDirName(String fullPath) + private static string GetDirName(string fullPath) { Debug.Assert(fullPath != null); diff --git a/src/System.IO.FileSystem/src/System/IO/DisableMediaInsertionPrompt.cs b/src/System.IO.FileSystem/src/System/IO/DisableMediaInsertionPrompt.cs new file mode 100644 index 0000000000..ca6261e8e7 --- /dev/null +++ b/src/System.IO.FileSystem/src/System/IO/DisableMediaInsertionPrompt.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.IO +{ + /// <summary> + /// Simple wrapper to safely disable the normal media insertion prompt for + /// removable media (floppies, cds, memory cards, etc.) + /// </summary> + /// <remarks> + /// Note that removable media file systems lazily load. After starting the OS + /// they won't be loaded until you have media in the drive- and as such the + /// prompt won't happen. You have to have had media in at least once to get + /// the file system to load and then have removed it. + /// </remarks> + public sealed class DisableMediaInsertionPrompt : IDisposable + { + private bool _disableSuccess; + private uint _oldMode; + + public DisableMediaInsertionPrompt() + { + _disableSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out _oldMode); + } + + public void Dispose() + { + uint ignore; + if (_disableSuccess) + Interop.Kernel32.SetThreadErrorMode(_oldMode, out ignore); + } + } +} diff --git a/src/System.IO.FileSystem/src/System/IO/Error.cs b/src/System.IO.FileSystem/src/System/IO/Error.cs index c8434ffad8..c0fd1450e2 100644 --- a/src/System.IO.FileSystem/src/System/IO/Error.cs +++ b/src/System.IO.FileSystem/src/System/IO/Error.cs @@ -2,16 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Runtime.InteropServices; -using System.Text; -using System.Globalization; using System.Diagnostics.Contracts; namespace System.IO { /// <summary> - /// Provides centralized methods for creating exceptions for System.IO.FileSystem. + /// Provides centralized methods for creating exceptions for System.IO.FileSystem. /// </summary> [Pure] internal static class Error diff --git a/src/System.IO.FileSystem/src/System/IO/File.cs b/src/System.IO.FileSystem/src/System/IO/File.cs index c58fed4c4b..af43f0e260 100644 --- a/src/System.IO.FileSystem/src/System/IO/File.cs +++ b/src/System.IO.FileSystem/src/System/IO/File.cs @@ -21,7 +21,7 @@ namespace System.IO internal const int DefaultBufferSize = 4096; - public static StreamReader OpenText(String path) + public static StreamReader OpenText(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -30,7 +30,7 @@ namespace System.IO return new StreamReader(path); } - public static StreamWriter CreateText(String path) + public static StreamWriter CreateText(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -39,7 +39,7 @@ namespace System.IO return new StreamWriter(path, append: false); } - public static StreamWriter AppendText(String path) + public static StreamWriter AppendText(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -51,14 +51,14 @@ namespace System.IO // Copies an existing file to a new file. An exception is raised if the // destination file already exists. Use the - // Copy(String, String, boolean) method to allow + // Copy(string, string, boolean) method to allow // overwriting an existing file. // // The caller must have certain FileIOPermissions. The caller must have // Read permission to sourceFileName and Create // and Write permissions to destFileName. // - public static void Copy(String sourceFileName, String destFileName) + public static void Copy(string sourceFileName, string destFileName) { if (sourceFileName == null) throw new ArgumentNullException(nameof(sourceFileName), SR.ArgumentNull_FileName); @@ -82,7 +82,7 @@ namespace System.IO // Read permission to sourceFileName // and Write permissions to destFileName. // - public static void Copy(String sourceFileName, String destFileName, bool overwrite) + public static void Copy(string sourceFileName, string destFileName, bool overwrite) { if (sourceFileName == null) throw new ArgumentNullException(nameof(sourceFileName), SR.ArgumentNull_FileName); @@ -101,15 +101,15 @@ namespace System.IO /// Note: This returns the fully qualified name of the destination file. /// </devdoc> [System.Security.SecuritySafeCritical] - internal static String InternalCopy(String sourceFileName, String destFileName, bool overwrite) + internal static string InternalCopy(string sourceFileName, string destFileName, bool overwrite) { Debug.Assert(sourceFileName != null); Debug.Assert(destFileName != null); Debug.Assert(sourceFileName.Length > 0); Debug.Assert(destFileName.Length > 0); - String fullSourceFileName = Path.GetFullPath(sourceFileName); - String fullDestFileName = Path.GetFullPath(destFileName); + string fullSourceFileName = Path.GetFullPath(sourceFileName); + string fullDestFileName = Path.GetFullPath(destFileName); FileSystem.Current.CopyFile(fullSourceFileName, fullDestFileName, overwrite); @@ -138,12 +138,12 @@ namespace System.IO // Your application must have Create, Read, and Write permissions to // the file. // - public static FileStream Create(String path, int bufferSize) + public static FileStream Create(string path, int bufferSize) { return new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize); } - public static FileStream Create(String path, int bufferSize, FileOptions options) + public static FileStream Create(string path, int bufferSize, FileOptions options) { return new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize, options); @@ -159,13 +159,13 @@ namespace System.IO // Your application must have Delete permission to the target file. // [System.Security.SecuritySafeCritical] - public static void Delete(String path) + public static void Delete(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); Contract.EndContractBlock(); - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.DeleteFile(fullPath); } @@ -179,7 +179,7 @@ namespace System.IO // Your application must have Read permission for the target directory. // [System.Security.SecuritySafeCritical] - public static bool Exists(String path) + public static bool Exists(string path) { try { @@ -210,22 +210,22 @@ namespace System.IO } [System.Security.SecurityCritical] // auto-generated - internal static bool InternalExists(String path) + internal static bool InternalExists(string path) { return FileSystem.Current.FileExists(path); } - public static FileStream Open(String path, FileMode mode) + public static FileStream Open(string path, FileMode mode) { return Open(path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.None); } - public static FileStream Open(String path, FileMode mode, FileAccess access) + public static FileStream Open(string path, FileMode mode, FileAccess access) { return Open(path, mode, access, FileShare.None); } - public static FileStream Open(String path, FileMode mode, FileAccess access, FileShare share) + public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share) { return new FileStream(path, mode, access, share); } @@ -242,113 +242,112 @@ namespace System.IO return dateTime.ToUniversalTime(); } - public static void SetCreationTime(String path, DateTime creationTime) + public static void SetCreationTime(string path, DateTime creationTime) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetCreationTime(fullPath, creationTime, asDirectory: false); } - public static void SetCreationTimeUtc(String path, DateTime creationTimeUtc) + public static void SetCreationTimeUtc(string path, DateTime creationTimeUtc) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetCreationTime(fullPath, GetUtcDateTimeOffset(creationTimeUtc), asDirectory: false); } [System.Security.SecuritySafeCritical] - public static DateTime GetCreationTime(String path) + public static DateTime GetCreationTime(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.GetCreationTime(fullPath).LocalDateTime; } [System.Security.SecuritySafeCritical] // auto-generated - public static DateTime GetCreationTimeUtc(String path) + public static DateTime GetCreationTimeUtc(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.GetCreationTime(fullPath).UtcDateTime; } - public static void SetLastAccessTime(String path, DateTime lastAccessTime) + public static void SetLastAccessTime(string path, DateTime lastAccessTime) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastAccessTime(fullPath, lastAccessTime, asDirectory: false); } - public static void SetLastAccessTimeUtc(String path, DateTime lastAccessTimeUtc) + public static void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastAccessTime(fullPath, GetUtcDateTimeOffset(lastAccessTimeUtc), asDirectory: false); } [System.Security.SecuritySafeCritical] - public static DateTime GetLastAccessTime(String path) + public static DateTime GetLastAccessTime(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.GetLastAccessTime(fullPath).LocalDateTime; } [System.Security.SecuritySafeCritical] // auto-generated - public static DateTime GetLastAccessTimeUtc(String path) + public static DateTime GetLastAccessTimeUtc(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.GetLastAccessTime(fullPath).UtcDateTime; } - public static void SetLastWriteTime(String path, DateTime lastWriteTime) + public static void SetLastWriteTime(string path, DateTime lastWriteTime) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastWriteTime(fullPath, lastWriteTime, asDirectory: false); } - public static void SetLastWriteTimeUtc(String path, DateTime lastWriteTimeUtc) + public static void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetLastWriteTime(fullPath, GetUtcDateTimeOffset(lastWriteTimeUtc), asDirectory: false); } [System.Security.SecuritySafeCritical] - public static DateTime GetLastWriteTime(String path) + public static DateTime GetLastWriteTime(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.GetLastWriteTime(fullPath).LocalDateTime; } [System.Security.SecuritySafeCritical] // auto-generated - public static DateTime GetLastWriteTimeUtc(String path) + public static DateTime GetLastWriteTimeUtc(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.GetLastWriteTime(fullPath).UtcDateTime; } [System.Security.SecuritySafeCritical] - public static FileAttributes GetAttributes(String path) + public static FileAttributes GetAttributes(string path) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); return FileSystem.Current.GetAttributes(fullPath); } [System.Security.SecurityCritical] - public static void SetAttributes(String path, FileAttributes fileAttributes) + public static void SetAttributes(string path, FileAttributes fileAttributes) { - String fullPath = Path.GetFullPath(path); + string fullPath = Path.GetFullPath(path); FileSystem.Current.SetAttributes(fullPath, fileAttributes); } [System.Security.SecuritySafeCritical] - public static FileStream OpenRead(String path) + public static FileStream OpenRead(string path) { return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); } - - public static FileStream OpenWrite(String path) + public static FileStream OpenWrite(string path) { return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); } [System.Security.SecuritySafeCritical] // auto-generated - public static String ReadAllText(String path) + public static string ReadAllText(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -360,7 +359,7 @@ namespace System.IO } [System.Security.SecuritySafeCritical] // auto-generated - public static String ReadAllText(String path, Encoding encoding) + public static string ReadAllText(string path, Encoding encoding) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -374,7 +373,7 @@ namespace System.IO } [System.Security.SecurityCritical] - private static String InternalReadAllText(String path, Encoding encoding) + private static string InternalReadAllText(string path, Encoding encoding) { Debug.Assert(path != null); Debug.Assert(encoding != null); @@ -385,7 +384,7 @@ namespace System.IO } [System.Security.SecuritySafeCritical] // auto-generated - public static void WriteAllText(String path, String contents) + public static void WriteAllText(string path, string contents) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -400,7 +399,7 @@ namespace System.IO } [System.Security.SecuritySafeCritical] // auto-generated - public static void WriteAllText(String path, String contents, Encoding encoding) + public static void WriteAllText(string path, string contents, Encoding encoding) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -417,19 +416,19 @@ namespace System.IO } [System.Security.SecuritySafeCritical] // auto-generated - public static byte[] ReadAllBytes(String path) + public static byte[] ReadAllBytes(string path) { return InternalReadAllBytes(path); } [System.Security.SecurityCritical] - private static byte[] InternalReadAllBytes(String path) + private static byte[] InternalReadAllBytes(string path) { // bufferSize == 1 used to avoid unnecessary buffer in FileStream using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1)) { long fileLength = fs.Length; - if (fileLength > Int32.MaxValue) + if (fileLength > int.MaxValue) throw new IOException(SR.IO_FileTooLong2GB); int index = 0; @@ -448,7 +447,7 @@ namespace System.IO } [System.Security.SecuritySafeCritical] // auto-generated - public static void WriteAllBytes(String path, byte[] bytes) + public static void WriteAllBytes(string path, byte[] bytes) { if (path == null) throw new ArgumentNullException(nameof(path), SR.ArgumentNull_Path); @@ -462,7 +461,7 @@ namespace System.IO } [System.Security.SecurityCritical] - private static void InternalWriteAllBytes(String path, byte[] bytes) + private static void InternalWriteAllBytes(string path, byte[] bytes) { Debug.Assert(path != null); Debug.Assert(path.Length != 0); @@ -473,7 +472,7 @@ namespace System.IO fs.Write(bytes, 0, bytes.Length); } } - public static String[] ReadAllLines(String path) + public static string[] ReadAllLines(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -484,7 +483,7 @@ namespace System.IO return InternalReadAllLines(path, Encoding.UTF8); } - public static String[] ReadAllLines(String path, Encoding encoding) + public static string[] ReadAllLines(string path, Encoding encoding) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -497,14 +496,14 @@ namespace System.IO return InternalReadAllLines(path, encoding); } - private static String[] InternalReadAllLines(String path, Encoding encoding) + private static string[] InternalReadAllLines(string path, Encoding encoding) { Debug.Assert(path != null); Debug.Assert(encoding != null); Debug.Assert(path.Length != 0); - String line; - List<String> lines = new List<String>(); + string line; + List<string> lines = new List<string>(); using (StreamReader sr = new StreamReader(path, encoding)) while ((line = sr.ReadLine()) != null) @@ -513,7 +512,7 @@ namespace System.IO return lines.ToArray(); } - public static IEnumerable<String> ReadLines(String path) + public static IEnumerable<string> ReadLines(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -524,7 +523,7 @@ namespace System.IO return ReadLinesIterator.CreateIterator(path, Encoding.UTF8); } - public static IEnumerable<String> ReadLines(String path, Encoding encoding) + public static IEnumerable<string> ReadLines(string path, Encoding encoding) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -537,12 +536,12 @@ namespace System.IO return ReadLinesIterator.CreateIterator(path, encoding); } - public static void WriteAllLines(String path, String[] contents) + public static void WriteAllLines(string path, string[] contents) { - WriteAllLines(path, (IEnumerable<String>)contents); + WriteAllLines(path, (IEnumerable<string>)contents); } - public static void WriteAllLines(String path, IEnumerable<String> contents) + public static void WriteAllLines(string path, IEnumerable<string> contents) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -555,12 +554,12 @@ namespace System.IO InternalWriteAllLines(new StreamWriter(path), contents); } - public static void WriteAllLines(String path, String[] contents, Encoding encoding) + public static void WriteAllLines(string path, string[] contents, Encoding encoding) { - WriteAllLines(path, (IEnumerable<String>)contents, encoding); + WriteAllLines(path, (IEnumerable<string>)contents, encoding); } - public static void WriteAllLines(String path, IEnumerable<String> contents, Encoding encoding) + public static void WriteAllLines(string path, IEnumerable<string> contents, Encoding encoding) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -575,21 +574,21 @@ namespace System.IO InternalWriteAllLines(new StreamWriter(path, false, encoding), contents); } - private static void InternalWriteAllLines(TextWriter writer, IEnumerable<String> contents) + private static void InternalWriteAllLines(TextWriter writer, IEnumerable<string> contents) { Debug.Assert(writer != null); Debug.Assert(contents != null); using (writer) { - foreach (String line in contents) + foreach (string line in contents) { writer.WriteLine(line); } } } - public static void AppendAllText(String path, String contents) + public static void AppendAllText(string path, string contents) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -603,7 +602,7 @@ namespace System.IO } } - public static void AppendAllText(String path, String contents, Encoding encoding) + public static void AppendAllText(string path, string contents, Encoding encoding) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -619,7 +618,7 @@ namespace System.IO } } - public static void AppendAllLines(String path, IEnumerable<String> contents) + public static void AppendAllLines(string path, IEnumerable<string> contents) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -632,7 +631,7 @@ namespace System.IO InternalWriteAllLines(new StreamWriter(path, append: true), contents); } - public static void AppendAllLines(String path, IEnumerable<String> contents, Encoding encoding) + public static void AppendAllLines(string path, IEnumerable<string> contents, Encoding encoding) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -647,12 +646,12 @@ namespace System.IO InternalWriteAllLines(new StreamWriter(path, true, encoding), contents); } - public static void Replace(String sourceFileName, String destinationFileName, String destinationBackupFileName) + public static void Replace(string sourceFileName, string destinationFileName, string destinationBackupFileName) { Replace(sourceFileName, destinationFileName, destinationBackupFileName, ignoreMetadataErrors: false); } - public static void Replace(String sourceFileName, String destinationFileName, String destinationBackupFileName, bool ignoreMetadataErrors) + public static void Replace(string sourceFileName, string destinationFileName, string destinationBackupFileName, bool ignoreMetadataErrors) { if (sourceFileName == null) throw new ArgumentNullException(nameof(sourceFileName)); @@ -675,7 +674,7 @@ namespace System.IO // permissions to destFileName. // [System.Security.SecuritySafeCritical] - public static void Move(String sourceFileName, String destFileName) + public static void Move(string sourceFileName, string destFileName) { if (sourceFileName == null) throw new ArgumentNullException(nameof(sourceFileName), SR.ArgumentNull_FileName); @@ -687,8 +686,8 @@ namespace System.IO throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destFileName)); Contract.EndContractBlock(); - String fullSourceFileName = Path.GetFullPath(sourceFileName); - String fullDestFileName = Path.GetFullPath(destFileName); + string fullSourceFileName = Path.GetFullPath(sourceFileName); + string fullDestFileName = Path.GetFullPath(destFileName); if (!InternalExists(fullSourceFileName)) { @@ -698,7 +697,7 @@ namespace System.IO FileSystem.Current.MoveFile(fullSourceFileName, fullDestFileName); } - public static void Encrypt(String path) + public static void Encrypt(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -711,7 +710,7 @@ namespace System.IO throw new PlatformNotSupportedException(SR.PlatformNotSupported_FileEncryption); } - public static void Decrypt(String path) + public static void Decrypt(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -907,7 +906,7 @@ namespace System.IO : InternalWriteAllBytesAsync(path, bytes, cancellationToken); } - private static async Task InternalWriteAllBytesAsync(String path, byte[] bytes, CancellationToken cancellationToken) + private static async Task InternalWriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken) { Debug.Assert(!string.IsNullOrEmpty(path)); Debug.Assert(bytes != null); diff --git a/src/System.IO.FileSystem/src/System/IO/FileInfo.cs b/src/System.IO.FileSystem/src/System/IO/FileInfo.cs index e13fcfe9f5..0a3540bace 100644 --- a/src/System.IO.FileSystem/src/System/IO/FileInfo.cs +++ b/src/System.IO.FileSystem/src/System/IO/FileInfo.cs @@ -2,13 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics; using System.Diagnostics.Contracts; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Runtime.Versioning; using System.Text; namespace System.IO @@ -18,13 +13,13 @@ namespace System.IO [Serializable] public sealed partial class FileInfo : FileSystemInfo { - private String _name; + private string _name; [System.Security.SecurityCritical] private FileInfo() { } [System.Security.SecuritySafeCritical] - public FileInfo(String fileName) + public FileInfo(string fileName) { if (fileName == null) throw new ArgumentNullException(nameof(fileName)); @@ -34,24 +29,24 @@ namespace System.IO } [System.Security.SecurityCritical] - private void Init(String fileName) + private void Init(string fileName) { OriginalPath = fileName; // Must fully qualify the path for the security check - String fullPath = Path.GetFullPath(fileName); + string fullPath = Path.GetFullPath(fileName); _name = Path.GetFileName(fileName); FullPath = fullPath; DisplayPath = GetDisplayPath(fileName); } - private String GetDisplayPath(String originalPath) + private string GetDisplayPath(string originalPath) { return originalPath; } [System.Security.SecuritySafeCritical] - internal FileInfo(String fullPath, String originalPath) + internal FileInfo(string fullPath, string originalPath) { Debug.Assert(Path.IsPathRooted(fullPath), "fullPath must be fully qualified!"); _name = originalPath ?? Path.GetFileName(fullPath); @@ -60,7 +55,7 @@ namespace System.IO DisplayPath = _name; } - public override String Name + public override string Name { get { return _name; } } @@ -80,7 +75,7 @@ namespace System.IO } /* Returns the name of the directory that the file is in */ - public String DirectoryName + public string DirectoryName { [System.Security.SecuritySafeCritical] get @@ -94,7 +89,7 @@ namespace System.IO { get { - String dirName = DirectoryName; + string dirName = DirectoryName; if (dirName == null) return null; return new DirectoryInfo(dirName); @@ -135,14 +130,14 @@ namespace System.IO // Copies an existing file to a new file. An exception is raised if the // destination file already exists. Use the - // Copy(String, String, boolean) method to allow + // Copy(string, string, boolean) method to allow // overwriting an existing file. // // The caller must have certain FileIOPermissions. The caller must have // Read permission to sourceFileName // and Write permissions to destFileName. // - public FileInfo CopyTo(String destFileName) + public FileInfo CopyTo(string destFileName) { if (destFileName == null) throw new ArgumentNullException(nameof(destFileName), SR.ArgumentNull_FileName); @@ -164,7 +159,7 @@ namespace System.IO // Read permission to sourceFileName and Create // and Write permissions to destFileName. // - public FileInfo CopyTo(String destFileName, bool overwrite) + public FileInfo CopyTo(string destFileName, bool overwrite) { if (destFileName == null) throw new ArgumentNullException(nameof(destFileName), SR.ArgumentNull_FileName); @@ -234,7 +229,6 @@ namespace System.IO return new FileStream(FullPath, mode, access, share); } - [System.Security.SecuritySafeCritical] // auto-generated public FileStream OpenRead() { @@ -242,7 +236,6 @@ namespace System.IO FileShare.Read, 4096, false); } - public FileStream OpenWrite() { return new FileStream(FullPath, FileMode.OpenOrCreate, @@ -258,7 +251,7 @@ namespace System.IO // permissions to destFileName. // [System.Security.SecuritySafeCritical] - public void MoveTo(String destFileName) + public void MoveTo(string destFileName) { if (destFileName == null) throw new ArgumentNullException(nameof(destFileName)); @@ -266,7 +259,7 @@ namespace System.IO throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destFileName)); Contract.EndContractBlock(); - String fullDestFileName = Path.GetFullPath(destFileName); + string fullDestFileName = Path.GetFullPath(destFileName); // These checks are in place to ensure Unix error throwing happens the same way // as it does on Windows.These checks can be removed if a solution to #2460 is @@ -290,19 +283,19 @@ namespace System.IO Invalidate(); } - public FileInfo Replace(String destinationFileName, String destinationBackupFileName) + public FileInfo Replace(string destinationFileName, string destinationBackupFileName) { return Replace(destinationFileName, destinationBackupFileName, ignoreMetadataErrors: false); } - public FileInfo Replace(String destinationFileName, String destinationBackupFileName, bool ignoreMetadataErrors) + public FileInfo Replace(string destinationFileName, string destinationBackupFileName, bool ignoreMetadataErrors) { File.Replace(FullPath, destinationFileName, destinationBackupFileName, ignoreMetadataErrors); return new FileInfo(destinationFileName); } // Returns the display path - public override String ToString() + public override string ToString() { return DisplayPath; } diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystem.cs b/src/System.IO.FileSystem/src/System/IO/FileSystem.cs index 87b304e4f5..9e3056e2cc 100644 --- a/src/System.IO.FileSystem/src/System/IO/FileSystem.cs +++ b/src/System.IO.FileSystem/src/System/IO/FileSystem.cs @@ -21,7 +21,6 @@ namespace System.IO public abstract void ReplaceFile(string sourceFullPath, string destFullPath, string destBackupFullPath, bool ignoreMetadataErrors); public abstract void DeleteFile(string fullPath); public abstract bool FileExists(string fullPath); - public abstract FileStream Open(string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent); public abstract void MoveFile(string sourceFullPath, string destFullPath); public abstract FileAttributes GetAttributes(string fullPath); @@ -42,8 +41,6 @@ namespace System.IO // Path public abstract string GetCurrentDirectory(); public abstract void SetCurrentDirectory(string fullPath); - public abstract int MaxPath { get; } - public abstract int MaxDirectoryPath { get; } // Volume public abstract string[] GetLogicalDrives(); diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs index 3c6aa499c5..301425c7df 100644 --- a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs +++ b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs @@ -126,7 +126,7 @@ namespace System.IO { // This should not throw, instead we store the result so that we can throw it // when someone actually accesses a property - _dataInitialized = Win32FileSystem.FillAttributeInfo(FullPath, ref _data, tryagain: false, returnErrorOnNotFound: false); + _dataInitialized = Win32FileSystem.FillAttributeInfo(FullPath, ref _data, returnErrorOnNotFound: false); } } } diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs index 5002a4c828..268eb289d9 100644 --- a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs +++ b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs @@ -16,9 +16,9 @@ namespace System.IO [Serializable] public abstract partial class FileSystemInfo : MarshalByRefObject, ISerializable { - protected String FullPath; // fully qualified path of the file or directory - protected String OriginalPath; // path passed in by the user - private String _displayPath = ""; // path that can be displayed to the user + protected string FullPath; // fully qualified path of the file or directory + protected string OriginalPath; // path passed in by the user + private string _displayPath = ""; // path that can be displayed to the user [System.Security.SecurityCritical] protected FileSystemInfo() @@ -36,7 +36,7 @@ namespace System.IO } // Full path of the directory/file - public virtual String FullName + public virtual string FullName { [System.Security.SecuritySafeCritical] get @@ -45,7 +45,7 @@ namespace System.IO } } - public String Extension + public string Extension { get { @@ -59,13 +59,13 @@ namespace System.IO if (PathInternal.IsDirectorySeparator(ch) || ch == Path.VolumeSeparatorChar) break; } - return String.Empty; + return string.Empty; } } // For files name of the file is returned, for directories the last directory in hierarchy is returned if possible, // otherwise the fully qualified name s returned - public abstract String Name + public abstract string Name { get; } @@ -181,7 +181,7 @@ namespace System.IO } } - internal String DisplayPath + internal string DisplayPath { get { diff --git a/src/System.IO.FileSystem/src/System/IO/MultiplexingWin32WinRTFileSystem.cs b/src/System.IO.FileSystem/src/System/IO/MultiplexingWin32WinRTFileSystem.cs index 9f4715fcd5..83ffc18458 100644 --- a/src/System.IO.FileSystem/src/System/IO/MultiplexingWin32WinRTFileSystem.cs +++ b/src/System.IO.FileSystem/src/System/IO/MultiplexingWin32WinRTFileSystem.cs @@ -20,9 +20,6 @@ namespace System.IO (IFileSystemObject)caller; } - public override int MaxPath { get { return Interop.Kernel32.MAX_PATH; } } - public override int MaxDirectoryPath { get { return Interop.Kernel32.MAX_DIRECTORY_PATH; } } - public override void CopyFile(string sourceFullPath, string destFullPath, bool overwrite) { Select(sourceFullPath, destFullPath).CopyFile(sourceFullPath, destFullPath, overwrite); @@ -105,12 +102,6 @@ namespace System.IO Select(sourceFullPath, destFullPath).MoveFile(sourceFullPath, destFullPath); } - public override FileStreamBase Open(string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) - { - bool isCreate = mode != FileMode.Open && mode != FileMode.Truncate; - return Select(fullPath, isCreate).Open(fullPath, mode, access, share, bufferSize, options, parent); - } - public override void RemoveDirectory(string fullPath, bool recursive) { Select(fullPath).RemoveDirectory(fullPath, recursive); @@ -235,7 +226,7 @@ namespace System.IO // the parent directory, so we walk up the path. fullPath = PathHelpers.GetDirectoryNameInternal(fullPath); // only walk up the path if we are creating a file/directory and not at the root - } while (isCreate && !String.IsNullOrEmpty(fullPath)); + } while (isCreate && !string.IsNullOrEmpty(fullPath)); return useWinRt; } diff --git a/src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs b/src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs index c0c3cc12ab..a8da668317 100644 --- a/src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs +++ b/src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs @@ -9,7 +9,7 @@ namespace System.IO internal static partial class PathHelpers { // Trim trailing whitespace, tabs etc but don't be aggressive in removing everything that has UnicodeCategory of trailing space. - // String.WhitespaceChars will trim more aggressively than what the underlying FS does (for ex, NTFS, FAT). + // string.WhitespaceChars will trim more aggressively than what the underlying FS does (for ex, NTFS, FAT). internal static readonly char[] TrimEndChars = { (char)0x9, (char)0xA, (char)0xB, (char)0xC, (char)0xD, (char)0x20, (char)0x85, (char)0xA0 }; internal static readonly char[] TrimStartChars = { ' ' }; diff --git a/src/System.IO.FileSystem/src/System/IO/PathHelpers.cs b/src/System.IO.FileSystem/src/System/IO/PathHelpers.cs index bc73175ff4..b6d966731e 100644 --- a/src/System.IO.FileSystem/src/System/IO/PathHelpers.cs +++ b/src/System.IO.FileSystem/src/System/IO/PathHelpers.cs @@ -11,8 +11,8 @@ namespace System.IO // Array of the separator chars internal static readonly char[] DirectorySeparatorChars = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; - // String-representation of the directory-separator character, used when appending the character to another - // string so as to avoid the boxing of the character when calling String.Concat(..., object). + // string-representation of the directory-separator character, used when appending the character to another + // string so as to avoid the boxing of the character when calling string.Concat(..., object). internal static readonly string DirectorySeparatorCharAsString = Path.DirectorySeparatorChar.ToString(); // System.IO.Path has both public Combine and internal InternalCombine @@ -34,7 +34,7 @@ namespace System.IO return path.Length == PathInternal.GetRootLength(path); } - internal static bool EndsInDirectorySeparator(String path) + internal static bool EndsInDirectorySeparator(string path) { return path.Length > 0 && PathInternal.IsDirectorySeparator(path[path.Length - 1]); } diff --git a/src/System.IO.FileSystem/src/System/IO/UnixFileSystem.cs b/src/System.IO.FileSystem/src/System/IO/UnixFileSystem.cs index 91df2c7c90..958d91037d 100644 --- a/src/System.IO.FileSystem/src/System/IO/UnixFileSystem.cs +++ b/src/System.IO.FileSystem/src/System/IO/UnixFileSystem.cs @@ -15,15 +15,6 @@ namespace System.IO { internal const int DefaultBufferSize = 4096; - public override int MaxPath { get { return Interop.Sys.MaxPath; } } - - public override int MaxDirectoryPath { get { return Interop.Sys.MaxPath; } } - - public override FileStream Open(string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) - { - return new FileStream(fullPath, mode, access, share, bufferSize, options); - } - public override void CopyFile(string sourceFullPath, string destFullPath, bool overwrite) { // The destination path may just be a directory into which the file should be copied. @@ -238,7 +229,7 @@ namespace System.IO while (stackDir.Count > 0) { string name = stackDir.Pop(); - if (name.Length >= MaxDirectoryPath) + if (name.Length >= Interop.Sys.MaxPath) { throw new PathTooLongException(SR.IO_PathTooLong); } diff --git a/src/System.IO.FileSystem/src/System/IO/Win32FileSystem.cs b/src/System.IO.FileSystem/src/System/IO/Win32FileSystem.cs index a2a6733554..7342c9c401 100644 --- a/src/System.IO.FileSystem/src/System/IO/Win32FileSystem.cs +++ b/src/System.IO.FileSystem/src/System/IO/Win32FileSystem.cs @@ -13,9 +13,6 @@ namespace System.IO { internal const int GENERIC_READ = unchecked((int)0x80000000); - public override int MaxPath { get { return Interop.Kernel32.MAX_PATH; } } - public override int MaxDirectoryPath { get { return Interop.Kernel32.MAX_DIRECTORY_PATH; } } - public override void CopyFile(string sourceFullPath, string destFullPath, bool overwrite) { Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default(Interop.Kernel32.SECURITY_ATTRIBUTES); @@ -99,7 +96,7 @@ namespace System.IO int i = length - 1; while (i >= lengthRoot && !somepathexists) { - String dir = fullPath.Substring(0, i + 1); + string dir = fullPath.Substring(0, i + 1); if (!DirectoryExists(dir)) // Create only the ones missing stackDir.Add(dir); @@ -119,12 +116,12 @@ namespace System.IO bool r = true; int firstError = 0; - String errorString = fullPath; + string errorString = fullPath; // If all the security checks succeeded create all the directories while (stackDir.Count > 0) { - String name = stackDir[stackDir.Count - 1]; + string name = stackDir[stackDir.Count - 1]; stackDir.RemoveAt(stackDir.Count - 1); r = Interop.Kernel32.CreateDirectory(name, ref secAttrs); @@ -157,7 +154,7 @@ namespace System.IO // Handle CreateDirectory("X:\\") when X: doesn't exist. Similarly for n/w paths. if ((count == 0) && !somepathexists) { - String root = Directory.InternalGetDirectoryRoot(fullPath); + string root = Directory.InternalGetDirectoryRoot(fullPath); if (!DirectoryExists(root)) throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_PATH_NOT_FOUND, root); return; @@ -169,7 +166,7 @@ namespace System.IO throw Win32Marshal.GetExceptionForWin32Error(firstError, errorString); } - public override void DeleteFile(System.String fullPath) + public override void DeleteFile(string fullPath) { bool r = Interop.Kernel32.DeleteFile(fullPath); if (!r) @@ -188,10 +185,10 @@ namespace System.IO return DirectoryExists(fullPath, out lastError); } - private bool DirectoryExists(String path, out int lastError) + private bool DirectoryExists(string path, out int lastError) { Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - lastError = FillAttributeInfo(path, ref data, false, true); + lastError = FillAttributeInfo(path, ref data, returnErrorOnNotFound: true); return (lastError == 0) && (data.fileAttributes != -1) && ((data.fileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0); @@ -220,128 +217,68 @@ namespace System.IO } } - // Returns 0 on success, otherwise a Win32 error code. Note that - // classes should use -1 as the uninitialized state for dataInitialized. - [System.Security.SecurityCritical] // auto-generated - internal static int FillAttributeInfo(String path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool tryagain, bool returnErrorOnNotFound) + /// <summary> + /// Returns 0 on success, otherwise a Win32 error code. Note that + /// classes should use -1 as the uninitialized state for dataInitialized. + /// </summary> + /// <param name="returnErrorOnNotFound">Return the error code for not found errors?</param> + [System.Security.SecurityCritical] + internal static int FillAttributeInfo(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool returnErrorOnNotFound) { - int errorCode = 0; - if (tryagain) // someone has a handle to the file open, or other error + int errorCode = Interop.Errors.ERROR_SUCCESS; + + // Neither GetFileAttributes or FindFirstFile like trailing separators + path = path.TrimEnd(PathHelpers.DirectorySeparatorChars); + + using (new DisableMediaInsertionPrompt()) { - Interop.Kernel32.WIN32_FIND_DATA findData; - findData = new Interop.Kernel32.WIN32_FIND_DATA(); - - // Remove trailing slash since this can cause grief to FindFirstFile. You will get an invalid argument error - String tempPath = path.TrimEnd(PathHelpers.DirectorySeparatorChars); - - // For removable media drives, normally the OS will pop up a dialog requesting insertion - // of the relevant media (CD, floppy, memory card, etc.). We don't want this prompt so we - // set SEM_FAILCRITICALERRORS to suppress it. - // - // Note that said dialog only shows once the relevant filesystem has been loaded, which - // does not happen until actual media is accessed at least once since booting. - - uint oldMode; - bool success = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode); - try + if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data)) { - bool error = false; - SafeFindHandle handle = Interop.Kernel32.FindFirstFile(tempPath, ref findData); - try + errorCode = Marshal.GetLastWin32Error(); + if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED) { - if (handle.IsInvalid) - { - error = true; - errorCode = Marshal.GetLastWin32Error(); + // Files that are marked for deletion will not let you GetFileAttributes, + // ERROR_ACCESS_DENIED is given back without filling out the data struct. + // FindFirstFile, however, will. Historically we always gave back attributes + // for marked-for-deletion files. - if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || - errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND || - errorCode == Interop.Errors.ERROR_NOT_READY) // Removable media not inserted + var findData = new Interop.Kernel32.WIN32_FIND_DATA(); + using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path, ref findData)) + { + if (handle.IsInvalid) { - if (!returnErrorOnNotFound) - { - // Return default value for backward compatibility - errorCode = 0; - data.fileAttributes = -1; - } + errorCode = Marshal.GetLastWin32Error(); } - return errorCode; - } - } - finally - { - // Close the Win32 handle - try - { - handle.Dispose(); - } - catch - { - // if we're already returning an error, don't throw another one. - if (!error) + else { - throw Win32Marshal.GetExceptionForLastWin32Error(); + errorCode = Interop.Errors.ERROR_SUCCESS; + data.PopulateFrom(ref findData); } } } } - finally - { - if (success) - Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode); - } - - // Copy the information to data - data.PopulateFrom(ref findData); } - else + + if (errorCode != Interop.Errors.ERROR_SUCCESS && !returnErrorOnNotFound) { - // For floppy drives, normally the OS will pop up a dialog saying - // there is no disk in drive A:, please insert one. We don't want that. - // SetErrorMode will let us disable this, but we should set the error - // mode back, since this may have wide-ranging effects. - bool success = false; - uint oldMode; - bool errorModeSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode); - try + switch (errorCode) { - success = Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data); - } - finally - { - if (errorModeSuccess) - Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode); - } - - if (!success) - { - errorCode = Marshal.GetLastWin32Error(); - if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND && - errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND && - errorCode != Interop.Errors.ERROR_NOT_READY) // floppy device not ready - { - // In case someone latched onto the file. Take the perf hit only for failure - return FillAttributeInfo(path, ref data, true, returnErrorOnNotFound); - } - else - { - if (!returnErrorOnNotFound) - { - // Return default value for backward compatibility - errorCode = 0; - data.fileAttributes = -1; - } - } + case Interop.Errors.ERROR_FILE_NOT_FOUND: + case Interop.Errors.ERROR_PATH_NOT_FOUND: + case Interop.Errors.ERROR_NOT_READY: // Removable media not ready + // Return default value for backward compatibility + data.fileAttributes = -1; + return Interop.Errors.ERROR_SUCCESS; } } return errorCode; } - public override bool FileExists(System.String fullPath) + public override bool FileExists(string fullPath) { Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - int errorCode = FillAttributeInfo(fullPath, ref data, false, true); + int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true); return (errorCode == 0) && (data.fileAttributes != -1) && ((data.fileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0); @@ -350,7 +287,7 @@ namespace System.IO public override FileAttributes GetAttributes(string fullPath) { Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - int errorCode = FillAttributeInfo(fullPath, ref data, false, true); + int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true); if (errorCode != 0) throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); @@ -362,7 +299,7 @@ namespace System.IO StringBuilder sb = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH + 1); if (Interop.Kernel32.GetCurrentDirectory(sb.Capacity, sb) == 0) throw Win32Marshal.GetExceptionForLastWin32Error(); - String currentDirectory = sb.ToString(); + string currentDirectory = sb.ToString(); // Note that if we have somehow put our command prompt into short // file name mode (i.e. by running edlin or a DOS grep, etc), then // this will return a short file name. @@ -390,7 +327,7 @@ namespace System.IO public override DateTimeOffset GetCreationTime(string fullPath) { Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - int errorCode = FillAttributeInfo(fullPath, ref data, false, false); + int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: false); if (errorCode != 0) throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); @@ -408,7 +345,7 @@ namespace System.IO public override DateTimeOffset GetLastAccessTime(string fullPath) { Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - int errorCode = FillAttributeInfo(fullPath, ref data, false, false); + int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: false); if (errorCode != 0) throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); @@ -419,7 +356,7 @@ namespace System.IO public override DateTimeOffset GetLastWriteTime(string fullPath) { Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - int errorCode = FillAttributeInfo(fullPath, ref data, false, false); + int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: false); if (errorCode != 0) throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); @@ -452,15 +389,10 @@ namespace System.IO } } - public override FileStream Open(string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) - { - return new FileStream(fullPath, mode, access, share, bufferSize, options); - } - [System.Security.SecurityCritical] private static SafeFileHandle OpenHandle(string fullPath, bool asDirectory) { - String root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath)); + string root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath)); if (root == fullPath && root[1] == Path.VolumeSeparatorChar) { // intentionally not fullpath, most upstack public APIs expose this as path. @@ -470,11 +402,11 @@ namespace System.IO Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default(Interop.Kernel32.SECURITY_ATTRIBUTES); SafeFileHandle handle = Interop.Kernel32.SafeCreateFile( fullPath, - (int)Interop.Kernel32.GenericOperations.GENERIC_WRITE, + Interop.Kernel32.GenericOperations.GENERIC_WRITE, FileShare.ReadWrite | FileShare.Delete, ref secAttrs, FileMode.Open, - asDirectory ? (int)Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS : (int)FileOptions.None, + asDirectory ? Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS : (int)FileOptions.None, IntPtr.Zero ); @@ -499,7 +431,7 @@ namespace System.IO // but for now we're much safer if we err on the conservative side. // This applies to symbolic links and mount points. Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - int errorCode = FillAttributeInfo(fullPath, ref data, false, true); + int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true); if (errorCode != 0) { // Ensure we throw a DirectoryNotFoundException. @@ -528,7 +460,7 @@ namespace System.IO // but for now we're much safer if we err on the conservative side. // This applies to symbolic links and mount points. // Note the logic to check whether fullPath is a reparse point is - // in Delete(String, String, bool), and will set "recursive" to false. + // in Delete(string, string, bool), and will set "recursive" to false. // Note that Win32's DeleteFile and RemoveDirectory will just delete // the reparse point itself. @@ -576,7 +508,7 @@ namespace System.IO if (data.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT) { // Use full path plus a trailing '\' - String mountPoint = Path.Combine(fullPath, data.cFileName + PathHelpers.DirectorySeparatorCharAsString); + string mountPoint = Path.Combine(fullPath, data.cFileName + PathHelpers.DirectorySeparatorCharAsString); if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint)) { errorCode = Marshal.GetLastWin32Error(); @@ -599,7 +531,7 @@ namespace System.IO // RemoveDirectory on a symbolic link will // remove the link itself. - String reparsePoint = Path.Combine(fullPath, data.cFileName); + string reparsePoint = Path.Combine(fullPath, data.cFileName); r = Interop.Kernel32.RemoveDirectory(reparsePoint); if (!r) { @@ -621,7 +553,7 @@ namespace System.IO } else { - String fileName = Path.Combine(fullPath, data.cFileName); + string fileName = Path.Combine(fullPath, data.cFileName); r = Interop.Kernel32.DeleteFile(fileName); if (!r) { diff --git a/src/System.IO.FileSystem/src/System/IO/Win32FileSystemEnumerable.cs b/src/System.IO.FileSystem/src/System/IO/Win32FileSystemEnumerable.cs index 5d305718f8..cc1d3daf6d 100644 --- a/src/System.IO.FileSystem/src/System/IO/Win32FileSystemEnumerable.cs +++ b/src/System.IO.FileSystem/src/System/IO/Win32FileSystemEnumerable.cs @@ -2,13 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Win32.SafeHandles; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security; -using Microsoft.Win32.SafeHandles; - namespace System.IO { // Overview: @@ -111,8 +110,6 @@ namespace System.IO private readonly SearchOption _searchOption; private readonly string _fullPath; private readonly string _normalizedSearchPath; - private readonly uint _oldMode; - private readonly bool _setBackOldMode; [SecuritySafeCritical] internal Win32FileSystemEnumerableIterator(string path, string originalUserPath, string searchPattern, SearchOption searchOption, SearchResultHandler<TSource> resultHandler) @@ -123,8 +120,6 @@ namespace System.IO Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly); Debug.Assert(resultHandler != null); - _setBackOldMode = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out _oldMode); - string normalizedSearchPattern = PathHelpers.NormalizeSearchPattern(searchPattern); if (normalizedSearchPattern.Length == 0) @@ -166,27 +161,31 @@ namespace System.IO Interop.Kernel32.WIN32_FIND_DATA data = new Interop.Kernel32.WIN32_FIND_DATA(); - // Open a Find handle - _hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data); - - if (_hnd.IsInvalid) + using (new DisableMediaInsertionPrompt()) { - int errorCode = Marshal.GetLastWin32Error(); - if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND && errorCode != Interop.Errors.ERROR_NO_MORE_FILES) - { - HandleError(errorCode, _searchData.FullPath); - } - else + // Open a Find handle + _hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data); + + if (_hnd.IsInvalid) { - // flag this as empty only if we're searching just top directory - // Used in fast path for top directory only - _empty = _searchOption == SearchOption.TopDirectoryOnly; + int errorCode = Marshal.GetLastWin32Error(); + if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND && errorCode != Interop.Errors.ERROR_NO_MORE_FILES) + { + throw HandleError(errorCode, _searchData.FullPath); + } + else + { + // flag this as empty only if we're searching just top directory + // Used in fast path for top directory only + _empty = _searchOption == SearchOption.TopDirectoryOnly; + } } } - // fast path for TopDirectoryOnly. If we have a result, go ahead and set it to - // current. If empty, dispose handle. + if (_searchOption == SearchOption.TopDirectoryOnly) { + // fast path for TopDirectoryOnly. If we have a result, go ahead and set it to + // current. If empty, dispose handle. if (_empty) { _hnd.Dispose(); @@ -200,10 +199,10 @@ namespace System.IO } } } - // for AllDirectories, we first recurse into dirs, so cleanup and add searchData - // to the list else { + // for AllDirectories, we first recurse into dirs, so cleanup and add searchData + // to the list _hnd.Dispose(); _searchList = new List<PathPair>(); _searchList.Add(_searchData); @@ -245,18 +244,10 @@ namespace System.IO { try { - if (_hnd != null) - { - _hnd.Dispose(); - } + _hnd?.Dispose(); } finally { - if (_setBackOldMode) - { - uint _ignore; - Interop.Kernel32.SetThreadErrorMode(_oldMode, out _ignore); - } base.Dispose(disposing); } } @@ -310,16 +301,25 @@ namespace System.IO // Execute searchCriteria against the current directory string searchPath = Path.Combine(_searchData.FullPath, _searchCriteria); - // Open a Find handle - _hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data); - if (_hnd.IsInvalid) + using (new DisableMediaInsertionPrompt()) { - int errorCode = Marshal.GetLastWin32Error(); - if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || errorCode == Interop.Errors.ERROR_NO_MORE_FILES || errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND) - continue; + // Open a Find handle + _hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data); - _hnd.Dispose(); - HandleError(errorCode, _searchData.FullPath); + if (_hnd.IsInvalid) + { + int errorCode = Marshal.GetLastWin32Error(); + switch (errorCode) + { + case Interop.Errors.ERROR_FILE_NOT_FOUND: + case Interop.Errors.ERROR_NO_MORE_FILES: + case Interop.Errors.ERROR_PATH_NOT_FOUND: + continue; + } + + _hnd.Dispose(); + throw HandleError(errorCode, _searchData.FullPath); + } } state = STATE_FIND_NEXT_FILE; @@ -342,32 +342,39 @@ namespace System.IO { if (_hnd != null) { - // Keep asking for more matching files/dirs, add it to the list - while (Interop.Kernel32.FindNextFile(_hnd, ref data)) + using (new DisableMediaInsertionPrompt()) { - TSource result; - if (IsResultIncluded(ref data, out result)) + // Keep asking for more matching files/dirs, add it to the list + while (Interop.Kernel32.FindNextFile(_hnd, ref data)) { - current = result; - return true; + TSource result; + if (IsResultIncluded(ref data, out result)) + { + current = result; + return true; + } } } // Make sure we quit with a sensible error. int errorCode = Marshal.GetLastWin32Error(); + _hnd?.Dispose(); - if (_hnd != null) - _hnd.Dispose(); - - // ERROR_FILE_NOT_FOUND is valid here because if the top level - // dir doesn't contain any subdirs and matching files then - // we will get here with this errorcode from the _searchList walk - if ((errorCode != 0) && (errorCode != Interop.Errors.ERROR_NO_MORE_FILES) - && (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)) + switch (errorCode) { - HandleError(errorCode, _searchData.FullPath); + case Interop.Errors.ERROR_SUCCESS: + case Interop.Errors.ERROR_NO_MORE_FILES: + + // ERROR_FILE_NOT_FOUND is valid here because if the top level + // dir doesn't contain any subdirs and matching files then + // we will get here with this errorcode from the _searchList walk + case Interop.Errors.ERROR_FILE_NOT_FOUND: + break; + default: + throw HandleError(errorCode, _searchData.FullPath); } } + if (_searchOption == SearchOption.TopDirectoryOnly) { state = STATE_FINISH; @@ -398,10 +405,10 @@ namespace System.IO } [SecurityCritical] - private void HandleError(int errorCode, string path) + private Exception HandleError(int errorCode, string path) { Dispose(); - throw Win32Marshal.GetExceptionForWin32Error(errorCode, path); + return Win32Marshal.GetExceptionForWin32Error(errorCode, path); } [SecurityCritical] // auto-generated @@ -412,20 +419,28 @@ namespace System.IO Interop.Kernel32.WIN32_FIND_DATA data = new Interop.Kernel32.WIN32_FIND_DATA(); try { - // Get all files and dirs - hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data); - - if (hnd.IsInvalid) + using (new DisableMediaInsertionPrompt()) { - int errorCode = Marshal.GetLastWin32Error(); + // Get all files and dirs + hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data); - // This could happen if the dir doesn't contain any files. - // Continue with the recursive search though, eventually - // _searchList will become empty - if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || errorCode == Interop.Errors.ERROR_NO_MORE_FILES || errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND) - return; + if (hnd.IsInvalid) + { + int errorCode = Marshal.GetLastWin32Error(); - HandleError(errorCode, localSearchData.FullPath); + // This could happen if the dir doesn't contain any files. + // Continue with the recursive search though, eventually + // _searchList will become empty + switch (errorCode) + { + case Interop.Errors.ERROR_FILE_NOT_FOUND: + case Interop.Errors.ERROR_NO_MORE_FILES: + case Interop.Errors.ERROR_PATH_NOT_FOUND: + return; + default: + throw HandleError(errorCode, localSearchData.FullPath); + } + } } // Add subdirs to _searchList. Exempt ReparsePoints as appropriate @@ -458,8 +473,7 @@ namespace System.IO } finally { - if (hnd != null) - hnd.Dispose(); + hnd?.Dispose(); } } diff --git a/src/System.IO.FileSystem/src/System/IO/WinRTFileStream.cs b/src/System.IO.FileSystem/src/System/IO/WinRTFileStream.cs deleted file mode 100644 index 3f83fa0e64..0000000000 --- a/src/System.IO.FileSystem/src/System/IO/WinRTFileStream.cs +++ /dev/null @@ -1,245 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Win32.SafeHandles; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Windows.Storage; - -namespace System.IO -{ - internal sealed class WinRTFileStream : FileStreamBase - { - private readonly FileAccess _access; - private bool _disposed; - private StorageFile _file; - private readonly Stream _innerStream; - private readonly FileOptions _options; - private static readonly SafeFileHandle s_invalidHandle = new SafeFileHandle(IntPtr.Zero, false); - - internal WinRTFileStream(Stream innerStream, StorageFile file, FileAccess access, FileOptions options, FileStream parent) - : base(parent) - { - Debug.Assert(innerStream != null); - Debug.Assert(file != null); - - this._access = access; - this._disposed = false; - this._file = file; - this._innerStream = innerStream; - this._options = options; - } - - ~WinRTFileStream() - { - Dispose(false); - } - - #region FileStream members - public override bool IsAsync { get { return true; } } - public override string Name { get { return _file.Name; } } - public override Microsoft.Win32.SafeHandles.SafeFileHandle SafeFileHandle { get { return s_invalidHandle; } } - internal override bool IsClosed => false; - - public override void Flush(bool flushToDisk) - { - // WinRT streams are not buffered, however the WinRT stream will be wrapped in a BufferedStream - // Flush & FlushAsync will flush the internal managed buffer of the BufferedStream wrapper - // The WinRT stream only exposes FlushAsync which flushes to disk. - // The managed Stream adapter does nothing for Flush() and forwards to WinRT for FlushAsync (flushing to disk). - if (flushToDisk) - { - // FlushAsync() will do the write to disk when it hits the WinRT->NetFx adapter - Task flushTask = _innerStream.FlushAsync(); - flushTask.Wait(); - } - else - { - // Flush doesn't write to disk - _innerStream.Flush(); - } - } - - public override void Lock(long position, long length) - { - throw new PlatformNotSupportedException(); // https://github.com/dotnet/corefx/issues/17470 - } - - public override void Unlock(long position, long length) - { - throw new PlatformNotSupportedException(); // https://github.com/dotnet/corefx/issues/17470 - } - #endregion - - #region Stream members - #region Properties - - public override bool CanRead - { - // WinRT doesn't support write-only streams, override what the stream tells us - // with what was passed in when creating it. - get { return _innerStream.CanRead && (_access & FileAccess.Read) != 0; } - } - - public override bool CanSeek - { - get { return _innerStream.CanSeek; } - } - - public override bool CanWrite - { - get { return _innerStream.CanWrite; } - } - - public override long Length - { - get { return _innerStream.Length; } - } - - public override long Position - { - get { return _innerStream.Position; } - set { _innerStream.Position = value; } - } - - public override int ReadTimeout - { - get { return _innerStream.ReadTimeout; } - set { _innerStream.ReadTimeout = value; } - } - - public override bool CanTimeout - { - get { return _innerStream.CanTimeout; } - } - - public override int WriteTimeout - { - get { return _innerStream.WriteTimeout; } - set { _innerStream.WriteTimeout = value; } - } - - #endregion Properties - - #region Methods - public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) - { - return _innerStream.CopyToAsync(destination, bufferSize, cancellationToken); - } - - protected override void Dispose(bool disposing) - { - try - { - if (disposing) - _innerStream.Dispose(); - - if ((_options & FileOptions.DeleteOnClose) != 0 && _file != null) - { - // WinRT doesn't directly support DeleteOnClose but we can mimic it - // There are a few reasons that this will fail - // 1) the file may not allow delete permissions for the current user - // 2) the storage file RCW may have already been disconnected - try - { - _file.DeleteAsync().AsTask().Wait(); - } - catch { } - } - - _disposed = true; - _file = null; - } - finally - { - base.Dispose(disposing); - } - } - - public override void Flush() - { - _parent.Flush(false); - } - - public override Task FlushAsync(CancellationToken cancellationToken) - { - return _innerStream.FlushAsync(cancellationToken); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (!_disposed && !CanRead) - throw Error.GetReadNotSupported(); - - return _innerStream.Read(buffer, offset, count); - } - - public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (!_disposed && !CanRead) - throw Error.GetReadNotSupported(); - - return _innerStream.ReadAsync(buffer, offset, count, cancellationToken); - } - - public override int ReadByte() - { - if (!_disposed && !CanRead) - throw Error.GetReadNotSupported(); - - return _innerStream.ReadByte(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - if (origin == SeekOrigin.Begin && offset < 0) - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_NEGATIVE_SEEK); - - return _innerStream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - _innerStream.SetLength(value); - - // WinRT ignores all errors when setting length, check after setting - - if (_innerStream.Length < value) - { - throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_FileLengthTooBig); - } - else if (_innerStream.Length != value) - { - throw new ArgumentException(SR.Argument_FileNotResized, nameof(value)); - } - - // WinRT doesn't update the position when truncating a file - if (value < _innerStream.Position) - _innerStream.Position = value; - } - - public override string ToString() - { - return _innerStream.ToString(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - _innerStream.Write(buffer, offset, count); - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); - } - - public override void WriteByte(byte value) - { - _innerStream.WriteByte(value); - } - #endregion Methods - #endregion Stream members - } -} diff --git a/src/System.IO.FileSystem/src/System/IO/WinRTFileSystem.cs b/src/System.IO.FileSystem/src/System/IO/WinRTFileSystem.cs index 1ddc7f834e..9d838d605c 100644 --- a/src/System.IO.FileSystem/src/System/IO/WinRTFileSystem.cs +++ b/src/System.IO.FileSystem/src/System/IO/WinRTFileSystem.cs @@ -19,65 +19,6 @@ namespace System.IO { internal sealed partial class WinRTFileSystem : FileSystem { - public override int MaxPath { get { return Interop.Kernel32.MAX_PATH; } } - public override int MaxDirectoryPath { get { return Interop.Kernel32.MAX_DIRECTORY_PATH; } } - - private static System.IO.FileAttributes ConvertFileAttributes(WinRTFileAttributes fileAttributes) - { - //namespace Windows.Storage - //{ - // [Flags] - // public enum FileAttributes - // { - // Normal = 0, - // ReadOnly = 1, - // Directory = 16, - // Archive = 32, - // Temporary = 256, - // LocallyIncomplete = 512, - // } - //} - - //namespace System.IO - //{ - // [Flags] - // public enum FileAttributes - // { - // ReadOnly = 1, - // Hidden = 2, - // System = 4, - // Directory = 16, - // Archive = 32, - // Device = 64, - // Normal = 128, - // Temporary = 256, - // SparseFile = 512, - // ReparsePoint = 1024, - // Compressed = 2048, - // Offline = 4096, - // NotContentIndexed = 8192, - // Encrypted = 16384, - // } - //} - - // Normal is a special case and happens to have different values in WinRT and Win32. - // It's meant to indicate the absence of other flags. On WinRT this logically is 0, - // however on Win32 it is represented with a discrete value of 128. - return (fileAttributes == WinRTFileAttributes.Normal) ? - FileAttributes.Normal : - (FileAttributes)fileAttributes; - } - - private static WinRTFileAttributes ConvertFileAttributes(FileAttributes fileAttributes) - { - // see comment above - // Here we make sure to remove the "normal" value since it is redundant - // We do not mask unsupported values - return (fileAttributes == FileAttributes.Normal) ? - WinRTFileAttributes.Normal : - (WinRTFileAttributes)(fileAttributes & ~FileAttributes.Normal); - } - public override void CopyFile(string sourceFullPath, string destFullPath, bool overwrite) { EnsureBackgroundThread(); @@ -117,391 +58,11 @@ namespace System.IO await DeleteFileAsync(sourceFullPath).ConfigureAwait(false); } - public override void CreateDirectory(string fullPath) - { - EnsureBackgroundThread(); - SynchronousResultOf(CreateDirectoryAsync(fullPath, failIfExists: false)); - } - - private async Task<StorageFolder> CreateDirectoryAsync(string fullPath, bool failIfExists) - { - if (fullPath.Length >= Interop.Kernel32.MAX_DIRECTORY_PATH) - throw new PathTooLongException(SR.IO_PathTooLong); - - Stack<string> stackDir = new Stack<string>(); - StorageFolder workingFolder = null; - string workingPath = fullPath; - - // walk up the path until we can get a directory - while (workingFolder == null) - { - try - { - workingFolder = await StorageFolder.GetFolderFromPathAsync(workingPath).TranslateWinRTTask(workingPath, isDirectory: true); - } - catch (IOException) { } - catch (UnauthorizedAccessException) { } - - if (workingFolder == null) - { - // we couldn't get the directory, we'll need to create it - string folderName = null; - PathHelpers.SplitDirectoryFile(workingPath, out workingPath, out folderName); - - if (String.IsNullOrEmpty(folderName)) - { - // we reached the root and it did not exist. we can't create roots. - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_PATH_NOT_FOUND, workingPath); - } - - stackDir.Push(folderName); - Debug.Assert(!String.IsNullOrEmpty(workingPath)); - } - } - - Debug.Assert(workingFolder != null); - - if (failIfExists && (stackDir.Count == 0)) - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_ALREADY_EXISTS, fullPath); - - // we have work to do. if stackDir is empty it means we were passed a path to an existing directory. - while (stackDir.Count > 0) - { - // use CreationCollisionOption.OpenIfExists to address a race conditions when creating directories - workingFolder = await workingFolder.CreateFolderAsync(stackDir.Pop(), CreationCollisionOption.OpenIfExists).TranslateWinRTTask(fullPath, isDirectory: true); - } - - return workingFolder; - } - - public override void DeleteFile(string fullPath) - { - EnsureBackgroundThread(); - SynchronousResultOf(DeleteFileAsync(fullPath)); - } - - private async Task DeleteFileAsync(string fullPath) - { - try - { - // Note the absence of TranslateWinRTTask, we translate below in the catch block. - StorageFile file = await StorageFile.GetFileFromPathAsync(fullPath).AsTask().ConfigureAwait(false); - await file.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask().ConfigureAwait(false); - } - catch (Exception exception) - { - // For consistency with Win32 we ignore missing files - if (exception.HResult != HResults.ERROR_FILE_NOT_FOUND) - throw exception.TranslateWinRTException(fullPath); - } - } - - public override bool DirectoryExists(string fullPath) - { - EnsureBackgroundThread(); - return SynchronousResultOf(DirectoryExistsAsync(fullPath)); - } - - private async Task<bool> DirectoryExistsAsync(string fullPath) - { - string directoryPath = null, fileName = null; - PathHelpers.SplitDirectoryFile(fullPath, out directoryPath, out fileName); - - // Rather than call await StorageFolder.GetFolderFromPathAsync(fullPath); and catch FileNotFoundException - // we try to avoid the exception by calling TryGetItemAsync. - // We can still hit an exception if the parent directory doesn't exist but it does provide better performance - // for the existing parent/non-existing directory case and avoids a first chance exception which is a developer - // pain point. - - StorageFolder parent = null; - try - { - parent = await StorageFolder.GetFolderFromPathAsync(directoryPath).TranslateWinRTTask(directoryPath, isDirectory: true); - } - catch (IOException) { } - catch (UnauthorizedAccessException) { } - - if (String.IsNullOrEmpty(fileName)) - { - // we were given a root - return parent != null; - } - - if (parent != null) - { - StorageFolder folder = await parent.TryGetItemAsync(fileName).TranslateWinRTTask(fullPath, isDirectory: true) as StorageFolder; - return folder != null; - } - else - { - // it's possible we don't have access to the parent but do have access to this folder - try - { - StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(fullPath).TranslateWinRTTask(fullPath, isDirectory: true); - return folder != null; - } - catch (IOException) { } - catch (UnauthorizedAccessException) { } - } - - return false; - } - - - public override IEnumerable<string> EnumeratePaths(string fullPath, string searchPattern, SearchOption searchOption, SearchTarget searchTarget) - { - IReadOnlyList<IStorageItem> storageFiles = SynchronousResultOf(EnumerateFileQuery(fullPath, searchPattern, searchOption, searchTarget)); - return IteratePathsFromStorageItems(storageFiles); - } - - public override IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string fullPath, string searchPattern, SearchOption searchOption, SearchTarget searchTarget) - { - IReadOnlyList<IStorageItem> storageFiles = SynchronousResultOf(EnumerateFileQuery(fullPath, searchPattern, searchOption, searchTarget)); - return IterateFileSystemInfosFromStorageItems(storageFiles); - } - - /// <summary> - /// Translates IStorageItems into FileSystemInfos and yields the results. - /// </summary> - private static IEnumerable<FileSystemInfo> IterateFileSystemInfosFromStorageItems(IReadOnlyList<IStorageItem> storageFiles) - { - int count = storageFiles.Count; - for (int i = 0; i < count; i++) - { - if (storageFiles[i].IsOfType(StorageItemTypes.Folder)) - { - yield return new DirectoryInfo(storageFiles[i].Path); - } - else // If it is neither a File nor folder then we treat it as a File. - { - yield return new FileInfo(storageFiles[i].Path); - } - } - } - - /// <summary> - /// Translates IStorageItems into string paths and yields the results. - /// </summary> - private static IEnumerable<string> IteratePathsFromStorageItems(IReadOnlyList<IStorageItem> storageFiles) - { - int count = storageFiles.Count; - for (int i = 0; i < count; i++) - { - yield return storageFiles[i].Path; - } - } - - private async static Task<IReadOnlyList<IStorageItem>> EnumerateFileQuery(string path, string searchPattern, SearchOption searchOption, SearchTarget searchTarget) - { - // Get a StorageFolder for "path" - string fullPath = Path.GetFullPath(path); - StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(fullPath).TranslateWinRTTask(fullPath, isDirectory: true); - - // Construct a query for the search. - QueryOptions query = new QueryOptions(); - - // Translate SearchOption into FolderDepth - query.FolderDepth = searchOption == SearchOption.AllDirectories ? FolderDepth.Deep : FolderDepth.Shallow; - - // Construct an AQS filter - string normalizedSearchPattern = PathHelpers.NormalizeSearchPattern(searchPattern); - if (normalizedSearchPattern.Length == 0) - { - // An empty searchPattern will return no results and requires no AQS parsing. - return new IStorageItem[0]; - } - else - { - // Parse the query as an ItemPathDisplay filter. - string searchPath = PathHelpers.GetFullSearchString(fullPath, normalizedSearchPattern); - string aqs = "System.ItemPathDisplay:~\"" + searchPath + "\""; - query.ApplicationSearchFilter = aqs; - - // If the filtered path is deeper than the given user path, we need to get a new folder for it. - // This occurs when someone does something like Enumerate("C:\first\second\", "C:\first\second\third\*"). - // When AllDirectories is set this isn't an issue, but for TopDirectoryOnly we have to do some special work - // to make sure something is actually returned when the searchPattern is a subdirectory of the path. - // To do this, we attempt to get a new StorageFolder for the subdirectory and return an empty enumerable - // if we can't. - string searchPatternDirName = Path.GetDirectoryName(normalizedSearchPattern); - string userPath = string.IsNullOrEmpty(searchPatternDirName) ? fullPath : Path.Combine(fullPath, searchPatternDirName); - if (userPath != folder.Path) - { - folder = await StorageFolder.GetFolderFromPathAsync(userPath).TranslateWinRTTask(userPath, isDirectory: true); - } - } - - // Execute our built query - if (searchTarget == SearchTarget.Files) - { - StorageFileQueryResult queryResult = folder.CreateFileQueryWithOptions(query); - return await queryResult.GetFilesAsync().TranslateWinRTTask(folder.Path, isDirectory: true); - } - else if (searchTarget == SearchTarget.Directories) - { - StorageFolderQueryResult queryResult = folder.CreateFolderQueryWithOptions(query); - return await queryResult.GetFoldersAsync().TranslateWinRTTask(folder.Path, isDirectory: true); - } - else - { - StorageItemQueryResult queryResult = folder.CreateItemQueryWithOptions(query); - return await queryResult.GetItemsAsync().TranslateWinRTTask(folder.Path, isDirectory: true); - } - } - - public override bool FileExists(string fullPath) - { - EnsureBackgroundThread(); - return SynchronousResultOf(FileExistsAsync(fullPath)); - } - - private async Task<bool> FileExistsAsync(string fullPath) - { - string directoryPath = null, fileName = null; - PathHelpers.SplitDirectoryFile(fullPath, out directoryPath, out fileName); - - if (String.IsNullOrEmpty(fileName)) - { - // No filename was provided - return false; - } - - // Rather than call await StorageFile.GetFileFromPathAsync(fullPath); and catch FileNotFoundException - // we try to avoid the exception by calling TryGetItemAsync. - // We can still hit an exception if the directory doesn't exist but it does provide better performance - // for the existing folder/non-existing file case and avoids a first chance exception which is a developer - // pain point. - - StorageFolder parent = null; - try - { - parent = await StorageFolder.GetFolderFromPathAsync(directoryPath).TranslateWinRTTask(directoryPath); - } - catch (IOException) { } - catch (UnauthorizedAccessException) { } - - StorageFile file = null; - - if (parent != null) - { - // The expectation is that this API will never throw, thus it is missing TranslateWinRTTask - file = await parent.TryGetItemAsync(fileName).TranslateWinRTTask(fullPath) as StorageFile; - } - else - { - // it's possible we don't have access to the parent but do have access to this file - try - { - file = await StorageFile.GetFileFromPathAsync(fullPath).TranslateWinRTTask(fullPath); - } - catch (IOException) { } - catch (UnauthorizedAccessException) { } - } - - return (file != null) ? file.IsAvailable : false; - } - - public override FileAttributes GetAttributes(string fullPath) - { - EnsureBackgroundThread(); - return SynchronousResultOf(GetAttributesAsync(fullPath)); - } - - private async Task<FileAttributes> GetAttributesAsync(string fullPath) - { - IStorageItem item = await GetStorageItemAsync(fullPath).ConfigureAwait(false); - - return ConvertFileAttributes(item.Attributes); - } - - public override DateTimeOffset GetCreationTime(string fullPath) - { - EnsureBackgroundThread(); - return SynchronousResultOf(GetCreationTimeAsync(fullPath)); - } - - private async Task<DateTimeOffset> GetCreationTimeAsync(string fullPath) - { - IStorageItem item = await GetStorageItemAsync(fullPath).ConfigureAwait(false); - - return item.DateCreated; - } - public override string GetCurrentDirectory() { throw new PlatformNotSupportedException(); // https://github.com/dotnet/corefx/issues/17470; } - public override IFileSystemObject GetFileSystemInfo(string fullPath, bool asDirectory) - { - return new WinRTFileSystemObject(fullPath, asDirectory); - } - - public override DateTimeOffset GetLastAccessTime(string fullPath) - { - EnsureBackgroundThread(); - return SynchronousResultOf(GetLastAccessTimeAsync(fullPath)); - } - - private async Task<DateTimeOffset> GetLastAccessTimeAsync(string fullPath) - { - IStorageItem item = await GetStorageItemAsync(fullPath).ConfigureAwait(false); - - return await GetLastAccessTimeAsync(item).ConfigureAwait(false); - } - - // declare a static to avoid unnecessary heap allocations - private static readonly string[] s_dateAccessedKey = { "System.DateAccessed" }; - - private static async Task<DateTimeOffset> GetLastAccessTimeAsync(IStorageItem item) - { - BasicProperties properties = await item.GetBasicPropertiesAsync().TranslateWinRTTask(item.Path); - - var propertyMap = await properties.RetrievePropertiesAsync(s_dateAccessedKey).TranslateWinRTTask(item.Path); - - // shell doesn't expose this metadata on all item types - if (propertyMap.ContainsKey(s_dateAccessedKey[0])) - { - return (DateTimeOffset)propertyMap[s_dateAccessedKey[0]]; - } - - // fallback to modified date - return properties.DateModified; - } - - public override DateTimeOffset GetLastWriteTime(string fullPath) - { - EnsureBackgroundThread(); - return SynchronousResultOf(GetLastWriteTimeAsync(fullPath)); - } - - private async Task<DateTimeOffset> GetLastWriteTimeAsync(string fullPath) - { - IStorageItem item = await GetStorageItemAsync(fullPath).ConfigureAwait(false); - - return await GetLastWriteTimeAsync(item).ConfigureAwait(false); - } - - private static async Task<DateTimeOffset> GetLastWriteTimeAsync(IStorageItem item) - { - BasicProperties properties = await item.GetBasicPropertiesAsync().TranslateWinRTTask(item.Path); - - return properties.DateModified; - } - - private static async Task<IStorageItem> GetStorageItemAsync(string fullPath) - { - string directoryPath, itemName; - PathHelpers.SplitDirectoryFile(fullPath, out directoryPath, out itemName); - - StorageFolder parent = await StorageFolder.GetFolderFromPathAsync(directoryPath).TranslateWinRTTask(directoryPath, isDirectory: true); - - if (String.IsNullOrEmpty(itemName)) - return parent; - - return await parent.GetItemAsync(itemName).TranslateWinRTTask(fullPath); - } - public override void MoveDirectory(string sourceFullPath, string destFullPath) { EnsureBackgroundThread(); @@ -519,10 +80,10 @@ namespace System.IO PathHelpers.SplitDirectoryFile(destFullPath, out destParent, out destFolderName); // same parent folder - if (String.Equals(sourceParent, destParent, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(sourceParent, destParent, StringComparison.OrdinalIgnoreCase)) { // not the same subfolder - if (!String.Equals(sourceFolderName, destFolderName, StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(sourceFolderName, destFolderName, StringComparison.OrdinalIgnoreCase)) { await sourceFolder.RenameAsync(destFolderName).TranslateWinRTTask(destFullPath, isDirectory: true); } @@ -581,171 +142,11 @@ namespace System.IO } } - public override FileStreamBase Open(string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) - { - EnsureBackgroundThread(); - return SynchronousResultOf(OpenAsync(fullPath, mode, access, share, bufferSize, options, parent)); - } - - private async Task<FileStreamBase> OpenAsync(string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) - { - // When trying to open the root directory, we need to throw an Access Denied - if (PathInternal.GetRootLength(fullPath) == fullPath.Length) - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_ACCESS_DENIED, fullPath); - - // Win32 CreateFile returns ERROR_PATH_NOT_FOUND when given a path that ends with '\' - if (PathHelpers.EndsInDirectorySeparator(fullPath)) - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_PATH_NOT_FOUND, fullPath); - - StorageFile file = null; - - // FileMode - if (mode == FileMode.Open || mode == FileMode.Truncate) - { - file = await StorageFile.GetFileFromPathAsync(fullPath).TranslateWinRTTask(fullPath); - } - else - { - CreationCollisionOption collisionOptions; - - switch (mode) - { - case FileMode.Create: - collisionOptions = CreationCollisionOption.ReplaceExisting; - break; - case FileMode.CreateNew: - collisionOptions = CreationCollisionOption.FailIfExists; - break; - case FileMode.Append: - case FileMode.OpenOrCreate: - default: - collisionOptions = CreationCollisionOption.OpenIfExists; - break; - } - - string directoryPath, fileName; - PathHelpers.SplitDirectoryFile(fullPath, out directoryPath, out fileName); - - StorageFolder directory = await StorageFolder.GetFolderFromPathAsync(directoryPath).TranslateWinRTTask(directoryPath, isDirectory: true); - - file = await directory.CreateFileAsync(fileName, collisionOptions).TranslateWinRTTask(fullPath); - } - - // FileAccess: WinRT doesn't support FileAccessMode.Write so we upgrade to ReadWrite - FileAccessMode accessMode = ((access & FileAccess.Write) != 0) ? FileAccessMode.ReadWrite : FileAccessMode.Read; - - // FileShare: cannot translate StorageFile uses a different sharing model (oplocks) that is controlled via FileAccessMode - - // FileOptions: ignore most values of FileOptions as they are hints and are not supported by WinRT. - // FileOptions.Encrypted is not a hint, and not supported by WinRT, but there is precedent for ignoring this (FAT). - // FileOptions.DeleteOnClose should result in an UnauthorizedAccessException when - // opening a file that can only be read, but we cannot safely reproduce that behavior - // in WinRT without actually deleting the file. - // Instead the failure will occur in the finalizer for WinRTFileStream and be ignored. - - // open our stream - Stream stream = (await file.OpenAsync(accessMode).TranslateWinRTTask(fullPath)).AsStream(bufferSize); - - if (mode == FileMode.Append) - { - // seek to end. - stream.Seek(0, SeekOrigin.End); - } - else if (mode == FileMode.Truncate) - { - // truncate stream to 0 - stream.SetLength(0); - } - - return new WinRTFileStream(stream, file, access, options, parent); - } - - public override void RemoveDirectory(string fullPath, bool recursive) - { - EnsureBackgroundThread(); - SynchronousResultOf(RemoveDirectoryAsync(fullPath, recursive)); - } - - private async Task RemoveDirectoryAsync(string fullPath, bool recursive) - { - StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(fullPath).TranslateWinRTTask(fullPath, isDirectory: true); - - // StorageFolder.DeleteAsync will always be recursive. Detect a non-empty folder up front and throw. - if (!recursive && (await folder.GetItemsAsync()).Count != 0) - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_DIR_NOT_EMPTY, fullPath); - - // StorageFolder.Delete ignores readonly attribute. Detect and throw. - if ((folder.Attributes & WinRTFileAttributes.ReadOnly) == WinRTFileAttributes.ReadOnly) - throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); - - StorageFolder parentFolder = await folder.GetParentAsync().TranslateWinRTTask(fullPath, isDirectory: true); - - // StorageFolder.Delete throws on hidden directories but we cannot prevent it. - await folder.DeleteAsync(StorageDeleteOption.PermanentDelete).TranslateWinRTTask(fullPath, isDirectory: true); - - // WinRT will ignore failures to delete in cases where files are in use. - // Throw if the folder still remains after successful DeleteAsync - if (null != await (parentFolder.TryGetItemAsync(folder.Name))) - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_DIR_NOT_EMPTY, fullPath); - } - - public override void SetAttributes(string fullPath, FileAttributes attributes) - { - EnsureBackgroundThread(); - SynchronousResultOf(SetAttributesAsync(fullPath, attributes)); - } - - private async Task SetAttributesAsync(string fullPath, FileAttributes attributes) - { - IStorageItem item = await GetStorageItemAsync(fullPath).ConfigureAwait(false); - - await SetAttributesAsync(item, attributes).ConfigureAwait(false); - } - - private static async Task SetAttributesAsync(IStorageItem item, FileAttributes attributes) - { - BasicProperties basicProperties = await item.GetBasicPropertiesAsync().TranslateWinRTTask(item.Path); - - // This works for only a subset of attributes, unsupported attributes are ignored. - // We don't mask the attributes since WinRT just ignores the unsupported ones and flowing - // them enables possible lightup in the future. - var property = new KeyValuePair<string, object>("System.FileAttributes", (UInt32)ConvertFileAttributes(attributes)); - try - { - await basicProperties.SavePropertiesAsync(new[] { property }).AsTask().ConfigureAwait(false); - } - catch (Exception exception) - { - if (exception.HResult != HResults.ERROR_INVALID_PARAMETER) - throw new ArgumentException(SR.Arg_InvalidFileAttrs); - - throw exception.TranslateWinRTException(item.Path); - } - } - - public override void SetCreationTime(string fullPath, DateTimeOffset time, bool asDirectory) - { - // intentionally noop : not supported - // "System.DateCreated" property is readonly - } - public override void SetCurrentDirectory(string fullPath) { throw new PlatformNotSupportedException(); // https://github.com/dotnet/corefx/issues/17470 } - public override void SetLastAccessTime(string fullPath, DateTimeOffset time, bool asDirectory) - { - // intentionally noop - // "System.DateAccessed" property is readonly - } - - public override void SetLastWriteTime(string fullPath, DateTimeOffset time, bool asDirectory) - { - // intentionally noop : not supported - // "System.DateModified" property is readonly - } - public override string[] GetLogicalDrives() { return DriveInfoInternal.GetLogicalDrives(); diff --git a/src/System.IO.FileSystem/src/System/IO/WinRTFileSystemObject.cs b/src/System.IO.FileSystem/src/System/IO/WinRTFileSystemObject.cs deleted file mode 100644 index a479fac8a9..0000000000 --- a/src/System.IO.FileSystem/src/System/IO/WinRTFileSystemObject.cs +++ /dev/null @@ -1,228 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.ExceptionServices; -using System.Threading.Tasks; -using Windows.Storage; -using Windows.Storage.FileProperties; - -namespace System.IO -{ - partial class WinRTFileSystem - { - internal sealed class WinRTFileSystemObject : IFileSystemObject - { - private readonly bool _asDirectory; - - // Cache the file/directory information - private readonly string _fullPath; - - // Cache the file information - private IStorageItem _item; - - // Cache any error retrieving the file/directory information - // We use this field in conjunction with the Refresh method which should never throw. - // If we succeed this is null, on failure we capture the Exception so that we can - // throw it when attempting to access the cached info later. - private ExceptionDispatchInfo _initializationException; - - public WinRTFileSystemObject(string fullPath, bool asDirectory) - { - _asDirectory = asDirectory; - _fullPath = fullPath; - _item = null; - _initializationException = null; - } - - public FileAttributes Attributes - { - get - { - EnsureItemInitialized(); - - if (_item == null) - return (FileAttributes)(-1); - - return ConvertFileAttributes(_item.Attributes); - } - set - { - EnsureItemExists(); - EnsureBackgroundThread(); - - try - { - SynchronousResultOf(SetAttributesAsync(_item, value)); - } - catch (UnauthorizedAccessException) - { - // For consistency with Win32 we remap ACCESS_DENIED to ArgumentException - // Intentionally omit argument name since this is mimicking the Win32 sourced ArgumentException - throw new ArgumentException(SR.UnauthorizedAccess_IODenied_NoPathName /*, intentionally omitted*/); - } - // reset our attributes - _item = null; - } - } - - public DateTimeOffset CreationTime - { - get - { - EnsureItemInitialized(); - - if (_item == null) - return DateTimeOffset.FromFileTime(0); - - return _item.DateCreated; - } - set - { - EnsureItemExists(); - // intentionally noop : not supported - } - } - - public bool Exists - { - get - { - // Do not throw - if (_item == null) - Refresh(); - - if (_item == null) - return false; - - return _item.IsOfType(_asDirectory ? StorageItemTypes.Folder : StorageItemTypes.File); - } - } - - public DateTimeOffset LastAccessTime - { - get - { - EnsureItemInitialized(); - - if (_item == null) - return DateTimeOffset.FromFileTime(0); - - EnsureBackgroundThread(); - return SynchronousResultOf(GetLastAccessTimeAsync(_item)); - } - set - { - EnsureItemExists(); - // intentionally noop : not supported - } - } - - public DateTimeOffset LastWriteTime - { - get - { - EnsureItemInitialized(); - - if (_item == null) - return DateTimeOffset.FromFileTime(0); - - EnsureBackgroundThread(); - return SynchronousResultOf(GetLastWriteTimeAsync(_item)); - } - set - { - EnsureItemExists(); - // intentionally noop : not supported - } - } - - public long Length - { - get - { - EnsureItemExists(); - EnsureBackgroundThread(); - return (long)SynchronousResultOf(GetLengthAsync()); - } - } - - private async Task<ulong> GetLengthAsync() - { - BasicProperties properties = await _item.GetBasicPropertiesAsync().TranslateWinRTTask(_fullPath, _asDirectory); - return properties.Size; - } - - // Consumes cached file/directory information and throw if any error occurred retrieving - // it, including file not found. - private void EnsureItemExists() - { - // If we've already tried and failed to get the item, throw - if (_initializationException != null) - _initializationException.Throw(); - - // We don't have the item, try and get it allowing any exception to be thrown - if (_item == null) - { - EnsureBackgroundThread(); - _item = SynchronousResultOf(GetStorageItemAsync(_fullPath)); - } - } - - private void EnsureItemInitialized() - { - // Refresh only if we haven't already done so once. - if (_item == null && _initializationException == null) - { - // Refresh will ignore file-not-found errors. - Refresh(); - } - - // Refresh was unable to initialize the data - if (_initializationException != null) - _initializationException.Throw(); - } - - public void Refresh() - { - EnsureBackgroundThread(); - SynchronousResultOf(RefreshAsync()); - } - - // Similar to WinRTFileSystem.TryGetStorageItemAsync but we only - // want to capture exceptions that are not related to file not - // found. This matches the behavior of the Win32 implementation. - private async Task RefreshAsync() - { - string directoryPath, itemName; - _item = null; - _initializationException = null; - - try - { - PathHelpers.SplitDirectoryFile(_fullPath, out directoryPath, out itemName); - - StorageFolder parent = null; - - try - { - parent = await StorageFolder.GetFolderFromPathAsync(directoryPath).TranslateWinRTTask(directoryPath, isDirectory: true); - } - catch (DirectoryNotFoundException) - { - // Ignore DirectoryNotFound, in this case we just return null; - } - - if (String.IsNullOrEmpty(itemName) || null == parent) - _item = parent; - else - _item = await parent.TryGetItemAsync(itemName).TranslateWinRTTask(_fullPath); - } - catch (Exception e) - { - _initializationException = ExceptionDispatchInfo.Capture(e); - } - } - } - } -} diff --git a/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs b/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs index a5db695dc5..641f11cd71 100644 --- a/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs +++ b/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs @@ -36,7 +36,7 @@ namespace System.IO.Tests public void PathWithInvalidCharactersAsPath_ThrowsArgumentException(string invalidPath) { if (invalidPath.Equals(@"\\?\") && !PathFeatures.IsUsingLegacyPathNormalization()) - Assert.Throws<IOException>(() => Create(invalidPath)); + AssertExtensions.ThrowsAny<IOException, UnauthorizedAccessException>(() => Create(invalidPath)); else if (invalidPath.Contains(@"\\?\") && !PathFeatures.IsUsingLegacyPathNormalization()) Assert.Throws<DirectoryNotFoundException>(() => Create(invalidPath)); else diff --git a/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm_fa_fs.delete.cs b/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm_fa_fs.delete.cs index 2d45705429..dcd4978f57 100644 --- a/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm_fa_fs.delete.cs +++ b/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm_fa_fs.delete.cs @@ -84,6 +84,7 @@ namespace System.IO.Tests Assert.True(File.Exists(newFileName)); } } + [Fact] [PlatformSpecific(TestPlatforms.Windows)] // file sharing restriction limitations on Unix public void FileShareDeleteExistingMultipleClients() @@ -95,7 +96,7 @@ namespace System.IO.Tests fs.WriteByte(0); } - Assert.True(File.Exists(fileName)); + Assert.True(File.Exists(fileName), $"'{fileName}' should exist after creating and closing filestream."); using (FileStream fs1 = CreateFileStream(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Delete | FileShare.ReadWrite)) { @@ -103,7 +104,7 @@ namespace System.IO.Tests { File.Delete(fileName); Assert.Equal(0, fs2.ReadByte()); - Assert.True(File.Exists(fileName)); + Assert.True(File.Exists(fileName), $"'{fileName}' should still exist after calling delete with two handles open."); } Assert.Equal(0, fs1.ReadByte()); @@ -112,7 +113,7 @@ namespace System.IO.Tests // Any attempt to reopen a file in pending-delete state will return Access-denied Assert.Throws<UnauthorizedAccessException>(() => CreateFileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite)); - Assert.True(File.Exists(fileName)); + Assert.True(File.Exists(fileName), $"'{fileName}' should still exist after calling delete with inner filestream closed."); } Assert.False(File.Exists(fileName)); diff --git a/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj b/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj index 85258bbfe6..14a24cd377 100644 --- a/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj +++ b/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj @@ -23,15 +23,9 @@ <Compile Include="$(CommonTestPath)\System\PerfUtils.cs"> <Link>Common\System\PerfUtils.cs</Link> </Compile> - <Compile Include="$(CommonTestPath)\System\IO\FileCleanupTestBase.cs"> - <Link>Common\System\IO\FileCleanupTestBase.cs</Link> - </Compile> <Compile Include="$(CommonTestPath)\System\IO\PathFeatures.cs"> <Link>Common\System\IO\PathFeatures.cs</Link> </Compile> - <Compile Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorTestBase.cs"> - <Link>Common\System\Diagnostics\RemoteExecutorTestBase.cs</Link> - </Compile> </ItemGroup> <ItemGroup> <ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj"> diff --git a/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj b/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj index 0332976b83..b57b70ef61 100644 --- a/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj +++ b/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj @@ -159,9 +159,6 @@ <Compile Include="FileInfo\AppendText.cs" /> <Compile Include="FileInfo\CopyTo.cs" /> <!-- Helpers --> - <Compile Include="$(CommonTestPath)\System\IO\FileCleanupTestBase.cs"> - <Link>Common\System\IO\FileCleanupTestBase.cs</Link> - </Compile> <Compile Include="$(CommonTestPath)\System\IO\TempFile.cs"> <Link>Common\System\IO\TempFile.cs</Link> </Compile> @@ -171,9 +168,6 @@ <Compile Include="$(CommonTestPath)\System\PlatformDetection.cs"> <Link>Common\System\PlatformDetection.cs</Link> </Compile> - <Compile Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorTestBase.cs"> - <Link>Common\System\Diagnostics\RemoteExecutorTestBase.cs</Link> - </Compile> <Compile Include="$(CommonTestPath)\System\AssertExtensions.cs"> <Link>Common\System\AssertExtensions.cs</Link> </Compile> |