파일 시스템 기초 ⭐⭐⭐

파일 시스템 기초 ⭐⭐⭐

개요

파일 시스템은 운영체제가 데이터를 디스크에 저장하고 관리하는 방법을 정의합니다. 파일의 개념, 속성, 연산, 디렉토리 구조, 접근 방법 등 핵심 개념을 학습합니다.


목차

  1. 파일의 개념
  2. 파일 속성
  3. 파일 연산과 시스템 콜
  4. 디렉토리 구조
  5. 파일 접근 방법
  6. 파일 시스템 마운트
  7. 연습 문제

1. 파일의 개념

1.1 파일이란?

┌─────────────────────────────────────────────────────────────────────────┐
│                         파일의 정의                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   파일 = 연관된 정보의 이름 붙은 집합                                   │
│          (Named collection of related information)                      │
│                                                                          │
│   운영체제 관점:                                                        │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                                                                  │   │
│   │   디스크 (물리적 저장장치)                                       │   │
│   │   ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐            │   │
│   │   │블록0│블록1│블록2│블록3│블록4│블록5│블록6│블록7│            │   │
│   │   └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘            │   │
│   │       ↑         ↑     ↑         ↑     ↑     ↑                   │   │
│   │       └────┬────┘     └────┬────┘     └──┬──┘                   │   │
│   │            │               │             │                       │   │
│   │         파일 A          파일 B        파일 C                     │   │
│   │                                                                  │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│   사용자 관점:                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                                                                  │   │
│   │   논리적 저장 단위                                               │   │
│   │                                                                  │   │
│   │   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │   │
│   │   │ report.docx  │  │ photo.jpg    │  │ program.exe  │          │   │
│   │   │ (문서)       │  │ (이미지)     │  │ (실행파일)   │          │   │
│   │   └──────────────┘  └──────────────┘  └──────────────┘          │   │
│   │                                                                  │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│   파일 시스템: 이 두 관점을 연결하는 추상화 계층                        │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

1.2 파일 유형

┌─────────────────────────────────────────────────────────────────────────┐
│                          파일 유형                                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌───────────────┬──────────────┬─────────────────────────────────┐    │
│   │     유형      │    확장자    │            설명                 │    │
│   ├───────────────┼──────────────┼─────────────────────────────────┤    │
│   │ 실행 파일     │ .exe, .com   │ 기계어 코드                     │    │
│   │               │ .bin, (없음) │                                 │    │
│   ├───────────────┼──────────────┼─────────────────────────────────┤    │
│   │ 오브젝트      │ .o, .obj     │ 컴파일된 목적 코드              │    │
│   ├───────────────┼──────────────┼─────────────────────────────────┤    │
│   │ 소스 코드     │ .c, .py, .js │ 프로그래밍 언어 소스            │    │
│   ├───────────────┼──────────────┼─────────────────────────────────┤    │
│   │ 텍스트        │ .txt, .md    │ 일반 텍스트                     │    │
│   ├───────────────┼──────────────┼─────────────────────────────────┤    │
│   │ 라이브러리    │ .a, .so      │ 정적/동적 라이브러리            │    │
│   │               │ .lib, .dll   │                                 │    │
│   ├───────────────┼──────────────┼─────────────────────────────────┤    │
│   │ 이미지        │ .jpg, .png   │ 그래픽 데이터                   │    │
│   │               │ .gif, .bmp   │                                 │    │
│   ├───────────────┼──────────────┼─────────────────────────────────┤    │
│   │ 압축          │ .zip, .tar   │ 압축된 아카이브                 │    │
│   │               │ .gz, .7z     │                                 │    │
│   └───────────────┴──────────────┴─────────────────────────────────┘    │
│                                                                          │
│   유닉스에서는 확장자가 필수가 아님 (Convention만 존재)                 │
│   내용에 따른 유형 판단: file 명령어                                   │
│                                                                          │
│   $ file /bin/ls                                                        │
│   /bin/ls: ELF 64-bit LSB shared object, x86-64...                     │
│                                                                          │
│   $ file report.pdf                                                     │
│   report.pdf: PDF document, version 1.4                                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2. 파일 속성

2.1 기본 속성 (Metadata)

