NAME

open, openat, creat - 파일을 열고 때에 따라 생성하기

SYNOPSIS

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

int creat(const char *pathname, mode_t mode);

int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);

/* openat2(2)에서 따로 설명: */
int openat2(int dirfd, const char *pathname,
            const struct open_how *how, size_t size);

glibc 기능 확인 매크로 요건 (feature_test_macros(7) 참고):

openat():
glibc 2.10부터:
_POSIX_C_SOURCE >= 200809L
glibc 2.10 전:
_ATFILE_SOURCE

DESCRIPTION

open() 시스템 호출은 pathname에 지정한 파일을 연다. 지정한 파일이 존재하지 않는 경우 선택적으로 (flagsO_CREAT을 지정한 경우) open()에서 생성할 수도 있다.

open()의 반환 값은 파일 디스크립터이다. 이는 작은 음수 아닌 정수이며 이후의 시스템 호출들(read(2), write(2), lseek(2), fcntl(2) 등)에서 그 열린 파일을 가리키는 데 쓴다. 호출이 성공하면 프로세스에서 현재 열려 있지 않은 가장 낮은 번호의 파일 디스크립터를 반환하게 된다.

기본적으로 새 파일 디스크립터는 execve(2)를 거칠 때 계속 열려 있도록 설정돼 있다. (즉 fcntl(2)에서 설명하는 파일 디스크립터 플래그 FD_CLOEXEC가 처음에는 비활성화돼 있다.) 아래에서 설명하는 O_CLOEXEC 플래그를 써서 이 기본 설정을 바꿀 수 있다. 파일 오프셋은 파일 시작점으로 설정돼 있다. (lseek(2) 참고.)

open() 호출은 새로운 열린 파일 기술 항목(open file description)을 만든다. 이는 시스템 전역 열린 파일 테이블의 항목이다. 열린 파일 기술 항목에서는 파일 오프셋과 파일 상태 플래그(아래 참고)를 기록한다. 파일 디스크립터(file descriptor)는 열린 파일 기술 항목에 대한 참조이다. 이 참조는 pathname이 이후 제거되거나 다른 파일을 가리키게 바뀌더라도 영향을 받지 않는다. 열린 파일 기술 항목에 대한 더 자세한 내용은 NOTES를 보라.

인자 flags에는 접근 모드 O_RDONLY, O_WRONLY, O_RDWR 중 하나가 포함돼야 한다. 각각 파일을 읽기 전용, 쓰기 전용, 읽기/쓰기로 열도록 요청한다.

flags에 추가로 파일 생성 플래그와 파일 상태 플래그를 0개 이상 비트 OR 할 수 있다. 파일 생성 플래그O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE, O_TRUNC이다. 파일 상태 플래그는 아래 나열된 플래그들 중 나머지 전부이다. 이 두 플래그 종류의 차이는 파일 생성 플래그가 열기 동작 자체의 동작 방식에 영향을 주는 반면 파일 상태 플래그는 이어지는 I/O 동작들의 동작 방식에 영향을 준다는 점이다. 파일 상태 플래그는 읽어 올 수 있으며 (일부 경우에) 변경할 수 있다. 자세한 내용은 fcntl(2) 참고.

파일 생성 플래그 및 파일 상태 플래그에 대한 전체 목록은 다음과 같다.

O_APPEND

파일을 덧붙이기 모드로 연다. write(2) 전마다 파일 오프셋을 lseek(2)으로 하듯 파일 끝으로 옮긴다. 그 파일 오프셋 변경과 쓰기 동작은 한 개의 원자적 단계로 수행된다.

여러 프로세스가 동시에 파일에 데이터를 덧붙이는 경우 NFS 파일 시스템 상에선 O_APPEND를 해도 파일 내용에 오류가 생길 수 있다. 파일에 덧붙이기 동작을 NFS에서 지원하지 않아서 클라이언트 커널에서 그걸 모사해야 하는데, 경쟁 조건 없이 하기가 불가능하기 때문이다.

O_ASYNC
시그널 주도 I/O를 켠다. 이 파일 디스크립터에서 입력이나 출력이 가능해지면 시그널(기본은 SIGIO이되 fcntl(2)로 변경 가능)을 생성한다. 이 기능은 터미널, 유사 터미널, 소켓, 그리고 (리눅스 2.6부터) 파이프 및 FIFO에 대해서만 사용 가능하다. 자세한 내용은 fcntl(2)을 보라. 아래 BUGS도 참고.
O_CLOEXEC (리눅스 2.6.23부터)

새 파일 디스크립터에 exec에서 닫기 플래그를 켠다. 이 플래그를 지정하면 프로그램에서 따로 fcntl(2) F_SETFD 동작으로 FD_CLOEXEC 플래그를 설정하지 않아도 된다.

참고로 일부 다중 스레드 프로그램에서는 이 플래그 사용이 필수적이다. 한 스레드가 파일 디스크립터를 열어서 fcntl(2)로 exec에서 닫기 플래그를 설정하려는데 동시에 다른 스레드에서 fork(2)execve(2)를 하는 경우에서 별도의 fcntl(2) F_SETFD 동작으로 FD_CLOEXEC 플래그를 설정하는 방식은 경쟁 조건을 피하는 데 충분치 않기 때문이다. 경쟁으로 인해 실행 순서에 따라선 open()이 반환한 파일 디스크립터가 fork(2)로 생긴 자식 프로세스에서 실행하는 프로그램에게 의도치 않게 누출될 수 있다. (원칙적으로 이런 종류의 경쟁은 exec에서 닫기 플래그를 설정해야 할 파일 디스크립터를 생성하는 모든 시스템 호출에서 가능하며, 그래서 여러 리눅스 시스템 호출에서 O_CLOEXEC 플래그 같은 방법을 제공해서 이 문제를 처리한다.)

O_CREAT

pathname이 존재하지 않으면 그 경로명으로 정규 파일을 만든다.

새 파일의 소유자(사용자 ID)는 프로세스의 실효 사용자 ID로 설정한다.

새 파일의 그룹 소유(그룹 ID)는 프로세스의 실효 그룹 ID(시스템 V 방식)나 부모 디렉터리의 그룹 ID(BSD 방식) 중 하나로 설정한다. 리눅스에서는 부모 디렉터리에 set-group-ID 모드 비트가 설정돼 있는지 여부에 따라 동작이 다르다. 그 비트가 설정돼 있으면 BSD 방식을 따르고, 아니면 시스템 V 방식을 적용한다. 일부 파일 시스템에서는 mount(8)에서 설명하는 마운트 옵션 bsdgroupssysvgroups에 따라서도 동작이 달라진다.

