Skip to content
Published on

[운영체제] 13. 파일 시스템 인터페이스

Authors

파일 시스템 인터페이스

파일 시스템은 운영체제에서 가장 눈에 띄는 부분 중 하나입니다. 사용자가 데이터를 저장하고 관리하는 논리적 인터페이스를 제공합니다. 이 글에서는 파일 개념, 접근 방법, 디렉토리 구조, 그리고 파일 보호 메커니즘을 살펴봅니다.


1. 파일 개념

파일은 보조 저장장치에 기록된 관련 정보의 이름 있는 집합입니다.

파일 속성

속성설명
이름(Name)사람이 읽을 수 있는 식별자
식별자(Identifier)파일 시스템 내 고유 번호 (inode 번호 등)
유형(Type)확장자 또는 매직 넘버로 식별
위치(Location)장치상 물리적 위치 포인터
크기(Size)현재 파일 크기 (바이트, 블록)
보호(Protection)읽기, 쓰기, 실행 권한
타임스탬프생성, 수정, 접근 시간
소유자(Owner)파일 소유 사용자

파일 연산

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    // 1. 파일 생성 및 열기
    int fd = open("example.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    // 2. 파일 쓰기
    const char *data = "Hello, File System!";
    write(fd, data, 19);

    // 3. 파일 닫기
    close(fd);

    // 4. 읽기 모드로 다시 열기
    fd = open("example.txt", O_RDONLY);

    // 5. 파일 읽기
    char buffer[256];
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
    buffer[bytes_read] = '\0';
    printf("읽은 내용: %s\n", buffer);

    // 6. 파일 위치 이동 (seek)
    lseek(fd, 0, SEEK_SET);  // 파일 시작으로 이동

    // 7. 파일 닫기
    close(fd);

    // 8. 파일 삭제
    unlink("example.txt");

    return 0;
}

오픈 파일 테이블

운영체제는 열린 파일을 관리하기 위해 테이블을 유지합니다.

프로세스 A                    프로세스 B
┌──────────────┐             ┌──────────────┐
│ fd 테이블    │             │ fd 테이블    │
0: stdin     │             │ 0: stdin     │
1: stdout    │             │ 1: stdout    │
2: stderr    │             │ 2: stderr    │
3: ─────────┐│             │ 3: ─────────┐│
└─────────────┘│             └─────────────┘│
               ↓                            ↓
        ┌──────────────────────────────────────┐
        │      시스템 전역 오픈 파일 테이블       │
        │ ┌─────────────────────────────────┐   │
        │ │ 파일 A: offset=100, refCount=1  │   │
        │ │ 파일 B: offset=0,   refCount=2  │ ← 공유│
        │ └─────────────────────────────────┘   │
        └──────────────────────────────────────┘
              ┌──────────────────┐
              │   inode 테이블    │
                (디스크 위치 등)              └──────────────────┘

2. 접근 방법

순차 접근 (Sequential Access)

파일의 처음부터 끝까지 순서대로 접근합니다. 테이프 모델에 기반합니다.

┌───┬───┬───┬───┬───┬───┬───┐
0123456 │  ← 레코드
└───┴───┴───┴───┴───┴───┴───┘
     현재 위치 포인터
     (앞으로만 이동하거나 되감기)
// 순차 접근 예시
FILE *fp = fopen("log.txt", "r");
char line[1024];

// 처음부터 끝까지 순서대로 읽기
while (fgets(line, sizeof(line), fp) != NULL) {
    printf("%s", line);
}

// 되감기 (처음으로)
rewind(fp);
fclose(fp);

직접 접근 (Direct / Random Access)

임의의 위치에 직접 접근할 수 있습니다. 디스크 모델에 기반합니다.

┌───┬───┬───┬───┬───┬───┬───┐
0123456 │  ← 블록 번호
└───┴───┴───┴───┴───┴───┴───┘
  ↑               ↑       ↑
  직접 접근 가능 (어느 블록이든)
// 직접 접근 예시 - 데이터베이스의 레코드 접근
#include <stdio.h>

typedef struct {
    int id;
    char name[50];
    double balance;
} Account;

// 특정 레코드 번호로 직접 접근
Account read_account(FILE *fp, int record_num) {
    Account acc;
    // 레코드 번호로 오프셋 계산하여 직접 이동
    fseek(fp, record_num * sizeof(Account), SEEK_SET);
    fread(&acc, sizeof(Account), 1, fp);
    return acc;
}

