본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Computer Science

파일 시스템

작성 2026. 10. 14.추가
목차12개 항목
출처와 참고

「하드 링크와 심볼릭 링크」 절은 팔만코딩경(42Seoul 커뮤니티 위키)의 「하드링크 / 심볼릭링크」를 바탕으로 보강했다. 「리눅스 디렉터리 구조: FHS」는 ByteByteGo의 System Design 101 가이드 「Linux File System Explained」를 바탕으로 보강했다. 「디렉터리 구조와 경로」, 「디렉터리 엔트리」 절은 강민철의 「혼자 공부하는 컴퓨터 구조+운영체제」 강의(한빛미디어)를 바탕으로 보강했다. 「파일 형식」 절과 「디렉터리 엔트리」의 파일 이동은 CrashCourse의 「Crash Course Computer Science」 강의를 바탕으로 보강했다. 디렉터리 구조의 다섯 단계, 파일의 세 종류와 절단·첨가 연산, 접근 제어 리스트는 고려사이버대학교 「운영체제이론 및 실습」(2024-1학기) 강의 내용으로 보강했다.

메모리는 주소로 접근하지만 파일은 이름으로 접근한다. 운영체제는 하드디스크·SSD·USB처럼 서로 다른 저장 장치를 "파일"이라는 같은 논리적 단위로 보이게 해 주는데, 이 일을 담당하는 부분이 파일 시스템이다.

파일과 메타데이터

  • 파일: 이름이 붙은, 서로 관련된 정보의 모음. 보통 비휘발성 보조기억장치에 저장된다.
  • 파일 연산: create, read, write, reposition(lseek), delete, open, close. 모두 I/O를 하는 시스템 콜이다. 읽기와 쓰기는 보통 위치 포인터 하나(현재 오프셋)를 함께 쓴다.
    • truncate(절단): 속성은 그대로 두고 내용만 지운다(O_TRUNC, truncate()). append(첨가): 기존 내용 뒤에 이어 쓴다(O_APPEND).
    • lseek: 파일에서 현재 접근 중인 위치(offset)를 옮긴다.
    • open: 작업 전에 파일의 메타데이터를 메모리에 올려 둔다.
  • 메타데이터(attribute): 파일 내용이 아니라 파일을 관리하기 위한 정보. 이름, 유형, 저장 위치, 크기, 접근 권한, 생성·수정·접근 시각, 소유자 등이 해당한다.
  • 파일 시스템: 파일과 메타데이터, 디렉터리를 관리하고 저장 방법과 보호를 결정하는 OS의 구성 요소.
  • 파일의 세 종류: 데이터를 담는 일반(정규) 파일, 다른 파일을 찾는 정보만 담는 디렉터리 파일, 장치나 커널 객체를 파일처럼 보이게 하는 특수 파일(문자·블록 장치 파일, 파이프·FIFO, 소켓)이다. ls -l의 첫 글자(-, d, c, b, p, s, 링크는 l)가 이 구분이다.

파일 형식

저장 장치에 놓인 파일은 텍스트든 그림이든 바이트의 긴 목록일 뿐이다. 그 바이트를 어떻게 읽을지 정한 약속이 파일 형식(file format) 이다. 형식을 모르면 같은 바이트도 읽을 수 없다. 직접 만들 수도 있지만 보통은 JPEG·MP3·PNG 같은 표준 형식을 쓴다.

형식구조읽는 법
텍스트(.txt)글자 코드의 나열. 헤더가 없다문자 인코딩(ASCII·UTF-8)으로 바이트를 글자로 바꾼다. 72는 ASCII로 H다(데이터의 표현)
WAV헤더(기본 PCM WAV는 44바이트. RIFF·WAVE 표지, 채널 수, 표본화율, 표본당 비트 수) + 진폭 표본의 나열헤더로 해석 규칙을 알아낸 뒤 표본을 차례로 스피커에 보낸다
BMP헤더(가로·세로 크기, 색 깊이) + 픽셀 값의 나열색 깊이만큼씩 끊어 RGB로 읽고, 가로 크기만큼 읽으면 다음 줄로 넘어간다
  • 파일 안의 데이터를 설명하는 데이터, 즉 메타데이터(metadata) 를 실제 데이터 앞에 두는 부분을 헤더(header) 라 한다. 위의 파일 메타데이터(이름, 권한)는 파일 시스템이 파일 밖에서 관리하고, 헤더는 파일 안에 들어 있다.
  • 많은 형식은 헤더 맨 앞에 정해진 바이트(매직 넘버)를 둔다. 확장자(.bmp, .wav)는 프로그램이 형식을 고르는 단서일 뿐이고, 실제 형식은 내용이 정한다. 매직 넘버로 형식을 판별하는 예는 C 입력과 파일 입출력에 있다.

