[Linux] 리눅스의 파일의 본질

mommers·2026년 2월 3일

Linux

목록 보기
30/59


리눅스에서 모든 객체(하드웨어 포함)는 '파일'로 취급되며, 우리는 fd(정수 번호) 라는 번호표를 통해 커널 안의 실제 파일과 소통한다.


1. 핵심 철학: Everything is a file

  • 추상화: 하드디스크 파일뿐만 아니라 키보드, 모니터, 프린터, 네트워크 소켓까지 전부 파일로 간주합니다.
  • 상호작용: 따라서 장치를 제어하는 방법도 복잡한 명령어가 아닌, 단순한 Read(읽기)와 Write(쓰기)로 통일됩니다.

2. 연결 고리: File Descriptor (fd)

  • 정체: int (비음수 정수). (예: 3, 4, 5...)
  • 역할: 사용자 프로그램(User)이 커널(Kernel) 내부에 열려 있는 실제 파일 객체(메타데이터)를 가리키는 인덱스(참조 번호)입니다.
  • 공유: 커널은 파일을 관리하고, 사용자에게는 이 번호표(fd)만 건네줍니다. 사용자는 이 번호만 알면 됩니다.

3. 시스템 프로그래밍의 표준 흐름 (Lifecycle)

리눅스 프로그래밍의 90%는 이 과정을 따릅니다.

  1. Open: "파일 열어줘" → 커널이 확인 후 fd 번호 발급.
  2. Access: "이 fd에 써줘" → 커널이 fd를 보고 실제 파일에 기록.
  3. Close: "이 fd 다 썼어" → 커널이 fd 회수 및 리소스 정리.

표준 파일 디스크립터 (Standard FD)

프로그램이 실행되자마자 기본적으로 할당받는 3가지 fd가 있습니다.

  • 0: 표준 입력 (Stdin) - 키보드
  • 1: 표준 출력 (Stdout) - 모니터
  • 2: 표준 에러 (Stderr) - 모니터 (에러용)

"Inode는 파일의 '주민등록증(고유 식별자)', fd는 현재 프로세스가 발급받은 '대기 번호표(접근 핸들)'.”

비교 항목Inode (Index Node)fd (File Descriptor)
정체파일 그 자체 (메타데이터)파일을 다루기 위한 번호 (핸들)
위치디스크 (물리적 저장)프로세스 메모리 (커널 관리 테이블)
유효 범위파일 시스템 전체에서 유일해당 프로세스 안에서만 유일
수명파일이 삭제될 때까지 영구적close() 하거나 프로세스 죽으면 사라짐
포함 정보권한, 소유자, 크기, 데이터 위치현재 읽기/쓰기 위치(Offset), 접근 모드

연결 구조 (Kernel Internal)

리눅스 커널은 이 둘을 3단계로 연결합니다.

  1. 프로세스 (fd 테이블): fd 3은 단순한 인덱스(번호)일 뿐입니다.
  2. 오픈 파일 테이블 (File Table Entry): fd가 가리키는 곳. "누가, 어떻게 열었고, 어디까지 읽었나(Offset)"를 저장.
  3. Inode 테이블 (Vnode): 실제 디스크의 물리적 위치와 권한 정보.

관계: 여러 프로세스가 같은 파일을 열면?

  • fd: 서로 다름 (A프로세스: 3, B프로세스: 4).
  • Open File Table: 서로 다름 (각자 읽는 위치가 다르니까).
  • Inode: 하나를 공유함 (물리적 파일은 하나니까).

Regular 파일

리눅스 파일은 '구조가 없는 바이트의 나열(Stream)'이며, 이름은 껍데기일 뿐 실체는 Inode이다.


1. 파일의 본질 (Byte Stream)

  • 정의: 바이트(Byte)들이 선형으로 쭉 늘어선 배열.
  • 특징:
    • No Structure: 리눅스 커널은 파일의 내용(이미지인지, 텍스트인지)을 모릅니다. 그냥 0과 1의 덩어리로 취급합니다.
    • 자유도: 파일 내부는 어떤 값이든 가질 수 있습니다.

2. 파일 접근과 오프셋 (File Offset)

  • 개념: 현재 파일의 "어디를 읽고/쓰고 있나"를 가리키는 위치 커서.
  • 동작:
    • 파일 열면 0에서 시작.
    • 읽거나(read) 쓰면(write) 그만큼 숫자가 증가.
  • 주의 (덮어쓰기):
    • 파일 중간에 데이터를 쓰면 끼워넣기(Insert)가 아니라 덮어쓰기(Overwrite)가 됩니다.
    • 파일 크기 확장은 보통 맨 끝(End of File)에 쓸 때 일어납니다.

