심볼릭 링크 루프 여부를 결정하는 알고리즘이 있습니까?


16

유닉스 시스템은 심볼릭 링크 루프 나 너무 많은 심볼릭 링크가 포함 된 경로에 직면 할 경우 대개 하나의 경로 검색에서 통과 할 심볼릭 링크 수에 제한이 있기 때문에 오류가 발생합니다. 그러나 유닉스가 따르려는 것보다 더 많은 링크를 포함하더라도 주어진 경로가 무언가로 해석되는지 또는 루프를 포함하는지 실제로 결정하는 방법이 있습니까? 아니면 이것이 공식적으로 결정 불가능한 문제입니까? 그리고 그것이 결정될 수 있다면, 합리적인 시간 / 메모리로 결정될 수 있습니까 (예를 들어, 파일 시스템의 모든 파일을 방문하지 않고도)?

몇 가지 예 :

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.


명령 줄 도구 readlink ...는 위 상황에 대해 무엇을 말합니까?
slm

1
루프가 있는지 경로 이름에서만 알 수 있는지 묻고 있습니까? 아니면 표준 도구를 사용하고 경로 이름의 다양한 구성 요소가 무엇을 확인하는지 실제 운영 체제 에서이 작업을 수행 할 수 있습니까?
Mike Diehn

@MikeDiehn 분명히 파일 시스템 작업을하지 않고 해결되면 경로에서 알 수 없습니다. 그러나 OS 환경에서는 해결하기 위해 많은 심볼릭 링크를 통과 해야하는 경로를 구분하는 것이 간단하지 않습니다.
JanKanis

답변:


10

나는 당신이 무엇을 요구하는지 완전히 이해하지 못합니다. 내가 더 잘 모른다면 파일을 처리하는 동안 이것을 감지하는 방법이 있는지 묻고 있다고 생각합니다. 나는 이것이 가능하다고 생각하지 않습니다.

내가 생각할 수있는 유일한 방법은 디렉토리 트리에서 특정 분기를 통해 특히 찾기 시작하는 위치를 찾는 것입니다.

$ 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

또한 MAXSYMLINKSLinux에서 커널이 최신 인 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_resolutionUnix가 디스크의 항목에 대한 경로를 결정하는 방법을 설명하는 매뉴얼 페이지 로 안내합니다. 특히이 단락.

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").

가능하다면 단일 경로가 주어지면 심볼릭 링크 루프를 감지하고 OS에서 허용하지 않고 프로그램에서 심볼릭 링크를 수동으로 해결하는 방법을 원합니다. 그러나 이것이 가능한지 궁금합니다. 찾기 솔루션은 재미있어 보이지만 / how / find가 심볼릭 링크 루프를 감지하고 그것이 사용하는 방법이 완료된 경우 (즉, 가능한 모든 루프를 감지하고 비 루프 경로를 잘못 식별하지 않는) 아이디어가 있습니까?
JanKanis

@Somejan-A에 대한 내 업데이트를 참조하십시오.
slm

5

더 많은 생각을 한 후에 분명한 해결책이 있다고 생각합니다.

중요한 통찰은 경로의 일부인 모든 링크가 무언가로 해석되면 전체 경로가 해석된다는 것입니다. 또는 다른 방법으로, 경로가 해결되지 않으면 해결되지 않는 통과가 필요한 특정 심볼릭 링크가 있어야합니다.

이전 에이 문제에 대해 생각하면서 루트에서 시작하여 경로의 요소를 순회하는 알고리즘을 사용하고 있었고 심볼 링크가 발생했을 때 해당 경로 요소를 심볼릭 링크의 내용으로 바꾼 다음 계속 순회했습니다. 이 방법은 현재 해결중인 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 에서 파이썬으로 구현되어 있습니다 .


3

파이썬에는이를 위해 사용될 수있는 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']]