mode 인자는 새 파일 생성 시 적용할 파일 모드 비트를 나타낸다. flagsO_CREATO_TMPFILE 어느 쪽도 지정하지 않은 경우에는 mode가 무시된다. (따라서 0으로 지정할 수도 있고, 그냥 생략할 수도 있다.) flagsO_CREAT이나 O_TMPFILE를 지정할 때는 mode 인자를 반드시 제공해야 한다. 주지 않으면 스택에 있는 임의의 바이트들이 파일 모드로 적용된다.

실제 적용되는 모드는 프로세스의 umask를 일반적 방식으로 써서 변경한 값이다. 즉 기본 ACL이 없는 경우 생성 파일의 모드는 (mode & ~umask)이다.

참고로 mode는 새로 생성되는 파일의 향후 접근에만 적용된다. 즉 읽기 전용 파일을 생성하게 돼 있는 open() 호출이 읽기/쓰기 가능한 파일 디스크립터를 반환하는 것도 충분히 가능하다.

mode를 위한 다음 상수 심볼들이 제공된다.

S_IRWXU 00700 사용자(파일 소유자)가 읽기, 쓰기, 실행 권한을 가짐
S_IRUSR 00400 사용자가 읽기 권한을 가짐
S_IWUSR 00200 사용자가 쓰기 권한을 가짐
S_IXUSR 00100 사용자가 실행 권한을 가짐
S_IRWXG 00070 그룹이 읽기, 쓰기, 실행 권한을 가짐
S_IRGRP 00040 그룹이 읽기 권한을 가짐
S_IWGRP 00020 그룹이 쓰기 권한을 가짐
S_IXGRP 00010 그룹이 실행 권한을 가짐
S_IRWXO 00007 기타가 읽기, 쓰기, 실행 권한을 가짐
S_IROTH 00004 기타가 읽기 권한을 가짐
S_IWOTH 00002 기타가 쓰기 권한을 가짐
S_IXOTH 00001 기타가 실행 권한을 가짐

POSIX에 따르면 mode에 설정된 다른 비트들의 효과는 명세되어 있지 않다. 리눅스에서는 mode에서 다음 비트들도 받는다.

S_ISUID 0004000 set-user-ID 비트
S_ISGID 0002000 set-group-ID 비트 (inode(7) 참고)
S_ISVTX 0001000 스티키 비트 (inode(7) 참고)
O_DIRECT (리눅스 2.4.10부터)

이 파일에 대한 I/O에서 캐시 효과를 최소화하려 노력한다. 일반적으로는 그렇게 하면 성능이 떨어지지만 응용에서 자체 캐싱을 하는 경우처럼 특수한 상황에서는 쓸모가 있다. 사용자 공간 버퍼와 직접 파일 I/O가 이뤄진다. O_DIRECT 플래그 그 자체에서 데이터를 동기적으로 전송하려는 노력을 하기는 하지만 데이터와 관련 메타데이터가 전송되는 O_SYNC 플래그의 보장을 해 주지는 않는다. 동기적 I/O를 보장하려면 O_DIRECT에 더해 O_SYNC를 사용해야 한다. 추가 설명은 아래 NOTES를 보라.

블록 장치에 대한 비슷한 (하지만 구식이 된) 인터페이스를 raw(8)에서 설명한다.

O_DIRECTORY
pathname이 디렉터리가 아니면 열기가 실패하도록 한다. 이 플래그는 커널 버전 2.1.126에서 추가된 것인데, FIFO 내지 테이프 장치에서 opendir(3)을 호출할 때의 서비스 거부 문제를 피하기 위해서였다.
O_DSYNC

파일에서의 쓰기 동작이 동기 I/O 데이터 무결성 완료 요건에 따라 완료되게 한다.

write(2)(또는 비슷한 함수)가 반환하는 시점에 출력 데이터가, 그리고 그 데이터를 가져오는 데 필요할 파일 메타데이터가 있으면 그것까지 기반 하드웨어로 전송돼 있다. (즉 각 write(2) 뒤에 fdatasync(2) 호출을 붙인 것과 같다.) 아래 NOTES를 보라.

O_EXCL

이 호출에서 꼭 파일을 만들도록 한다. 이 플래그가 O_CREAT와 함께 지정돼 있는데 pathname이 이미 존재하면 open()EEXIST 오류로 실패한다.

그 두 플래그가 지정된 경우에는 심볼릭 링크를 따라가지 않는다. pathname이 심볼릭 링크면 그게 어디를 가리키는지와 상관없이 open()이 실패한다.

일반적으로 O_CREAT 없이 사용 시 O_EXCL의 동작 방식은 규정돼 있지 않다. 여기에 한 가지 예외가 있는데, 리눅스 2.6 및 이후에서는 pathname이 블록 장치를 가리키는 경우 O_EXCLO_CREAT 없이 쓸 수 있다. 그 블록 장치를 시스템에서 사용 중이면 (가령 마운트 돼 있으면) open()EBUSY 오류로 실패한다.

NFS인 경우, 커널 2.6 내지 이후에서 NFSv3 내지 이후 버전을 쓸 때만 O_EXCL을 지원한다. 락킹 작업 수행에 있어 이에 의존하는 프로그램이 있다면 O_EXCL을 지원하지 않는 NFS 환경에서 경쟁 조건이 있게 된다. 락 파일을 이용해 원자적 파일 락킹을 수행하고 싶은데 NFS의 O_EXCL 지원에 의지하는 건 피하고 싶은 이식 가능한 프로그램에서는 같은 파일 시스템 상에 (가령 호스트명과 PID를 합쳐서) 유일한 파일을 만들고 link(2)를 사용해 그 락 파일에 대한 링크를 만들 수 있다. link(2)가 0을 반환한다면 락이 성공한 것이다. 그렇지 않은 경우 그 유일한 파일에 stat(2)을 해서 링크 카운트가 2로 올라갔는지 확인한다. 그렇다면 그 경우 역시 락이 성공한 것이다.

