Использование JNA для получения уникального идентификатора для файлов и папок

Я пытаюсь реализовать синхронизацию файлов в сочетании с java.nio watchevent. Хотя, как известно и обсуждается в других публикациях, он не обрабатывает переименования и перемещения. Я опробовал jpathwatch, который на самом деле не охватывал сценарии, в которых я нуждался, поэтому я пытаюсь получить уникальные идентификаторы объектов, таким образом, имея возможность самостоятельно отслеживать эти события.

У меня проблема в том, что я пытался реализовать BY_HANDLE_FILE_INFORMATION с помощью JNA, и он работал нормально для файлов. Но я получаю нулевое возвращение и ошибку 6, когда я пытаюсь получить доступ к каталогам таким образом. Так что я пытаюсь убедиться, что это лучший способ получить отслеживаемый идентификатор для файлов и папок. Если я допустил какую-либо ошибку, у меня возникла проблема с сомом локально или с затмением, или, если мне, возможно, нужно искать эту информацию в другом месте.

Мой тест-код выглядит следующим образом:

@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;
}

А также:

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);

}

Если кто-то обнаружит какие-либо проблемы или может дать мне толчок в правильном направлении, я был бы очень благодарен.

Я использую Wondows 10 / Eclipse, но у меня была та же проблема в Windows 8.

ОБНОВЛЕНИЕ: понял, что я вызвал getlasterror поздно, но обновил код, и он выдает med сначала ошибку 5, затем ошибку 6. Ошибка 5 указывает на проблему с разрешениями, но полное разрешение для всех пользователей и запуск затмения в режиме администратора, к сожалению, не помогли. Все файлы работают нормально, папок нет.

1 ответ

Решение

Нашел проблему, которая была с dwFlagsAndAttributes в createFile.

Использование этих параметров помогло получить идентификаторы для файлов и папок.

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;

И при вызове 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);
Другие вопросы по тегам