Skip to content

Commit 5c15498

Browse files
committed
os: support reading empty root directories on Windows
GetFileInformationByHandleEx can return `ERROR_FILE_NOT_FOUND` when no files were found in a root directory, as per MS-FSA 2.1.5.6.3 [1]. This error code should not be treated as an error, but rather as an indication that no files were found, in which case `readdir` should return an empty slice. This CL doesn't add any test as it is difficult to trigger this error code. Empty root directories created using Windows utilities such as `net use` always report at least the optional `.` and `..` entries. A reproducer is provided in #61159, but it requires WinFSP to be installed. Fixes #61159 [1] https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsa/fa8194e0-53ec-413b-8315-e8fa85396fd8 Change-Id: Id46452030f5355c292e5b0abbf5e22af434a84d2 Reviewed-on: https://go-review.googlesource.com/c/go/+/507775 Reviewed-by: Nick Craig-Wood <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Quim Muntal <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]> Reviewed-by: Bryan Mills <[email protected]>
1 parent 894d24d commit 5c15498

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

src/os/dir_windows.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []Di
8484
if err == syscall.ERROR_NO_MORE_FILES {
8585
break
8686
}
87+
if infoClass == windows.FileIdBothDirectoryRestartInfo && err == syscall.ERROR_FILE_NOT_FOUND {
88+
// GetFileInformationByHandleEx doesn't document the return error codes when the info class is FileIdBothDirectoryRestartInfo,
89+
// but MS-FSA 2.1.5.6.3 [1] specifies that the underlying file system driver should return STATUS_NO_SUCH_FILE when
90+
// reading an empty root directory, which is mapped to ERROR_FILE_NOT_FOUND by Windows.
91+
// Note that some file system drivers may never return this error code, as the spec allows to return the "." and ".."
92+
// entries in such cases, making the directory appear non-empty.
93+
// The chances of false positive are very low, as we know that the directory exists, else GetVolumeInformationByHandle
94+
// would have failed, and that the handle is still valid, as we haven't closed it.
95+
// See go.dev/issue/61159.
96+
// [1] https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsa/fa8194e0-53ec-413b-8315-e8fa85396fd8
97+
break
98+
}
8799
if s, _ := file.Stat(); s != nil && !s.IsDir() {
88100
err = &PathError{Op: "readdir", Path: file.name, Err: syscall.ENOTDIR}
89101
} else {

0 commit comments

Comments
 (0)