O_LARGEFILE
(LFS) off_t로 크기를 표현할 수 없는 (하지만 off64_t로는 할 수 있는) 파일을 여는 것을 허용한다. 이 정의를 쓸 수 있으려면 (어떤 헤더 파일도 포함시키기 전에) _LARGEFILE64_SOURCE 매크로가 정의돼 있어야 한다. 하지만 32비트 시스템에서 큰 파일에 접근하는 바람직한 방법은 (O_LARGEFILE을 쓰는 게 아니라) 기능 확인 매크로 _FILE_OFFSET_BITS를 64로 설정하는 것이다. (feature_test_macros(7) 참고.)
O_NOATIME (리눅스 2.6.8부터)

파일을 read(2) 할 때 파일 최근 접근 시간(아이노드의 st_atime)을 갱신하지 않는다.

다음 중 한 조건이라도 참인 경우에만 이 플래그를 쓸 수 있다.

  • 프로세스의 실효 UID가 파일의 소유자 UID와 일치한다.

  • 호출 프로세스가 자기 사용자 네임스페이스에서 CAP_FOWNER 역능을 가지고 있으며 그 네임스페이스에 파일 소유자 UID의 매핑이 있다.

이 플래그는 사용 시 디스크 활동량을 크게 떨어뜨릴 수 있는 색인 프로그램이나 백업 프로그램에서 쓰기 위한 것이다. 모든 파일 시스템에서 이 플래그가 효과가 있지는 않을 수도 있다. 한 예로 서버에서 접근 시간을 유지하는 NFS가 있다.

O_NOCTTY
pathname이 터미널 장치(tty(4) 참고)를 가리키는 경우에 프로세스에 제어 터미널이 없더라도 그 장치가 프로세스의 제어 터미널이 되지 않게 한다.
O_NOFOLLOW

pathname의 마지막 부분(즉 basename)이 심볼릭 링크면 열기가 ELOOP 오류로 실패한다. 경로명 앞쪽 부분의 심볼릭 링크는 여전히 따라간다. (참고로 이 경우 발생할 수 있는 ELOOP 오류는 경로명 선두부 구성 항목들을 해석하는 과정에서 너무 많은 심볼릭 링크를 발견해서 열기가 실패하는 경우와 구별이 불가능하다.)

이 플래그는 FreeBSD 확장이며 리눅스에는 버전 2.1.126에 추가되었다. 그 뒤 POSIX.1-2008에서 표준화되었다.

아래의 O_PATH도 참고.

O_NONBLOCK 또는 O_NDELAY

가능한 경우 파일을 논블로킹 모드로 연다. 그 open() 동작이나 반환된 파일 디스크립터에 대한 이후의 어떤 I/O 동작에서도 호출 프로세스가 대기하지 않게 된다.

참고로 이 플래그 설정은 poll(2), select(2), epoll(7) 등의 동작에는 아무 영향도 주지 않는다. 그 인터페이스들은 파일 디스크립터가 "준비" 상태인지를, 즉 O_NONBLOCK 플래그가 설정 안 된 파일 디스크립터에 수행하는 I/O 동작이 블록 할 것인지를 호출자에게 알려줄 뿐이다.

참고로 정규 파일과 블록 장치에 대해선 이 플래그가 효과가 없다. 즉 O_NONBLOCK이 설정돼 있는지와 관계없이 장치 활동이 필요할 때는 I/O 동작이 (잠시) 블록 하게 된다. 결국에는 O_NONBLOCK 동작 방식이 구현될 수도 있으므로 응용에서는 정규 파일 및 블록 장치에 이 플래그 지정 시 블로킹 동작을 확신하지 않는 게 좋다.

FIFO(이름 있는 파이프) 처리에 대해선 fifo(7)를 보라. 강제적 파일 락 및 파일 리스와 관련한 O_NONBLOCK의 효과에 대한 설명은 fcntl(2)을 보라.

O_PATH (리눅스 2.6.39부터)

파일 시스템 트리 내 위치를 나타내는 것과 순수하게 파일 디스크립터 수준에서만 이뤄지는 동작을 수행하는 두 용도에 쓸 수 있는 파일 디스크립터를 얻는다. 파일 자체를 열지 않으며 다른 파일 동작들(가령 read(2), write(2), fchmod(2), fchown(2), fgetxattr(2), ioctl(2), mmap(2))은 EBADF 오류로 실패한다.

결과 파일 디스크립터에 다음 동작을 수행할 수 있다.

  • close(2)

  • fchdir(2), 파일 디스크립터가 디렉터리를 가리키는 경우 (리눅스 3.5부터)

  • fstat(2) (리눅스 3.6부터)

  • fstatfs(2) (리눅스 3.12부터)

  • 파일 디스크립터 복제 (dup(2), fcntl(2) F_DUPFD 등)

  • 파일 디스크립터 플래그 얻기 및 설정하기 (fcntl(2)F_GETFDF_SETFD)

  • fcntl(2) F_GETFL 동작으로 열린 파일 상태 플래그 얻기. 반환되는 플래그에 O_PATH 비트가 포함돼 있게 된다.

  • 파일 디스크립터를 openat() 및 기타 "*at()" 시스템 호출의 dirfd 인자로 전달하기. 파일이 디렉터리가 아닌 경우에도 AT_EMPTY_PATH로 (또는 AT_SYMLINK_FOLLOW로 procfs를 통해) linkat(2) 하는 것도 포함된다.

  • 파일 디스크립터를 유닉스 도메인 소켓을 통해 다른 프로세스로 보내기. (unix(7)SCM_RIGHTS 참고)

flagsO_PATH가 지정돼 있을 시 O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW 외의 플래그 비트들은 무시한다.

O_PATH 플래그로 파일이나 디렉터리를 열 때는 객체 자체에 대한 어떤 권한도 필요치 않다. (하지만 경로 선두부 디렉터리들에 대한 실행 권한은 필요하다.) 이후의 동작에 따라 적절한 파일 권한 검사가 이뤄질 수 있다. (가령 fchdir(2)에서는 파일 디스크립터 인자가 가리키는 디렉터리에 대한 실행 권한이 필요하다.) 반면 파일 시스템 객체를 O_RDONLY로 열어서 참조를 얻으려면 그 객체에 대한 읽기 권한이 호출자에게 있어야 한다. 이후의 동작(가령 fchdir(2), fstat(2))에서 그 객체에 대한 읽기 권한이 필요하지 않더라도 그렇다.

pathname이 심볼릭 링크이고 O_NOFOLLOW 플래그가 함께 지정돼 있는 경우에는 그 심볼릭 링크를 가리키는 파일 디스크립터를 반환한다. 이 파일 디스크립터를 fchownat(2), fstatat(2), linkat(2), readlinkat(2)dirfd 인자에 빈 경로명과 함께 쓸 수 있으며, 그러면 호출이 그 심볼릭 링크에 대해서 동작한다.