하드 링크와 심볼릭 링크

UNIX 파일 시스템에서 파일의 실체는 i-node(소유자, 권한, 크기, 데이터 블록 위치를 담은 구조체)이고, 디렉터리는 이름 → i-node 번호 표일 뿐이다. 그래서 한 파일에 이름을 여러 개 붙일 수 있다. ls -i로 i-node 번호를 본다.

구분하드 링크 (ln a b)심볼릭 링크 (ln -s a b)
가리키는 것같은 i-node (원본과 완전히 동등한 이름)대상의 경로 문자열을 담은 별도 파일 (자기 i-node가 따로 있다)
원본 이름을 지우면데이터는 그대로. i-node의 링크 수만 줄어든다깨진 링크(dangling)가 된다
다른 파일 시스템불가 (i-node 번호는 파일 시스템 안에서만 유효)가능
디렉터리불가 (순환 방지)가능
비유같은 사람의 다른 이름바로 가기 아이콘
  • 파일 삭제 시스템 콜이 unlink()인 이유가 여기 있다. 이름 하나를 끊을 뿐이고, 링크 수가 0이 되고 그 파일을 연 프로세스도 없을 때 비로소 i-node와 데이터 블록이 해제된다. 실행 중인 프로그램의 로그 파일을 지워도 디스크 공간이 바로 돌아오지 않는 이유다.
  • cp는 새 i-node에 내용을 복사하므로 사본을 고쳐도 원본은 그대로다. 하드 링크는 어느 이름으로 고쳐도 같은 내용이 바뀐다.
  • 데이터 블록에서 i-node 포인터만 지울 뿐 내용을 지우지는 않으므로, 완전 삭제가 필요하면 덮어쓰기 도구를 쓴다(SSD는 TRIM·암호화가 더 확실하다).

디렉터리와 파티션

  • 디렉터리: 그 아래 있는 파일들의 이름과 메타데이터 일부를 내용으로 가지는 특별한 파일. 파일 찾기·생성·삭제, 목록 보기, 이름 변경, 파일 시스템 순회 같은 연산을 지원한다.
  • 파티션(논리 디스크): OS가 보는 디스크 단위. 하나의 물리 디스크를 여러 파티션으로 나누거나, 여러 물리 디스크를 하나의 파티션으로 묶을 수 있다. 각 파티션에는 파일 시스템을 설치하거나 스왑 영역 등 다른 용도로 쓸 수 있다.

파일 시스템은 파티션을 포맷할 때 정해진다. 포맷은 흔히 "지우기"로 이해하지만 본래 뜻은 파티션에 파일 시스템을 만들어 새 데이터를 쓸 준비를 하는 일(논리적 포매팅)이고, 파티션마다 다른 파일 시스템을 쓸 수 있다. 파티셔닝과 물리·논리 포매팅의 구분은 디스크 관리와 스케줄링에 있다.

디렉터리 구조와 경로

초기 운영체제는 디렉터리가 하나뿐인 1단계 디렉터리를 썼다. 파일이 많아지면서 디렉터리 안에 서브 디렉터리를 두는 트리 구조 디렉터리가 표준이 되었다. 디렉터리 구조가 발전한 단계를 정리하면 다음과 같다.

구조모양한계
1단계모든 사용자의 모든 파일이 디렉터리 하나에이름이 전부 달라야 하고, 파일이 많아지면 찾기 어렵다
2단계사용자마다 디렉터리 하나사용자별로 이름 충돌이 사라지고 검색이 빨라지지만, 그 아래에 서브 디렉터리를 만들 수 없어 주제별로 묶지 못한다
트리루트 아래로 누구나 서브 디렉터리를 계속 만든다한 파일이 한 부모에만 속해 여러 곳에서 공유할 수 없다
비순환 그래프트리에 링크를 더해 한 파일·디렉터리를 여러 경로에서 가리킨다같은 파일에 이름이 여럿이라 삭제 시점을 정해야 한다. 하드 링크는 참조 계수가 0이 될 때 지우고, 심볼릭 링크는 원본이 지워지면 깨진 채 남는다(아래 「하드 링크와 심볼릭 링크」)
일반 그래프링크가 사이클을 만들어도 허용순회가 사이클을 돌며 끝나지 않을 수 있고, 자기 자신을 가리키는 사이클 때문에 참조 계수가 0이 되지 않아 지울 수 없는 파일이 생긴다. 쓰레기 수집으로 찾아야 한다

