I hava a Java program that needs to monitor a directory tree for changes. I have JNI code that uses ReadDirectoryChangesW()
. The directory is opened like:
HANDLE dirHandle = CreateFile(
path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL
);
and then I pass dirHandle
to ReadDirectoryChangesW()
. All of that works just fine.
The problem is that other parts of the code (on the Java side) use File.setLastModified()
to "touch" files or directories (update their timestamps to be "now"). This generally works; however, it fails when it tried to "touch" the directory that was opened using CreateFile()
.
To see what Windows error is actually occurring, I looked at the JDK source for File.setLastModified()
and reimplemented it in my own code with the addition of printing the error from GetLastError()
; the error is:
ERROR_SHARING_VIOLATION (error 32)
"The process cannot access the file because it is being used by another process."
WTF? It's the same process. I even passed FILE_SHARE_READ
and FILE_SHARE_WRITE
to CreateFile()
.
Is there a way to make this work?
The native code implementation of File.setLastModified()
in the JDK does a:
h = CreateFileW(pathbuf, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
If I change the first 0
to FILE_SHARE_READ | FILE_SHARE_WRITE
, it all works. So it seems that the JDK implementation is a little broken. :(
So my question now becomes: Is there a way to make this work without having to use my own (re)implementation of File.setLastModified()
?
Although the error message is a bit misleading in this case, what you're seeing is normal behaviour.
By opening the directory with dwShareMode
set to zero, the JDK is, in effect, asking for exclusive access, which will cause any other access attempt to fail with a sharing violation error. This applies equally to accesses
from other processes and from within your own process.
The CreateFile
documentation describes the dwShareMode
parameter:
If this parameter is zero and CreateFile succeeds, the file or device cannot be shared and cannot be opened again until the handle to the file or device is closed.
You cannot request a sharing mode that conflicts with the access mode that is specified in an existing request that has an open handle.
CreateFile
would fail and theGetLastError
function would returnERROR_SHARING_VIOLATION
.
So, it seems you've answered your own question: you need a custom setLastModified
function that specifies FILE_SHARE_READ | FILE_SHARE_WRITE
when accessing the directory.