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.
https://bugs.winehq.org/show_bug.cgi?id=50283
--- Comment #1 from Erich E. Hoover erich.e.hoover@gmail.com --- It took me a while this weekend to figure out a way "around" this problem, but the solution I came up with is really interesting: === dir_fd = openat( fd, ".", O_RDONLY | O_DIRECTORY | O_NONBLOCK ); if (dir_fd == -1) return -1; if (!(dir = fdopendir( dir_fd ))) ... closedir( dir ); close( dir_fd ); === Essentially, we can "recreate" the fd with new permissions using openat() so that it has the correct access rights for fdopendir(). This may be very useful for implementing some other features...
Anyway, if you don't mind checking, this issue should now be fixed by staging commit cfe1b94e0f53219cf292fea9b4618d909c282fbf.
https://bugs.winehq.org/show_bug.cgi?id=50283
Martin Storsjö martin@martin.st changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |FIXED
--- Comment #2 from Martin Storsjö martin@martin.st --- This one also seems to be working as it should now, thanks!
https://bugs.winehq.org/show_bug.cgi?id=50283
Erich E. Hoover erich.e.hoover@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #3 from Erich E. Hoover erich.e.hoover@gmail.com --- Fixed in wine-staging 6.2.