3. 동시성 및 공유 (Concurrency)

  • 다중 오픈: 하나의 파일을 여러 프로세스가(혹은 한 프로세스가 여러 번) 동시에 open() 할 수 있음.
  • 고유성: 열 때마다 새로운 *fd가 발급됨. (서로 다른 오프셋을 가짐).
  • 동기화: 커널은 교통정리를 안 해줍니다. A가 쓰고 있는데 B가 덮어써도 막지 않습니다. (사용자 공간에서 flock 등으로 직접 동기화 필수).

4. 식별자 (Inode vs Filename)

  • 파일명: 사용자가 보기 편하게 붙인 별명(껍데기).
  • Inode (i-number): 파일 시스템이 파일을 관리하는 진짜 주민등록번호(실체).
    • 모든 파일 접근은 내부적으로 파일명Inode 번호 변환을 거쳐 일어납니다.

Inode

Inode는 파일의 실체(메타데이터+데이터 위치)이며, 파일명은 이 Inode를 가리키는 문패(Link)일 뿐이다.


1. Inode의 정체 (Metadata Store)

  • 정의: 파일에 대한 모든 정보(메타데이터)를 담고 있는 핵심 자료구조.
  • 포함하는 것:
    • 속성: 파일 크기, 소유자(UID), 권한(Permission), 시간(Timestamps).
    • 위치 정보: 실제 데이터가 디스크 어디(Block)에 저장되어 있는지 가리키는 포인터.
  • 포함하지 않는 것: 파일 이름(Filename). (이름은 디렉터리가 관리함).
  • 존재 형태:
    • 물리적: 디스크의 특정 영역(Inode Table)에 저장된 객체.
    • 논리적: 리눅스 커널 메모리에 로드된 struct inode 객체.
  • 파일명: 파일 그 자체가 아니라, Inode 번호를 가리키는 별명(Link)에 불과합니다.
  • 디렉터리 엔트리: 디렉터리는 (파일 이름, Inode 번호) 쌍을 저장하는 리스트입니다.
  • 하드 링크(Hard Link):
    • 여러 개의 파일명(별명)이 동일한 Inode 번호를 가리킬 수 있습니다.
    • 파일명은 달라도 실체(Inode)는 하나이므로 데이터도 같습니다.

3. 파일 접근 흐름 (Lookup)

  1. 요청: 사용자가 /home/pi/test.txt 읽기 요청.
  2. 검색: 커널이 디렉터리를 뒤져 test.txt라는 이름에 매핑된 Inode 번호를 찾음.
  3. 로딩: 해당 번호의 Inode를 메모리로 읽어옴.
  4. 접근: Inode 안에 적힌 권한을 확인하고, 데이터 블록 위치를 찾아 데이터를 읽음.



"디렉터리는 파일을 담는 상자가 아니라, '파일 이름'과 'Inode 번호'를 짝지어 놓은 전화번호부(Mapping Table)이다.”

1. 디렉터리와 링크의 본질

  • 디렉터리 (Directory):
    • 역할: 사용자에게 사람이 읽을 수 있는 이름을 제공하고, 커널이 쓰는 Inode 번호로 변환(Mapping)해주는 특수 파일.
    • 구조: 내부적으로는 단순히 {파일 이름 : Inode 번호} 쌍(Link)들의 리스트만 담고 있음.
    • 목적: 복잡한 Inode 번호를 직접 외우는 번거로움을 없애고 접근 제어(보안)를 도움.
  • 링크 (Link):
    • 디렉터리 안에 기록된 [파일 이름] + [Inode]의 매핑 한 줄.

2. 경로 이름 해석 (Pathname Resolution)

커널이 /home/pi/file.c라는 요청을 받았을 때의 동작 과정입니다.
"이름 → 디렉터리 뒤지기 → Inode 획득 → 파일 접근"

  1. 디렉터리 열기: 해당 이름이 포함된 디렉터리(예: /home)를 읽음.
  2. 검색: 디렉터리 리스트에서 파일 이름(pi)과 일치하는 항목을 찾음.
  3. Inode 추출: 그 이름 옆에 적힌 Inode 번호를 알아냄.
  4. 반복/접근: 최종 파일에 도달할 때까지 이 과정을 반복하여 실제 Inode(데이터)에 접근.

3. 경로의 종류 (Pathname)

종류설명예시

