CH39 파일과 디렉터리 #2 디렉터리
39.11 디렉터리 생성
디렉터리 관련 시스템 콜들은 디렉터리를 생성하고, 읽고, 삭제하지만 디렉터리에는 절대로 직접 쓸 수 없다
디렉터리는 파일 시스템의 메타데이터로 분류되며 파일 시스템이 디렉터리의 무결성을 책임져야 하므로 항상 간접적으로만 변경된다
🐣 디렉터리는 단순히 데이터를 저장하는 "일반 파일" 이 아니고, 파일 시스템에서 특정 파일들의 위치와 이름 정보를 관리하는 구조체이다 디렉터리 내부에는 파일 이름, 파일 속성, inode 번호 등 중요한 정보가 포함되기 때문에 파일 시스템은 디렉터리의 구조와 무결성을 유지해야 한다, 비유하자면, 파일과 관련된 중요한 책장을 관리하는 사서 같은 존재라서 사서의 허락 없이는 책장에 손을 댈 수 없다
디렉터리를 생성할 때는 mkdir() 시스템 콜을 사용한다, 디렉터리가 처음 생성되면 빈 상태로 보이지만
빈 디렉터리에는 디렉터리 자신과 자신의 부모 디렉터리를 가리키는 항목이 존재한다
int mkdir(const char *pathname, mode_t mode);
성공하면 0, 실패하면 -1 을 리턴한다, 실패 시 오류 원인을 나타내는 값이 errno 에 설정된다
디렉터리 자신은 '.' (dot) 으로, 부모 디렉터리는 '..' (dot-dot) 이라고 표현한다
39.12 디렉터리 읽기
ls 명령어로 디렉터리를 읽을 수 있지만, opendir(), readdir(), closedir() 을 사용할 수도 있다
간단한 반복문을 사용하여 디렉터리 항목을 하나씩 읽고, 디렉터리의 각 파일의 이름과 아이노드 번호를 출력한다
int main (int argc, char *argv[]) {
DIR *dp = opendir(".");
asssert (dp != NULL);
struct dirent *d;
while ((d = readdir(dp)) != NULL) {
printf("%lu %s\n", (unsigned long) d_.di_into, d->d_name);
}
closedir(dp);
return 0;
}
🐣 디렉터리는 파일 이름과 inode 번호를 매핑한 데이터구조이다 🐣
/home/user/
├── file1.txt (inode 101)
├── file2.txt (inode 102)
└── subdir/ (inode 103)
각 디렉터리 항목에 저장된 struct dirent 자료 구조 형태는 아래와 같다
/* struct dirent 자료 구조 형태 */
struct dirent {
char d_name[256]; // 파일 이름
ino_t d_ino; // 아이노드 넘버
off_t d_off; // 다음 dirent 까지의 오프셋
unsigned short d_reclen; // 이 레코드의 길이
unsigned char d_type; // 파일 타입
};
디렉터리에는 많은 정보가 있지 않기 때문에, 프로그램은 각 파일에 stat() 을 호출하여 구체적인 정보를 얻는다
ls 도 -l 플래그를 전달받았을 때 추가 정보를 얻기 위해 stat() 을 호출한다
39.13 디렉터리 삭제하기
디렉터리를 삭제할 때는 rmdir() 시스템 콜을 사용한다, 디렉터리를 삭제할 때 아주 많은 양의 데이터를 지울 수 있기 때문에
rmdir() 으로 디렉터리를 지우기 전에는 디렉터리가 비어 있어야 한다, 비어 있지 않은 디렉터리에 rmdir() 을 호출하면 실패한다
🐣 비어 있지 않은 디렉터리를 지우기 위해서는 다른 명령어가 추가로 필요하다 🐣
39.14 하드 링크
link() 시스템 콜은 파일 시스템 트리에 항목을 추가하는 시스템 콜이다
원래의 경로명과 새로운 경로명을 인자로 받아, 원래 파일 이름에 새로운 이름을 "link (연결)"하여 동일한 파일을 접근할 수 있다
prompt> echo hello > file
prompt> cat file
hello
prompt> ln file file2
prompt> cat file2
hello
link() 는 새로 링크하려는 이름 항목을 디렉터리에 생성하고, 원래 파일과 같은 아이노드 번호를 가리키도록 한다
파일은 복사되지 않고, 대신 같은 파일을 가리키는 두 개의 이름이 생성된다
즉, link() 는 동일한 아이노드 번호에 대한 새로운 링크를 생성하고, 파일 이름은 다르지만 동일한 메타데이터를 공유하여 데이터가 유지된다고 볼 수 있다
파일을 생성할 때는 1) 파일과 관련 거의 모든 정보를 관리하는 자료 구조 (아이노드) 를 만든다
2) 해당 파일에 사람이 읽을 수 있는 이름을 연결하고 그 연결 정보를 디렉터리에 생성한다
아이노드 번호의 참조 횟수 Reference Count (때로는, 연결 횟수 Link Count) 는 특정 아이노드에 대해 다른 이름이 몇 개나 연결되어 있는지 관리하고, unlink() 가 호출되면 이름과 해당 아이노드 번호 간의 "연결"을 끊고 참조 횟수를 하나 줄인다
참조 횟수가 0에 도달하면 파일 시스템은 아이노드와 관련된 데이터 블럭을 해제하여 파일을 진정으로 "삭제"한다
(참조 횟수는 stat 명령어를 사용하여 확인할 수 있다)
🐣 우리가 보는 파일명은 포인터라고 생각하면 된다, 실제로 컴퓨터가 식별하는 정보는 inode 번호이다
파일 이름은 inode 번호를 가리키는 포인터이다, 처음 만드는 파일 이름이 첫 하드 링크이다
하드 링크는 inode를 공유해서 데이터의 새 이름을 만드는 것이고, 파일 복사는 데이터를 완전히 독립적으로 복제하는 것이다 🐣
39.15 심볼릭 링크
하드 링크는 제한이 많다
1. 디렉터리에 대해서는 하드 링크를 만들 수 없다 - 디렉터리 트리에 순환 구조를 만들 것을 우려하여
2. 다른 디스크 파티션에 있는 파일에 대해서 하드 링크를 걸 수 없다 - 아이노드 번호는 하나의 파일 시스템 내에서만 유일하다
그래서 새로운 종류의 심볼릭 링크 Symbolic Link, 소프트 링크 Soft Link 가 만들어졌다
심볼릭 링크를 만들기 위해서는 ln 프로그램에 -s 플래그를 전달해야 한다
prompt> echo hello > file
prompt> ln -s file file2
prompt> cat file2
hello
하드 링크와 비교했을 때 심볼릭 링크가 다른 점은, 심볼릭 링크는 다른 형식의 독립된 파일이라는 점이다
🐣 파일 시스템은 파일, 디렉터리, 심볼릭 링크를 관리하고 있고, 파일 시스템이 관리하는 것은 큰 맥락에서 파일이라고 볼 수 있다
그리고 심볼릭 링크는 아이노드를 가지고 있고, 아이노드를 가지고 있는 것은 파일이라고 볼 수 있다
파일과 포인터를 구분해야 한다 🐣
심볼릭 링크는 파일 시스템에 존재하는 (파일, 디렉터리 다음으로) 세번째 종류의 유형이다
ls -al 에서 긴 형식의 첫 글자가 - 이면 일반 파일, d 는 디렉터리, 1 은 소프트 링크를 나타낸다
심볼릭 링크는 연결의 대상도 보여주고 (file2->file)
파일의 데이터가 아닌, 연결하는 파일의 경로명을 저장한다 (그래서 크기가 4 임)
하드 링크와 달리, 원래 파일인 file 을 삭제하면 심볼릭 링크가 가리키는 실제 파일은 더 이상 존재하지 않기 때문에
Dangling Reference 라는 문제가 발생할 수도 있다
🐣 Dangling Reference 유효하지 않거나 존재하지 않는 메모리를 참조하는 상태이다
심볼릭 링크는 파일 경로를 가리키는 포인터처럼 동작한다, 만약 심볼릭 링크가 가리키는 대상 파일이 삭제되거나 이동되면, 심볼릭 링크는 여전히 존재하지만 더이상 유효한 파일을 참조하지 못하는 상태가 된다 🐣
구분 | 하드 링크 Hard Link | 심볼릭 링크 Symbolic Link |
정의 | 동일한 파일 시스템 내에서 원본 파일의 또 다른 이름 | 원본 파일 경로를 참조하는 별도의 파일 |
파일 시스템 제약 | 동일한 파일 시스템에서만 생성 가능 | 다른 파일 시스템 간에도 생성 가능 |
파일 삭제 시 | 원본 파일이 삭제되어도 하드 링크는 접근 가능 (모든 링크 삭제 시에 데이터 삭제) |
원본 파일이 삭제되면 접근 불가 (링크가 깨짐) |
용량 차지 여부 | 추가 용량을 차지하지 않음 | 링크 파일 자체가 추가 용량을 차지 |
동작 방식 | 원본 파일의 inode 를 공유 | 원본 파일의 경로를 저장 |
디렉터리 링크 | 디렉터리에 하드 링크 생성 불가 | 디렉터리에도 심볼릭 링크 생성 가능 |
구현 명령어 | ln [원본 파일] [하드 링크] | ln -s [원본 파일] [심볼릭 링크] |
속도 | 비교적 빠름 (inode 직접 접근) | 약간 느림 (원본 경로를 탐색) |
유효성 | 파일과 링크가 동일한 inode 번호를 공유 | 별도의 inode 번호를 가진다 |
39.16 권한 비트와 접근 제어 목록
파일 시스템 역시 디스크에 대한 가상화를 제공하지만, CPU와 메모리의 가상화와는 다르게
파일은 일반적으로 다수의 사용자들과 다수의 프로세스들이 공유한다
파일 시스템은 고유 범위를 한정하는 다양한 기법들을 제공한다
1. 권한 비트 Permission Bits
ls -l 을 출력한 결과의 앞 부분 중 맨 앞 글자는 파일의 종류를 나타내고 ( - 일반 파일, d 디렉터리, 1 심볼릭 링크 )
그 이후 아홉 개의 글자들은 세 개의 그룹의 권한을 나타낸다
처음 세 개의 비트는 소유자 Owner 의 권한, 다음 세 개의 비트는 그룹 Group 의 권한,
마지막 세 비트는 나머지 사용자 Other 가 할 수 있는 일을 나타내고, 각각 읽기, 쓰기, 실행하기의 권한을 나타낼 수 있다
🐣 읽기 r, 쓰기 w, 실행 x 🐣
파일의 소유자가 chmod 명령을 사용하면 파일 모드 File Mode 와 권한의 설정을 바꿀 수 있다 🐣 chmod 는 change mode 🐣
소유자만 파일을 접근할 수 있도록 바꾸려면 읽기 비트 (4) 와 쓰기 비트 (2) 를 켜서 (OR 연산으로 6 을 얻어) 아래와 같이 설정할 수 있다
prompt> chmod 600 foo.txt
// 결과 rw-------
디렉터리의 경우는 실행 비트가 설정되어 있으면 사용자가 (또는 그룹이나 그 외 사람들) 가 다른 위치로 디렉터리를 변경 (cd) 할 수 있고, 쓰기 비트도 설정되어 있으면 해당 디렉터리에서 파일도 생성할 수 있다
권한 설정 비트 외에도 AFS 와 같은 분산 파일 시스템에서 접근 제어 목록 Access Control List, ACL 으로 누가 특정 자원을 접근할 수 있는지 좀 더 일반적으로 강력한 방법으로 표현할 수 있다
파일 시스템은 소유자/ 그룹/ 그 외 라는 어느 정도 제한된 구조를 갖고 있는 것에 반해
AFS 는 특정 파일들에 대해 읽기 가능 여부가 표시된 사용자들의 목록을 생성할 수 있다
prompt> fs listacl private
Access list for private is
Normal rights:
system:administrator rlidwka
remzi rlidwka
다른 사람들의 접근을 허용하려면 아래의 명령어로 접근 권한을 줄 수 있다
prompt> fs setacl private/ andrea rl
🐣 Permission Bits와 ACL 비교 (From 막둥)
특징 | Permission Bits | Access Control Lists (ACLs) |
설정 가능 대상 | 소유자, 그룹, 다른 사용자 | 특정 사용자 또는 그룹 |
세부 설정 가능 여부 | 제한적 (3가지 범주) | 매우 세밀한 권한 설정 가능 |
복잡성 | 단순함 | 더 복잡한 설정 필요 |
사용 사례 | 대부분의 기본 파일 시스템 | 분산 파일 시스템 또는 고급 설정 필요 시 |
39.17 파일 시스템 생성과 마운트
유닉스 (혹은 리눅스) 에서는 여러 개의 파일 시스템 파티션을 모아서 하나의 큰 디렉터리를 구성할 수 있다
각각의 파일 시스템을 생성하고, 이들을 "마운트"하여 단일 디렉터리 트리를 구성한다
mkfs 라는 도구로 파일 시스템을 생성하고, 장치명 (디스크 파티션, ex, /dev/sdal) 과 파일 시스템 타입 (ex. EXT3) 을 전달하면
해당 파티션에 전달된 파일 시스템 (ex. EXT3) 형식으로 구성된 빈 파일 시스템을 생성한다
새로 생성된 파일 시스템을 루트 디렉터리에서 시작하는 기존의 디렉터리 구성을 통해 접근할 수 있도록 해주는 작업을
"마운트" 라고 하고, 이 작업은 mount 프로그램을 사용한다 (내부적으로 mount() 시스템 콜을 사용하여 작업을 처리한다)
기존의 디렉터리 중 하나를 마운트 지점 mount point 으로 지정하고,
마운트 지점에 생성된 파일 시스템을 "붙여 넣으면" 마운트 작업이 완료된다
마운트 명령어는 아래와 같이 사용할 수 있다
prompt> mount -t [파일 시스템] [마운트할 디바이스나 기존 경로] [마운트하고자 하는 위치]
🐣 파일 시스템은 ex) ext4, xfs, nfs, vfat 등, 파일 시스템을 자동으로 탐지하려면 생략할 수 있다
마운트하고자 하는 위치는 이미 존재해야 한다 🐣
마운트를 하면 모든 파일 시스템들을 하나의 트리 아래에 통합시킬 수 있고
이로써 객체의 호칭을 일관성있고 편리하게 쓸 수 있다
39.18 요약
UNIX 파일 시스템 인터페이스는 운영체제 공부에서 기본이다
인터페이스를 완전히 익히기 위해서 많은 내용에 대한 이해가 필요하다
많이 읽고 많이 사용해라
'크래프톤정글 > 운영체제' 카테고리의 다른 글
[OSTEP][영속성] CH41 지역성과 Fast File System (1) | 2024.11.29 |
---|---|
[OSTEP][영속성] CH40 파일 시스템 구현 (3) | 2024.11.27 |
[OSTEP][영속성] CH39 파일과 디렉터리 #1 (0) | 2024.11.24 |
[OSTEP] CH38 Redundant Array of Inexpensive Disk, RAID (0) | 2024.11.22 |
[OSTEP][영속성] CH35 대화 + CH36 I/O 장치 (0) | 2024.11.17 |