유닉스 시스템은 심볼릭 링크 루프 나 너무 많은 심볼릭 링크가 포함 된 경로에 직면 할 경우 대개 하나의 경로 검색에서 통과 할 심볼릭 링크 수에 제한이 있기 때문에 오류가 발생합니다. 그러나 유닉스가 따르려는 것보다 더 많은 링크를 포함하더라도 주어진 경로가 무언가로 해석되는지 또는 루프를 포함하는지 실제로 결정하는 방법이 있습니까? 아니면 이것이 공식적으로 결정 불가능한 문제입니까? 그리고 그것이 결정될 수 있다면, 합리적인 시간 / 메모리로 결정될 수 있습니까 (예를 들어, 파일 시스템의 모든 파일을 방문하지 않고도)?
몇 가지 예 :
a/b/c/d
where a/b is a symlink to ../e
and e is a symlink to f
and f is a symlink to a/b
a/b/c/d
where a/b/c is a symlink to ../c
a/b/c/d
where a/b/c is a symlink to ../c/d
a/b/c/d
where a/b/c is a symlink to /a/b/e
where a/b/e is a symlink to /a/b/f
where a/b/f is a symlink to /a/b/g
편집 :
명확히하기 위해, 나는 파일 시스템에서 루프를 찾는 것에 대해 묻지 않고 주어진 경로를 결정된 파일 / 디렉토리로 해결할지 또는 전혀 해결하지 않을지를 결정하는 결정 알고리즘에 대해 묻습니다. 예를 들어 다음 시스템에는 루프가 있지만 주어진 경로는 여전히 잘 해결됩니다.
/ -- a -- b
where b is a symlink to /a
이 디렉토리 트리에는 분명히주기가 있지만 경로는 a/b/b/b/b/b
여전히 /a
.
답변
나는 당신이 무엇을 요구하는지 완전히 이해하지 못합니다. 내가 더 잘 모른다면 파일을 처리하는 동안 이것을 감지하는 방법이 있는지 묻고 있다고 생각합니다. 나는 이것이 가능하다고 생각하지 않습니다.
내가 생각할 수있는 유일한 방법은 디렉토리 트리에서 특정 분기를 통해 특히 찾기 시작하는 위치를 찾는 것입니다.
예
$ tree
.
`-- a
`-- b
|-- c
| `-- d
| `-- e -> ../../../../a/b
`-- e -> e
5 directories, 1 file
find
명령은이 루프를 감지하지만 정말 당신에게 그것에 대해 훨씬 말한다.
$ find -L . -mindepth 15
find: File system loop detected; `./a/b/c/d/e' is part of the same file system loop as `./a/b'.
find: `./a/b/e': Too many levels of symbolic links
에 의해 표시되는 출력을 차단하기 위해 임의로 15 레벨을 선택했습니다 find
. 그러나 -mindepth
표시되는 디렉토리 트리에 신경 쓰지 않으면 해당 스위치 ( )를 삭제할 수 있습니다 . find
명령은 여전히 루프와 중지를 감지 :
$ find -L .
.
./a
./a/b
./a/b/c
./a/b/c/d
find: File system loop detected; `./a/b/c/d/e' is part of the same file system loop as `./a/b'.
find: `./a/b/e': Too many levels of symbolic links
또한 MAXSYMLINKS
Linux에서 커널이 최신 인 3.x 버전의 40 인 기본값을 무시하려면 이 U & L Q & A 제목 : MAXSYMLINKS를 늘리는 방법을 참조하십시오 .
symlinks 명령 사용
FTP 사이트 관리자가 호출 할 수있는 도구가 있습니다.이 도구를 사용 symlinks
하면 기호 링크로 인해 도구가 길거나 매달려있는 나무에 문제가 노출 될 수 있습니다.
경우에 symlinks
따라이 도구를 사용하여 문제가되는 링크를 삭제할 수도 있습니다.
예
$ symlinks -srv a
lengthy: /home/saml/tst/99159/a/b/c/d/e -> ../../../../a/b
dangling: /home/saml/tst/99159/a/b/e -> e
glibc 라이브러리
glibc 라이브러리는 이것에 대한 일부 C 함수를 제공하는 것으로 보이지만 그 역할이나 실제로 어떻게 사용하는지 완전히 알지 못합니다. 그래서 나는 단지 그것들을 단지 당신에게 지적 할 수 있습니다.
매뉴얼 페이지 man symlink
에는이라는 함수의 함수 정의가 표시 symlink()
됩니다. 설명은 다음과 같습니다.
symlink ()는 문자열 oldpath를 포함하는 newpath라는 기호 링크를 작성합니다.
오류 중 하나는이 함수가 다음을 반환한다는 것입니다.
ELOOP newpath를 해결하는 데 너무 많은 기호 링크가 발생했습니다.
또한 man path_resolution
Unix가 디스크의 항목에 대한 경로를 결정하는 방법을 설명하는 매뉴얼 페이지 로 안내합니다. 특히이 단락.
If the component is found and is a symbolic link (symlink), we first
resolve this symbolic link (with the current lookup directory as starting
lookup directory). Upon error, that error is returned. If the result is
not a directory, an ENOTDIR error is returned. If the resolution of the
symlink is successful and returns a directory, we set the current lookup
directory to that directory, and go to the next component. Note that the
resolution process here involves recursion. In order to protect the
kernel against stack overflow, and also to protect against denial of
service, there are limits on the maximum recursion depth, and on the maximum
number of symbolic links followed. An ELOOP error is returned when the
maximum is exceeded ("Too many levels of symbolic links").
답변
더 많은 생각을 한 후에 분명한 해결책이 있다고 생각합니다.
중요한 통찰은 경로의 일부인 모든 링크가 무언가로 해석되면 전체 경로가 해석된다는 것입니다. 또는 다른 방법으로, 경로가 해결되지 않으면 해결되지 않는 통과가 필요한 특정 심볼릭 링크가 있어야합니다.
이전 에이 문제에 대해 생각하면서 루트에서 시작하여 경로의 요소를 순회하는 알고리즘을 사용하고 있었고 심볼 링크가 발생했을 때 해당 경로 요소를 심볼릭 링크의 내용으로 바꾼 다음 계속 순회했습니다. 이 방법은 현재 해결중인 symlink를 기억하지 않기 때문에 비 해결 루프에있을 때이를 감지 할 수 없습니다.
알고리즘이 현재 해결중인 심볼릭 링크 (또는 재귀 링크의 경우 어떤 심볼릭 링크)를 추적하는 경우 링크를 다시 재귀 적으로 확인하려고 시도 중인지 여부를 여전히 확인할 수 있습니다.
연산:
initialize `location` to the current working directory
initialize `link_contents` to the path we want to resolve
initialize `active_symlinks` to the empty set
def resolve_symlink(location, link_contents, active_symlinks) :
loop forever:
next_location = location / [first element of link_contents]
see if next_location is a symlink.
if so:
if next_location in active_symlinks: abort, we have a loop
location = resolve_symlink(location, readlink(next_location), active_symlinks ∪ {next_location})
else:
location = next_location
strip first element of link_contents
if link_contents is empty:
return location
편집 :
나는 https://bitbucket.org/JanKanis/python-inotify/src/853ed903e870cbfa283e6ce7a5e41aeffe16d4e7/inotify/pathresolver.py?at=pathwatcher 에서 파이썬으로 구현되어 있습니다 .
답변
파이썬에는이를 위해 사용될 수있는 networkx.simple_cycles ()라는 함수가 있습니다. 그러나 시스템의 모든 파일을 읽어야합니다.
>>> import networkx as nx
>>> G = nx.DiGraph()
>>> G.add_edge('A', 'B')
>>> G.add_edge('B', 'C')
>>> G.add_edge('C', 'D')
>>> G.add_edge('C', 'A')
>>> nx.simple_cycles(G)
[['A', 'B', 'C', 'A']]
답변
대기 시스템 (예 : 변경 사항이없는 경우)에는 알고리즘이 있습니다. 유한 한 수의 심볼릭 링크가 있으므로 유한 그래프를 구성하며주기를 감지하는 것은 간단한 과정입니다.
라이브 시스템에서는 사이클 탐지기가 실행되는 동안 심볼릭 링크가 변경 될 수 있으므로 사이클을 감지 할 방법이 없습니다. 각 심볼릭 링크를 읽는 것은 원자 적이지만 심볼릭 링크를 따르는 것은 아닙니다. 커널이 순회를 수행하는 동안 일부 심볼릭 링크가 계속 변경되면 고유 링크와 관련된 무한 경로가 될 수 있습니다.
답변
현재 Linux 커널 소스를 살펴보면 알 수 있듯이 모든 커널은 수행하는 링크 수를 세고, 숫자보다 크면 오류가 발생합니다. 주석 및 기능 에 대해서는 namei.c의 1330 행을 참조하십시오 nested_symlink()
. ELOOP 매크로 ( read(2)
이 상황에 대한 시스템 호출 에서 반환 된 오류 번호 )는 해당 파일의 여러 위치에 표시되므로 링크를 계산하는 것만 큼 간단하지는 않지만 그 모양은 확실합니다.
링크 된 목록 ( Floyd의주기 감지 알고리즘 ) 또는 직접 그래프 에서 “주기”를 찾기위한 많은 알고리즘 이 있습니다 . 특정 경로에서 실제 “루프”또는 “사이클”을 감지하기 위해 어떤 작업을 수행해야하는지 명확하지 않습니다. 어쨌든 알고리즘을 실행하는 데 시간이 오래 걸릴 수 있으므로 기호 링크 수를 세는 것만으로도 목표 달성의 90 %를 달성 할 수 있습니다.