Best buffer size to store pathnames, PATH_MAX
Buffer size to store pathnames
보통 filename (또는 file name)이라고 하면 어떤 파일 이름 그 자체를
나타냅니다 (예: "hello.c" 또는 "src") 그리고 pathname이라고 하면
filename 또는 이 파일의 위치 정보까지 포함된 문자열을 뜻합니다. (예:
"/usr/bin
", "./a.out
", "/home/cinsk/.emacs
" 등) 이 때 pathname은 보통
root 디렉토리에서 시작하느냐의 여부에 따라 absolute pathname
(절대경로) 또는 relative pathname (상대 경로)로 나타냅니다. Absolute
pathname의 경우, "/"로 시작하는 pathname입니다.
파일 또는 디렉토리를 다루는 프로그램을 작성하다보면, filename이나
pathname을 취급할 경우가 많은데, 이 때 주어진 pathname을 저장하기
위해, 흔히 적당히 큰 문자 배열을 준비하고 쓰는 경우가 많습니다. 이런
식으로 작성한 프로그램은 적당히 크다고 생각한 값이 별로 크지 않을
경우, 버그가 발생할 수도 있으며, 나중에 수정하기도 꽤
어렵습니다. 따라서 이 경우에는 POSIX가 정의하고 있는
PATH_MAX
란 상수를 쓰는 것이 바람직합니다.
PATH_MAX
는 패스 이름이 가질 수 있는 최대 글자 수를 나타냅니다. 패스
이름이란 디렉토리 이름을 포함한 파일 이름을 뜻합니다. (예:
"/usr/bin/ls
", "/opt/share/info
"). 문자열의 끝을 나타내는 '\0
'도
포함입니다. 따라서 정확히 파일이 가질 수 있는 글자 수의 총 길이는
PATH_MAX - 1
이 됩니다.
따라서 파일 이름을 처리하거나 저장할 경우, PATH_MAX
크기의 메모리
공간을 준비해 놓고 작업하면 됩니다. 예를 들면 다음과 같습니다:
void foo(const char *pathname)
{
char buf[PATH_MAX];
buf[0] = '\0';
strncpy(buf, pathname, PATH_MAX - 1);
...
}
인생이 이렇게 단순했으면 얼마나 좋겠습니까만… 사실 이게 전부가 아닙니다.
먼저, POSIX 호환 시스템이라 하더라도 PATH_MAX
가 정의되어 있지 않은
경우가 있습니다. 왜 정의가 되어 있지 않냐면, 파일 이름의 길이 제한이
파일 시스템마다 달라질 수 있기 때문입니다. 예를 들어 무조건 한 파일
시스템만 사용하는 OS나, 여러 파일 시스템을 지원하더라도 파일 길이
제한의 값이 같은 OS라면 PATH_MAX
가 정의되어 있습니다. 하지만, 만약 여러
파일 시스템을 지원하고, 또 각 파일 시스템마다 지원하는 최대 파일 이름
길이가 다르다면, 단순히 한 상수로 최대 파일 이름 길이를 나타낼 수
없습니다.
또한, 드물지만, 파일 이름 길이에 제한이 없다면, PATH_MAX
가 정의되어
있지 않습니다.
둘째, PATH_MAX
가 정의되어 있다 하더라도, 이 매크로가 배열의 크기로
쓰기에는 너무나 큰 상수일 가능성이 있습니다. 따라서 다음과 같이, 배열의
크기를 지정하는 목적으로 PATH_MAX
를 쓰는 것은 별로 바람직한 방법은
아닙니다. (저도 여유가 없으면 자주 쓰는 방식이긴 하지만.. -_-;;)
char buf[PATH_MAX];
세째, PATH_MAX
의 정확한 뜻에 관한 것입니다. PATH_MAX
는 임의의 한
pathname이 가질 수 있는 최대 값을 나타내는 것이 아닙니다. 다시 말해,
PATH_MAX
보다 큰 pathname이 존재할 수도 있습니다. 여기에 관한 것은 바로
뒤에 pathconf(3)를 설명할 때 다루겠습니다.
그럼 PATH_MAX
가 정의되어 있지 않다면 어떻게 pathname의 최대값을 얻을 수
있느냐? 답은 pathconf(3)나 fpathconf(3)를 쓰는 것입니다.
#include <unistd.h>
long fpathconf(itn filedes, int name);
long pathconf(const char *path, int name);
두 함수 모두, pathname에 관련된 정보를 얻는 목적으로 쓰이며,
fpathconf()는 이미 열려있는 file descriptor를, pathconf()는
파일/디렉토리 이름을 첫 인자로 받습니다. PATH_MAX
의 값을 얻으려면 두
함수 모두 두번째 인자에 _PC_PATH_MAX
를 주면 됩니다.
왜 file descriptor나 파일/디렉토리 이름이 필요한지 궁금해 하는 분도 있을 것입니다. 그 이유는, 앞에서 잠깐 말했듯이, pathname의 최대값은 현재 파일 시스템에 따라 달라질 수 있기 때문에, 기준이 되는 파일/디렉토리 이름이 필요하기 때문입니다.
이 두 함수 모두, 다른 정보를 얻기 위해 사용되기도 합니다. 예를 들어,
단순한 파일 이름의 최대값을 얻으려면 위 함수의 두번째 인자로
_PC_NAME_MAX
를 사용합니다. 또 주어진 파일이 pipe (또는 FIFO)인 경우,
파이프 버퍼의 크기를 얻기 위해 _PC_PIPE_BUF
를 쓸 수도 있습니다.
한가지 주의할 것은 이 때 얻은 PATH_MAX
값의 정확한 뜻입니다. 두 번째
인자로 _PC_PATH_MAX
를 쓸 경우, 첫 번째 인자로 전달한 파일 이름이나
file descriptor는 반드시 디렉토리에 대한 이름 또는 file
descriptor이어야 합니다. 첫 번째 인자가 디렉토리를 가르킬 경우, 이 때
리턴한 값은 주어진 디렉토리를 기준으로한 상대 경로가 가질 수 있는 최대
길이를 뜻합니다. 만약 첫번째 인자가 디렉토리를 가리키지 않는다면, 리턴
값과 주어진 파일과 어떤 관계가 있다는 것을 보장할 수 없습니다. 또한
pathname의 길이에 대한 제한이 없는 경우, 이 두 함수는 -1을 리턴하고
errno를 설정하지 않습니다.
추가적으로, POSIX는 _POSIX_PATH_MAX
란 매크로를 256으로 정의하고
있습니다. 그리고 PATH_MAX
는 적어도 _POSIX_PATH_MAX
와 같거나 큰 값을
가져야한다고 정의합니다. 또 오래된 유닉스 시스템은 전통적으로
MAXPATHLEN이란 매크로를 쓰는 경우가 많습니다. (주의, 필자는
MAXPATHLEN의 정확한 뜻이나 유래에 대해 잘 모릅니다. 아시는 분은 제게
알려주시면 고맙겠습니다.)
또, ISO C 표준은 파일 이름을 저장하기 위한 배열의 크기를 지정할
목적으로 FILENAME_MAX
란 매크로를 <stdio.h>
에 정의하고 있습니다. 이
매크로는 배열을 선언할 때 쓸 목적으로 만든 것이기 때문에 다음과 같이
쓰는 것이 가능합니다:
char buf[FILENAME_MAX];
하지만, 사용가능한 파일의 최대 길이가 제한이 없는 경우라면, 문자 배열의
크기로 쓸만한 값을 FILENAME_MAX
로 정의한다고 나와 있습니다. 따라서
파일의 최대 길이가 제한이 없는 경우라면 pathconf()나 fpathconf()를
써야만 알 수 있습니다. (errno 변경없이 -1을 리턴)
따라서 이식성이 뛰어난 프로그램을 만들고 싶다면 다음과 같은 코드를 헤더 파일에 포함시키는 것도 좋을 것입니다:
#include <unistd.h>
#include <limits.h>
#ifndef _POSIX_PATH_MAX
#define _POSIX_PATH_MAX 256
#endif
#if !defined =PATH_MAX= && defined _PC_PATH_MAX
# define PATH_MAX (pathconf("/", _PC_PATH_MAX) < 1 ? 1024 \
: pathconf("/", _PC_PATH_MAX))
#endif
#if !defined PATH_MAX && defined MAXPATHLEN
# define PATH_MAX MAXPATHLEN
#endif
#if !defined PATH_MAX && defined FILENAME_MAX
# define PATH_MAX FILENAME_MAX
#endif
#ifndef PATH_MAX
# define PATH_MAX _POSIX_PATH_MAX
#endif
물론 완벽한 것은 아닙니다. 사실 위 코드는 gnulib 패키지의 <pathmax.h>를 조금 손본 것이며, pathname 길이에 제한이 없는 경우는 고려하지 않았습니다.
Summary
지금까지 내용을 요약해 보면,
- pathname을 저장하기 위해,
PATH_MAX
를 쓰는 것은 바람직하나,PATH_MAX
보다 큰 pathname이 존재할 수도 있다는 것. -
PATH_MAX
를 쓸 경우, 동적으로 메모리를 할당하는 방식 (예: malloc() 함수)을 쓰는 것이 바람직하다는 것. -
PATH_MAX
는 마지막 '\0'도 포함한다는 것. 즉PATH_MAX
+ 1과 같은 형태로 쓸 필요가 없다는 것. -
PATH_MAX
가 정의되어 있지 않을 경우, pathconf(3) 또는 fpathconf(3)를 써서PATH_MAX
의 값을 얻을 수 있다는 것. - 세번째 목적으로 pathconf(3)나 fpatconf(3)를 쓸 때, 첫번째 인자는 디렉토리를 가리키고 있어야 한다는 것입니다.
마지막으로, FILENAME_MAX
를 제외한 모든 매크로, 함수는 SUS 표준
(POSIX)이며, ISO C 표준에는 나와 있지 않다는 것을 말해 둡니다.
댓글
Comments powered by Disqus