파일을 크게 만드는 것만으로 공간이 확보되지는 않습니다
ftruncate로 파일 길이를 늘려도 확장된 영역이 실제 디스크 블록으로 모두 할당된다는 보장은 없습니다. 희소 파일을 지원하는 파일시스템에서는 hole로 남을 수 있습니다. 파일의 논리적인 길이와 저장 장치에 확보한 공간은 구분해야 합니다.
| 작업 | 기대할 수 있는 결과 |
|---|---|
ftruncate(fd, size) | 파일의 논리적인 길이를 조절합니다. 길이를 늘렸다고 전체 영역의 블록을 미리 예약하는 것은 아닙니다. |
posix_fallocate(fd, offset, len) | 지정 범위에 필요한 공간을 확보합니다. 성공하면 그 범위의 쓰기가 디스크 공간 부족 때문에 실패하지 않도록 합니다. |
fsync(fd) | 변경 내용을 저장 장치에 반영하는 동작입니다. 공간 예약과는 목적이 다릅니다. |
공간을 예약해도 장치 I/O 오류, 잘못된 파일 디스크립터, 신호로 인한 중단 등 다른 쓰기 실패가 모두 사라지는 것은 아닙니다. 데이터가 영구 저장되었다는 보장도 별도로 다뤄야 합니다.
posix_fallocate는 오류 번호를 직접 반환합니다
int error = posix_fallocate(fd, 0, length);
if (error != 0) {
fprintf(stderr, "posix_fallocate: %s\n", strerror(error));
}성공하면 0이고, 실패하면 ENOSPC 등의 오류 번호가 반환값입니다. 일반적인 시스템 호출처럼 == -1로 검사하거나 곧바로 perror를 호출하면 다른 오류를 설명할 수 있습니다. errno를 설정하는 fallocate(2)와도 반환 규칙이 다릅니다.
- posix_fallocate반환값 0: 성공 / 0이 아님: 그 값이 오류 번호
- 일반적인 -1·errno 방식반환값 -1을 확인한 뒤 errno를 읽습니다.
상자는 실행 순서가 아니라 API 반환 규칙의 비교입니다. 같은 파일 할당 작업이라도 함수별 규칙을 확인해야 합니다.
새 임시 파일에 1MiB를 확보합니다
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
char name[] = "./preallocate-XXXXXX";
int fd = mkstemp(name);
if (fd == -1) { perror("mkstemp"); return 1; }
if (unlink(name) == -1) {
perror("unlink"); close(fd); return 1;
}
int error = posix_fallocate(fd, 0, 1024 * 1024);
if (error != 0) {
fprintf(stderr, "posix_fallocate: %s\n", strerror(error));
close(fd);
return 1;
}
struct stat st;
if (fstat(fd, &st) == -1) {
perror("fstat"); close(fd); return 1;
}
printf("logical size=%lld bytes\n", (long long)st.st_size);
if (close(fd) == -1) { perror("close"); return 1; }
return 0;
}cc -std=c17 -Wall -Wextra preallocate.c -o preallocate로 빌드합니다. 실행하는 디렉터리의 파일시스템에 임시 파일을 만듭니다. 성공하면 논리 크기 1048576바이트를 출력하고, 마지막 열린 참조를 닫을 때 파일 공간을 회수합니다.
| 코드 | 상태 변화 |
|---|---|
mkstemp | 기존 파일을 덮어쓰지 않고 새 임시 파일을 만듭니다. 수정 가능한 문자 배열로 이름을 전달합니다. |
unlink | 디렉터리의 이름을 제거합니다. fd가 열려 있으므로 파일 객체는 계속 사용할 수 있습니다. |
posix_fallocate | 빈 파일의 처음 1MiB에 공간을 확보합니다. 파일 크기도 그 범위까지 늘어납니다. |
fstat | fd가 가리키는 파일의 크기를 읽습니다. |
close | 이 예제의 마지막 열린 참조를 닫습니다. |
파일시스템과 C 라이브러리의 차이를 확인합니다
파일시스템이 직접 할당 기능을 지원하지 않을 때 일부 C 라이브러리는 다른 방식으로 동작을 흉내 낼 수 있습니다. glibc의 대체 구현에는 동시 쓰기·크기 변경과의 경쟁 문제가 있으므로, 여러 스레드가 이미 쓰는 파일에 무조건 안전하다고 설명하면 안 됩니다. 위 예제는 새 파일을 만든 한 프로세스가 먼저 공간을 확보합니다.
Linux 전용 fallocate는 KEEP_SIZE 등 추가 동작을 제공하지만, 지원하는 모드는 파일시스템마다 다릅니다. 지원하지 않는다는 오류를 받았을 때의 처리도 정해야 합니다.