pathname이 automount 지점을 가리키는데 아직 작동을 안 해서 거기 다른 파일 시스템이 마운트 돼 있지 않은 경우에는 마운트를 작동시키지 않으면서 그 automount 디렉터리를 가리키는 파일 디스크립터를 반환한다. 그러면 fstatfs(2)를 사용해 그게 실제로 작동 안 한 automount 지점인지 (.f_type == AUTOFS_SUPER_MAGIC) 알아낼 수 있다.

정규 파일에 있어 O_PATH의 용도 한 가지는 POSIX.1의 O_EXEC와 동등한 기능성을 제공하는 것이다. 다음과 같은 단계를 통해 실행 권한은 있지만 읽기 권한은 없는 파일을 열어서 그 파일을 실행할 수 있다.

char buf[PATH_MAX];
fd = open("some_prog", O_PATH);
snprintf(buf, PATH_MAX, "/proc/self/fd/%d", fd);
execl(buf, "some_prog", (char *) NULL);

O_PATH 파일 디스크립터를 fexecve(3) 인자로 줄 수도 있다.

O_SYNC

파일에서의 쓰기 동작이 (O_DSYNC에서 제공하는 동기 I/O 데이터 무결성 완료가 아니라) 동기 I/O 파일 무결성 완료 요건에 따라 완료되게 한다.

write(2)(또는 비슷한 함수)가 반환하는 시점에 출력 데이터와 관련 파일 메타데이터가 기반 하드웨어로 전송돼 있다. (즉 각 write(2) 뒤에 fsync(2) 호출을 붙인 것과 같다.) 아래 NOTES를 보라.

O_TMPFILE (리눅스 3.11부터)

이름 없는 임시 정규 파일을 만든다. pathname 인자가 디렉터리를 지정하며 그 디렉터리의 파일 시스템 내에 이름 없는 아이노드가 생기게 된다. 그렇게 생긴 파일에 써넣은 내용은 그 파일에 이름을 주지 않는 한 마지막 파일 디스크립터가 닫힐 때 사라지게 된다.

O_TMPFILEO_RDWRO_WRONLY와 함께 지정해야 하며, 선택적으로 O_EXCL과 함께 지정할 수 있다. O_EXCL을 지정하지 않은 경우에는 다음 코드처럼 linkat(2)으로 그 임시 파일을 파일 시스템 내로 링크 해서 영속 파일로 만들 수 있다.

char path[PATH_MAX];
fd = open("/path/to/dir", O_TMPFILE | O_RDWR,
                        S_ISUSR | S_IWUSR);

/* 'fd'에서 파일 I/O... */

linkat(fd, NULL, AT_FDCWD, "/path/for/file", AT_EMPTY_PATH);

/* 호출자에게 (linkat(2)에 AT_EMPTY_PATH를 쓰려면 필요한)
   CAP_DAC_READ_SEARCH 역능이 없고 proc(5) 파일 시스템이
   마운트 되어 있다면 위의 linkat(2) 호출을 다음으로
   대체할 수 있다.

snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd);
linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file",
                        AT_SYMLINK_FOLLOW);
*/

이 경우 open()mode 인자가 O_CREAT에서처럼 파일 권한 모드를 결정한다.

O_TMPFILEO_EXCL을 함께 지정하면 위 방식으로 임시 파일을 파일 시스템 내로 링크 하지 못하게 한다. (참고로 이 경우에서 O_EXCL의 의미는 다른 경우에서 O_EXCL의 의미와 다르다.)

O_TMPFILE의 주된 용도가 두 가지가 있다.

  • 향상된 tmpfile(3) 기능성: (1) 닫힐 때 자동으로 삭제되고 (2) 어떤 경로명을 통해서도 절대 도달할 수 없으며 (3) 심볼릭 링크 공격 대상이 아니며 (4) 호출자가 유일한 이름을 만들어 낼 필요가 없는 임시 파일을 경쟁 없는 방식으로 생성한다.

  • 처음에는 안 보이는 파일을 만들고서 데이터를 채우고 적절한 파일 시스템 속성을 갖도록 조정(fchown(2), fchmod(2), fsetxattr(2) 등)한 다음에 (위에 설명한 것처럼 linkat(2)을 써서) 완전한 상태로 파일 시스템 내로 원자적으로 링크 하기.

O_TMPFILE에는 기반 파일 시스템의 지원이 필요하다. 리눅스 파일 시스템들 중 일부만 지원을 제공한다. 최초 구현에서는 ext2, ext3, ext4, UDF, Minix, tmpfs 파일 시스템에서 지원을 제공했다. 이어서 XFS (리눅스 3.15), Btrfs (리눅스 3.16), F2FS (리눅스 3.16), ubifs (리눅스 4.9) 파일 시스템 지원이 추가되었다.

O_TRUNC
파일이 이미 존재하고 정규 파일이며 접근 모드에서 쓰기를 허용(즉 O_RDWRO_WRONLY)하면 파일을 길이 0으로 잘라낸다. 파일이 FIFO나 터미널 장치 파일이면 O_TRUNC 플래그를 무시한다. 그 외 경우에 O_TRUNC의 효과는 명세돼 있지 않다.

creat()

creat() 호출은 flagsO_CREAT|O_WRONLY|O_TRUNC로 해서 open()을 호출하는 것과 동등하다.

openat()

openat() 시스템 호출은 여기 설명하는 차이점을 빼면 open()과 똑같이 동작한다.

pathname에 준 경로명이 상대 경로이면 (상대 경로명에 대해 open()에서 하듯 호출 프로세스의 현재 작업 디렉터리를 기준으로 하는 게 아니라) 파일 디스크립터 dirfd가 가리키는 디렉터리를 기준으로 경로명을 해석한다.

pathname이 상대 경로이고 dirfd가 특수 값 AT_FDCWD이면 (open()처럼) 호출 프로세스의 현재 작업 디렉터리를 기준으로 pathname을 해석한다.

pathname이 절대 경로이면 dirfd를 무시한다.

openat2(2)

openat2(2) 시스템 호출은 openat()의 확장판이며 openat()을 포괄하는 기능을 제공한다. openat2(2)에서 따로 설명한다.

RETURN VALUE

