2006년 12월 22일 금요일

리눅스에서 2G 이상 파일 다루기

리눅스 커널 2.4부터 2기가 파일제한이 풀렸다.

커널만 지원한다고 다 해결될 일이 아니다. 표준함수를 쓴다면 표준 라이브러리(glibc에 뭉쳐 있겠지?)가 지원해야한다. 다행히 표준 라이브러리는 2기가 이상 파일(large file이라고 한다)을 지원한다.

단, 다른 이름으로 제공한다. 예를 들어 fopen이 있으면 fopen64가 따로 있다. off_t 역시 off64_t가 따로 존재한다. 또한 이 라이브러리를 사용하고 싶다면 _LARGEFILE_SOURCE를 정의해야한다. 즉 컴파일 옵션에 -D_LARGEFILE_SOURCE를 포함해야한다.

ㅡ_-); 불편하다. 그냥 fopen == fopen64 이렇게 쓸 수 없나? 소스 안 고쳐도 되고 말이야.

그래서 _FILE_OFFSET_BITS가 있다. 컴파일 옵션에 -D_FILE_OFFSET_BITS=64를 하면 모든 *64 함수/변수형은 기존 이름으로 바뀐다. 즉 소스에 fopen이라고 쓰더라도 fopen64를 호출한다.

ㅡ_-); 결국 2기가 이상 파일을 쓰려면 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64를 옵션으로 써야한다. (테스트해보니 _FILE_OFFSET_BITS만 64로 정의했어도 잘 돌아간다.)

테스트 코드 (offset.c)
#include <stdio.h>
#include <unistd.h>

int
main(int,char**)
{
        printf("fopen: %p\n", fopen);
        printf("fopen64: %p\n", fopen64);
        printf("size of off_t: %d\n", sizeof(off_t));
        return 0;
}

컴파일 결과
32bit CPU
$ gcc -o offset offset.c
$ ./offset
fopen: 0x80483dc
fopen64: 0x80483cc
size of off_t: 4
(fopen과 fopen64의 함수 주소 값이 다르다)

$ gcc -o offset offset.c -D_FILE_OFFSET_BITS=64
$ ./offset
fopen: 0x80483a8
fopen64: 0x80483a8
size of off_t: 8
(fopen과 fopen64의 함수 주소 값이 같다)

64bit CPU (x86_64)
$ gcc -o offset offset.c
$ ./offset
fopen: 0x4004f0
fopen64: 0x400510
size of off_t: 8
(fopen과 fopen64의 함수 주소 값이 다르다)

$ gcc -o offset offset.c -D_FILE_OFFSET_BITS=64
$ ./offset
fopen: 0x4004c0
fopen64: 0x4004c0
size of off_t: 8
(fopen과 fopen64의 함수 주소 값이 같다)


Fedora Core 6에서 x86_64(64bit cpu) 깔아서 해봤더니 옵션 없을 때 off_t 크기가 8로 나오더군. 그러나 fopen과 fopen64 주소값이 다른 걸로 보아, 될 수 있으면 _FILE_OFFSET_BITS를 세팅해주는 센스를 발휘하는게 좋을 듯 싶다.