
이번 시간에는 Unix의 File Path에 대해 알아보자.
사실 path는 단순히 파일 시스템상에서 파일 위치를 나타내는 문자열로
본체는 파일 시스템에 있다.
그렇다면 바로 Unix의 파일 시스템에 대해 알아보자.
먼저 파일 시스템이란 디스크에 데이터를 저장하고 조직하는 방법을 정의하는 시스템을 뜻한다.
Unix의 파일 시스템은 계층적 트리 구조를 사용하여 파일들을 구성한다.
이 구조는 루트/에서 시작하여 하위 디렉토리와 파일로 확장된다.
마치 트리에 루트 노드가 있고 자식노드들이 있는 것과 유사하다. (트리니깐)
파일 시스템의 구조는 크게 네 가지 영역으로 나눌 수 있다.
inode는 index node라는 뜻으로 파일에 대한 정보를 담은 자료구조다.
파일의 소유자, 권한, 크기 등과 같은 메타데이터와
실제 데이터를 담은 데이터 블록에 대한 포인터를 포함한다.
데이터 블록은 디스크의 작은 단위로, 파일의 데이터는 여러 데이터 블록에 분산 저장된다. inode는 이러한 데이터 블록에 대한 포인터들을 다중 간접 포인터를 사용하여 저장한다.
간접 포인터(indirect pointer)란?
간접 포인터란 포인터가 대상을 직접 가리키지 않고,
타고타고 들어갔을 때 가리키는걸 의미한다.
파일 시스템에서 파일의 생성과 삭제는
inode와 데이터 블록을 관리하는 일련의 절차를 통해 이루어진다.
각 동작에 대해 자세한 프로세스를 알아보자.
파일 생성 시 파일 시스템은 사용 가능한 빈 inode를 할당하고 초기화한다.
(슈퍼 블록은 이 사용 가능한 inode 목록을 유지하고 있는다.)
파일을 생성할 디렉토리 파일을 연다.
새로운 디렉토리 엔트리를 생성하고, 파일 이름과 방금 만든 inode 번호를 추가한다.
데이터 블록을 할당 해 파일의 데이터를 저장한다.
inode의 데이터 블록 포인터가 방금 할당한 데이터 블록을 가리키게 업데이트한다.
파일의 크기, 생성 시간 등의 메타데이터를 inode에 기록한다.
파일의 수정 시 변경된 내용을 메타데이터를 업데이트한다.
파일이 위치한 디렉토리 파일을 연다.
해당 파일의 엔트리를 찾아서 제거한다.
inode의 link count를 하나 줄인다.
만약 0이 되면 inode를 해제하여 가용한 inode 목록에 추가한다.
여기서 link count는 inode를 참조하고 있는 디렉토리 엔트리의 수이다.
link count가 0이 될 경우, inode의 데이터 블록 포인터를 따라가며 모든 데이터 블록을 해제한다.
해제된 데이터 블록은 파일 시스템의 가용한 데이터 블록 목록에 추가된다.
그렇다면 정확히 어떤 프로세스를 거쳐 파일 경로 문자열에서 실제 파일까지 찾아갈 수 있을까.
이를 알기 위해 먼저 디렉토리 파일에 대해 알아보자.
Unix에서 모든 것은 파일로 이루어져 있으며, 디렉토리도 예외는 아니다.
디렉토리 파일은 여러 디렉토리 엔트리로 구성되어 있는 특별한 형식의 파일로,
각 엔트리는 파일 이름과 해당 파일의 inode 번호를 매핑하고 있다.
예를 들어, 디렉토리 /home/user가 다음과 같은 구조를 가질 때,
/home/user
├── file1.txt
├── file2.txt
└── dir1
디렉토리 파일은 다음과 같은 디렉토리 엔트리를 포함한다.
file1.txt -> inode 1234file2.txt -> inode 0918dir1 -> inode 960918또한 모든 디렉토리를 두 개의 특별한 디렉토리 엔트리를 가지는데,
바로 현재 디렉토리에 대한 엔트리 .와 상위 디렉토리에 대한 엔트리 ..이다.
이를 통해 계층 구조에서 부모와 자식으로 탐색이 가능해진다.
경로 탐색은 path 문자열을 따라가면서 각 디렉토리 엔트리에서 inode를 찾고,
최종적으로 목표 파일의 inode를 얻는 과정이다.
이 과정은 절대 경로 상대 경로 상관 없이 동일한 방식으로 이루어진다.
/home/user/test.txt가 있을 때 실제 파일에 접근하는 과정을 살펴 보자.
경로 파싱
path 문자열을 디렉토리와 파일 이름 단위로 분리한다.
/, home, user, test.txt
디렉토리 엔트리 탐색
디렉토리의 내용을 탐색하여 다음 경로 컴포넌트를 찾는다.
루트 디렉토리 inode의 데이터 블록 포인터를 통해
루트 디렉토리의 내용을 읽어 home 디렉토리 엔트리를 찾는다.
(루트 디렉토리의 inode는 파일 시스템이 이미 알고 있다)
이후 같은 프로세스로 user 디렉토리의 데이터까지 읽어 test.txt 파일 엔트리를 찾는다.
inode loading
test.txt의 inode 번호를 사용하여 해당 inode를 메모리에 로드한다.
데이터 블록 접근
파일 inode의 데이터 블록 포인터를 통해
데이터 블록에 있는 파일의 실제 데이터를 읽는다.
이 때 블록 포인터는 다중 간접 포인터 형태를 띌 수 있으므로
다 파고들어서 하나의 파일 데이터로 만든다.
여기까지가 file path 문자열에서
실제 path가 나타내는 파일에 접근하기 까지의 과정이었다.
비교적 어렵지 않은 내용들이라 이해하는 데에 큰 어려움은 없었을 거라 생각한다.
이번엔 path에 집중해서 file system과 연관지어 알아보았고,
file system에 대한 좀 더 자세한 내용이 궁금하다면
File System 시리즈의 이전 포스팅들을 확인해보길 바란다.