┌─────────────────────────────────────────────────────────────────────────┐
│                         파일 속성                                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────┬───────────────────────────────────────────────┐   │
│   │      속성       │                  설명                          │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 이름 (Name)     │ 사용자가 읽을 수 있는 파일명                  │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 식별자          │ 파일 시스템 내 고유 번호 (inode 번호)         │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 유형 (Type)     │ 일반파일, 디렉토리, 심볼릭링크, 디바이스 등   │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 위치 (Location) │ 디스크에서의 저장 위치 (블록 포인터)          │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 크기 (Size)     │ 파일의 바이트 수                              │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 보호 (Protection)│ 접근 권한 (rwxrwxrwx)                        │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 소유자 (Owner)  │ 파일 소유자 (UID)                             │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 그룹 (Group)    │ 파일 그룹 (GID)                               │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 시간 정보       │ 생성, 수정, 접근 시간                         │   │
│   └─────────────────┴───────────────────────────────────────────────┘   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2.2 Unix/Linux stat 구조체

#include <sys/stat.h>
#include <time.h>

// stat 구조체 (파일 속성 저장)
struct stat {
    dev_t     st_dev;      // 장치 ID
    ino_t     st_ino;      // inode 번호
    mode_t    st_mode;     // 파일 모드 (유형 + 권한)
    nlink_t   st_nlink;    // 하드 링크 수
    uid_t     st_uid;      // 소유자 UID
    gid_t     st_gid;      // 그룹 GID
    dev_t     st_rdev;     // 장치 ID (특수 파일)
    off_t     st_size;     // 총 크기 (바이트)
    blksize_t st_blksize;  // I/O 블록 크기
    blkcnt_t  st_blocks;   // 할당된 512B 블록 수

    // 시간 정보
    struct timespec st_atim;  // 마지막 접근 시간
    struct timespec st_mtim;  // 마지막 수정 시간
    struct timespec st_ctim;  // 마지막 상태 변경 시간
};

// 파일 속성 조회 예제
void print_file_info(const char* path) {
    struct stat sb;

    if (stat(path, &sb) == -1) {
        perror("stat");
        return;
    }

    printf("파일: %s\n", path);
    printf("inode: %lu\n", sb.st_ino);
    printf("크기: %ld 바이트\n", sb.st_size);
    printf("블록: %ld\n", sb.st_blocks);
    printf("권한: %o\n", sb.st_mode & 0777);
    printf("소유자: %d\n", sb.st_uid);
    printf("링크: %lu\n", sb.st_nlink);

    // 파일 유형
    if (S_ISREG(sb.st_mode))  printf("유형: 일반 파일\n");
    if (S_ISDIR(sb.st_mode))  printf("유형: 디렉토리\n");
    if (S_ISLNK(sb.st_mode))  printf("유형: 심볼릭 링크\n");
    if (S_ISCHR(sb.st_mode))  printf("유형: 문자 장치\n");
    if (S_ISBLK(sb.st_mode))  printf("유형: 블록 장치\n");

    printf("수정 시간: %s", ctime(&sb.st_mtime));
}

2.3 ls -l 출력 해석

┌─────────────────────────────────────────────────────────────────────────┐
│                     ls -l 출력 분석                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   $ ls -l                                                               │
│   -rw-r--r-- 1 user group 4096 Jan 15 10:30 document.txt               │
│   │├──┤├─┤│  │  │     │     │      │     │     └── 파일명             │
│   ││  │ │ │  │  │     │     │      │     └── 시간                     │
│   ││  │ │ │  │  │     │     │      └── 날짜                           │
│   ││  │ │ │  │  │     │     └── 크기 (바이트)                         │
│   ││  │ │ │  │  │     └── 그룹                                        │
│   ││  │ │ │  │  └── 소유자                                            │
│   ││  │ │ │  └── 하드 링크 수                                         │
│   ││  │ │ └── 기타 권한                                               │
│   ││  │ └── 그룹 권한                                                 │
│   ││  └── 소유자 권한                                                 │
│   │└── 파일 유형                                                      │
│   └── - 일반파일, d 디렉토리, l 링크, c 문자장치, b 블록장치         │
│                                                                          │
│   권한:                                                                  │
│   r (4) = 읽기                                                          │
│   w (2) = 쓰기                                                          │
│   x (1) = 실행 (디렉토리는 접근)                                       │
│                                                                          │
│   예: rw-r--r-- = 644 = 소유자: rw, 그룹: r, 기타: r                   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3. 파일 연산과 시스템 콜

3.1 기본 파일 연산