또한 일종의 그래프 알고리즘 사용에 대해 생각했지만 심볼릭 링크가있는 디렉토리 트리를 간단한 그래프로 적절하게 나타낼 수 있는지 확실하지 않습니다. c가 ..에 대한 심볼릭 링크 인 디렉토리 트리 abc에는 루프가 있지만 a / b / c / b / c / b와 같은 경로는 루프를 유한 한 횟수만큼만 따라 가지 않고 여전히 해결됩니다. 계속 반복하십시오.
JanKanis

@Somejan : 파일 시스템 네임 스페이스 그래프이고 파일 이름 해당 그래프에서 선택한 경로입니다.
ninjalj

@ninjalj : 예 파일 시스템은 그래프이지만 파일 이름이 단순히 그래프의 경로 라고 생각하지 않습니다 . 파일 이름은 그래프를 통과하는 방법에 대한 일련의 지침으로 볼 수 있습니다. 그래프에주기가 포함되어 있어도 그주기를 따르는 파일 이름이 반드시 해결되지는 않습니다. 이전 주석의 예를 참조하십시오.
JanKanis

3

대기 시스템 (예 : 변경 사항이없는 경우)에는 알고리즘이 있습니다. 유한 한 수의 심볼릭 링크가 있으므로 유한 그래프를 구성하며주기를 감지하는 것은 간단한 과정입니다.

라이브 시스템에서는 사이클 탐지기가 실행되는 동안 심볼릭 링크가 변경 될 수 있으므로 사이클을 감지 할 방법이 없습니다. 각 심볼릭 링크를 읽는 것은 원자 적이지만 심볼릭 링크를 따르는 것은 아닙니다. 커널이 순회를 수행하는 동안 일부 심볼릭 링크가 계속 변경되면 고유 링크와 관련된 무한 경로가 될 수 있습니다.


이러한 변경 사항을 완화하여 최대 98-99 %의 정확도를 얻을 수있는 방법이 있습니다. 파일의 타임 스탬프에주의를 기울일 수 있으며 실제로 링크를 따르는 것은 제안하지 않습니다. 루트에서 재귀하므로 나중에 실제 디렉토리를 찾을 수 있습니다.
Back2Basics

1
@ Back2Basics이 숫자는 완전히 의미가 없습니다. 이것은 커널 인터페이스입니다. 항상 작동하지 않으면 작동하지 않습니다.
Gilles 'SO- 악의를 멈추십시오'

2

현재 Linux 커널 소스를 살펴보면 알 수 있듯이 모든 커널은 수행하는 링크 수를 세고, 숫자보다 크면 오류가 발생합니다. 주석 및 기능 에 대해서는 namei.c의 1330 행을 참조하십시오 nested_symlink(). ELOOP 매크로 ( read(2)이 상황에 대한 시스템 호출 에서 반환 된 오류 번호 )는 해당 파일의 여러 위치에 표시되므로 링크를 계산하는 것만 큼 간단하지는 않지만 그 모양은 확실합니다.

링크 된 목록 ( Floyd의주기 감지 알고리즘 ) 또는 직접 그래프 에서 "주기"를 찾기위한 많은 알고리즘 이 있습니다 . 특정 경로에서 실제 "루프"또는 "사이클"을 감지하기 위해 어떤 작업을 수행해야하는지 명확하지 않습니다. 어쨌든 알고리즘을 실행하는 데 시간이 오래 걸릴 수 있으므로 기호 링크 수를 세는 것만으로도 목표 달성의 90 %를 달성 할 수 있습니다.


실제 사용의 경우 트래버스 된 링크 수를 계산하는 것이 좋습니다. 특히 커널이 수행하는 것이기 때문에 너무 많은 심볼릭 링크가있는 올바르게 해결되는 경로가 발생하더라도 실제 경로에는 여전히 해당 경로를 사용할 수 없습니다 ( 즉, 수동으로 심볼릭 링크를 해결하지 않습니다)
JanKanis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.