성공 시 open(), openat(), creat()은 새 파일 디스크립터(음수 아닌 정수)를 반환한다. 오류 시 -1을 반환하며 오류를 나타내도록 errno를 설정한다.

ERRORS

open(), openat(), creat()이 다음 오류로 실패할 수 있다.

EACCES
파일에 요청한 접근 방식이 허용되지 않거나, pathname 경로 선두부의 한 디렉터리에 대해 탐색 권한이 거부되었거나, 파일이 아직 존재하지 않고 부모 디렉터리에 대한 쓰기 접근이 허용되지 않는다. (path_resolution(7)도 참고.)
EACCES
O_CREAT을 지정했는데, sysctl 항목 protected_fifosprotected_regular가 켜져 있고, 파일이 이미 존재하며 FIFO 또는 정규 파일이고, 파일 소유자가 현재 사용자도 아니고 그 파일을 담은 디렉터리의 소유자도 아니며, 담은 디렉터리가 기타 또는 그룹이 쓰기 가능이면서 스티키이다. 자세한 내용은 proc(5)/proc/sys/fs/protected_fifos/proc/sys/fs/protected_regular 설명을 보라.
EBUSY
flagsO_EXCL을 지정했는데 pathname이 시스템에서 사용 중인 (가령 마운트 되어 있는) 블록 장치를 가리킨다.
EDQUOT
O_CREAT를 지정한 경우에서 파일이 존재하지 않으며 그 파일 시스템 상에서 사용자의 디스크 블록 내지 아이노드 쿼터가 고갈되었다.
EEXIST
pathname이 이미 존재하는데 O_CREATO_EXCL을 썼다.
EFAULT
pathname이 접근 가능한 주소 공간 밖을 가리킨다.
EFBIG
EOVERFLOW를 보라.
EINTR
느린 장치(가령 FIFO. fifo(7) 참고) 열기가 끝나기를 기다리며 블록돼 있는 동안 호출이 시그널 인터럽트에 의해 중단되었다. signal(7) 참고.
EINVAL
파일 시스템에서 O_DIRECT 플래그를 지원하지 않는다. 추가 정보는 NOTES 참고.
EINVAL
flags에 유효하지 않은 값.
EINVAL
flagsO_TMPFILE을 지정했는데 O_WRONLYO_RDWR 어느 것도 지정하지 않았다.
EINVAL
flagsO_CREAT을 지정했는데 새 파일 pathname의 마지막 부분("basename")이 유효하지 않다. (가령 기반 파일 시스템에서 허용하지 않는 문자를 담고 있다.)
EINVAL
pathname의 마지막 부분("basename")이 유효하지 않다. (가령 기반 파일 시스템에서 허용하지 않는 문자를 담고 있다.)
EISDIR
pathname이 디렉터리를 가리키는데 요청한 접근 방식에 쓰기가 수반된다. (즉 O_WRONLYO_RDWR를 설정했다.)
EISDIR
pathname이 기존 디렉터리를 가리키며 flagsO_TMPFILEO_WRONLYO_RDWR와 함께 지정했는데 이 커널 버전에서 O_TMPFILE 기능을 제공하지 않는다.
ELOOP
pathname을 해석하는 동안 너무 많은 심볼릭 링크를 만났다.
ELOOP
pathname이 심볼릭 링크인데 flagsO_NOFOLLOW를 지정하고 O_PATH는 지정하지 않았다.
EMFILE
열린 파일 디스크립터 개수에 대한 프로세스별 제한에 도달했다. (getrlimit(2)RLIMIT_NOFILE 설명 참고.)
ENAMETOOLONG
pathname이 너무 길다.
ENFILE
열린 파일 총개수에 대한 시스템 전역 제한에 도달했다.
ENODEV
pathname이 장치 특수 파일을 가리키는데 대응하는 장치가 존재하지 않는다. (이는 리눅스 커널 버그이다. 이 경우에 ENXIO를 반환해야 한다.)
ENOENT
O_CREAT을 설정하지 않았고 지명한 파일이 존재하지 않는다.
ENOENT
pathname의 어느 디렉터리 요소가 존재하지 않거나 깨진 심볼릭 링크이다.
ENOENT
pathname이 존재하지 않는 디렉터리를 가리키며, flagsO_TMPFILEO_WRONLYO_RDWR와 함께 지정했는데 이 커널 버전에서 O_TMPFILE 기능을 제공하지 않는다.
ENOMEM
지명한 파일이 FIFO인데 파이프용 메모리 할당에 대한 사용자별 경성 제한에 도달했고 호출자에게 특권이 없어서 FIFO 버퍼를 위한 메모리를 할당할 수 없다. pipe(7) 참고.
ENOMEM
사용 가능한 커널 메모리가 충분하지 않다.
ENOSPC
pathname을 생성해야 하는데 pathname을 담은 장치에 새 파일을 위한 공간이 없다.
ENOTDIR
pathname에서 디렉터리로 쓰인 요소가 실제로는 디렉터리가 아니거나, O_DIRECTORY를 지정했는데 pathname이 디렉터리가 아니다.
ENXIO
O_NONBLOCK | O_WRONLY를 설정했고 지명한 파일이 FIFO인데 그 FIFO를 읽기용으로 열고 있는 프로세스가 없다.
ENXIO
파일이 장치 특수 파일인데 대응하는 장치가 존재하지 않는다.
ENXIO
파일이 유닉스 도메인 소켓이다.
EOPNOTSUPP
pathname을 담고 있는 파일 시스템에서 O_TMPFILE을 지원하지 않는다.
EOVERFLOW
pathname이 열기에 너무 큰 정규 파일을 가리키고 있다. 일반적인 시나리오는 32비트 플랫폼에서 -D_FILE_OFFSET_BITS=64 없이 컴파일 한 응용이 크기가 (1<<31)-1 바이트를 넘는 파일을 열려고 하는 경우이다. 위의 O_LARGEFILE도 보라. POSIX.1에 명세된 오류인데, 리눅스 커널 2.6.24 전에선 이 경우에 EFBIG 오류를 내놓았다.
EPERM
O_NOATIME 플래그를 지정했지만 호출자의 실효 사용자 ID가 파일의 소유자와 일치하지 않으며 호출자에게 특권이 없다.
EPERM
파일 봉인 때문에 동작이 막혔다. fcntl(2) 참고.
EROFS
pathname이 읽기 전용 파일 시스템 상의 파일을 가리키는데 쓰기 접근을 요청했다.
ETXTBSY
pathname이 현재 실행 중인 실행 이미지를 가리키는데 쓰기 접근을 요청했다.
ETXTBSY
pathname이 현재 스왑 파일로 사용 중인 파일을 가리키는데 O_TRUNC 플래그를 지정했다.
ETXTBSY
pathname이 현재 커널에서 (가령 모듈/펌웨어 적재를 위해) 읽는 중인 파일을 가리키는데 쓰기 접근을 요청했다.
EWOULDBLOCK
O_NONBLOCK 플래그를 지정했는데 파일에 호환 불가능한 리스가 잡혀 있다. (fcntl(2) 참고.)

