Wrong behavior of standard IO library when interacting with Samba (very serious)
Glavo
zjx001202 at gmail.com
Mon Mar 7 05:33:16 UTC 2022
I am a Java application developer. I noticed that when my program runs on
Windows in a samba shared folder (mounted as a drive, or accessed via a UNC
path), the Java standard IO library has some unusual behavior.
Note that these issues only occur when accessing a folder shared by
*Samba*, but not for the folder shared via SMB by another Windows host.
One of the bugs was reported years ago (JDK-8154915): `Files.isWritable`
always returns false for files shared by samba. It's worth noting for this
question that `File::canWrite()`'s behavior is normal.
(So in my program I pass `!Files.isWritable(p) && p.toFile().canWrite()` to
detect if it's shared by samba and give the user a warning)
This problem keeps showing up on several of my devices, so it should be
fine to reproduce. The reason it wasn't resolved seems to be that the
OpenJDK maintainers didn't understand that it came up when interacting with
Samba (not just SMB).
In addition to this, there is another, more significant problem: After a
series of IO operations, Java will recognize a normal folder as a regular
file, not a folder.
This vicious bug hinders the possibility of our program running on Samba
shared folders, and I can't find a workaround to make the program work
temporarily.
I've spent many days catching this bug, it always appears on our program,
but I'm currently unable to find a minimal reproducer that reproduces it
stably.
After this bug occurs, the folder affected by the bug will have the
following properties:
1. It is only misidentified in the current JVM process, other processes are
not affected.
2. This JVM process continues to recognize errors until the JVM is
restarted.
3. For this folder, `Files.exists` will return false, but `File::exists()`
will return true.
4. Although `Files.exists` thinks it does not exist,
`Files.readAttributes` can still return the result normally.
5. In its BasicFileAttributes, `isRegularFile` is true and `isDirectory` is
false.
6. For this folder, `File::isFile` returns true, and `File.isDirectory`
returns false.
7. After this bug occurs, without exiting the JVM process, and opening the
parent of this folder in the Windows Explorer, the JVM process correctly
recognizes it as a folder again.
We can always reproduce it in we open source third-party Minecraft
launchers:
https://github.com/huanghongxun/HMCL
Reproducing it in HMCL is very simple, just put HMCL in a samba shared
folder and start it, then install any version of Minecraft in it, and it
will fail to install because of this bug.
However, I can't extract a minimal reproducer from it that can reproduce it
stably.
I've observed that one of the possibilities for the bug is to use
`Files.copy` to copy a file into this folder and fail because the file
already exists.
After this failed copy, the bug appeared on the parent folder of the target
file.
According to this, I provide a reproducer:
https://github.com/Glavo/nio-samba-bug-report
But strangely, it reproduces stably on a folder shared by my Ubuntu
computer, but only occasionally reproduces it once in a folder shared by my
TrueNAS SCALA NAS.
This is a very vicious bug and I can't find a workaround to get around it,
so I hope someone can work with me on it and fix it.
I'll do what I can to help, such as a test environment.
More information about the core-libs-dev
mailing list