1

Im trying to implement file synchronization in conjunction with java.nio watchevent. Though, as known and discussed in other posts, it doesnt handle renames and moves. I tried out jpathwatch which didnt really seem to cover the scenarios i needed so i try to get unique object identifiers thus being able to track these events myself.

The problem i have is that i tried implement BY_HANDLE_FILE_INFORMATION using JNA and it worked fine for files. But i get null return and error 6 when i try to access directories this way. So what im trying to ascertain is the best way to get a trackable id for both files and folders. If ive made some error, i have som issue locally or with eclipse, or if i perhaps need to look elsewhere for this information.

My testcode is as follows:

@Override
public String getUniqueFileId(Path file) {
    BY_HANDLE_FILE_INFORMATION nfo = new BY_HANDLE_FILE_INFORMATION();
    HANDLE handle = com.sun.jna.platform.win32.Kernel32.INSTANCE.CreateFile(file.toString(), 0x80000000, 0x00000001, null, 3, 0x80, null);
    if(Kernel32.INSTANCE.GetLastError() != 0) {
        LOGGER.error("Error occured for '" + file.toString() + "' (Error " + Kernel32.INSTANCE.GetLastError() + ")");
    }
    Kernel32.INSTANCE.GetFileInformationByHandle(handle, nfo);
    if(Kernel32.INSTANCE.GetLastError() != 0) {
        LOGGER.error("Error occured for '" + file.toString() + "' (Error " + Kernel32.INSTANCE.GetLastError() + ")");
    }
    String identifier = nfo.nFileIndexHigh + nfo.nFileIndexLow.toString() + Integer.toHexString(nfo.dwVolumeSerialNumber.intValue());
    com.sun.jna.platform.win32.Kernel32.INSTANCE.CloseHandle(handle); 
    return identifier;
}

And:

public interface Kernel32 extends StdCallLibrary {
final static Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
    private static final long serialVersionUID = 1L;
    {
        put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
        put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
    }
};

public Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("Kernel32", Kernel32.class, WIN32API_OPTIONS);

public int GetLastError();

public class BY_HANDLE_FILE_INFORMATION extends Structure {
    public DWORD    dwFileAttributes;
    public FILETIME ftCreationTime;
    public FILETIME ftLastAccessTime;
    public FILETIME ftLastWriteTime;
    public DWORD    dwVolumeSerialNumber;
    public DWORD    nFileSizeHigh;
    public DWORD    nFileSizeLow;
    public DWORD    nNumberOfLinks;
    public DWORD    nFileIndexHigh;
    public DWORD    nFileIndexLow;

    public List<String> getFieldOrder() {
        return Arrays.asList(new String[] { 
            "dwFileAttributes", 
            "ftCreationTime", 
            "ftLastAccessTime", 
            "ftLastWriteTime",
            "dwVolumeSerialNumber",
            "nFileSizeHigh",
            "nFileSizeLow",
            "nNumberOfLinks",
            "nFileIndexHigh",
            "nFileIndexLow"
        });
    };  
}; 

boolean GetFileInformationByHandle(HANDLE hFile, BY_HANDLE_FILE_INFORMATION lpFileInformation);

}

If someone spots any problem or could give me a push in the right direction i would be greatful.

Im using Wondows 10 / Eclipse but had same issue on Windows 8.

UPDATE: realized i called the getlasterror to late, but updated the code and it gives med first error 5, then error 6. Error 5 indicate permission issue, but full permission for all users and running eclipse in administrator mode unfortunately didnt help. All files work fine, no folder work.

Base
  • 1,061
  • 1
  • 11
  • 27
  • According to the createFile documentation on msdn it states that folders should be reachable as well (Creates or opens a file or I/O device. The most commonly used I/O devices are as follows: file, file stream, directory, physical disk, volume, console buffer, tape drive, communications resource, mailslot, and pipe.). But an earlier post indicated that folders werent identifieable (http://stackoverflow.com/questions/10132686/unique-folder-identifier) so im a bit uncertain if there is a way to solve this or not. – Base Jul 29 '15 at 19:52
  • 1
    BTW, you could have your `Kernel32` extend the one provided in `platform.jar` and use the same library load options (`W32APIOptions.DEFAULT_OPTIONS`). – technomage Jul 30 '15 at 16:07

1 Answers1

0

Found the problem, which was with the dwFlagsAndAttributes in createFile.

Using these parameters worked for retrieveing identifiers for both files and folders.

private final int GENERIC_READ = 0x80000000;
private final int FILE_SHARE_READ = 0x00000001;
private WinBase.SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES = null;
private final int OPEN_EXISTING = 3;
private final int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;

And when calling createFile

HANDLE handle = com.sun.jna.platform.win32.Kernel32.INSTANCE.CreateFile(file.toString(), GENERIC_READ, FILE_SHARE_READ, SECURITY_ATTRIBUTES, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, null);
Base
  • 1,061
  • 1
  • 11
  • 27