┌─────────────────────────────────────────────────────────────────────────┐
│                        파일 연산 종류                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────┬───────────────────────────────────────────────┐   │
│   │     연산        │                  설명                          │   │
│   ├─────────────────┼───────────────────────────────────────────────┤   │
│   │ 생성 (Create)   │ 새 파일 생성, 디렉토리에 엔트리 추가          │   │
│   │ 열기 (Open)     │ 파일 접근 준비, 파일 디스크립터 반환          │   │
│   │ 읽기 (Read)     │ 현재 위치에서 데이터 읽기                     │   │
│   │ 쓰기 (Write)    │ 현재 위치에 데이터 쓰기                       │   │
│   │ 이동 (Seek)     │ 파일 내 현재 위치 변경                        │   │
│   │ 닫기 (Close)    │ 파일 접근 종료, 리소스 해제                   │   │
│   │ 삭제 (Delete)   │ 파일 제거, 디렉토리에서 엔트리 삭제           │   │
│   │ 자르기 (Truncate)│ 파일 크기를 0으로 (내용 삭제)                │   │
│   └─────────────────┴───────────────────────────────────────────────┘   │
│                                                                          │
│   추가 연산:                                                             │
│   - Append: 파일 끝에 데이터 추가                                       │
│   - Rename: 파일명 변경                                                 │
│   - Get/Set Attributes: 속성 조회/변경                                  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3.2 시스템 콜 예제

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

// 파일 생성 및 쓰기
void create_and_write(const char* path) {
    // O_CREAT: 없으면 생성
    // O_WRONLY: 쓰기 전용
    // O_TRUNC: 기존 내용 삭제
    // 0644: 권한 (rw-r--r--)
    int fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        exit(1);
    }

    const char* data = "Hello, File System!\n";
    ssize_t written = write(fd, data, strlen(data));

    if (written == -1) {
        perror("write");
    } else {
        printf("%zd 바이트 기록됨\n", written);
    }

    close(fd);
}

// 파일 읽기
void read_file(const char* path) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return;
    }

    char buffer[1024];
    ssize_t bytes_read;

    // read()는 읽은 바이트 수 반환, 0은 EOF
    while ((bytes_read = read(fd, buffer, sizeof(buffer) - 1)) > 0) {
        buffer[bytes_read] = '\0';
        printf("%s", buffer);
    }

    if (bytes_read == -1) {
        perror("read");
    }

    close(fd);
}

// 파일 위치 이동 (Seek)
void seek_example(const char* path) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) return;

    // 파일 끝으로 이동하여 크기 확인
    off_t size = lseek(fd, 0, SEEK_END);
    printf("파일 크기: %ld 바이트\n", size);

    // 처음으로 되돌아가기
    lseek(fd, 0, SEEK_SET);

    // 10바이트 앞으로 이동
    lseek(fd, 10, SEEK_CUR);

    char buffer[100];
    read(fd, buffer, 10);
    buffer[10] = '\0';
    printf("10바이트 이후 10글자: %s\n", buffer);

    close(fd);
}

// 파일 복사 구현
int copy_file(const char* src, const char* dst) {
    int src_fd = open(src, O_RDONLY);
    if (src_fd == -1) return -1;

    int dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (dst_fd == -1) {
        close(src_fd);
        return -1;
    }

    char buffer[4096];
    ssize_t bytes;

    while ((bytes = read(src_fd, buffer, sizeof(buffer))) > 0) {
        ssize_t written = write(dst_fd, buffer, bytes);
        if (written != bytes) {
            close(src_fd);
            close(dst_fd);
            return -1;
        }
    }

    close(src_fd);
    close(dst_fd);
    return 0;
}

int main() {
    create_and_write("test.txt");
    read_file("test.txt");
    seek_example("test.txt");
    copy_file("test.txt", "test_copy.txt");
    return 0;
}

3.3 Open File Table