| Absolute Path
(절대 경로) | 루트(/)부터 시작하는 완전한 주소 (Fully Qualified). | /home/pi/lab/ch02/access.c |
| Relative Path
(상대 경로) | 현재 위치(pwd)를 기준으로 찾아가는 주소. | lab/ch02/access.c |

4. 디렉터리 조작 (Operation)

디렉터리도 파일(dentry)이지만, 구조가 깨지면 파일 시스템 전체가 꼬이기 때문에 일반적인 쓰기(write)가 금지되어 있습니다.

  • 일반 조작: open(), write() 불가능.
  • 전용 시스템 콜:
    • 생성: mkdir()
    • 삭제: rmdir() (단, 비어있을 때만 가능. rm -r은 재귀적으로 비우고 지우는 유틸리티 기능)


"Hard Link는 '동일한 파일의 또 다른 이름(별명)', Symbolic Link는 '원본 위치를 가리키는 바로가기(Shortcut)'."

"하나의 Inode를 여러 이름이 공유하는 것."

  • 구조: 원본 파일과 동일한 Inode 번호를 가짐.
  • 특징:
    • 원본과 링크의 구분이 없음 (완벽하게 동등한 파일).
    • rm으로 원본을 지워도, 링크가 남아있다면 데이터는 삭제되지 않음 (Inode Reference Count가 0이 되어야 삭제됨).
  • 제약: 같은 파일 시스템(파티션) 내에서만 생성 가능. (Inode 번호는 파티션마다 따로 관리되므로).

"다른 파일을 가리키는 경로(Path)를 담은 별도의 파일."

  • 구조: 자신만의 고유한 Inode를 가짐.
  • 내용: 실제 데이터가 아니라, 원본 파일이 있는 "경로 문자열"만 저장하고 있음.
  • 특징:
    • 윈도우의 '바로가기 아이콘'과 동일.
    • 파일 시스템(파티션)을 넘나들 수 있음.
    • 오버헤드: 원본을 찾기 위해 경로를 해석하는 과정이 추가되므로 Hard Link보다 느림.
  • 제약: 원본 파일을 지우면 링크는 "깨진 링크(Broken Link)"가 되어 사용 불가.

3. 비교 요약

구분Hard LinkSymbolic Link
Inode 번호원본과 같음 (공유)다름 (새로 생성)
데이터원본 데이터 직접 가리킴원본의 경로(Path) 저장
파티션 이동불가능 (동일 파티션만)가능 (어디든 참조 가능)
원본 삭제 시파일 살아있음 (접근 가능)링크 깨짐 (접근 불가)
속도빠름 (직접 접근)약간 느림 (경로 해석 필요)
명령어ln 원본 링크명ln -s 원본 링크명

특수 파일(Special files)


"리눅스는 하드웨어 장치(키보드, 디스크)나 통신 채널(소켓)도 전부 '파일'로 취급하여 관리한다.”

1. 장치 파일 (Device Files) - /dev

하드웨어를 제어하기 위한 인터페이스입니다.

구분Block Device (블록 장치)Character Device (문자 장치)
데이터 구조바이트 배열 (Array)선형 큐 (Queue)
접근 방식Random Access (순서 무관, 임의 접근)Sequential Access (순서대로, 스트림)
동작 특징데이터를 블록 단위로 버퍼링하여 전송데이터를 한 바이트씩 흐르는 대로 처리
예시하드디스크, SSD, USB 메모리키보드, 마우스, 시리얼 포트, 프린터
비고lseek으로 위치 이동 가능이동 불가. (읽을 게 없으면 EOF 또는 대기)

2. IPC(통신) 파일 - 프로세스 간 대화 수단

① Named Pipe (FIFO)

  • 정의: 파일 시스템에 이름(파일명)을 가지고 존재하는 파이프.
  • 특징:
    • 부모-자식 관계가 아닌 전혀 다른 프로세스끼리도 통신 가능.
    • mkfifo 명령어로 생성.
    • 한쪽이 읽기 전까지 쓰기 작업이 블로킹(대기)됨.

② Socket (소켓)

  • 정의: 네트워크 또는 로컬 통신을 위한 진보된 IPC의 끝점(Endpoint).
  • 유형:
    • Unix Domain Socket: 동일 머신 내에서 가장 빠른 통신 (파일 경로 사용).
    • Internet Socket: 다른 머신(네트워크) 간 통신 (IP 주소 + Port 번호 필요).
  • 특징: 양방향 통신이 가능하며, 현대 서버 프로그래밍의 핵심.
profile
임베디드 개발자가 되기 위해 공부중입니다!

0개의 댓글