UNIX 계열이 디렉터리에 하드 링크를 금지하고 심볼릭 링크만 허용하는 것은 비순환 그래프를 유지해 일반 그래프의 문제를 피하기 위해서다. find가 기본적으로 심볼릭 링크를 따라가지 않는 것(-L을 줘야 따라간다)도 같은 이유다. 맨 위의 디렉터리가 루트 디렉터리이고, UNIX 계열은 /, Windows는 C:\처럼 드라이브 이름으로 나타낸다.

경로(path) 는 디렉터리를 따라 파일·디렉터리의 위치와 이름을 특정하는 문자열이다. UNIX 계열에서 /는 루트이면서 디렉터리 구분자다. 같은 디렉터리 안에서는 이름이 겹칠 수 없지만, 경로가 다르면 같은 이름의 파일이 있어도 된다(/etc/a.sh와 /home/minchul/a.sh).

경로기준예 (현재 디렉터리가 /home일 때 d.jpg)
절대 경로루트 디렉터리부터. 파일마다 하나로 정해진다/home/guest/d.jpg
상대 경로현재 디렉터리부터guest/d.jpg

디렉터리 엔트리

많은 운영체제는 디렉터리를 일반 파일과 크게 구분하지 않고 특별한 형태의 파일로 다룬다. 일반 파일의 내용이 데이터라면, 디렉터리의 내용은 그 안에 담긴 파일·디렉터리에 대한 정보를 담은 표다. 표를 어떤 자료구조(선형 리스트, 해시 테이블)로 구현하는지는 파일 시스템 구현에 있다. 표의 한 행이 디렉터리 엔트리다.

엔트리에 담기는 것설명
이름디렉터리에 들어 있는 파일·서브 디렉터리의 이름
위치를 알아낼 정보그 대상이 보조기억장치의 어디에 있는지 찾을 단서. 무엇을 적는지는 할당 방식과 파일 시스템마다 다르다(파일 시스템 구현)
속성(일부 파일 시스템)FAT처럼 크기·생성 시각 같은 속성까지 엔트리에 적는 파일 시스템도 있다

엔트리에는 보통 .(현재 디렉터리)와 ..(상위 디렉터리)도 들어 있다. .. 엔트리에 상위 디렉터리의 위치가 적혀 있으므로 /home/minchul에서 ..를 따라 /home으로, 다시 ..를 따라 /로 거슬러 올라갈 수 있다.

파일의 위치 정보가 디렉터리 엔트리에 있으므로, 같은 파일 시스템 안에서 파일을 다른 디렉터리로 옮기는 일(mv, rename())은 데이터 블록을 건드리지 않는다. 옛 디렉터리에서 엔트리를 지우고 새 디렉터리에 엔트리를 더할 뿐이라, 파일 크기와 상관없이 즉시 끝난다. 다른 파일 시스템으로 옮길 때만 내용을 복사하고 원본을 지운다.

리눅스 디렉터리 구조: FHS

리눅스는 루트(/)에서 시작하는 하나의 트리다. 어떤 배포판에서든 프로그램이 같은 위치에서 설정·라이브러리·로그를 찾을 수 있도록 파일 시스템 계층 표준(FHS, Filesystem Hierarchy Standard) 이 디렉터리마다 용도를 정한다. 1994년 처음 나온 뒤 리눅스 재단이 관리한다. 배포판마다 조금씩 다르게 따르기도 한다.

디렉터리용도
/bin, /sbin기본 명령과 시스템 관리 명령. 지금 배포판 대부분은 /usr/bin, /usr/sbin으로 합치고 링크만 남긴다
/etc시스템·서비스 설정 파일
/home사용자별 홈 디렉터리. root의 홈은 /root
/usr배포판이 설치한 프로그램·라이브러리·문서(읽기 위주)
/usr/local, /opt관리자가 직접 설치한 소프트웨어, 독립 패키지
/var실행 중 크기가 변하는 데이터: 로그(/var/log), 캐시, 스풀, DB 파일
/tmp임시 파일. 재부팅 때 지워질 수 있다
/dev장치 파일(/dev/sda, /dev/null)
/proc, /sys커널이 실시간으로 보여 주는 가상 파일 시스템(프로세스 정보, 커널 설정)
/boot커널과 부트 로더 파일
/lib기본 명령이 쓰는 공유 라이브러리와 커널 모듈
/mnt, /media다른 파일 시스템을 임시로, 이동식 매체를 자동으로 마운트하는 자리