┌─────────────────────────────────────────────────────────────────────────┐
│                     Open File Table 구조                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   프로세스 A                프로세스 B                                  │
│   ┌──────────────────┐      ┌──────────────────┐                       │
│   │ fd table         │      │ fd table         │                       │
│   ├──────────────────┤      ├──────────────────┤                       │
│   │ 0: stdin         │      │ 0: stdin         │                       │
│   │ 1: stdout        │      │ 1: stdout        │                       │
│   │ 2: stderr        │      │ 2: stderr        │                       │
│   │ 3: ─────────────┐│      │ 3: ─────────────┐│                       │
│   │ 4: ────────────┐││      └─────────────────┼┘                       │
│   └────────────────┼┼┘                        │                        │
│                    ││                         │                        │
│                    ▼▼                         │                        │
│   System-wide Open File Table                 │                        │
│   ┌─────────────────────────────────────────┐ │                        │
│   │ 엔트리 1:                               │ │                        │
│   │   - 파일 위치 (offset): 100             │◀┘                        │
│   │   - 접근 모드: O_RDONLY                 │                          │
│   │   - 참조 카운트: 2                      │                          │
│   │   - inode 포인터: ──────────────────────┼───┐                      │
│   ├─────────────────────────────────────────┤   │                      │
│   │ 엔트리 2:                               │   │                      │
│   │   - 파일 위치 (offset): 500             │   │                      │
│   │   - 접근 모드: O_RDWR                   │   │                      │
│   │   - 참조 카운트: 1                      │   │                      │
│   │   - inode 포인터: ──────────────────────┼───┼───┐                  │
│   └─────────────────────────────────────────┘   │   │                  │
│                                                 │   │                  │
│   In-Memory inode Table                         │   │                  │
│   ┌─────────────────────────────────────────┐   │   │                  │
│   │ inode 1234:                             │◀──┘   │                  │
│   │   - 파일 크기: 4096                     │       │                  │
│   │   - 디스크 블록 위치                    │       │                  │
│   │   - 권한, 소유자 등                     │       │                  │
│   ├─────────────────────────────────────────┤       │                  │
│   │ inode 5678:                             │◀──────┘                  │
│   │   - 파일 크기: 8192                     │                          │
│   │   - ...                                 │                          │
│   └─────────────────────────────────────────┘                          │
│                                                                          │
│   fork() 시: fd table 복사, open file entry 공유 (offset 공유!)        │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4. 디렉토리 구조

4.1 단일 레벨 디렉토리

┌─────────────────────────────────────────────────────────────────────────┐
│                    단일 레벨 디렉토리                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                         루트 디렉토리                            │   │
│   ├─────────────────────────────────────────────────────────────────┤   │
│   │ cat │ bo │ a │ test │ data │ mail │ cont │ hex │ records │     │   │
│   └──┬──┴──┬─┴──┬─┴───┬──┴───┬──┴───┬──┴───┬──┴──┬──┴────┬────┘     │   │
│      │     │    │     │      │      │      │     │       │           │   │
│      ▼     ▼    ▼     ▼      ▼      ▼      ▼     ▼       ▼           │   │
│     파일  파일  파일  파일   파일   파일   파일  파일    파일         │   │
│                                                                          │
│   문제점:                                                               │
│   - 파일명 충돌: 모든 사용자가 같은 이름 사용 불가                     │
│   - 관리 어려움: 파일 수 증가시 찾기 어려움                            │
│   - 그룹화 불가: 관련 파일을 묶을 수 없음                              │
│                                                                          │
│   초기 운영체제 (CP/M)에서 사용                                         │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4.2 2단계 디렉토리

┌─────────────────────────────────────────────────────────────────────────┐
│                      2단계 디렉토리                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│                    마스터 파일 디렉토리 (MFD)                           │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │            user1              user2              user3          │   │
│   └───────────────┬────────────────┬─────────────────┬──────────────┘   │
│                   │                │                 │                  │
│                   ▼                ▼                 ▼                  │
│        사용자 파일 디렉토리 (UFD)                                       │
│   ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐          │
│   │ cat   test  a   │ │ cat   data  b   │ │ hex   mail     │          │
│   └──┬──────┬────┬──┘ └──┬──────┬────┬──┘ └──┬──────┬──────┘          │
│      │      │    │       │      │    │       │      │                  │
│      ▼      ▼    ▼       ▼      ▼    ▼       ▼      ▼                  │
│                                                                          │
│   장점:                                                                  │
│   - 사용자별 독립적 이름 공간                                           │
│   - user1의 cat ≠ user2의 cat                                          │
│                                                                          │
│   단점:                                                                  │
│   - 사용자 간 파일 공유 어려움                                          │
│   - 하위 디렉토리 없음                                                  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4.3 트리 구조 디렉토리

