-
UNIX file system에는 다음과 같은 4가지 파일 유형이 있다.
- 일반 파일(Ordinary file) - 텍스트 파일, 바이너리 파일, ...
- 디렉토리(Directory)
- 특수 파일(Special file) - 소켓, 디바이스, ...
- 지명(Named) - 지명 파이프(FIFO)
이런 파일들을 다루기 위해 유닉스 계열 운영체제는 파일의 정보와 관련된 구조체, 함수 등을 제공한다.
이 포스트에선 구조체를 기준으로 나누어 설명하도록 하겠다.
- struct stat
c에서는 일반 파일들의 정보를 저장할 수 있도록 stat 구조체를 제공한다.
또한 c에서는 아래와 같은 함수도 제공한다.
1. int stat(const char *pathname, struct stat *buf);
2. int lstat(const char *pathname, struct stat *buf);
3. int fstat(int fd, struct stat *buf);
struct stat buf; ... stat(pathname, &buf); lstat(pathname, &buf); int fd = open(pathname, O_RDONLY); fstat(fd, &buf);
세 함수 모두 파일의 정보를 읽어오는 함수이다. 하지만, 약간의 차이점이 존재한다.
1번 함수는 파일의 경로를 인자로 받아, 인자로 넣어주는 stat 구조체 buf에 해당 파일의 정보를 저장한다.
2번 함수는 1번과 동일하다. 단, 심볼릭 링크 파일의 경우,
링크가 가리키는 원본 파일의 정보가 아닌, 링크 파일 자체의 정보를 읽은다.
3번 함수도 1번과 동일하다. 단, 인자로 파일의 경로를 넣어주는 게 아닌, 파일 지시자를 넣어준다.
참고로, 링크에는 하드 링크(Hard link)와 심볼릭 링크(Symbolic link) 두 종류가 있는데,
하드 링크는 원본 파일과 동일한 inode를 가지는 링크로, 원본 파일을 삭제해도 하드 링크를 통해 접근이 가능하다.
심볼릭 링크는 원본 파일과 다른 inode를 가지는 링크로, 원본 파일을 가리키는 포인터이기 때문에,
원본 파일이 삭제되는 경우에는 접근이 불가능하다. (마치 바로가기 링크)
- struct passwd
c에서는 또한 사용자의 정보를 저장할 수 있도록 passwd 구조체를 제공한다.
또한 c에서는 아래와 같은 함수도 제공한다.
1. struct passwd *getpwuid(uid_t uid);
struct stat fileInfo; struct passwd *userInfo; ... stat(pathname, &fileInfo); userInfo = getpwuid(fileInfo.st_uid);
이 함수는 유저의 uid를 인자로 받아, 해당 uid에 해당하는 유저의 정보를 읽고
passwd 구조체 형태로 메모리 공간에 저장한 뒤, 그 메모리 공간에 대한 포인터를 반환한다.
위 코드는 파일의 정보를 읽고, 해당 파일의 주인에 해당하는 uid값을 getpwuid로 호출하여 유저 정보를 가져오는 코드이다.
- struct dirent
디렉토리는 일련의 디렉토리 엔트리로 구성되는데,
각 엔트리는 디렉토리에 포함되어 있는 파일이나 디렉토리의 inode 번호, 이름을 저장하는 문자 필드 등으로 구성된다.
특이하게, 디렉토리는 다른 파일들과 다르게 creat(), open() 함수를 통한 생성이 불가능하다.
c에서는 또한 디렉토리의 정보를 저장할 수 있도록 dirent 구조체를 제공한다.
또한 c에서는 아래와 같은 함수도 제공한다.
1. int chdir(const char *pathname);
2. char *getcwd(char *buf, size_t size);
char cwd[MAX_PATH_LEN + 1] = { '0\', }; ... chdir(".."); getcwd(cwd, MAX_PATH_LEN);
chdir은 pathname 경로로 현재 작업 디렉토리를 바꿔주고,
getcwd는 MAX_PATH_LEN 길이만큼 현재 작업 디렉토리 경로를 읽어와 cwd에 저장한다.
3. int mkdir(const char *pathname, mode_t mode);
4. int rmdir(const char *pathname);
#define PERMS 0755 ... mkdir("직박구리", PERMS);
현재 디렉토리 안에 직박구리 라는 이름의 폴더를 PERMS 권한으로 만든다.
rmdir 함수는 해당 이름의 비어있는 폴더를 삭제한다.
5. DIR *opendir(const char *pathname);
6. int closedir(DIR *dirp);
7. struct dirent *readdir(DIR *drip);
DIR *dirp; struct dirent *dirInfo; ... dirp = opendir(pathname); while ((dirInfo = readdir(dirp)) != NULL) { printf("inode No. %lld, Name: %s\n", dirInfo->d_ino, dirInfo->d_name); } closedir(dirp);
opendir 함수로 pathname에 해당하는 디렉토리의 디렉토리 스트림 핸들을 dirp로 받아온다.
readdir 함수로 디렉토리 스트림 핸들 dirp를 이용하여 디렉토리 정보을 읽고
dirent 구조체 형태로 메모리 공간에 저장한 뒤, 그 메모리 공간에 대한 포인터를 dirInfo에 저장한다.
같은 디렉토리 스트림 핸들을 readdir로 읽을 경우 읽었던 디렉토리 엔트리의 다음 엔트리를 계속해서 읽어온다.
즉, 위 코드와 같이 구현하면, 디렉토리 내의 모든 디렉토리 엔트리를 읽어올 수 있다.
마지막으로 closedir 함수를 이용하여 디렉토리 스트림 핸들을 닫아준다.