views:

291

answers:

1

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?

More Info

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()?

+1  A: 

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 the GetLastError function would return ERROR_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.

ChrisN
Yes, buy WHY is the JDK asking for exclusive access? It doesn't seem necessary in this case.
Paul J. Lucas