┌─────────────────────────────────────────────────────────────────────────┐
│                     트리 구조 디렉토리                                   │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│                              /                                           │
│                              │                                           │
│           ┌──────────────────┼──────────────────┐                       │
│           │                  │                  │                       │
│          bin               home               etc                       │
│           │                  │                  │                       │
│     ┌─────┴─────┐    ┌───────┼───────┐    ┌────┴────┐                  │
│    ls          cat   │       │       │   passwd   hosts                │
│                    user1   user2   user3                                │
│                      │       │       │                                  │
│                 ┌────┴────┐  │    documents                             │
│               docs     code  data     │                                  │
│                │         │    │    ┌──┴──┐                              │
│            ┌───┼───┐   main.c  │   report  notes                        │
│          a.txt b.txt         file.txt                                   │
│                                                                          │
│   특징:                                                                  │
│   - 임의 깊이의 하위 디렉토리 허용                                      │
│   - 절대 경로: /home/user1/docs/a.txt                                   │
│   - 상대 경로: ./docs/a.txt (현재 디렉토리 기준)                        │
│   - 현재 디렉토리 (.), 상위 디렉토리 (..)                              │
│                                                                          │
│   현재 대부분의 운영체제가 사용                                         │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4.4 비순환 그래프 디렉토리 (Acyclic Graph)

┌─────────────────────────────────────────────────────────────────────────┐
│                   비순환 그래프 디렉토리                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│                              /                                           │
│                              │                                           │
│           ┌──────────────────┼──────────────────┐                       │
│           │                  │                  │                       │
│          home              shared              │                        │
│           │                  │                 │                        │
│     ┌─────┴─────┐           project ◀─────────┘                        │
│   user1       user2          │ ▲                                        │
│     │           │      ┌─────┴─────┐                                    │
│  myproj ───────────────│           │                                    │
│                        │      공유 파일                                  │
│                   ourproj ────┘                                          │
│                                                                          │
│   파일/디렉토리 공유 방법:                                              │
│                                                                          │
│   1. 하드 링크 (Hard Link):                                             │
│      - 같은 inode를 가리키는 다른 이름                                  │
│      - ln target link_name                                              │
│      - 삭제 시 링크 카운트만 감소                                       │
│      - 디렉토리에는 사용 불가 (순환 방지)                               │
│                                                                          │
│   2. 심볼릭 링크 (Symbolic Link):                                       │
│      - 다른 파일의 경로를 저장                                          │
│      - ln -s target link_name                                           │
│      - 원본 삭제 시 끊어진 링크 (dangling link)                         │
│      - 디렉토리에도 사용 가능                                           │
│                                                                          │
│   $ ln /shared/project myproj          # 하드 링크                      │
│   $ ln -s /shared/project myproj       # 심볼릭 링크                    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

5. 파일 접근 방법

5.1 순차 접근 (Sequential Access)

┌─────────────────────────────────────────────────────────────────────────┐
                        순차 접근                                         
├─────────────────────────────────────────────────────────────────────────┤
                                                                          
   파일                                                                   
   ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐                            
    A  B  C  D  E  F  G  H  I  J                             
   └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘                            
                                                                         
          현재 위치                                                       
                                                                          
   연산:                                                                  
   - read(): 현재 위치에서 읽고, 위치 전진                               
   - write(): 현재 위치에 쓰고, 위치 전진                                
   - reset(): 처음으로 되돌리기                                          
                                                                          
   특징:                                                                  
   - 테이프 기반 시스템에서 유래                                         
   - 편집기, 컴파일러에서 주로 사용                                      
   - 로그 파일 처리에 적합                                               
                                                                          
   : 파일 끝까지 순차 읽기                                             
   while (read(fd, &buf, size) > 0) {                                    
       process(buf);                                                      
   }                                                                      
                                                                          
└─────────────────────────────────────────────────────────────────────────┘

5.2 직접 접근 (Direct/Random Access)

┌─────────────────────────────────────────────────────────────────────────┐
                        직접 접근                                         
├─────────────────────────────────────────────────────────────────────────┤
                                                                          
   파일 (논리적 블록 단위)                                               
   블록:  0     1     2     3     4     5     6     7     8     9        
   ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐        
                                                             
   └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘        
                                                                        
        블록 1                  블록 5                                    
         읽기                    읽기                                     
                                                                          
   연산:                                                                  
   - read(n): 블록 n 읽기                                                
   - write(n): 블록 n 쓰기                                               
   - seek(n): 블록 n으로 이동                                            
                                                                          
   특징:                                                                  
   - 디스크 기반 시스템                                                  
   - 데이터베이스에 적합                                                 
   - 순서 없이 임의 위치 접근                                            
                                                                          
   : 레코드 직접 접근                                                   
   #define RECORD_SIZE 100                                               
   lseek(fd, record_num * RECORD_SIZE, SEEK_SET);                        
   read(fd, &record, RECORD_SIZE);                                       
                                                                          
