C의 파일 설명자에서 파일 이름 검색


105

C에서 파일 설명자 (Linux)의 파일 이름을 가져올 수 있습니까?


나는 그의 솔루션이 더 나은 이식성을 가지고 있고 주목할만한 액세스 문제가 없기 때문에 선택한 대답을 zneak에 제공해야한다고 생각합니다.
Sergei

Ubuntu 14.04 (커널 3.16.0-76-generic)에서는 지원되지 않습니다. Linux에서는 전혀 지원되지 않는 것 같습니다.
felipou

macOS의 경우 D. Nathanael의 다른 질문에 대한 이 답변 을 참조하십시오 .
Jonathan Leffler 19 년

답변:


120

당신은 사용할 수 있습니다 readlink/proc/self/fd/NNNNNN은 파일 기술자입니다. 이렇게하면 파일을 열었을 때의 파일 이름이 제공됩니다. 그러나 그 이후로 파일이 이동되거나 삭제 된 경우 더 이상 정확하지 않을 수 있습니다 (일부 경우 Linux에서 이름 변경을 추적 할 수 있음). 확인하려면, stat파일 이름이 주어 fstat은 당신이하고 있는지 확인 전략 중 st_devst_ino동일합니다.

물론 모든 파일 설명자가 파일을 참조하는 것은 아니며, pipe:[1538488]. 실제 파일 이름은 모두 절대 경로이므로 어느 것이 충분한 지 쉽게 결정할 수 있습니다. 또한 다른 사람들이 언급했듯이 파일에는 파일을 가리키는 여러 개의 하드 링크가있을 수 있습니다. 이것은 파일이 열린 파일 만보고합니다. 주어진 파일의 모든 이름을 찾으려면 전체 파일 시스템을 탐색하면됩니다.


9
원본 파일에 여전히 참조가있는 한 (열린 fd것은 그러한 참조가 됨) inode 번호 재사용 할 수 없습니다 . 파일을 닫은 후 또는 열기 전에 inode 번호를 사용하는 모든 소프트웨어는 본질적으로 경쟁 조건의 영향을받습니다.
R .. GitHub STOP HELPING ICE

3
위험 해, 윌 로빈슨! 이것이 항상 작동하는 것은 아닙니다 --- setuid()트릭을 사용하면 /proc/self/fd프로세스에서 액세스 할 수 없을 수도 있습니다. 참조 : permalink.gmane.org/gmane.linux.kernel/1302546
데이비드을 감안할 때

2
@bdonlan : 그리고 / proc이 마운트되지 않은 경우?
user2284570

1
@ user2284570,이 답변은 Linux 전용입니다. NetBSD가 procfs를 지원하는지 전혀 모르겠습니다. 공유 호스트가 제공하지 않는다면 아마도 NetBSD가 그것을 전혀 지원하지 않고 대신 다른 메커니즘을 사용하기 때문일 것입니다. NetBSD가이 정보를 노출하는 방법을 아는 사람이 있는지 확인하기 위해 NetBSD에 초점을 맞춘 다른 질문을 게시 할 수 있습니다 (아래에서 zneak의 답변을 시도 할 수도 있습니다. OS X는 Linux보다 BSD와 더 유사합니다)
bdonlan

1
@bdonlan : NetBSD는 / proc을 지원하지만 반드시 마운트해야하는 것은 아닙니다. 제가 언급 할 때마다 대답은 "고비용 공급자로 전환하면 / proc를 얻게됩니다"가되었습니다. 그래서 저는 절차없는 솔루션을 찾고 있습니다.
user2284570

90

Mac OS X에서이 문제가 발생했습니다. /proc가상 파일 시스템이 없으므로 허용 된 솔루션이 작동하지 않습니다.

대신 다음 F_GETPATH명령이 있습니다 fcntl.

 F_GETPATH          Get the path of the file descriptor Fildes.  The argu-
                    ment must be a buffer of size MAXPATHLEN or greater.

따라서 파일 설명자에 연결된 파일을 가져 오려면 다음 코드 조각을 사용할 수 있습니다.

#include <sys/syslimits.h>
#include <fcntl.h>

char filePath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filePath) != -1)
{
    // do something with the file path
}

MAXPATHLEN정의 된 위치를 기억하지 못하기 때문에 PATH_MAXsyslimits에서 괜찮을 것이라고 생각 했습니다.


@uchuugaka, 아마 아닙니다. 사용 getsockname.
zneak

2
당신은 무엇을 기대합니까? UNIX 소켓이 아니면 연결된 파일이 없습니다.
zneak

2
@uchuugaka 예, 모든 것이 파일이지만 모든 것이 파일 시스템 트리 내부의 이름과 위치 가있는 디렉토리 항목 은 아닙니다 . 파일은 inode로 표시되며 파일을 참조하는 디렉토리 항목없이 존재할 수 있습니다.
lgeorget

9
<sys / param.h>에서 : #define MAXPATHLEN PATH_MAX
geowar

