File System
- OS는 의미있는 정보들을 파일 단위로 모아서 정리해준다.
- File System은 파일과 속성들의 집합이다.
- 파일의 위치나 이름 등을 별도로 관리한다.
- 디스크에 새 파일을 만들면 파일의 위치를 직접 접근하는 대신 파일 이름과 offset을 통해서 접근할 수 있게 해준다.
- 대부분의 파일 시스템은 트리 구조를 가지고 있다.

Directory
- 디렉토리는 파일의 한 종류이다.
- 디렉토리는 directory entrie를 포함하는 파일을 의미한다.
- directory entrie는 파일 이름과 offset의 쌍을 의미한다.
- 디렉토리는 안에 다른 파일을 포함할 수 있다.
Directory의 종류
- Root directory
- ‘/’
- 파일 시스템 트리에서 맨 위에 있는 디렉토리다.
- 모든 파일은 루트 디렉토리 아래(안)에 있다.
- Parent directory
- “..”
- 현재 작업중인 디렉토리의 부모 디렉토리를 나타낸다.
- Current working directory
- Home directory
- "~"
- 사용자 아이디와 암호를 가지고 시스템에 로그인 한 후 제일 처음으로 들어가는 디렉토리를 나타낸다.
- 보통 사용자 이름의 디렉토리다.
- Sub-directory
- 다른 디렉토리 안에 속해 있는 디렉토리를 나타낸다.
Pathname
- 작업 경로를 나타낼 수 있는 방식은 두가지가 있다.
- 절대 경로 : 무조건 "/"로 시작하며 루트부터 기준으로 파일 위치를 나타낸다.
- 상대 경로 : 현재 작업 디렉토리를 기준으로 파일 위치를 나타낸다.
Change Directory
#include <unistd.h>
int chdir(const char *path);
- chdir은 현재 디렉토리를 지정한 디렉토리로 바꾸는 명령어다.
- path : 내가 가고 싶은 디렉토리
- Return
- 만약 성공적으로 변경했으면 0을 반환한다.
- 만약 실패했으면 -1을 반환한다.
Get Current Directory
#include <unistd.h>
char *getcwd(char *buf, size_t size);
- getcwd는 현재 디렉토리를 알려주는 명령어다.
- buf : 현재 디렉토리를 buf에 저장한다(output).
- size : buffer의 크기
- Return
- 만약 성공적으로 변경했으면 buf를 반환한다.
- 만약 실패했으면 NULL을 반환한다
Buffer Size
Search Paths
- 실행 파일의 이름만 주게 되면, OS는 실행 파일의 이름을 PATH라는 환경 변수에 지정된 경로에서부터 찾는다.
- "which" 명령을 통해서 파일 이름에 따른 경로를 찾을 수 있다.
- 현재 작업 디렉토리를 추가하는, 다시 말해 PATH에 "."을 추가하는 방법은 편리하지만 보안상의 문제가 존재한다.
- 만약 악성 파일 "ls"를 누가 추가해놓는다.
- 사용자가 "ls"명령어를 사용한다.
- 이 때 PATH에 "."을 추가했으면 ls명령어가 사용되는 것이 아닌 악성 파일 "ls"가 실행 될 가능성이 존재한다.
Directory Access
- 프로그램 상에서 디렉토리를 참조하는 함수는 3가지가 있다.
- opendir
- closedir
- readdir
Opendir
- Opendir을 통해서 디렉토리를 열 수 있다.
#include <sys/types.h>
#include <dirent.h>
DIR *opendir (const char *dirname);
- const char *dirname : 열고자 하는 타겟 디렉토리의 이름을 의미한다
- return value
- 성공 : DIR pointer를 반환한다. , name of directory that we want to open
- 실패 : null pointer를 반환한다.
- DIR은 directory stream을 의미한다.
- directory stream은 타겟 디렉토리 안에 나열된 정보들의 sequence를 말한다.
Readdir
- Readdir을 통해서 디렉토리를 읽을 수 있다.
#include <sys/types.h>
#include <dirent.h>
struct dirent *readdir (DIR *dirptr);
- DIR *dirptr : 읽고자 하는 디렉토리의 directory stream을 의미한다.
- Readdir은 디렉토리 안의 entry값을 참조하고 있다. 참조값은 읽을 때마다 이동하며, file offset과 비슷한 역할을 한다고 볼 수 있다.
- return value
- 성공 : 첫번째 디렉토리 entry값이 구조체 dirent * 형태로 반환된다. 이후 다음으로 옮겨간다.
- 실패 : null pointer를 반환한다.
- 구조체 dirent는 여러개의 요소가 있지만 중요한 건 아래 두가지다.
- ino_t : inode 번호
- char : 파일이름
Closedir
- Closedir을 통해서 디렉토리를 닫을 수 있다.
#include <dirent.h>
int closedir (DIR *dirptr);
- DIR *dirptr : 닫고자 하는 디렉토리의 directory stream을 의미한다.
- return value
- 성공 : 0을 반환한다.
- 실패 : -1을 반환한다.
Rewinddir
- Readdir를 사용하면 디렉토리에서 참조하는 entry값이 자동으로 변한다.
- Rewinddir은 참조하는 entry값을 최초로 되돌린다.
#include <dirent.h>
int rewinddir (DIR *dirptr);
- DIR *dirptr : 처음으로 되돌리고자 하는 디렉토리의 directory stream을 의미한다.
- 파일을 만들게 되면 그 파일에 대한 여러가지 정보가 존재한다.
- 파일의 정보를 얻을 수 있는 함수는 2가지가 있다.
- lstat : 링크 파일에 대한 정보를 반환한다.
- stat : 링크가 가리키고 있는 원본 파일의 정보를 반환한다.
- 이 두가지 정보는 파일 경로가 symbolic link일 때 사용한다.
#include <sys/stat.h>
int lstat(const char *restrict path, struct stat *restrict buf);
int stat(const char *restrict path, struct stat *restrict buf);
구조체 stat structure