└─────────────────────────────────────────────────────────────────────────┘

5.3 인덱스 접근 (Indexed Access)

┌─────────────────────────────────────────────────────────────────────────┐
│                       인덱스 접근                                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   인덱스 파일                             데이터 파일                    │
│   ┌────────────────────┐                 ┌─────────────────────────┐    │
│   │ 키      │ 블록 포인터│                 │ 블록 0                  │    │
│   ├─────────┼───────────┤                 ├─────────────────────────┤    │
│   │ "Apple" │     7     │────────────────▶│ 블록 7: Apple 데이터    │    │
│   │ "Banana"│     3     │────────────┐   ├─────────────────────────┤    │
│   │ "Cherry"│     12    │──────────┐ │   │ 블록 3: Banana 데이터   │◀──┤
│   │ "Date"  │     5     │────────┐ │ │   ├─────────────────────────┤    │
│   │  ...    │   ...     │        │ │ │   │ 블록 12: Cherry 데이터  │◀──┘
│   └─────────┴───────────┘        │ │ │   ├─────────────────────────┤
│                                  │ │ │   │ 블록 5: Date 데이터     │◀──┐
│                                  │ │ └──▶│                         │   │
│                                  │ │     └─────────────────────────┘   │
│                                  │ │                                    │
│                                  └─┼────────────────────────────────────┘
│                                    │
│                                    └── (인덱스에서 위치를 찾아 직접 접근)
│
│   특징:                                                                  │
│   - 큰 파일의 빠른 검색                                                 │
│   - 인덱스 자체가 너무 크면 다단계 인덱스                               │
│   - 데이터베이스의 B+트리 인덱스                                        │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

6. 파일 시스템 마운트

6.1 마운트 개념

┌─────────────────────────────────────────────────────────────────────────┐
│                         파일 시스템 마운트                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   마운트 전:                                                             │
│                                                                          │
│   루트 파일 시스템 (/)                USB 드라이브                       │
│           /                          독립된 트리                         │
│          ╱│╲                              │                             │
│        bin home etc                      ╱ ╲                            │
│             │                         photo  doc                         │
│           user1                                                          │
│            │                                                             │
│          mnt (빈 디렉토리)                                              │
│                                                                          │
│   마운트 후 (mount /dev/sdb1 /home/user1/mnt):                          │
│                                                                          │
│           /                                                              │
│          ╱│╲                                                            │
│        bin home etc                                                      │
│             │                                                            │
│           user1                                                          │
│            │                                                             │
│          mnt ◀─────────── 마운트 포인트                                 │
│          ╱ ╲                                                            │
│       photo  doc   ← USB 드라이브의 내용이 여기에 보임                  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

6.2 마운트 명령어

# 마운트 상태 확인
$ mount
/dev/sda1 on / type ext4 (rw,relatime)
/dev/sdb1 on /mnt/usb type vfat (rw,user)

# USB 드라이브 마운트
$ sudo mount /dev/sdb1 /mnt/usb

# 옵션과 함께 마운트
$ sudo mount -t ext4 -o ro,noexec /dev/sdc1 /mnt/backup

# 마운트 옵션:
# ro: 읽기 전용
# rw: 읽기/쓰기
# noexec: 실행 파일 실행 불가
# nosuid: setuid 무시
# user: 일반 사용자가 마운트 가능

# 언마운트
$ sudo umount /mnt/usb

# /etc/fstab - 부팅 시 자동 마운트 설정
# 장치              마운트포인트     타입    옵션               덤프 패스
/dev/sda1          /               ext4    defaults           1    1
/dev/sda2          /home           ext4    defaults           1    2
/dev/sdb1          /mnt/data       ext4    defaults,nofail    0    2
UUID=xxxx-xxxx     /mnt/usb        vfat    user,noauto        0    0

연습 문제

문제 1: 파일 속성 해석

ls -l 출력이 다음과 같을 때 각 필드를 해석하시오.

