Per-directory case sensitivity and WSL

If you have used the Windows Subsystem for Linux, you’re probably aware that it allows you to treat your Windows file systems (mounted under /mnt/c, /mnt/d, etc.) as case sensitive. This means, among other things, that you can create files whose names differ only by case (e.g. foo.txt and FOO.TXT).

However, using those files in Windows was not really possible. Since Windows applications treat the file system as case insensitive, they cannot distinguish between files whose names only differ in case. While File Explorer would show both files, only one would be opened regardless of which one you clicked.

Starting with Windows insider build 17093, we’ve introduced a new way to handle case sensitive files in Windows: per-directory case sensitivity. We use this ability in the Windows Subsystem for Linux to give you better interoperability when using case sensitive files, and you can also use it yourself with regular Windows applications. As of insider build 17110, this behavior is the default.

Case sensitivity in Windows

The Windows NT family of operating systems (including Windows 10) has always had the ability to perform case sensitive file system operations. Applications can pass the FILE_FLAG_POSIX_SEMANTICS flag to the CreateFile API to indicate that they want the path to be treated as case sensitive. However, for compatibility reasons, there is a global registry key that overrides this behavior; when this key is set, all file operations are case insensitive, even when the FILE_FLAG_POSIX_SEMANTICS flag is specified. Since Windows XP, this has been the default.

The Windows Subsystem for Linux uses another mechanism, which itself bypasses that registry key, allowing us to perform case sensitive file system operations. This is what allows Linux applications running in WSL to use file names that differ only by case, just like they can on real Linux, even with that global registry key set.

Unfortunately, this leaves you with files that can’t be accessed by Windows applications. While you could change the global registry key, that still would only work for those applications that use FILE_FLAG_POSIX_SEMANTICS, and this would change the behavior for all files on all drives, which may not be intended and may break some applications.

Per-directory case sensitivity

To solve this problem, we added a new case sensitive flag that can be applied to directories. For directories that have this flag set, all operations on files in that directory are case sensitive, regardless of whether FILE_FLAG_POSIX_SEMANTICS was specified. This means that if you have two files that differ only by case in a directory marked as case sensitive, all applications will be able to access them.

In Windows insider build 17107, we have added the ability to view and modify this flag to the fsutil.exe command. To check if a directory is case sensitive, run the following command:
fsutil.exe file queryCaseSensitiveInfo <path>

To mark a directory as case sensitive, or case insensitive respectively:
fsutil.exe file setCaseSensitiveInfo <path> enable
fsutil.exe file setCaseSensitiveInfo <path> disable

Note that the per-directory case sensitivity flag is not inherited; directories created in a case sensitive directory are not automatically case sensitive themselves. You must explicitly mark each directory as case sensitive. Changing the flag requires “write attributes” permission to the directory.

fsutil demo

Per-directory case sensitivity in WSL

The Windows Subsystem for Linux makes use of the per-directory case sensitivity flag to improve its interoperability with the Windows file systems mounted under /mnt/c, /mnt/d, etc. We have several new case sensitivity modes, which can be controlled with the “case” mount option for DrvFs. This option controls which directories are treated as case sensitive, and whether new directories created with WSL will have the flag set. There are three values: dir, off, and force. Their behavior is listed in the table below.

case=dir case=off case=force
Directory with flag enabled Case sensitive Case sensitive Case sensitive
Directory with flag disabled Case insensitive Case insensitive Case sensitive
Flag on directories created in WSL Enabled Disabled Enabled

Essentially, directories with the case sensitivity flag set are always treated as case sensitive. Directories without the flag set are treated as case insensitive, unless you’re using case=force. New directories created by DrvFs get the flag set unless you’re using case=off.

Using case=force is equivalent to WSL’s old behavior (except for the fact that the flag gets set on new directories).

To mount DrvFs with a specific case sensitivity setting, use /etc/wsl.conf to set the default mount options for all drives, or /etc/fstab to specify options for a specific drive.

Not all file systems support per-directory case sensitivity; currently, it only works on local NTFS drives. To make sure your drive was successfully mounted with the desired case sensitivity option, use the mount command and see if the option was applied.

mount command output

Using per-directory case sensitivity has a number of advantages. Not only can you create files that differ by case and have them accessible in Windows, you can also create case-differing files in Windows in those directories. And, since all other directories on your system are not marked case sensitive, you don’t need to care about case sensitivity from within WSL when accessing common Windows files. This means for example that you can launch applications using interop without matching the exact case of the  executable file (e.g. running “NOTEPAD.EXE” now works in WSL the same  as it does in Windows). NT symlinks whose targets don’t use the exact case of the actual file now also work  in WSL.

Notepad demo

If you need to create a case insensitive directory while using “case=dir” or “case=force”, or want to create a case sensitive directory while using “case=off”, you can simply use fsutil.exe after creating the directory. You can, of course, invoke fsutil.exe from WSL using interop.

Note: if you change the case sensitive flag on an existing directory while WSL is running, please make sure WSL has no references to that directory. That means no WSL processes may have that directory, or any of its descendants, open. That includes using that directory, or its descendants, as the current working directory. If you don’t, WSL continues to act like the directory has its old case sensitivity setting, which may lead to unexpected results.

Starting with build 17110, DrvFs’s default behavior is now equivalent to using “case=dir”. This means that any directories you created with WSL before build 17093 will not be treated as case sensitive anymore. To fix this, use fsutil.exe to mark your existing directories as case sensitive.

If you require the old behavior, you can still mount DrvFs using “case=force”, though we strongly recommend using per-directory case sensitivity going forward. As of build 17110, using “case=force” requires setting a registry key, which you can do by running the following command from an elevated command prompt:

reg.exe add HKLM\SYSTEM\CurrentControlSet\Services\lxss /v DrvFsAllowForceCaseSensitivity /t REG_DWORD /d 1

As you can see, per-directory case sensitivity improves interoperability between files created with WSL and Windows significantly. Let us know what you think in the comments!

Comments (3)

  1. fransv says:

    Nice to see this surfaced and it does help interop quite a bit.
    Would be great to see this flag supported by Windows commands throughout also (like xcopy, robocopy and explorer).
    Creating a copy of a directory with the flag enabled from command line or explorer currently does not set the flag on the destination directory.

  2. Can you explain how this flag is persisted? I take it the NTFS version hasn’t changed, so the options are limited. My guess would be attributes or extended attributes or a metafile analogous to $Extend\$Reparse.

    Will the respective functionality be documented in either the SDKs or WDKs in time?

    Last but not least, is there a special reason why the flag seemingly cares only about case-sensitivity? Wouldn’t it have been more logical to enable accessing other files as well, such as those whose name ends in a dot? Similarly my guess is that reserved file names such as CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9 could be created using WSL (they could be created in SUA, IIRC) but still not accessed from the Windows subsystem. Limiting the flag purely to case-sensitivity seems halfhearted (albeit a big step forward).

    PS: the term “NT symlinks” seems kind of ambiguous in the text. My first thought was “object manager!”, but in the context it seems to refer to file system symlinks, the kind implemented via reparse points.

Skip to main content