https://bugs.winehq.org/show_bug.cgi?id=50283
Bug ID: 50283 Summary: FILE_OPEN_REPARSE_POINT breaks error reporting for deletes of directories Product: Wine-staging Version: unspecified Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: -unknown Assignee: wine-bugs@winehq.org Reporter: martin@martin.st CC: erich.e.hoover@gmail.com, leslie_alistair@hotmail.com, z.figura12@gmail.com Distribution: ---
Created attachment 68840 --> https://bugs.winehq.org/attachment.cgi?id=68840 Test program
In order to generically delete a file system entry, regardless of whether it is a regular file, symlink or directory, one can open a handle to it and delete it with a call to SetFileInformationByHandle(FileDispositionInfo). By opening the handle with FILE_FLAG_OPEN_REPARSE_POINT, a potential symlink gets handled by removing the symlink itself, not the target file it points to.
If a handle opened with the FILE_FLAG_OPEN_REPARSE_POINT flag set turns out to be a directory, error reporting for the SetFileInformationByHandle call fails. This is caused by [1] in combination with [2]. These two cases make O_SYMLINK, which includes O_PATH, be added when opening the file descriptor which turns out to be a directory. The O_PATH flag causes the later fdopendir() and readdir() to not return anything, causing is_dir_empty [3] to indicate that the directory is empty and removal will succeed, even though it doesn't.
This triggers errors in a std::filesystem testcase in libc++ [4], when checking to make sure that attempts to remove a non-empty directory properly signals errors.
[1] https://github.com/wine-staging/wine-staging/blob/fce121fcd95380ca56c9d027be... [2] https://github.com/wine-staging/wine-staging/blob/fce121fcd95380ca56c9d027be... [3] https://source.winehq.org/git/wine.git/blob/fac1e40aaf0726a3e328a922cb496927... [4] https://github.com/llvm/llvm-project/blob/1e260f955d3123351fc68de8c2dde02b1b...
The issue can be reproduced with the attached fairly minimal test program.