Skip to content

Conversation

@Neo-vortex
Copy link
Contributor

@Neo-vortex Neo-vortex commented Nov 23, 2025

fixes #116087

Fix CreateSubdirectory failing for root directories

Summary

Fixes a bug where DirectoryInfo.CreateSubdirectory(path) incorrectly throws ArgumentException when called on root directory instances (e.g., C:\).

Problem

Path.TrimEndingDirectorySeparator preserves trailing separators for root paths to maintain valid path format. This causes the boundary validation logic to use an incorrect index when checking for directory separators.

Example failure:

var rootDir = new DirectoryInfo(@"C:\");
rootDir.CreateSubdirectory("test"); // Throws ArgumentException

The check at index [3] evaluates the character 't' instead of the separator '\' at index [2], causing validation to fail.

Solution

After calling Path.TrimEndingDirectorySeparator, explicitly check if trimmedCurrentPath still has a trailing separator (root directory case) and remove it manually before performing boundary validation.

if (trimmedCurrentPath.Length > 0 && 
    PathInternal.IsDirectorySeparator(trimmedCurrentPath[trimmedCurrentPath.Length - 1]))
{
    trimmedCurrentPath = trimmedCurrentPath.Slice(0, trimmedCurrentPath.Length - 1);
}

This ensures consistent behavior: trimmedCurrentPath never ends with a separator, making the boundary index check work correctly for all directory types.

Impact

  • Fixes: Root directory subdirectory creation (Windows: C:\, D:\, )
  • No breaking changes: Non-root directory behavior unchanged
  • Low risk: Localized change to validation logic only

Testing

  • Existing tests continue to pass (non-root directories)
  • Manual testing confirms fix for root directories:
  new DirectoryInfo(@"C:\").CreateSubdirectory("test");     // ✓ Works
  new DirectoryInfo(@"C:\Users").CreateSubdirectory("Docs"); // ✓ Still works

Path.TrimEndingDirectorySeparator preserves trailing separators for root
paths like "C:\" or "/", causing boundary validation to check the wrong
index. Added explicit trim of trailing separator from trimmedCurrentPath
to fix the boundary check for root directory cases.

Signed-off-by: Mohamadreza Nakhleh <neo.vortex@pm.me>
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Nov 23, 2025
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Nov 23, 2025
@vcsjones vcsjones added area-System.IO and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Nov 23, 2025
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-io
See info in area-owners.md if you want to be subscribed.

Signed-off-by: Mohamadreza Nakhleh <neo.vortex@pm.me>
@kasperk81
Copy link
Contributor

Example failure:

that can be a test case

Signed-off-by: Mohamadreza Nakhleh <neo.vortex@pm.me>
@Neo-vortex
Copy link
Contributor Author

I added a test
@kasperk81

@Neo-vortex
Copy link
Contributor Author

Neo-vortex commented Nov 25, 2025

it seems Linux is also effected.
this code fails with the same error without this PR

var dir = new DirectoryInfo("/");
dir.CreateSubdirectory("test");

I added a test for linux as well

Signed-off-by: Mohamadreza Nakhleh <neo.vortex@pm.me>
@Neo-vortex
Copy link
Contributor Author

linux tests are failing because of permission.

      System.UnauthorizedAccessException : Access to the path '/TestFolder_1aa9354d27554fa5a93f0ad594276905' is denied.
      ---- System.IO.IOException : Permission denied

the fact that it is trying to create the folder but gets Permission denied is an indication that this PR also fixes linux.
the problem is now how to make a test that actually passes without accessing the "/" itself

@Neo-vortex
Copy link
Contributor Author

@vcsjones
how should we process from here ?

@kasperk81
Copy link
Contributor

linux tests are failing because of permission.

if only the newly added tests in PR are failing, then change them to:

try { Assert... } catch (Exception ex) { Assert(Exception is UnauthorizedAccessException) }

both cases are acceptable, either original assert passed or the op failed because of access issue. other exceptions are unexpected and should fail.

Neo-vortex and others added 3 commits December 2, 2025 10:47
…Directory/EnumerableTests.cs

Co-authored-by: kasperk81 <83082615+kasperk81@users.noreply.github.com>
…Directory/EnumerableTests.cs

Co-authored-by: kasperk81 <83082615+kasperk81@users.noreply.github.com>
…Directory/EnumerableTests.cs

Co-authored-by: kasperk81 <83082615+kasperk81@users.noreply.github.com>
@Neo-vortex
Copy link
Contributor Author

@vcsjones
what's next here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.IO community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DirectoryInfo.CreateSubdirectory fails when DirectoryInfo path is a root directory

3 participants