openat()에서 추가로 다음 오류가 발생할 수 있다.

EBADF
dirfd가 유효한 파일 디스크립터가 아니다.
ENOTDIR
pathname이 상대 경로명이고 dirfd가 디렉터리 아닌 파일을 가리키는 파일 디스크립터이다.

VERSIONS

리눅스 커널 2.6.16에서 openat()이 추가되었다. glibc 버전 2.4에서 라이브러리 지원이 추가되었다.

CONFORMING TO

open(), creat(): SVr4, 4.3BSD, POSIX.1-2001, POSIX.1-2008.

openat(): POSIX.1-2008.

openat2(2)는 리눅스 전용이다.

O_DIRECT, O_NOATIME, O_PATH, O_TMPFILE 플래그는 리눅스 전용이다. 그 정의를 이용할 수 있으려면 _GNU_SOURCE를 정의해야 한다.

O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW 플래그는 POSIX.1-2001에는 명세돼 있지 않고 POSIX-1.2008에는 명세돼 있다. glibc 2.12부터 200809L과 같거나 그보다 큰 값으로 _POSIX_C_SOURCE를 정의하거나 700과 같거나 그보다 큰 값으로 _XOPEN_SOURCE를 정의하면 그 정의들을 이용할 수 있다.

feature_test_macros(7)에서 지적하듯 _POSIX_C_SOURCE, _XOPEN_SOURCE, _GNU_SOURCE 같은 기능 확인 매크로는 어떤 헤더 파일도 포함시키기 전에 정의돼 있어야 한다.

NOTES

리눅스에서는 파일을 열고 싶지만 꼭 읽기나 쓰기를 하려는 건 아닌 경우에 O_NONBLOCK 플래그를 쓸 때가 있다. 예를 들어 장치를 열어서 ioctl(2)에 쓸 파일 디스크립터를 얻는 데 쓸 수 있다.

O_RDONLY | O_TRUNC의 (규정돼 있지 않은) 효과는 구현에 따라 다르다. 많은 시스템에서는 파일이 실제 잘린다.

참고로 open()으로 장치 특수 파일을 열 수는 있지만 creat()으로 만들 수는 없다. mknod(2)를 써야 한다.

파일이 새로 생성되는 경우 그 st_atime, st_ctime, st_mtime 필드(각기 최근 접근 시간, 최근 상태 변경, 최근 수정 시간. stat(2) 참고)가 현재 시간으로 설정되고 부모 디렉터리의 st_ctimest_mtime 필드도 그렇게 설정된다. 그렇지 않은 경우에 O_TRUNC 플래그 때문에 파일이 수정되면 그 st_ctimest_mtime 필드가 현재 시간으로 설정된다.

/proc/[pid]/fd 디렉터리의 파일들은 PID가 pid인 프로세스의 열린 파일 디스크립터들을 보여 준다. /proc/[pid]/fdinfo 디렉터리의 파일들은 그 파일 디스크립터들에 대해 추가 정보를 보여 준다. 두 디렉터리에 대한 더 자세한 내용은 proc(5)을 보라.

리눅스 헤더 파일 <asm/fcntl.h>에는 O_ASYNC가 정의돼 있지 않다. 대신 (BSD에서 유래한) 같은 의미의 FASYNC가 정의돼 있다.

열린 파일 기술 항목

열린 파일 기술 항목(open file description)은 POSIX에서 시스템 전역 열린 파일 테이블의 항목들을 나타내는 데 쓰는 용어다. 다른 맥락에서는 이 객체를 "열린 파일 객체", "파일 핸들", "열린 파일 테이블 항목", (커널 개발자 용어로) struct file 등으로 다양하게 부른다.

파일 디스크립터를 (dup(2) 등으로) 복제할 때 사본은 원래 파일 디스크립터와 같은 열린 파일 기술 항목을 가리키며, 따라서 두 파일 디스크립터가 파일 오프셋과 파일 상태 플래그를 공유한다. 그런 공유가 프로세스 사이에서도 이뤄질 수 있다. fork(2)를 통해 생성된 자식 프로세스는 부모 프로세스의 파일 디스크립터들의 사본을 물려받으며 그 사본은 같은 열린 파일 기술 항목을 가리킨다.

각 파일 open()마다 새 열린 파일 기술 항목을 만든다. 즉 한 파일 노드에 대응하는 열린 파일 기술 항목이 여럿 있을 수 있다.

리눅스에서 kcmp(2) KCMP_FILE 동작을 사용해 (동일 프로세스의 또는 다른 두 프로세스의) 두 파일 디스크립터가 같은 열린 파일 기술 항목을 가리키는지 확인할 수 있다.

동기 I/O

POSIX.1-2008 "synchronized I/O" 옵션에서는 다양한 동기 I/O 형태를 명세하고 동작 방식을 제어하기 위한 open() 플래그 O_SYNC, O_DSYNC, O_RSYNC를 명세한다. 구현에서 옵션을 지원하는지 여부와 상관없이 적어도 정규 파일에 대한 O_SYNC 사용은 지원해야 한다.

리눅스에서는 O_SYNCO_DSYNC를 구현하고 O_RSYNC는 구현하지 않고 있다. glibc에서는 O_RSYNCO_SYNC와 같은 값을 가지도록 정의하는데, 이는 다소 부정확하다. (HP PA-RISC에서 리눅스 헤더 파일 <asm/fcntl.h>O_RSYNC가 정의돼 있지만 쓰이지는 않는다.)

O_SYNC는 동기 I/O 파일 무결성 완료를 제공하는데, 쓰기 동작에서 데이터와 관련 메타데이터 모두를 기반 하드웨어로 플러시 한다는 뜻이다. O_DSYNC는 동기 I/O 데이터 무결성 완료를 제공하는데, 쓰기 동작에서 데이터를 기반 하드웨어로 플러시 하되 메타데이터 갱신 사항은 이후 읽기 동작이 성공적으로 완료되는 데 필요한 것만 플러시 한다는 뜻이다. 데이터 무결성 완료 방식은 파일 무결성 완료 방식의 보장 수준까지는 필요치 않은 응용에서 디스크 동작 횟수를 줄여 줄 수 있다.