Defined in sys/stat.h
- dev_t st_dev;
- 파일을 포함하고 있는 Device의 Device ID
- ino_t st_ino;
- mode_t st_mode;
- nlink_t st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- off_t st_size;
- time_t st_atime;
- time_t st_mtime;
- time_t st_ctime;
UNIX File Implementation
- POSIX는 파일의 타입을 크게 구분하지 않는다. 대부분 사용자의 편의를 위해 파일을 구분한다.
- 그 대신 유닉스는 tree structure를 통해 파일을 정리한다.
- 디렉토리는 파일 이름과 파일을 찾아갈 수 있는 inode를 가진다.
inode
- 파일이 생성되었을 때, 파일에 대한 정보를 저장하는 데이터 구조를 inode라고 한다.
- 모든 파일은 inode를 표시하는 inode number를 부여받는다.
- inode는 다음과 같은 파일의 정보를 저장한다.
- user나 group의 ownership
- 엑세스 모드
- 파일의 타입
- stat structure의 요소들
- ...
- 시스템에서 만들 수 있는 inode의 개수는 정해져 있다.
- inode의 크기는 고정되어 있다.

- file information : 파일에 대한 정보를 저장한다.
- direct pointers : 파일 블럭을 직접 가리킨다. 다이렉트 포인터를 따라가면 직접 파일에 접근할 수 있다.
- indirect pointer : 간접적으로 파일을 가리키는 포인터다.
- single indirect pointer : 한 단계 거쳐서 파일을 가리킨다. 인다이렉트 포인터는 포인터 블럭을 가리키게 된다. 이 포인터 블럭 안에는 다이렉트 포인터가 쌓여 있기 때문에, 포인터 블럭의 요소들을 참조해서 파일에 직접 접근할 수 있다.
- double indirect pointer : 두 단계 거쳐서 파일을 가리킨다. 더블 인다이렉트 포인터는 싱글 인다이렉트 포인터를 가리킨다. 그러므로 싱글 인다이렉트 포인터보다 큰 파일을 참조할 수 있다.
- triple indirect pointer : 세 단계 거쳐서 파일을 가리킨다. 더블 인다이렉트 포인터와 하는 일이 비슷하며, 엄청나게 큰 파일에 접근할 때 사용한다.
Directory implementation
- 디렉토리 또한 하나의 파일이다. 디렉토리 타입의 파일인 것이다.
- 디렉토리는 파일 이름과 파일 경로를 가지고 있다.
- 디렉토리 = inode number + filename
- inode에 접근하는 방법은 다음과 같다.
- 프로그램은 경로 이름을 통해서 파일에 접근한다.
- OS는 root directory에서부터 하나씩 접근하며 파일 이름과 inode number를 찾는다.
- OS가 inode number를 찾으면 이를 통해 파일에 직접적으로 접근 가능하다.
- inode + filename 구조를 통해 얻는 이점은 다음과 같다.
- 파일 이름을 바꿀 때 directory entry만 바꾸면 되는 것이므로 간편하다.
- 파일의 경로를 바꿀 때 directory entry만 바꾸면 되는 것이므로 간편한다.
- 디스크 상에 물리적인 실체는 하나만 존재해도 그 파일을 나타내는 이름은 여러개가 존재할 수 있다. 예를 들어 바로가기 같은 경우는 파일을 복사할 필요가 없이 같은 directory entry를 가지는 파일을 추가하면 된다.
- directory entry는 파일 크기가 작기 때문에 용량이나 성능면으로도 큰 이점이 생긴다.
inode pointer의 예시
어떤 inode 객체가 128 bytes이고, 포인터는 4 bytes이며, status information은 68 bytes를 차지한다고 가정해보자.
- 블럭의 사이즈는 8K bytes이고 block pointers는 4 bytes라고 가정한다.
- 이 inode안에 direct pointers는 얼마나 있는가?
– single, double, triple indirect pointers는 4 bytes씩 차지한다.(12 bytes)
– 128-68-12 = 48 bytes -> 48/4 = 12 direct pointers
- direct pointer를 가지고 얼마나 큰 파일을 가리킬 수 있는가?
- 8K = 8 * 2^10 bytes
- 8192 * 12 = 98,304 bytes
- singel indirect pointers는 얼마나 큰 파일을 가리킬 수 있는가?
- single indirect pointer는 8K 블럭을 가리킨다. 8K 블럭은 8192/4 = 2048 pointers 개의 direct pointer를 가질 수 있다.
- 2048 * 8192 = 16,777,216 bytes
- (2 2^10) (8 2^10) = (2 8) * (2^20) = 16 MB
Hard Links and Symbolic Links
- Link는 filename과 inode간의 관계를 표현한 것이다.
- UNIX는 두 가지의 Link를 가진다.
- Hard Link
- Symbolic Link(Soft Link)
- Directory entiy는 hard link로 불린다. 왜나하면 filename과 inode를 직접 연결시키기 때문이다.
- Symbolic Link는 간접적인 연결을 한다. Symbolic Link는 하나의 파일이다. 이 파일은 원본 파일로 가는 경로를 가지고 있다. 이후 경로를 다시 탐색해서 원본 파일으로 접근한다.
- 어떤 inode를 가리키는 hard link는 여러개가 있을 수 있다. 그렇기 때문에 inode는 자신을 가리키고 있는 hard link의 개수를 가지고 있다.
Hard Link
- Hard link는 하드디스크상의 inode를 찾아갈 수 있는 직접적인 pointer 정보를 가지고 있다.
- 같은 파일을 가리키는 Hard link가 여러개일 수 있다.
- 어떠한 파일을 Hard link를 통해서 접근한다. 이 때 다른 이름을 통해서 접근하면, 모든 변경은 원본 파일에 영향을 준다.
- Hard link는 같은 파일 시스템 안에서만 통한다.
- 기존 파일을 가리키는 새로운 Hard link를 생성할 수 있으며 directory entry만 추가된다.
- ln 명령어를 사용하면 Hard link를 생성할 수 있다.
- 새로운 Hard link를 생성하면 inode의 link count가 증가하며, Hard link를 삭제하면 참조하던 inode의 link count가 감소한다.
#include <unistd.h>
int link (const char *path1, const char *path2);
int unlink (const char *path);
- link
- path1 : 원본 파일의 경로명
- path2 : 새롭게 만들어진 hardlink의 경로명
- unlink
Link Counter
- 대부분의 파일 시스템은 위에서 말한 Hard Link를 구현한다.
- inode가 언제 필요없는지를 확인하기 위해 Link Counter가 필요하다.
- Link Counter는 integer값이다.
- Link Counter는 자신을 참조하는 Hard Link값을 나타낸다.
- 새로운 Hard link가 생기면 Link Counter값은 증가한다.
- 기존에 참조하던 Hard Link가 없어지면 Link Counter값은 감소한다.
- Hard Link값이 0이 되면 시스템은 대부분 inode 자체를 삭제한다(파일을 삭제한다).
Symbolic Links
- Symbolic Link는 filname과 inode간에 간접적인 영향을 가지는 Link이다.
- Symbolic Link를 만들면 Symbolic Link라는 파일을 만들게 된다.
- 이 파일은 원본 파일의 경로를 가지고 있다.
- OS는 Symbolic Link의 파일을 열면 경로를 발견하게 된다.
- 이후 탐색을 중단하는 것이 아니라 다시 경로를 탐색한다.
- Symbolic Link를 만들려면 ln 명령어에 -s라는 옵션을 준다.
- Symbolic Link는 inode의 link count에 영향을 주지 않는다.
#include <unistd.h>
int symlink (const char *path1, const char *path2);
- symlink
- path1 : 원본 파일의 경로명
- path2 : 새롭게 만들어진 hardlink의 경로명