cd로 옮겨 다니고 ls로 들여다보며 트리를 익히는 것이 가장 빠르다. 자주 쓰는 명령은 자주 쓰는 리눅스 명령어 지도에 있다.

open()은 무슨 일을 하나

open("/a/b/c")를 호출하면 파일 c의 메타데이터를 메모리로 가져와야 한다. 이를 위해 경로를 한 단계씩 따라간다.

  1. 루트 디렉터리 /의 메타데이터를 열고, 그 내용에서 a의 위치를 찾는다.
  2. a를 열어 읽고 b의 위치를 찾는다.
  3. b를 열어 읽고 c의 위치를 찾는다.
  4. c를 연다.

경로 탐색은 비용이 크기 때문에 open을 read/write와 분리해 두고, 한 번 연 파일은 이후 탐색 없이 바로 읽고 쓴다.

관련 자료구조

open이 돌려주는 fd는 프로세스별 fd 테이블의 번호이고, 그 칸은 커널 전역의 열린 파일 테이블 항목을 가리킨다. 현재 오프셋은 이 열린 파일 항목에 있어서 fork·dup한 fd끼리 공유된다. 세 테이블의 구조는 UNIX 파일 입출력과 파일 디스크립터에 있다.

UNIX 계열에서 C 표준 라이브러리의 fopen()이 돌려주는 FILE *도 내부적으로는 이 fd를 감싼 것이다(C 입력과 파일 입출력). open이 메타데이터를 메모리에 올리고 fd를 반환하면 이후 read(fd, ...)는 그 fd로 파일에 접근한다. 읽은 내용은 커널의 버퍼 캐시에 복사해 두었다가 사용자에게 전달한다. 파일 접근은 항상 시스템 콜이라 OS가 모든 접근을 알고 있으므로, 버퍼 캐시에서는 LRU·LFU 같은 교체 알고리즘을 자유롭게 쓸 수 있다.

파일 보호

각 파일에 대해 누가, 어떤 접근(읽기·쓰기·실행)을 할 수 있는지 정해야 한다.

방법특징
Access Control Matrix사용자 × 파일 전체 권한을 표로 관리. 정확하지만 대부분 칸이 비어 있어 낭비가 크다. 그래서 행렬을 파일 기준으로 잘라 파일마다 「누가 무엇을 할 수 있나」 목록만 두는 접근 제어 리스트(ACL) 로 구현한다. 사용자가 많으면 목록이 길어지고 관리가 번거롭다
Groupingowner / group / others 세 그룹 × rwx, 단 9비트로 표현 (UNIX 방식)
Password파일마다 비밀번호. 관리가 어려움

대부분의 시스템은 Grouping을 기본으로 쓰고, 세밀한 제어가 필요할 때만 ACL을 덧붙인다(Linux의 setfacl·getfacl, Windows NTFS는 ACL이 기본). 예를 들어 chmod 751 file은 소유자 rwx, 그룹 r-x, 그 외 --x다.

마운트 (Mounting)

파티션마다 다른 파일 시스템을 설치할 수 있는데, 다른 파일 시스템의 루트 디렉터리를 현재 파일 시스템의 특정 디렉터리에 연결(mount) 하면 그 경로로 바로 접근할 수 있다.

접근 방식 (Access Methods)

  • 순차 접근(sequential): 카세트테이프처럼 앞에서부터 차례로 접근. 읽거나 쓰면 오프셋이 자동으로 증가한다.
  • 직접 접근(direct, random): LP 레코드판처럼 임의 위치에 바로 접근.

직접 접근이 가능한 매체라도, 데이터를 어떻게 관리하느냐(예: 연결 할당)에 따라 순차 접근만 가능할 수 있다. 디스크에 실제로 어떻게 저장하는지는 파일 시스템 구현에서 다룬다.

관련 노트: 파일 시스템 구현, UNIX 파일 입출력과 파일 디스크립터, 리눅스 접근 제어: DAC, MAC, sudo, 자주 쓰는 리눅스 명령어 지도

원본 기록7

댓글

GitHub 계정으로 댓글을 남길 수 있어요.