두 완료 방식의 차이를 이해하기 위해 두 가지 파일 메타데이터 조각, 즉 최근 수정 타임스탬프(st_mtime)와 파일 길이를 생각해 보자. 최근 파일 수정 타임스탬프는 모든 쓰기 동작에서 갱신하지만 파일 길이는 파일 끝에 데이터를 추가하는 쓰기에서만 바꾸게 된다. 그리고 최근 수정 타임스탬프는 읽기의 성공적 완료를 보장하는 데 필요하지 않지만 파일 길이는 필요하다. 따라서 O_DSYNC에서는 파일 길이 메타데이터 갱신을 플러시 하는 것만 보장한다. (반면 O_SYNC에서는 최근 수정 타임스탬프 메타데이터도 항상 플러시 하게 된다.)

리눅스 2.6.33 전에서 리눅스는 open()O_SYNC 플래그만 구현하고 있었다. 하지만 그 플래그 지정 시 대다수 파일 시스템에서 실제로는 동기 I/O 데이터 무결성 완료에 해당하는 동작을 제공했다. (즉 O_SYNC가 실제로는 O_DSYNC에 해당하는 방식으로 구현되었다.)

리눅스 2.6.33부터 제대로 된 O_SYNC 지원을 제공한다. 하지만 하위 바이너리 호환성을 보장하기 위해 O_DSYNC는 이전 O_SYNC와 같은 값으로 정의했고 O_SYNC는 새로운 (두 비트짜리) 플래그 값으로 정의해서 O_DSYNC 플래그 값을 포함하게 했다. 이렇게 하면 새 헤더로 컴파일 한 응용들이 2.6.33 전 커널에서 적어도 O_DSYNC 동작은 얻게 된다.

C 라이브러리/커널 차이

버전 2.26부터 glibc의 open() 래퍼 함수가 커널의 open() 시스템 호출 대신 openat() 시스템 호출을 이용한다. 어떤 아키텍처에서는 glibc 버전 2.26 전에서도 그렇다.

NFS

NFS의 기반이 되는 프로토콜에 여러 부적절한 부분이 있어서 특히 O_SYNCO_NDELAY에 영향을 준다.

UID 매핑을 켠 NFS 파일 시스템에서 open()이 파일 디스크립터를 반환하고서도 가령 read(2) 요청이 EACCES로 거부될 수도 있다. 이는 클라이언트에서 open()을 수행할 때 권한 검사는 하지만 UID 매핑은 읽기 및 쓰기 요청 때 서버에서 수행하기 때문이다.

FIFO

FIFO의 읽기 쪽 내지 쓰기 쪽을 여는 동작은 (다른 프로세스나 스레드가) 반대편도 열 때까지 블록 한다. 자세한 내용은 fifo(7) 참고.

파일 접근 모드

flags에 지정할 수 있는 다른 값들과 달리 접근 모드 값인 O_RDONLY, O_WRONLY, O_RDWR은 개별 비트를 나타내는 게 아니다. 대신 함께 flags의 하위 두 비트를 규정하며, 각기 0, 1, 2로 정의돼 있다. 달리 말해 O_RDONLY | O_WRONLY는 논리적 오류이며 전혀 O_RDWR와 같은 의미가 아니다.

리눅스에서는 flags에 비표준 접근 모드 3(이진수로 11)을 따로 두고 있는데, 파일에서 읽기 및 쓰기 권한을 검사하되 읽기 및 쓰기에 사용할 수 없는 파일 디스크립터를 반환하는 걸 뜻한다. 일부 리눅스 드라이버에서 장치별 ioctl(2) 동작에만 사용해야 하는 파일 디스크립터를 반환하게 하는 데 이 비표준 접근 모드를 쓴다.

openat() 및 기타 디렉터리 파일 디스크립터 API의 배경

openat()과 디렉터리 파일 디스크립터 인자를 받는 여타 시스템 호출 및 라이브러리 함수들(즉 fexecveat(2), faccessat(2), fanotify_mark(2), fchmodat(2), fchownat(2), fspick(2), fstatat(2), futimesat(2), linkat(2), mkdirat(2), move_mount(2), mknodat(2), name_to_handle_at(2), open_tree(2), openat2(2), readlinkat(2), renameat(2), statx(2), symlinkat(2), unlinkat(2), utimensat(2), mkfifoat(3), scandirat(3))은 선행 인터페이스에 있는 두 가지 문제를 다룬다. 여기선 openat() 호출을 가지고 설명하지만 다른 인터페이스들의 근거도 비슷하다.

첫째로, 응용에서 openat()을 쓰면 현재 작업 디렉터리 아닌 디렉터리의 파일을 open()으로 열 때 발생할 수 있는 경쟁 조건을 피할 수 있다. 그 경쟁 조건은 open()에 준 디렉터리 선두부의 어느 구성 요소가 open() 호출과 동시에 바뀔 수도 있다는 사실에서 온다. 예를 들어 dir1/dir2/xxx라는 파일이 존재한다면 dir1/dir2/xxx.dep라는 파일을 만들고 싶다고 해 보자. 문제는 존재 여부 검사 단계와 파일 생성 단계 사이에 (심볼릭 링크일 수도 있을) dir1이나 dir2가 다른 위치를 가리키게 변경될 수도 있다는 것이다. 대상 디렉터리에 대한 파일 디스크립터를 연 다음 그 파일 디스크립터를 (가령) fstatat(2)openat()dirfd 인자로 지정한다면 그런 경쟁을 피할 수 있다. dirfd 파일 디스크립터 사용에는 다른 이득도 있다.

둘째로, openat()을 쓰면 응용에서 파일 디스크립터(들)을 유지하며 스레드별 "현재 작업 디렉터리"를 구현할 수 있다. (/proc/self/fd/dirfd를 이용하는 기법으로도 같은 기능성을 얻을 수 있지만 덜 효율적이다.)

이 API들에 쓸 dirfd 인자는 open()이나 openat()으로 (O_RDONLY 또는 O_PATH 플래그를 써서) 디렉터리를 열어서 얻을 수 있다. 또는 opendir(3)로 만든 디렉터리 스트림에 dirfd(3)를 적용해서 얻을 수도 있다.

