diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 31613fdb4a950e..2d07a361eefbaf 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -414,11 +414,9 @@
-
-
@@ -1840,7 +1838,6 @@
-
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs
index e63935c5f0c804..29dff0c4d009fc 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs
@@ -16,10 +16,9 @@ namespace System.IO
{
// Class for creating FileStream objects, and some basic file management
// routines such as Delete, etc.
- public static partial class File
+ public static class File
{
- // Don't use Array.MaxLength. MS.IO.Redist targets .NET Framework.
- private const int MaxByteArrayLength = 0x7FFFFFC7;
+ private const int ChunkSize = 8192;
private static Encoding? s_UTF8NoBOM;
// UTF-8 without BOM and with error detection. Same as the default encoding for StreamWriter.
@@ -121,6 +120,12 @@ public static bool Exists([NotNullWhen(true)] string? path)
return false;
}
+ ///
+ /// Initializes a new instance of the class with the specified path, creation mode, read/write and sharing permission, the access other FileStreams can have to the same file, the buffer size, additional file options and the allocation size.
+ ///
+ /// for information about exceptions.
+ public static FileStream Open(string path, FileStreamOptions options) => new FileStream(path, options);
+
public static FileStream Open(string path, FileMode mode)
=> Open(path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.None);
@@ -130,6 +135,44 @@ public static FileStream Open(string path, FileMode mode, FileAccess access)
public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share)
=> new FileStream(path, mode, access, share);
+ ///
+ /// Initializes a new instance of the class with the specified path, creation mode, read/write and sharing permission, the access other SafeFileHandles can have to the same file, additional file options and the allocation size.
+ ///
+ /// A relative or absolute path for the file that the current instance will encapsulate.
+ /// One of the enumeration values that determines how to open or create the file. The default value is
+ /// A bitwise combination of the enumeration values that determines how the file can be accessed. The default value is
+ /// A bitwise combination of the enumeration values that determines how the file will be shared by processes. The default value is .
+ /// The initial allocation size in bytes for the file. A positive value is effective only when a regular file is being created, overwritten, or replaced.
+ /// Negative values are not allowed. In other cases (including the default 0 value), it's ignored.
+ /// An object that describes optional parameters to use.
+ /// is .
+ /// is an empty string (""), contains only white space, or contains one or more invalid characters.
+ /// -or-
+ /// refers to a non-file device, such as CON:, COM1:, LPT1:, etc. in an NTFS environment.
+ /// refers to a non-file device, such as CON:, COM1:, LPT1:, etc. in a non-NTFS environment.
+ /// is negative.
+ /// -or-
+ /// , , or contain an invalid value.
+ /// The file cannot be found, such as when is or , and the file specified by does not exist. The file must already exist in these modes.
+ /// An I/O error, such as specifying when the file specified by already exists, occurred.
+ /// -or-
+ /// The disk was full (when was provided and was pointing to a regular file).
+ /// -or-
+ /// The file was too large (when was provided and was pointing to a regular file).
+ /// The caller does not have the required permission.
+ /// The specified path is invalid, such as being on an unmapped drive.
+ /// The requested is not permitted by the operating system for the specified , such as when is or and the file or directory is set for read-only access.
+ /// -or-
+ /// is specified for , but file encryption is not supported on the current platform.
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ public static SafeFileHandle OpenHandle(string path, FileMode mode = FileMode.Open, FileAccess access = FileAccess.Read,
+ FileShare share = FileShare.Read, FileOptions options = FileOptions.None, long preallocationSize = 0)
+ {
+ Strategies.FileStreamHelpers.ValidateArguments(path, mode, access, share, bufferSize: 0, options, preallocationSize);
+
+ return SafeFileHandle.Open(Path.GetFullPath(path), mode, access, share, options, preallocationSize);
+ }
+
// File and Directory UTC APIs treat a DateTimeKind.Unspecified as UTC whereas
// ToUniversalTime treats this as local.
internal static DateTimeOffset GetUtcDateTimeOffset(DateTime dateTime)
@@ -537,9 +580,9 @@ private static async Task InternalReadAllBytesUnknownLengthAsync(FileStr
if (bytesRead == rentedArray.Length)
{
uint newLength = (uint)rentedArray.Length * 2;
- if (newLength > MaxByteArrayLength)
+ if (newLength > Array.MaxLength)
{
- newLength = (uint)Math.Max(MaxByteArrayLength, rentedArray.Length + 1);
+ newLength = (uint)Math.Max(Array.MaxLength, rentedArray.Length + 1);
}
byte[] tmp = ArrayPool.Shared.Rent((int)newLength);
@@ -731,5 +774,176 @@ private static void Validate(string path, Encoding encoding)
if (path.Length == 0)
throw new ArgumentException(SR.Argument_EmptyPath, nameof(path));
}
+
+ private static byte[] ReadAllBytesUnknownLength(FileStream fs)
+ {
+ byte[]? rentedArray = null;
+ Span buffer = stackalloc byte[512];
+ try
+ {
+ int bytesRead = 0;
+ while (true)
+ {
+ if (bytesRead == buffer.Length)
+ {
+ uint newLength = (uint)buffer.Length * 2;
+ if (newLength > Array.MaxLength)
+ {
+ newLength = (uint)Math.Max(Array.MaxLength, buffer.Length + 1);
+ }
+
+ byte[] tmp = ArrayPool.Shared.Rent((int)newLength);
+ buffer.CopyTo(tmp);
+ byte[]? oldRentedArray = rentedArray;
+ buffer = rentedArray = tmp;
+ if (oldRentedArray != null)
+ {
+ ArrayPool.Shared.Return(oldRentedArray);
+ }
+ }
+
+ Debug.Assert(bytesRead < buffer.Length);
+ int n = fs.Read(buffer.Slice(bytesRead));
+ if (n == 0)
+ {
+ return buffer.Slice(0, bytesRead).ToArray();
+ }
+ bytesRead += n;
+ }
+ }
+ finally
+ {
+ if (rentedArray != null)
+ {
+ ArrayPool.Shared.Return(rentedArray);
+ }
+ }
+ }
+
+ private static void WriteToFile(string path, FileMode mode, string? contents, Encoding encoding)
+ {
+ ReadOnlySpan preamble = encoding.GetPreamble();
+ int preambleSize = preamble.Length;
+
+ using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.None, GetPreallocationSize(mode, contents, encoding, preambleSize));
+ long fileOffset = mode == FileMode.Append && fileHandle.CanSeek ? RandomAccess.GetLength(fileHandle) : 0;
+
+ if (string.IsNullOrEmpty(contents))
+ {
+ if (preambleSize > 0 // even if the content is empty, we want to store the preamble
+ && fileOffset == 0) // if we're appending to a file that already has data, don't write the preamble.
+ {
+ RandomAccess.WriteAtOffset(fileHandle, preamble, fileOffset);
+ }
+ return;
+ }
+
+ int bytesNeeded = preambleSize + encoding.GetMaxByteCount(Math.Min(contents.Length, ChunkSize));
+ byte[]? rentedBytes = null;
+ Span bytes = bytesNeeded <= 1024 ? stackalloc byte[1024] : (rentedBytes = ArrayPool.Shared.Rent(bytesNeeded));
+
+ try
+ {
+ if (fileOffset == 0)
+ {
+ preamble.CopyTo(bytes);
+ }
+ else
+ {
+ preambleSize = 0; // don't append preamble to a non-empty file
+ }
+
+ Encoder encoder = encoding.GetEncoder();
+ ReadOnlySpan remaining = contents;
+ while (!remaining.IsEmpty)
+ {
+ ReadOnlySpan toEncode = remaining.Slice(0, Math.Min(remaining.Length, ChunkSize));
+ remaining = remaining.Slice(toEncode.Length);
+ int encoded = encoder.GetBytes(toEncode, bytes.Slice(preambleSize), flush: remaining.IsEmpty);
+ Span toStore = bytes.Slice(0, preambleSize + encoded);
+
+ RandomAccess.WriteAtOffset(fileHandle, toStore, fileOffset);
+
+ fileOffset += toStore.Length;
+ preambleSize = 0;
+ }
+ }
+ finally
+ {
+ if (rentedBytes is not null)
+ {
+ ArrayPool.Shared.Return(rentedBytes);
+ }
+ }
+ }
+
+ private static async Task WriteToFileAsync(string path, FileMode mode, string? contents, Encoding encoding, CancellationToken cancellationToken)
+ {
+ ReadOnlyMemory preamble = encoding.GetPreamble();
+ int preambleSize = preamble.Length;
+
+ using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous, GetPreallocationSize(mode, contents, encoding, preambleSize));
+ long fileOffset = mode == FileMode.Append && fileHandle.CanSeek ? RandomAccess.GetLength(fileHandle) : 0;
+
+ if (string.IsNullOrEmpty(contents))
+ {
+ if (preambleSize > 0 // even if the content is empty, we want to store the preamble
+ && fileOffset == 0) // if we're appending to a file that already has data, don't write the preamble.
+ {
+ await RandomAccess.WriteAtOffsetAsync(fileHandle, preamble, fileOffset, cancellationToken).ConfigureAwait(false);
+ }
+ return;
+ }
+
+ byte[] bytes = ArrayPool.Shared.Rent(preambleSize + encoding.GetMaxByteCount(Math.Min(contents.Length, ChunkSize)));
+
+ try
+ {
+ if (fileOffset == 0)
+ {
+ preamble.CopyTo(bytes);
+ }
+ else
+ {
+ preambleSize = 0; // don't append preamble to a non-empty file
+ }
+
+ Encoder encoder = encoding.GetEncoder();
+ ReadOnlyMemory remaining = contents.AsMemory();
+ while (!remaining.IsEmpty)
+ {
+ ReadOnlyMemory toEncode = remaining.Slice(0, Math.Min(remaining.Length, ChunkSize));
+ remaining = remaining.Slice(toEncode.Length);
+ int encoded = encoder.GetBytes(toEncode.Span, bytes.AsSpan(preambleSize), flush: remaining.IsEmpty);
+ ReadOnlyMemory toStore = new ReadOnlyMemory(bytes, 0, preambleSize + encoded);
+
+ await RandomAccess.WriteAtOffsetAsync(fileHandle, toStore, fileOffset, cancellationToken).ConfigureAwait(false);
+
+ fileOffset += toStore.Length;
+ preambleSize = 0;
+ }
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(bytes);
+ }
+ }
+
+ private static long GetPreallocationSize(FileMode mode, string? contents, Encoding encoding, int preambleSize)
+ {
+ // for a single write operation, setting preallocationSize has no perf benefit, as it requires an additional sys-call
+ if (contents is null || contents.Length < ChunkSize)
+ {
+ return 0;
+ }
+
+ // preallocationSize is ignored for Append mode, there is no need to spend cycles on GetByteCount
+ if (mode == FileMode.Append)
+ {
+ return 0;
+ }
+
+ return preambleSize + encoding.GetByteCount(contents);
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/File.netcoreapp.cs b/src/libraries/System.Private.CoreLib/src/System/IO/File.netcoreapp.cs
deleted file mode 100644
index 1e627dae597329..00000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/IO/File.netcoreapp.cs
+++ /dev/null
@@ -1,233 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Buffers;
-using System.Diagnostics;
-using System.IO.Strategies;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Win32.SafeHandles;
-
-namespace System.IO
-{
- public static partial class File
- {
- private const int ChunkSize = 8192;
-
- ///
- /// Initializes a new instance of the class with the specified path, creation mode, read/write and sharing permission, the access other FileStreams can have to the same file, the buffer size, additional file options and the allocation size.
- ///
- /// for information about exceptions.
- public static FileStream Open(string path, FileStreamOptions options) => new FileStream(path, options);
-
- ///
- /// Initializes a new instance of the class with the specified path, creation mode, read/write and sharing permission, the access other SafeFileHandles can have to the same file, additional file options and the allocation size.
- ///
- /// A relative or absolute path for the file that the current instance will encapsulate.
- /// One of the enumeration values that determines how to open or create the file. The default value is
- /// A bitwise combination of the enumeration values that determines how the file can be accessed. The default value is
- /// A bitwise combination of the enumeration values that determines how the file will be shared by processes. The default value is .
- /// The initial allocation size in bytes for the file. A positive value is effective only when a regular file is being created, overwritten, or replaced.
- /// Negative values are not allowed. In other cases (including the default 0 value), it's ignored.
- /// An object that describes optional parameters to use.
- /// is .
- /// is an empty string (""), contains only white space, or contains one or more invalid characters.
- /// -or-
- /// refers to a non-file device, such as CON:, COM1:, LPT1:, etc. in an NTFS environment.
- /// refers to a non-file device, such as CON:, COM1:, LPT1:, etc. in a non-NTFS environment.
- /// is negative.
- /// -or-
- /// , , or contain an invalid value.
- /// The file cannot be found, such as when is or , and the file specified by does not exist. The file must already exist in these modes.
- /// An I/O error, such as specifying when the file specified by already exists, occurred.
- /// -or-
- /// The disk was full (when was provided and was pointing to a regular file).
- /// -or-
- /// The file was too large (when was provided and was pointing to a regular file).
- /// The caller does not have the required permission.
- /// The specified path is invalid, such as being on an unmapped drive.
- /// The requested is not permitted by the operating system for the specified , such as when is or and the file or directory is set for read-only access.
- /// -or-
- /// is specified for , but file encryption is not supported on the current platform.
- /// The specified path, file name, or both exceed the system-defined maximum length.
- public static SafeFileHandle OpenHandle(string path, FileMode mode = FileMode.Open, FileAccess access = FileAccess.Read,
- FileShare share = FileShare.Read, FileOptions options = FileOptions.None, long preallocationSize = 0)
- {
- FileStreamHelpers.ValidateArguments(path, mode, access, share, bufferSize: 0, options, preallocationSize);
-
- return SafeFileHandle.Open(Path.GetFullPath(path), mode, access, share, options, preallocationSize);
- }
-
- private static byte[] ReadAllBytesUnknownLength(FileStream fs)
- {
- byte[]? rentedArray = null;
- Span buffer = stackalloc byte[512];
- try
- {
- int bytesRead = 0;
- while (true)
- {
- if (bytesRead == buffer.Length)
- {
- uint newLength = (uint)buffer.Length * 2;
- if (newLength > Array.MaxLength)
- {
- newLength = (uint)Math.Max(Array.MaxLength, buffer.Length + 1);
- }
-
- byte[] tmp = ArrayPool.Shared.Rent((int)newLength);
- buffer.CopyTo(tmp);
- byte[]? oldRentedArray = rentedArray;
- buffer = rentedArray = tmp;
- if (oldRentedArray != null)
- {
- ArrayPool.Shared.Return(oldRentedArray);
- }
- }
-
- Debug.Assert(bytesRead < buffer.Length);
- int n = fs.Read(buffer.Slice(bytesRead));
- if (n == 0)
- {
- return buffer.Slice(0, bytesRead).ToArray();
- }
- bytesRead += n;
- }
- }
- finally
- {
- if (rentedArray != null)
- {
- ArrayPool.Shared.Return(rentedArray);
- }
- }
- }
-
- private static void WriteToFile(string path, FileMode mode, string? contents, Encoding encoding)
- {
- ReadOnlySpan preamble = encoding.GetPreamble();
- int preambleSize = preamble.Length;
-
- using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.None, GetPreallocationSize(mode, contents, encoding, preambleSize));
- long fileOffset = mode == FileMode.Append && fileHandle.CanSeek ? RandomAccess.GetLength(fileHandle) : 0;
-
- if (string.IsNullOrEmpty(contents))
- {
- if (preambleSize > 0 // even if the content is empty, we want to store the preamble
- && fileOffset == 0) // if we're appending to a file that already has data, don't write the preamble.
- {
- RandomAccess.WriteAtOffset(fileHandle, preamble, fileOffset);
- }
- return;
- }
-
- int bytesNeeded = preambleSize + encoding.GetMaxByteCount(Math.Min(contents.Length, ChunkSize));
- byte[]? rentedBytes = null;
- Span bytes = bytesNeeded <= 1024 ? stackalloc byte[1024] : (rentedBytes = ArrayPool.Shared.Rent(bytesNeeded));
-
- try
- {
- if (fileOffset == 0)
- {
- preamble.CopyTo(bytes);
- }
- else
- {
- preambleSize = 0; // don't append preamble to a non-empty file
- }
-
- Encoder encoder = encoding.GetEncoder();
- ReadOnlySpan remaining = contents;
- while (!remaining.IsEmpty)
- {
- ReadOnlySpan toEncode = remaining.Slice(0, Math.Min(remaining.Length, ChunkSize));
- remaining = remaining.Slice(toEncode.Length);
- int encoded = encoder.GetBytes(toEncode, bytes.Slice(preambleSize), flush: remaining.IsEmpty);
- Span toStore = bytes.Slice(0, preambleSize + encoded);
-
- RandomAccess.WriteAtOffset(fileHandle, toStore, fileOffset);
-
- fileOffset += toStore.Length;
- preambleSize = 0;
- }
- }
- finally
- {
- if (rentedBytes is not null)
- {
- ArrayPool.Shared.Return(rentedBytes);
- }
- }
- }
-
- private static async Task WriteToFileAsync(string path, FileMode mode, string? contents, Encoding encoding, CancellationToken cancellationToken)
- {
- ReadOnlyMemory preamble = encoding.GetPreamble();
- int preambleSize = preamble.Length;
-
- using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous, GetPreallocationSize(mode, contents, encoding, preambleSize));
- long fileOffset = mode == FileMode.Append && fileHandle.CanSeek ? RandomAccess.GetLength(fileHandle) : 0;
-
- if (string.IsNullOrEmpty(contents))
- {
- if (preambleSize > 0 // even if the content is empty, we want to store the preamble
- && fileOffset == 0) // if we're appending to a file that already has data, don't write the preamble.
- {
- await RandomAccess.WriteAtOffsetAsync(fileHandle, preamble, fileOffset, cancellationToken).ConfigureAwait(false);
- }
- return;
- }
-
- byte[] bytes = ArrayPool.Shared.Rent(preambleSize + encoding.GetMaxByteCount(Math.Min(contents.Length, ChunkSize)));
-
- try
- {
- if (fileOffset == 0)
- {
- preamble.CopyTo(bytes);
- }
- else
- {
- preambleSize = 0; // don't append preamble to a non-empty file
- }
-
- Encoder encoder = encoding.GetEncoder();
- ReadOnlyMemory remaining = contents.AsMemory();
- while (!remaining.IsEmpty)
- {
- ReadOnlyMemory toEncode = remaining.Slice(0, Math.Min(remaining.Length, ChunkSize));
- remaining = remaining.Slice(toEncode.Length);
- int encoded = encoder.GetBytes(toEncode.Span, bytes.AsSpan(preambleSize), flush: remaining.IsEmpty);
- ReadOnlyMemory toStore = new ReadOnlyMemory(bytes, 0, preambleSize + encoded);
-
- await RandomAccess.WriteAtOffsetAsync(fileHandle, toStore, fileOffset, cancellationToken).ConfigureAwait(false);
-
- fileOffset += toStore.Length;
- preambleSize = 0;
- }
- }
- finally
- {
- ArrayPool.Shared.Return(bytes);
- }
- }
-
- private static long GetPreallocationSize(FileMode mode, string? contents, Encoding encoding, int preambleSize)
- {
- // for a single write operation, setting preallocationSize has no perf benefit, as it requires an additional sys-call
- if (contents is null || contents.Length < ChunkSize)
- {
- return 0;
- }
-
- // preallocationSize is ignored for Append mode, there is no need to spend cycles on GetByteCount
- if (mode == FileMode.Append)
- {
- return 0;
- }
-
- return preambleSize + encoding.GetByteCount(contents);
- }
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileInfo.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileInfo.cs
index 4f42c95ff454f9..2ce33d996d61ea 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/FileInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileInfo.cs
@@ -1,9 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.Diagnostics;
-using System.IO;
using System.Text;
using System.Runtime.Versioning;
@@ -11,7 +9,7 @@ namespace System.IO
{
// Class for creating FileStream objects, and some basic file management
// routines such as Delete, etc.
- public sealed partial class FileInfo : FileSystemInfo
+ public sealed class FileInfo : FileSystemInfo
{
private FileInfo() { }
@@ -72,6 +70,12 @@ public bool IsReadOnly
}
}
+ ///
+ /// Initializes a new instance of the class with the specified creation mode, read/write and sharing permission, the access other FileStreams can have to the same file, the buffer size, additional file options and the allocation size.
+ ///
+ /// for information about exceptions.
+ public FileStream Open(FileStreamOptions options) => File.Open(NormalizedPath, options);
+
public StreamReader OpenText()
=> new StreamReader(NormalizedPath, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileInfo.netcoreapp.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileInfo.netcoreapp.cs
deleted file mode 100644
index 4c6c5f343e24fa..00000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/IO/FileInfo.netcoreapp.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace System.IO
-{
- public sealed partial class FileInfo : FileSystemInfo
- {
- ///
- /// Initializes a new instance of the class with the specified creation mode, read/write and sharing permission, the access other FileStreams can have to the same file, the buffer size, additional file options and the allocation size.
- ///
- /// for information about exceptions.
- public FileStream Open(FileStreamOptions options) => File.Open(NormalizedPath, options);
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Win32.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Win32.cs
deleted file mode 100644
index a9893cd1736c5e..00000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Win32.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace System.IO
-{
- internal static partial class FileSystem
- {
- public static void Encrypt(string path)
- {
- string fullPath = Path.GetFullPath(path);
-
- if (!Interop.Advapi32.EncryptFile(fullPath))
- {
- ThrowExceptionEncryptDecryptFail(fullPath);
- }
- }
-
- public static void Decrypt(string path)
- {
- string fullPath = Path.GetFullPath(path);
-
- if (!Interop.Advapi32.DecryptFile(fullPath))
- {
- ThrowExceptionEncryptDecryptFail(fullPath);
- }
- }
-
- private static unsafe void ThrowExceptionEncryptDecryptFail(string fullPath)
- {
- int errorCode = Marshal.GetLastWin32Error();
- if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED)
- {
- // Check to see if the file system support the Encrypted File System (EFS)
- string name = DriveInfoInternal.NormalizeDriveName(Path.GetPathRoot(fullPath)!);
-
- using (DisableMediaInsertionPrompt.Create())
- {
- if (!Interop.Kernel32.GetVolumeInformation(name, null, 0, null, null, out int fileSystemFlags, null, 0))
- {
- errorCode = Marshal.GetLastWin32Error();
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, name);
- }
-
- if ((fileSystemFlags & Interop.Kernel32.FILE_SUPPORTS_ENCRYPTION) == 0)
- {
- throw new NotSupportedException(SR.PlatformNotSupported_FileEncryption);
- }
- }
- }
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
- }
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs
index b94d7eeb74fafb..56ca40921ae275 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs
@@ -2,18 +2,59 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Win32.SafeHandles;
-using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
-using System.IO;
-using System.Text;
using System.Buffers;
namespace System.IO
{
internal static partial class FileSystem
{
+ public static void Encrypt(string path)
+ {
+ string fullPath = Path.GetFullPath(path);
+
+ if (!Interop.Advapi32.EncryptFile(fullPath))
+ {
+ ThrowExceptionEncryptDecryptFail(fullPath);
+ }
+ }
+
+ public static void Decrypt(string path)
+ {
+ string fullPath = Path.GetFullPath(path);
+
+ if (!Interop.Advapi32.DecryptFile(fullPath))
+ {
+ ThrowExceptionEncryptDecryptFail(fullPath);
+ }
+ }
+
+ private static unsafe void ThrowExceptionEncryptDecryptFail(string fullPath)
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED)
+ {
+ // Check to see if the file system support the Encrypted File System (EFS)
+ string name = DriveInfoInternal.NormalizeDriveName(Path.GetPathRoot(fullPath)!);
+
+ using (DisableMediaInsertionPrompt.Create())
+ {
+ if (!Interop.Kernel32.GetVolumeInformation(name, null, 0, null, null, out int fileSystemFlags, null, 0))
+ {
+ errorCode = Marshal.GetLastWin32Error();
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, name);
+ }
+
+ if ((fileSystemFlags & Interop.Kernel32.FILE_SUPPORTS_ENCRYPTION) == 0)
+ {
+ throw new NotSupportedException(SR.PlatformNotSupported_FileEncryption);
+ }
+ }
+ }
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
+ }
+
public static void CopyFile(string sourceFullPath, string destFullPath, bool overwrite)
{
int errorCode = Interop.Kernel32.CopyFile(sourceFullPath, destFullPath, !overwrite);
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs
index 6cbb6770004c4b..348b0bf4f15a52 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs
@@ -18,9 +18,6 @@ public static partial class RandomAccess
{
private static readonly IOCompletionCallback s_callback = AllocateCallback();
- // TODO: Use SystemPageSize directly when #57442 is fixed.
- private static readonly int s_cachedPageSize = Environment.SystemPageSize;
-
internal static unsafe long GetFileLength(SafeFileHandle handle)
{
Interop.Kernel32.FILE_STANDARD_INFO info;
@@ -441,7 +438,7 @@ private static unsafe bool TryPrepareScatterGatherBuffers(IReadOnly
THandler handler, [NotNullWhen(true)] out MemoryHandle[]? handlesToDispose, out IntPtr segmentsPtr, out int totalBytes)
where THandler : struct, IMemoryHandler
{
- int pageSize = s_cachedPageSize;
+ int pageSize = Environment.SystemPageSize;
Debug.Assert(BitOperations.IsPow2(pageSize), "Page size is not a power of two.");
// We take advantage of the fact that the page size is
// a power of two to avoid an expensive modulo operation.