- Authors

- Name
- Youngju Kim
- @fjvbn20031
ファイルシステムインターフェース
ファイルシステムはオペレーティングシステムで最も目に見える部分の一つです。 ユーザーがデータを保存・管理するための論理的なインターフェースを提供します。 この記事では、ファイルの概念、アクセス方法、ディレクトリ構造、そしてファイル保護メカニズムを解説します。
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)
ファイルの先頭から末尾まで順番にアクセスします。テープモデルに基づきます。
┌───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ ← レコード
└───┴───┴───┴───┴───┴───┴───┘
↑
現在位置ポインタ
(前進またはリワインド)
// 순차 접근 예시
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)
任意の位置に直接アクセスできます。ディスクモデルに基づきます。
┌───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ ← ブロック番号
└───┴───┴───┴───┴───┴───┴───┘
↑ ↑ ↑
直接アクセス可能(どのブロックでも)
// 직접 접근 예시 - 데이터베이스의 레코드 접근
#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, 1000 │
│ Kim │ ──────────────┐ │ ├─────────────────┤
│ Lee │ ────────────┐ │ │ │ レコード 1 │
│ Park │ ──────┐ │ │ │ │ Lee, 2000 │
│ Smith│ ──────┼─────┼─┼──┘ ├─────────────────┤
└──────┴───────┘ │ │ │ レコード 2 │
│ └──────→│ Kim, 3000 │
│ ├─────────────────┤
└────────→│ レコード 3 │
│ Park, 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) | 1つのプロセスのみアクセス可能 | すべてのロックと非互換 |
| 強制ロック(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;
}
特殊権限ビット
| ビット | シンボル | 効果 |
|---|---|---|
| setuid | s(所有者実行) | 実行時にファイル所有者の権限で実行 |
| setgid | s(グループ実行) | 実行時にファイルグループの権限で実行 |
| sticky bit | t(その他実行) | ディレクトリ内のファイルは所有者のみ削除可能 |
# 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ディレクトリに設定されており、すべてのユーザーがファイルを作成できますが、 他のユーザーのファイルは削除できないようにしています。