Pytanie Określić, czy plik jest skrzyżowaniem (w systemie Windows), czy nie?


Szukałem w pobliżu, próbując znaleźć sposób, aby ustalić, czy plik jest skrzyżowaniem, czy nie, i nie znalazłem zadowalających odpowiedzi.

Pierwszą rzeczą, której próbowałem, było:

Files.isSymbolicLink(aPath)

Wykrywa tylko dowiązania symboliczne, a nie pliki zwane skrzyżowaniami w systemie Windows.

Wypróbowałem również proponowane tutaj rozwiązanie (używając biblioteki JNA): Pytanie Stackoverflow (3249117) , ale nigdy nie powróciło ono do żadnego z plików, o których wiem, że są skrzyżowaniami.

Jedynym sposobem, jaki znalazłem, aby określić, które pliki są złączami, jest następujące polecenie uruchomione w wierszu polecenia systemu Windows:

DIR /S /A:L

Na moim komputerze zwraca 66 folderów, wheras Files.isSymbolicLink (aPath) zwróciło tylko 2. Więc przypuszczam, że mógłbym znaleźć sposób na wykorzystanie tego, ale nie sądzę, że byłoby to bardzo skuteczne przy przechodzeniu przez filetree.

Czy jest jakiś sposób to zrobić przy użyciu standardowej biblioteki Java lub alternatywnie JNA?


11
2017-12-05 22:02


pochodzenie




Odpowiedzi:


Jeśli możesz napisać natywny kod w JNA, możesz bezpośrednio wywołać Win32 API GetFileAttributes() funkcja i sprawdź dla FILE_ATTRIBUTE_REPARSE_POINT flagę (skrzyżowania są zaimplementowane jako punkty ponownej analizy).

Aktualizacja: Aby rozróżnić różne typy punktów ponownej analizy, musisz powrócić do ReparseTag rzeczywistego punktu ponownej analizy. W przypadku punktu połączenia zostanie on ustawiony na IO_REPARSE_TAG_MOUNT_POINT (0xA0000003).

Istnieją dwa sposoby odzyskania ReparseTag:

  1. Posługiwać się DeviceIoControl() z FSCTL_GET_REPARSE_POINT kod kontrolny do uzyskania REPARSE_DATA_BUFFER struct, który jako ReparseTag pole. Możesz zobaczyć przykład IsDirectoryJunction() implementacja za pomocą tej techniki w następującym artykule:

    Twarde łącza NTFS, łącza katalogowe i skróty systemu Windows

  2. Posługiwać się FindFirstFile() uzyskać a WIN32_FIND_DATA struct. Jeśli ścieżka ma FILE_ATTRIBUTE_REPARSE_POINT atrybut, dwReserved0 pole będzie zawierało ReparseTag.


4
2017-12-05 22:19



Dziękuję, nigdy tak naprawdę nie korzystałem z JNA, z wyjątkiem kopiowania i wklejania kodu, ale jeśli to jedyny sposób, jak sądzę, lepiej się uczę. - Martin
Sugerowana przez Ciebie sugestia jest podobna do sugestii zawartej w zamieszczonym przeze mnie linku. Byłaby bardzo przydatna, gdybyś mógł mi podać przykład sprawdzenia flagi reparse. - Martin
FILE_ATTRIBUTE_REPARSE_POINT jest zdefiniowany jako 0x400, więc przykładowy kod, z którym się łączysz, sprawdza FILE_ATTRIBUTE_REPARSE_POINT konkretnie. - Remy Lebeau
Dziękuję za wyjaśnienie, wydaje się, że wystąpiła pewna rozbieżność między wynikami uzyskanymi z linii poleceń i JNA, ale nie mogę ich teraz znaleźć, więc jeśli nie można tego zrobić w standardowej bibliotece Java, zaakceptuję to jako odpowiedź. Dziękuję za cierpliwość. - Martin
To nie wykryje tylko skrzyżowań. Wykrywa wszystkie punkty ponownej analizy. Połączenia są tylko jednym z przykładów punktu ponownej analizy. - David Heffernan


Nie może być sposobu, aby to zrobić bez JNA, jeśli masz prawo Java, takie jak Oracle jdk 8. Jest podejrzany, może przestać działać, ale ....

Możesz uzyskać interfejs BasicFileAttributes związany z linkiem:

BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);

Może się zdarzyć, że ta implementacja interfejsu jest klasą sun.nio.fs.WindowsFileAttributes. A ta klasa ma metodę isReparsePoint, która zwraca wartość true zarówno dla punktów połączenia, jak i dowiązań symbolicznych. Możesz spróbować użyć refleksji i wywołać metodę:

    boolean isReparsePoint = false;
    if (DosFileAttributes.class.isInstance(attr))
        try {
            Method m = attr.getClass().getDeclaredMethod("isReparsePoint");
            m.setAccessible(true);
            isReparsePoint = (boolean) m.invoke(attr);
        } catch (Exception e) {
            // just gave it a try
        }

Teraz możesz tylko odkryć, czy rzeczywiście jest to link symboliczny: Files.isSymbolicLink(path)

Jeśli nie, ale jest to punkt ponownej analizy, to jest skrzyżowanie.


7
2018-04-15 10:30



Możesz zapisać potrzebę Files.isSylmbolicLink(path) krok przez refleksyjne sprawdzenie parseTag dziedzinie WindowsFileAttributes Węzeł będzie miał wartość -1610612733 (i symboliczne -1610612724), po prostu zastąp to, co jest w try zablokuj tym: Field field = attr.getClass().getDeclaredField("reparseTag"); field.setAccessible(true); int parseTag = (int) field.get(attr); boolean isJunction = parseTag == -1610612733; - Javaru


Z J2SE 1.7 użyj Java NIO

/**
* returns true if the Path is a Windows Junction
*/
private static boolean isJunction(Path p) {
    boolean isJunction = false;
    try {
        isJunction = (p.compareTo(p.toRealPath()) != 0);
    } catch (IOException e) {
        e.printStackTrace(); // TODO: handleMeProperly
    }
    return isJunction;
}

4
2018-04-17 12:38



wydaje się, że to nie działa. Funkcja toRealPath () jest taka sama jak sama ścieżka dla skrzyżowania. - Osman-pasha
Właśnie tego oczekuje się na skrzyżowaniu. - Peter Kirschner
Ten kod nie działa, prawda? Dla skrzyżowania p.compareTo (p.toRealPath ()) wynosi 0, jak ustaliłeś i jak zobaczyłem w teście. - Osman-pasha
działa dla mnie ... zobacz gist.github.com/peterkir/1df3f0bf8508d8836101 - Peter Kirschner
Tak naprawdę. Dziękuję za wyjaśnienie! - Osman-pasha


W systemie Windows atrybuty złącza mają isSymbolicLink() == false, to jest isOther() == true. Możesz zrobić coś takiego:

BasicFileAttributes attrs = Files.readAttributes(aPath, BasicFileAttributes.class);
boolean isJunction = isWindows && attrs.isDirectory() && attrs.isOther();

1
2018-01-16 23:30