void write_account(FILE *fp, int record_num, Account *acc) {
    fseek(fp, record_num * sizeof(Account), SEEK_SET);
    fwrite(acc, sizeof(Account), 1, fp);
}

인덱스 접근

인덱스 파일을 통해 데이터 파일의 레코드를 찾는 방식입니다.

인덱스 파일:                     데이터 파일:
┌──────┬─────────┐              ┌─────────────────┐
│ 키   │ 포인터  │              │ 레코드 0├──────┼─────────┤        ┌───→│ Smith, 1000Kim  │ ──────────────┐  │    ├─────────────────┤
Lee  │ ────────────┐ │  │    │ 레코드 1Park │ ──────┐     │ │  │    │ Lee, 2000Smith│ ──────┼─────┼─┼──┘    ├─────────────────┤
└──────┴───────┘     │ │       │ 레코드 2                     │ └──────→│ Kim, 3000                     │         ├─────────────────┤
                     └────────→│ 레코드 3Park, 4000                               └─────────────────┘

3. 디렉토리 구조

디렉토리는 파일 이름을 해당 파일의 메타데이터로 매핑하는 테이블입니다.

단일 수준 디렉토리

┌──────────────────────────────────────┐
│             루트 디렉토리              │
│                                      │
│  cat  bo  a   test  data  mail  hex  │
│   │   │   │    │     │     │     │   │
│   ○   ○   ○    ○     ○     ○     ○   │
└──────────────────────────────────────┘
모든 파일이 같은 디렉토리에 존재
→ 이름 충돌 문제, 그룹화 불가

2단계 디렉토리

┌────────────────────────────────────┐
│          마스터 파일 디렉토리        │
│                                    │
│   user1        user2       user3   │
│     │            │           │     │
│  ┌──┴──┐     ┌──┴──┐    ┌──┴──┐  │
│  │ UFD │     │ UFD │    │ UFD │  │
│  │cat a│     │cat b│    │  a  │  │
│  └─────┘     └─────┘    └─────┘  │
└────────────────────────────────────┘
사용자별 별도 디렉토리 → 이름 충돌 해결

트리 구조 디렉토리

현대 파일 시스템의 기본 구조입니다.

              / (루트)
            ╱   │    ╲
         home  etc    var
        ╱   ╲   │      │
     user1 user2 passwd log
      │      │          │
    docs   code      syslog
    │  │     │
  a.txt b.txt main.c
# 트리 구조에서의 경로
# 절대 경로: 루트부터 시작
/home/user1/docs/a.txt

# 상대 경로: 현재 디렉토리 기준
# 현재 디렉토리가 /home/user1 일 때
docs/a.txt

비순환 그래프 디렉토리

파일이나 디렉토리를 여러 곳에서 공유할 수 있습니다. (하드 링크, 심볼릭 링크)

         /
      home
     ╱    ╲
  user1   user2
    │       │
  shared ──┘  (심볼릭 링크 또는 하드 링크)
  project
// 하드 링크 생성 (같은 inode를 가리킴)
#include <unistd.h>

int main() {
    // 하드 링크: 동일한 inode에 대한 새 이름
    link("/home/user1/shared/project",
         "/home/user2/project");

    // 심볼릭(소프트) 링크: 경로명을 가리키는 특수 파일
    symlink("/home/user1/shared/project",
            "/home/user2/project_link");

    return 0;
}

하드 링크 vs 심볼릭 링크

특성하드 링크심볼릭 링크
inode원본과 동일별도 inode
파일 시스템 간불가가능
디렉토리 링크불가 (루프 방지)가능
원본 삭제 시데이터 유지깨진 링크
크기디렉토리 엔트리만경로명 크기

4. 파일 공유

다중 사용자 환경에서의 파일 공유

사용자 A (소유자)
    ├── 파일 X (읽기/쓰기/실행)
    │      │
    │      ├── 사용자 B (그룹) → 읽기/실행
    │      │
    │      └── 기타 사용자 → 읽기만
    └── 그룹: developers

파일 잠금 (File Locking)

#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd = open("shared_data.txt", O_RDWR);

    struct flock lock;
    lock.l_type   = F_WRLCK;    // 쓰기 잠금
    lock.l_whence = SEEK_SET;
    lock.l_start  = 0;          // 시작 오프셋
    lock.l_len    = 0;          // 전체 파일

    // 잠금 획득 (다른 프로세스는 대기)
    fcntl(fd, F_SETLKW, &lock);

    // 파일 작업 수행
    write(fd, "critical data", 13);

    // 잠금 해제
    lock.l_type = F_UNLCK;
    fcntl(fd, F_SETLK, &lock);

    close(fd);
    return 0;
}

