diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/DirectoryInfo.cs b/src/libraries/System.Private.CoreLib/src/System/IO/DirectoryInfo.cs index 835ab22793730c..4b889b8aba92e0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/DirectoryInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/DirectoryInfo.cs @@ -83,7 +83,10 @@ public DirectoryInfo CreateSubdirectory(string path) string newPath = Path.GetFullPath(Path.Combine(FullPath, path)); ReadOnlySpan trimmedNewPath = Path.TrimEndingDirectorySeparator(newPath.AsSpan()); - ReadOnlySpan trimmedCurrentPath = Path.TrimEndingDirectorySeparator(FullPath.AsSpan()); + + // Trim any trailing separator, including from a root path for proper boundary checking. + // TrimEndingDirectorySeparator does not trim the character from path roots. + ReadOnlySpan trimmedCurrentPath = FullPath.TrimEnd(Path.DirectorySeparatorChar); // We want to make sure the requested directory is actually under the subdirectory. if (trimmedNewPath.StartsWith(trimmedCurrentPath, PathInternal.StringComparison) diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DirectoryInfo/CreateSubdirectory.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DirectoryInfo/CreateSubdirectory.cs index 0878b396b0983e..f16bd0c1617f73 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DirectoryInfo/CreateSubdirectory.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DirectoryInfo/CreateSubdirectory.cs @@ -218,6 +218,41 @@ public void ExtendedPathSubdirectory() Assert.StartsWith(IOInputs.ExtendedPrefix, subDir.FullName); } + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void CreateSubdirectory_RootDriveSubfolder_Windows() + { + string rootDrive = Path.GetPathRoot(Environment.SystemDirectory); + DirectoryInfo rootDirectory = new DirectoryInfo(rootDrive); + string testFolderName = GetTestFileName(); + + try + { + DirectoryInfo subDirectory = rootDirectory.CreateSubdirectory(testFolderName); + + Assert.True(subDirectory.Exists); + Assert.Equal(Path.Combine(rootDrive, testFolderName), subDirectory.FullName); + } + finally + { + string testFolderPath = Path.Combine(rootDrive, testFolderName); + if (Directory.Exists(testFolderPath)) + { + Directory.Delete(testFolderPath, recursive: true); + } + } + } + + [Fact] + [PlatformSpecific(TestPlatforms.Linux)] + public void CreateSubdirectory_RootDriveSubfolder_ThrowsUnauthorizedAccessException_Linux() + { + DirectoryInfo rootDirectory = new DirectoryInfo("/"); + string testFolderName = GetTestFileName(); + + Assert.Throws(() => rootDirectory.CreateSubdirectory(testFolderName)); + } + [Fact] [PlatformSpecific(TestPlatforms.Windows)] // UNC shares public void UNCPathWithOnlySlashes()