Как узнать, является ли папка жесткой ссылкой, и получить ее реальный путь

Я пытаюсь выяснить, действительно ли папка является жесткой ссылкой на другую, и в этом случае узнать ее реальный путь.

Я сделал простой пример на питоне следующим образом (symLink.py):

#python 3.4
import os
dirList = [x[0] for x in os.walk('.')]

print (dirList)

for d in dirList:
    print (os.path.realpath(d), os.path.islink(d))

"""
Given this directories structure:
<dir_path>\Example\
    <dir_path>\Example\symLinks.py
    <dir_path>\Example\hardLinkToF2 #hard link pointing to <dir_path>\Example\FOLDER1\FOLDER2
    <dir_path>\Example\softLinkToF2 #soft link pointing to <dir_path>\Example\FOLDER1\FOLDER2
    <dir_path>\Example\FOLDER1
        <dir_path>\Example\FOLDER1\FOLDER2

The output from executing: C:\Python34\python <dir_path>\Example\symLinks.py is:
['.', '.\\FOLDER1', '.\\FOLDER1\\FOLDER2', '.\\hardLinkToF2']
<dir_path>\Example False
<dir_path>\Example\FOLDER1 False
<dir_path>\Example\FOLDER1\FOLDER2 False
<dir_path>\Example\hardLinkToF2 False
"""

В этом примере os.path.islink всегда возвращает False как для жесткой, так и для мягкой ссылки. С другой стороны, os.path.realpath возвращает фактический путь для программных ссылок, а не для жестких ссылок.

Я сделал этот пример, используя python 3.4 в Windows 8. Я понятия не имею, делаю ли я что-то не так или есть ли другой способ добиться этого.


person Andres Tiraboschi    schedule 30.01.2017    source источник
comment
Жесткая ссылка указывает на тот же индексный дескриптор, что и исходный файл, но не ссылается на исходный файл. Поэтому я не уверен, что по жесткой ссылке можно определить исходный файл. Символическая ссылка ссылается на исходный файл по имени. Таким образом, можно добраться до исходного файла по символической ссылке. Поэтому я думаю, что поведение, которое вы описываете, это то, как оно работает.   -  person RobertB    schedule 30.01.2017
comment
Во-вторых, в документах говорится, что islink возвращает Always False, если среда выполнения Python не поддерживает символические ссылки. Возможно, это имеет отношение к поведению символической ссылки, которое вы видите.   -  person RobertB    schedule 30.01.2017
comment
Согласитесь с @RobertB: две жесткие ссылки на один и тот же файл должны быть неразличимы, на самом деле они не являются ссылками с точки зрения любого, кто их использует, все, что вы можете сказать, это то, что на базовый файл ссылаются в N разных местах. Лучшее, что вы можете сделать, это просканировать всю файловую систему, пока не найдете все записи с одинаковым номером индекса. Просто для ясности, вы используете настоящие символические ссылки или соединения NTFS? Похоже, что переходы неправильно определяются как ссылки.   -  person ShadowRanger    schedule 30.01.2017
comment
В Windows Vista и более поздних версиях это легко сделать для жестких ссылок. Используйте FindFirstFileNameW, FindNextFileNameW и FindClose. Для этого вы можете использовать ctypes или, если у вас установлен PyWin32, используйте win32file.FindFileNames (похоже, есть ошибка, оставляющая конечный NUL в имени файла).   -  person Eryk Sun    schedule 30.01.2017
comment
Обратите внимание, что NTFS не допускает жестких ссылок на каталоги, и в этом случае вы можете вместо этого иметь точку повторной обработки (соединение, символическая ссылка и т. д.).   -  person Eryk Sun    schedule 30.01.2017


Ответы (2)


Чтобы не быть слишком суровым, я потратил 1 минуту на гугление и получил все ответы. Подсказка Подсказка.

Чтобы определить, являются ли они жесткими ссылками, вы должны отсканировать все файлы, а затем сравнить их результаты os.stat, чтобы увидеть, указывают ли они на один и тот же индексный дескриптор. Пример:

https://gist.github.com/simonw/229186

Для символических ссылок в python в Windows это может быть сложнее... но, к счастью, на этот вопрос уже дан ответ:

Проблемы с реализацией функции readlink()

(согласно @ShadowRanger в комментариях), убедитесь, что вы не используете соединения вместо символических ссылок, так как они могут не сообщаться правильно. - ShadowRanger

https://bugs.python.org/issue29250

person RobertB    schedule 30.01.2017
comment
Вторая ссылка не нужна. Это характерно для версий Python до 3.2, где realpath (в Windows) был псевдонимом для abspath. На 3.4, как показывает вопрос ОП, похоже, что пути разрешаются (хотя возможно, что они разрешаются os.walk до того, как realpath доберется до них, поскольку os.walk не понимает соединения и отслеживает их даже с follow_symlinks=False по умолчанию). realpath должен работать на 3.4, просто islink может неправильно сообщать о переходах. - person ShadowRanger; 30.01.2017
comment
Хм... Неважно. Похоже, по крайней мере, на моем Python 3.4 realpath остается псевдонимом для abspath. Блех. - person ShadowRanger; 30.01.2017
comment
Вы можете просто протестировать os.path.realpath is os.path.abspath, чтобы проверить. islink сообщает False о перекрестках, которые я могу проверить прямо сейчас, а realpath не соответствует symlink. os.walk, кажется, исключает соединение из обхода только из-за проблемы с разрешениями, которая молча игнорируется; единственные соединения, которые я могу протестировать, — это те, с которыми ОС поставляется со странными разрешениями. Единственный способ проверить, я могу выяснить, является ли это соединением, используя lstat и stat и используя os.path.samestat (только в Windows с версии 3.4), чтобы определить, относится ли это к одному и тому же. - person ShadowRanger; 30.01.2017
comment
Этот ответ точен, но пример кода не должен быть на внешнем сайте, а социальный подход немного груб. - person monokrome; 25.08.2020
comment
Вы можете проверить, являются ли два файла жесткими ссылками на один и тот же файл с помощью os.path.samefile(file1,file2). - person mmj; 11.03.2021

Ссылки на каталоги в Windows реализованы с помощью точек повторной обработки. Они могут принимать форму «соединения каталогов» или «символических ссылок». Жесткие ссылки на каталоги невозможны в Windows NTFS.

По крайней мере, начиная с Python 3.8 os.path.samefile(dir1, dir2) поддерживает как символические ссылки, так и соединения каталогов и возвращает True, если оба разрешаются в одно и то же место назначения.

os.path.realpath(dirpath) также будет работать, чтобы дать вам реальный (полностью разрешенный) путь как для символических ссылок, так и для соединений каталогов.

Если вам нужно определить, какой из двух каталогов является точкой повторной обработки, вы можете использовать os.lstat(), так как os.path.islink() поддерживает только символические ссылки.

import os
import stat

def is_reparse_point(dirpath):
    return os.lstat(dirpath).st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT

Поскольку это может быть полезно для тестирования, вот несколько полезных утилит, доступных в оболочке Windows CMD.

Запросить данные точки повторной обработки:

>fsutil reparsepoint query <path to directory>

Создайте точки повторной обработки как «символической ссылки», так и «перекрестка каталогов» *:

>mklink /d <symbolic link name> <path to target directory>
>mklink /j <junction name>      <path to target directory>

Подробнее о разнице между жесткими ссылками см. и соединения, символические ссылки и точки повторной обработки в документации Microsoft.

*Обратите внимание, что для создания символических ссылок обычно требуются права администратора.

person scienceplease    schedule 02.05.2020