이 API들에 dirfd 인자로 AT_FDCWD를 주거나 경로명이 절대 경로이면 대응하는 전통적 API와 같은 방식으로 경로명 인자를 다룬다. 하지만 이 경우에도 여러 API에는 flags 인자가 있어서 대응하는 전통적 API에서 이용할 수 없는 기능들에 접근할 수 있다.

O_DIRECT

O_DIRECT 플래그 사용 시 사용자 공간 버퍼의 길이와 주소, 그리고 I/O의 파일 오프셋에 정렬 제약이 있을 수 있다. 리눅스의 정렬 제약은 파일 시스템과 커널 버전에 따라 다르며 아예 없을 수도 있다. 하지만 응용에서 어떤 파일이나 파일 시스템에 대해 그런 제약을 알아낼 수 있는 파일 시스템 독립적 인터페이스는 현재 없다. 어떤 파일 시스템에서는 이를 위한 자체 인터페이스를 제공하기도 하는데, 예를 들어 xfsctl(3)XFS_IOC_DIOINFO가 있다.

리눅스 2.4에서는 전송 크기, 사용자 버퍼의 정렬, 파일 오프셋이 모두 파일 시스템의 논리적 블록 크기의 배수여야 한다. 리눅스 2.6.0부터는 기반 저장소의 논리적 블록 크기(보통 512바이트)에 정렬된 것으로 충분하다. ioctl(2) BLKSSZGET 동작을 이용하거나 셸에서 다음 명령을 사용해 그 논리적 블록 크기를 알아낼 수 있다.

blockdev --getss

메모리 버퍼가 비공유 매핑(즉 mmap(2) MAP_PRIVATE 플래그로 만든 매핑. 힙과 정적 할당 버퍼에 할당된 메모리 포함)이라면 절대 O_DIRECT I/O를 fork(2) 시스템 호출과 동시에 실행하지 말아야 한다. 그런 I/O가 있으면 비동기 I/O 인터페이스를 통해 제출된 것이든 프로세스의 다른 스레드에서 이뤄지는 것이든 fork(2) 호출 전에 완료돼야 한다. 그렇게 하지 않으면 부모 프로세스와 자식 프로세스에서 데이터 오염과 규정 안 된 동작이 발생할 수 있다. O_DIRECT I/O를 위한 메모리 버퍼를 shmat(2)이나 MAP_SHARED 플래그를 쓴 mmap(2)으로 만든 경우에는 이 제약이 적용되지 않는다. 또는 메모리 버퍼에 madvise(2)MADV_DONTFORK 조언을 줘서 fork(2) 후 자식에서 사용 가능하지 않게 만든 경우에도 이 제약이 적용되지 않는다.

O_DIRECT 플래그는 SGI IRIX에서 도입되었으며 거기서의 정렬 제약은 리눅스 2.4와 비슷하다. IRIX에는 적절한 정렬 및 크기를 질의할 수 있는 fcntl(2) 호출도 있다. FreeBSD 4.x에서 같은 이름의 플래그를 도입했는데 정렬 제약은 없다.

리눅스에서 O_DIRECT 지원이 추가된 건 커널 버전 2.4.10에서였다. 그 전의 리눅스 커널들은 이 플래그를 그냥 무시한다. 일부 파일 시스템에서 이 플래그를 구현하고 있지 않을 수 있으며, 그 경우 플래그를 쓰면 open()EINVAL 오류로 실패한다.

응용에서 같은 파일에 대해 O_DIRECT I/O와 보통 I/O를 섞어 쓰는 걸 피하는 게 좋으며 같은 파일의 겹치는 바이트 영역에 대해선 특히 그렇다. 파일 시스템에서 일관성 문제를 올바르게 처리한다 하더라도 전체 I/O 스루풋이 어느 한 모드만 쓰는 경우보다 느릴 것이다. 마찬가지로 응용에서 같은 파일에 대해 파일 mmap(2)과 직접 I/O를 섞어 쓰는 걸 피하는 게 좋다.

NFS에서 O_DIRECT의 동작 방식은 로컬 파일 시스템에서와 다르다. 구식 커널이나 특정 방식으로 구성한 커널에서는 그 조합을 지원하지 않을 수도 있다. NFS 프로토콜에서는 서버로 플래그를 전달하는 걸 지원하지 않으므로 O_DIRECT I/O는 클라이언트에서의 페이지 캐시만을 건너뛰게 된다. 즉 서버에서는 여전히 I/O를 캐싱 할 수 있다. 클라이언트에서 서버에게 I/O를 동기적으로 만들어 달라고 요청해서 O_DIRECT의 동기성 의미론을 유지한다. 그런데 어떤 서버는 이런 경우에, 특히 I/O 크기가 작을 때 성능이 나빠지게 된다. 또 어떤 서버는 클라이언트에게 I/O가 안정적 저장소에 도달했다고 거짓말을 하게 구성돼 있을 수도 있다. 그러면 성능 불이익은 피하지만 서버 전원 장애 시 데이터 무결성에 대한 위험을 얼마간 지게 된다. 리눅스 NFS 클라이언트에서는 O_DIRECT I/O에 대해 어떤 정렬 제약도 두지 않는다.

요컨대 O_DIRECT는 잠재적으로 강력한 도구이지만 주의해서 써야 한다. 응용에서 O_DIRECT 이용을 성능 개선 옵션으로 생각해서 기본적으로 비활성화해 두는 걸 권장한다.

BUGS

현재 open() 호출 시에 O_ASYNC를 지정해서 시그널 주도 I/O를 켜는 게 불가능하다. 그 플래그를 켜려면 fcntl(2)를 사용하라.

커널에서 O_TMPFILE 기능을 지원하는지 여부를 알아내려 할 때 두 가지 다른 오류 코드 EISDIRENOENT를 확인해야 한다.

flagsO_CREATO_DIRECTORY가 같이 지정돼 있고 pathname으로 지정한 파일이 존재하지 않을 때 open()이 정규 파일을 만들게 된다. (즉 O_DIRECTORY를 무시한다.)

SEE ALSO

chmod(2), chown(2), close(2), dup(2), fcntl(2), link(2), lseek(2), mknod(2), mmap(2), mount(2), open_by_handle_at(2), openat2(2), read(2), socket(2), stat(2), umask(2), unlink(2), write(2), fopen(3), acl(5), fifo(7), inode(7), path_resolution(7), symlink(7)


2021-03-22