-rwxr-x--- 2 alice developers 8192 Mar 15 14:30 script.sh
정답 보기
- : 일반 파일 (d면 디렉토리, l이면 링크)
rwx : 소유자(alice) 권한 - 읽기/쓰기/실행
r-x : 그룹(developers) 권한 - 읽기/실행
--- : 기타 사용자 권한 - 없음
2 : 하드 링크 수 (이 파일에 대한 이름이 2개)
alice : 소유자
developers : 소유 그룹
8192 : 파일 크기 (8KB)
Mar 15 14:30 : 마지막 수정 시간
script.sh : 파일 이름

권한 숫자: 750 (7=rwx, 5=r-x, 0=---)

문제 2: 시스템 콜 시퀀스

파일 /tmp/log.txt에 "Hello World"를 추가(append)하는 시스템 콜 시퀀스를 작성하시오.

정답 보기
int fd = open("/tmp/log.txt", O_WRONLY | O_APPEND | O_CREAT, 0644);
// O_APPEND: 항상 파일 끝에 쓰기
// O_CREAT: 파일이 없으면 생성
// 0644: 권한 설정

if (fd == -1) {
    perror("open failed");
    exit(1);
}

const char* msg = "Hello World\n";
ssize_t written = write(fd, msg, strlen(msg));

if (written == -1) {
    perror("write failed");
}

close(fd);

문제 3: 하드 링크 vs 심볼릭 링크

다음 시나리오에서 각 링크 유형의 동작을 설명하시오.

$ echo "original" > file.txt
$ ln file.txt hardlink.txt       # 하드 링크
$ ln -s file.txt symlink.txt     # 심볼릭 링크
$ rm file.txt
$ cat hardlink.txt
$ cat symlink.txt
정답 보기
$ cat hardlink.txt
original
→ 하드 링크는 같은 inode를 가리킴
→ file.txt 삭제해도 데이터는 여전히 존재
→ 링크 카운트가 1 감소했을 뿐

$ cat symlink.txt
cat: symlink.txt: No such file or directory
→ 심볼릭 링크는 "file.txt"라는 경로를 저장
→ file.txt가 삭제되면 끊어진 링크 (dangling link) 가리키는 대상이 없어서 오류

하드 링크 특징:
- 같은 inode 번호 공유
- 원본과 동등한 지위
- 디렉토리에는 사용 불가

심볼릭 링크 특징:
- 별도의 inode (경로 문자열 저장)
- 원본에 의존적
- 디렉토리에도 사용 가능
- 다른 파일 시스템도 가리킬  있음

문제 4: 디렉토리 탐색

/home/user/docs/../code/./main.c 경로를 정규화하시오.

정답 보기
/home/user/docs/../code/./main.c

1. /home/user/docs 까지 이동
2. .. 으로 상위로 이동: /home/user
3. code 로 이동: /home/user/code
4. . 은 현재 디렉토리 (무시): /home/user/code
5. main.c 파일: /home/user/code/main.c

정규화된 경로: /home/user/code/main.c

Linux에서 확인:
$ realpath /home/user/docs/../code/./main.c
/home/user/code/main.c

문제 5: Open File Table

프로세스 A가 파일을 열고 fork()로 프로세스 B를 생성합니다. 두 프로세스가 같은 파일에 각각 100바이트를 write()하면 파일의 최종 크기는?

정답 보기
fork()  자식은 부모의 fd table을 복사합니다.
 프로세스의 fd는 같은 open file entry를 공유합니다.
따라서 같은 offset을 공유합니다!

시나리오:
1. 부모 open(), offset = 0
2. fork(), 자식도 같은 open file entry 공유
3. 부모 write(100), offset = 100
4. 자식 write(100), offset = 200 (이어서 쓰기)

최종 파일 크기: 200 바이트

만약 자식이 별도로 open()했다면:
- 별도의 open file entry 생성
- 별도의 offset
-   0부터 시작하면 덮어쓰기!
- 최종 크기: 100 바이트

주의: 실제로는 write() 원자성과 버퍼링에 따라
결과가 다를  있음. O_APPEND 사용 권장.

다음 단계

17_File_System_Implementation.md에서 파일 시스템의 내부 구현을 배워봅시다!


참고 자료

  • Silberschatz, "Operating System Concepts" Chapter 13
  • Linux man pages: open(2), read(2), write(2), stat(2)
  • POSIX 파일 시스템 표준
  • The Linux Programming Interface by Michael Kerrisk
to navigate between lessons