잠금 유형

유형설명호환성
공유 잠금 (Read Lock)여러 프로세스가 동시 읽기 가능공유 잠금끼리 호환
배타 잠금 (Write Lock)하나의 프로세스만 접근 가능모든 잠금과 비호환
강제 잠금 (Mandatory)커널이 강제 적용시스템 의존
권고 잠금 (Advisory)프로세스가 자발적 준수POSIX 기본

5. 보호 (Protection)

접근 제어 리스트 (ACL)

파일: /project/secret.txt

ACL (Access Control List):
┌──────────┬─────────────────┐
│ 사용자   │ 권한             │
├──────────┼─────────────────┤
│ admin    │ 읽기, 쓰기, 실행 │
│ user1    │ 읽기, 쓰기       │
│ user2    │ 읽기             │
│ group:dev│ 읽기, 실행       │
│ others    (없음)└──────────┴─────────────────┘

UNIX 권한 모델

UNIX는 소유자(owner), 그룹(group), 기타(others)의 3가지 범주와 읽기(r), 쓰기(w), 실행(x)의 3가지 권한을 조합합니다.

$ ls -l example.txt
-rwxr-x--- 1 user1 developers 1024 Mar 19 10:00 example.txt

 │││││││││
 │├┤├┤├┤
 │ │ │ └── others:  --- (권한 없음)
 │ │ └──── group:   r-x (읽기, 실행)
 │ └────── owner:   rwx (읽기, 쓰기, 실행)
 └──────── 파일 유형: - (일반 파일)
#include <sys/stat.h>

int main() {
    // 8진수로 권한 설정
    // 7=rwx, 5=r-x, 0=---
    chmod("example.txt", 0750);

    // 소유자 변경
    chown("example.txt", 1000, 100);  // uid=1000, gid=100

    // 새 파일 생성 시 기본 권한 마스크
    umask(0022);  // 기본 권한에서 group/others의 쓰기 제거

    return 0;
}

특수 권한 비트

비트심볼효과
setuids (소유자 실행)실행 시 파일 소유자 권한으로 실행
setgids (그룹 실행)실행 시 파일 그룹 권한으로 실행
sticky bitt (기타 실행)디렉토리 내 파일은 소유자만 삭제 가능
# setuid 설정 예시 (passwd 명령어)
# 일반 사용자도 root 소유 파일을 수정 가능
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 ... /usr/bin/passwd
    ^
    setuid 비트 설정됨

# sticky bit 설정 예시 (/tmp 디렉토리)
$ ls -ld /tmp
drwxrwxrwt 15 root root 4096 ... /tmp
         ^
         sticky bit 설정됨

6. 정리

  • 파일 개념: 이름 있는 정보 집합으로, 속성과 연산이 정의됨
  • 접근 방법: 순차(테이프 모델), 직접(디스크 모델), 인덱스 접근
  • 디렉토리 구조: 단일 수준에서 비순환 그래프까지 발전. 현대 시스템은 트리 + 링크
  • 파일 공유: 잠금 메커니즘(공유/배타, 강제/권고)으로 동시 접근 관리
  • 보호: UNIX 권한 모델(rwx, owner/group/others)과 ACL로 접근 제어
퀴즈: 파일 시스템 인터페이스

Q1. 하드 링크와 심볼릭 링크의 차이점을 설명하세요.

A1. 하드 링크는 원본 파일과 동일한 inode를 공유하므로 원본이 삭제되어도 데이터에 접근할 수 있습니다. 심볼릭 링크는 별도의 inode를 가지며 경로명을 저장하므로, 원본이 삭제되면 깨진 링크가 됩니다. 하드 링크는 파일 시스템 경계를 넘을 수 없고 디렉토리에 적용할 수 없지만, 심볼릭 링크는 두 가지 모두 가능합니다.

Q2. UNIX 파일 권한 0754는 어떤 의미인가요?

A2. 소유자(7=rwx): 읽기, 쓰기, 실행 모두 가능. 그룹(5=r-x): 읽기와 실행 가능, 쓰기 불가. 기타(4=r--): 읽기만 가능.

Q3. sticky bit의 용도는 무엇인가요?

A3. sticky bit이 디렉토리에 설정되면, 해당 디렉토리 내의 파일은 파일의 소유자, 디렉토리의 소유자, 또는 root만 삭제할 수 있습니다. /tmp 디렉토리에 설정되어 모든 사용자가 파일을 만들 수 있지만 다른 사용자의 파일은 삭제할 수 없게 합니다.