1
방금 테스트했으며 파일이 이동되고 다시 호출하면 올바른 상태로 유지됩니다 (즉, 파일의 새 경로를 얻음). 그러나 이것은 Linux에서 지원되지 않습니다 (Ubuntu 14.04에서 테스트 됨-F_GETPATH가 정의되지 않음).
felipou


15

Tyler가 지적했듯이 주어진 FD는 0 개의 파일 이름 (다양한 경우) 또는> 1 (여러 개의 "하드 링크"가 후자의 상황이 일반적으로 설명되는 방식에 해당 할 수 있기 때문에 "직접적이고 안정적으로"필요한 작업을 수행 할 수있는 방법이 없습니다.) ). 모든 제한이있는 기능이 여전히 필요한 경우 (속도 및 1이 아닌 0, 2, ... 결과를 얻을 수있는 가능성) 다음과 같이 할 수 있습니다. 첫째, FD를 fstat- 이것은 알려줍니다. , 그 결과 struct stat파일이 어떤 장치에 있는지, 얼마나 많은 하드 링크가 있는지, 특수 파일인지 여부 등이 이미 귀하의 질문에 답할 수 있습니다. 예를 들어 하드 링크가 0 개인 경우 실제로 해당 파일 이름이 없음을 알 수 있습니다. 디스크에.

통계가 희망을 준다면 모든 하드 링크를 찾을 때까지 관련 장치에있는 디렉토리의 "트리를 걸어야"합니다 (또는 둘 이상이 필요하지 않은 경우에는 첫 번째 링크 만 가능합니다. ). 그 목적을 위해 readdir (물론 opendir & c) struct dirent을 사용하여 원래의 inode 번호와 동일한 inode 번호를받을 때까지 반복적으로 하위 디렉토리를 엽니 다 struct stat(이름이 아닌 전체 경로를 원하는 경우, 재구성하려면 디렉토리 체인을 뒤로 걸어야합니다.)

이 일반적인 접근 방식이 허용되지만 더 자세한 C 코드가 필요하면 작성하기가 어렵지 않을 것입니다 (쓸모없는 경우 작성하지 않을 것입니다. 즉, 필연적으로 느린 성능 또는 응용 프로그램의 목적에 따라! = 1 개의 결과를 얻을 가능성 ;-).


9

불가능하다고 쓰기 전에 lsof 명령 의 소스 코드를 살펴볼 것을 제안합니다 .

제한이있을 수 있지만 lsof는 파일 설명자와 파일 이름을 결정할 수있는 것으로 보입니다. 이 정보는 / proc 파일 시스템에 있으므로 프로그램에서 얻을 수 있어야합니다.


6

fstat ()를 사용하여 struct stat로 파일의 inode를 가져올 수 있습니다. 그런 다음 readdir ()을 사용하여 찾은 inode를 디렉토리에있는 inode (struct dirent)와 비교할 수 있습니다 (디렉토리를 알고 있다고 가정하고 그렇지 않으면 전체 파일 시스템을 검색해야 함) 해당 파일 이름을 찾을 수 있습니다. 추잡한?


2

불가능한. 파일 디스크립터는 파일 시스템에서 여러 이름을 가질 수 있거나 이름이 전혀 없을 수 있습니다.

편집 : OS를 지정하지 않았기 때문에 OS 별 API가없는 평범한 오래된 POSIX 시스템에 대해 이야기하고 있다고 가정합니다.


4
내 대답이 적용됩니다. Linux에는이를 수행 할 수있는 기능이 없습니다. Linux (POSIX) 파일 설명자는 반드시 파일을 참조하는 것은 아니며 파일 이름이 아니라 inode를 참조한다고해도 참조합니다. 설명자는 삭제 된 파일 (이름이 없으므로 임시 파일을 만드는 일반적인 방법)을 가리 키거나 여러 이름 (하드 링크)을 가진 inode를 가리킬 수 있습니다.
Tyler McHenry

3
lsof 소스 코드를 살펴보십시오. :) 그게 제가 얼마 전에 같은 질문을 받았을 때 제가 한 일입니다. lsof는 흑마 법과 희생 염소에 대해 연구합니다. 당신은 그 행동을 복제하기를 바랄 수 없습니다. 좀 더 구체적으로 말하자면, lsof는 리눅스 커널과 밀접하게 결합되어 있으며 사용자 영역 코드에 사용할 수있는 API를 통해 수행하는 작업을 수행하지 않습니다.
Tyler McHenry

27
Linux에는이를위한 이식 불가능한 proc API가 있습니다. 실제로 한계가 있지만 불가능하다고 말하는 것은 명백한 거짓입니다.
bdonlan

1
@Tyler-lsof는 사용자 공간에서 실행됩니다. 따라서, :) 유저 랜드 코드에 사용할 수 않는 무엇에 대한 API가
bdonlan

1
@Duck, 이식성 때문에 lsof의 소스가 흑 마법을 많이 가지고있는 이유 일 것입니다. 각 UNIX 변형은 다르게 수행합니다. 리눅스 proc 인터페이스는 너무 나쁘지 않고, 실제로는 드물게 문서화되어 있습니다.
bdonlan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.