SFUSE_Documentation
로딩중...
검색중...
일치하는것 없음
fs.c
이 파일의 문서화 페이지로 가기
1// File: src/fs.c
2
3#include "fs.h"
4#include "bitmap.h"
5#include "block.h"
6#include "dir.h"
7#include "inode.h"
8#include "super.h"
9#include <errno.h>
10#include <fuse3/fuse.h>
11#include <linux/fs.h>
12#include <stdbool.h>
13#include <stdint.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/ioctl.h>
18#include <sys/stat.h>
19#include <time.h>
20#include <unistd.h>
21
23extern bool g_force_format;
24
35static int fs_format_filesystem(int fd, struct sfuse_superblock *sb) {
36 struct stat st;
37 if (fstat(fd, &st) < 0)
38 return -1;
39 uint32_t total_all = st.st_size / SFUSE_BLOCK_SIZE;
40
41 /* 비트맵 블록 수 계산 */
42 uint32_t bm_blocks = (total_all > 32768 ? 2 : 1);
43 uint32_t inodes_per_block = SFUSE_BLOCK_SIZE / sizeof(struct sfuse_inode);
44 uint32_t it_blocks =
45 (SFUSE_MAX_INODES + inodes_per_block - 1) / inodes_per_block;
46
47 /* 디스크 용량 체크 */
48 if (total_all <= 1 + 1 + bm_blocks + it_blocks)
49 return -1;
50
51 /* 슈퍼블록 설정 */
52 sb->magic = SFUSE_MAGIC;
54 sb->inode_bitmap_start = 1;
55 sb->block_bitmap_start = 2;
56 sb->inode_table_start = 2 + bm_blocks;
57 sb->data_block_start = sb->inode_table_start + it_blocks;
58 sb->total_blocks = total_all - sb->data_block_start;
60 sb->free_blocks = sb->total_blocks;
61
62 /* 비트맵 초기화 (0으로 채움) */
63 struct sfuse_bitmaps bmaps;
64 memset(&bmaps, 0, sizeof(bmaps));
65 /* 아이노드 0,1 예약 (루트) */
66 bmaps.inode.map[0] |= 0x03;
67 sb->free_inodes -= 2;
68
69 /* 루트 inode 초기화 */
70 struct sfuse_inode root;
71 memset(&root, 0, sizeof(root));
72 root.mode = S_IFDIR | 0755;
73 root.uid = getuid();
74 root.gid = getgid();
75 root.size = 0;
76 time_t now = time(NULL);
77 root.atime = root.mtime = root.ctime = (uint32_t)now;
78
79 /* 디스크에 기록 */
80 /* 1) 슈퍼블록 */
81 if (pwrite(fd, sb, SFUSE_BLOCK_SIZE, 0) != SFUSE_BLOCK_SIZE)
82 return -1;
83 /* 2) 아이노드 비트맵 */
84 if (pwrite(fd, &bmaps.inode, SFUSE_BLOCK_SIZE,
86 return -1;
87 /* 3) 블록 비트맵 */
88 if (pwrite(fd, &bmaps.block, bm_blocks * SFUSE_BLOCK_SIZE,
90 return -1;
91 /* 4) 루트 아이노드 */
92 if (inode_sync(fd, sb, 1, &root) < 0)
93 return -1;
94
95 return 0;
96}
97
105struct sfuse_fs *fs_initialize(const char *path, int *error_out) {
106 int fd = open(path, O_RDWR);
107 if (fd < 0) {
108 *error_out = errno;
109 return NULL;
110 }
111
112 struct stat st;
113 if (fstat(fd, &st) < 0) {
114 *error_out = errno;
115 close(fd);
116 return NULL;
117 }
118
119 off_t img_size;
120 bool is_blkdev = S_ISBLK(st.st_mode);
121 if (is_blkdev) {
122 // 블록 디바이스: ioctl로 전체 크기(바이트) 가져오기
123 uint64_t size64;
124 if (ioctl(fd, BLKGETSIZE64, &size64) < 0) {
125 *error_out = errno;
126 close(fd);
127 return NULL;
128 }
129 img_size = size64;
130 } else {
131 // 일반 파일: lseek로 크기 측정
132 img_size = lseek(fd, 0, SEEK_END);
133 if (img_size < 0) {
134 *error_out = errno;
135 close(fd);
136 return NULL;
137 }
138 }
139
140 // 강제 포맷 시 이미지 파일만 ftruncate — 블록 디바이스는 넘어감
141 if (g_force_format && !is_blkdev) {
142 if (ftruncate(fd, img_size) < 0) {
143 *error_out = errno;
144 close(fd);
145 return NULL;
146 }
147 }
148
149 // 다음 I/O를 위해 파일 포인터를 맨 앞으로
150 if (lseek(fd, 0, SEEK_SET) < 0) {
151 *error_out = errno;
152 close(fd);
153 return NULL;
154 }
155}
156
165void fs_teardown(struct sfuse_fs *fs) {
166 if (!fs)
167 return;
168
169 /* 슈퍼블록 동기화 */
170 sb_sync(fs->backing_fd, &fs->sb);
171
172 /* 비트맵 동기화 */
173 uint32_t bits_per_block = SFUSE_BLOCK_SIZE * 8;
174 uint32_t im_blocks =
175 (fs->sb.total_inodes + bits_per_block - 1) / bits_per_block;
176 uint32_t bm_blocks =
177 (fs->sb.total_blocks + bits_per_block - 1) / bits_per_block;
179 im_blocks + bm_blocks);
180
181 /* 메모리 및 파일 디스크립터 정리 */
182 free(fs->inode_table);
183 free(fs->bmaps);
184 close(fs->backing_fd);
185 free(fs);
186}
187
198int fs_resolve_path(struct sfuse_fs *fs, const char *path, uint32_t *out_ino) {
199 if (strcmp(path, "/") == 0) {
200 *out_ino = 1; /* 루트 inode */
201 return 0;
202 }
203
204 /* 경로 복사 및 분할 */
205 char *path_copy = strdup(path);
206 if (!path_copy)
207 return -ENOMEM;
208
209 uint32_t current = 1; /* 루트부터 시작 */
210 char *token = strtok(path_copy, "/");
211 while (token) {
212 uint32_t next;
213 int ret = dir_lookup(fs, current, token, &next);
214 if (ret < 0) {
215 free(path_copy);
216 return ret;
217 }
218 current = next;
219 token = strtok(NULL, "/");
220 }
221 free(path_copy);
222
223 *out_ino = current;
224 return 0;
225}
226
237int fs_getattr(struct sfuse_fs *fs, const char *path, struct stat *stbuf) {
238 uint32_t ino;
239 int ret = fs_resolve_path(fs, path, &ino);
240 if (ret < 0)
241 return ret;
242
243 struct sfuse_inode inode;
244 if (inode_load(fs->backing_fd, &fs->sb, ino, &inode) < 0)
245 return -EIO;
246
247 /* stat 구조체 초기화 및 채우기 */
248 memset(stbuf, 0, sizeof(*stbuf));
249 stbuf->st_mode = inode.mode;
250 stbuf->st_nlink = S_ISDIR(inode.mode) ? 2 : 1;
251 stbuf->st_uid = inode.uid;
252 stbuf->st_gid = inode.gid;
253 stbuf->st_size = inode.size;
254 stbuf->st_atime = inode.atime;
255 stbuf->st_mtime = inode.mtime;
256 stbuf->st_ctime = inode.ctime;
257 return 0;
258}
259
272int fs_readdir(struct sfuse_fs *fs, const char *path, void *buf,
273 fuse_fill_dir_t filler, off_t offset) {
274 uint32_t ino;
275 if (fs_resolve_path(fs, path, &ino) < 0)
276 return -ENOENT;
277 return dir_list(fs, ino, buf, filler, offset);
278}
279
290int fs_open(struct sfuse_fs *fs, const char *path, struct fuse_file_info *fi) {
291 (void)fi;
292 uint32_t ino;
293 if (fs_resolve_path(fs, path, &ino) < 0)
294 return -ENOENT;
295 return 0;
296}
297
310int fs_read(struct sfuse_fs *fs, const char *path, char *buf, size_t size,
311 off_t offset) {
312 uint32_t ino;
313 if (fs_resolve_path(fs, path, &ino) < 0)
314 return -ENOENT;
315
316 struct sfuse_inode inode;
317 if (inode_load(fs->backing_fd, &fs->sb, ino, &inode) < 0)
318 return -EIO;
319
320 /* 디렉터리는 읽을 수 없음 */
321 if ((inode.mode & S_IFDIR) == S_IFDIR)
322 return -EISDIR;
323
324 /* 오프셋이 파일 크기를 넘으면 0 리턴 */
325 if ((size_t)offset >= inode.size)
326 return 0;
327
328 /* 요청 크기가 파일 끝을 넘으면 조정 */
329 if ((size_t)offset + size > inode.size)
330 size = inode.size - offset;
331
332 size_t bytes_read = 0;
333 uint8_t block_buf[SFUSE_BLOCK_SIZE];
334
335 /* 필요한 블록을 반복해서 읽음 */
336 while (bytes_read < size) {
337 uint32_t block_index =
338 (offset + bytes_read) / SFUSE_BLOCK_SIZE;
339 uint32_t block_offset =
340 (offset + bytes_read) % SFUSE_BLOCK_SIZE;
341 uint32_t to_read =
342 SFUSE_BLOCK_SIZE - block_offset;
343
344 if (to_read > size - bytes_read)
345 to_read = size - bytes_read;
346
347 uint32_t disk_block = 0;
348
349 /* 직접 블록 참조 */
350 if (block_index < 12U) {
351 disk_block = inode.direct[block_index];
352 }
353 /* 단일 간접 블록 참조 */
354 else if (block_index < 12U + SFUSE_PTRS_PER_BLOCK) {
355 if (!inode.indirect)
356 break;
357 uint32_t ptrs[SFUSE_PTRS_PER_BLOCK];
358 if (read_block(fs->backing_fd, inode.indirect, ptrs) < 0)
359 return -EIO;
360 disk_block = ptrs[block_index - 12U];
361 }
362 /* 이중 간접 블록 참조 */
363 else {
364 if (!inode.double_indirect)
365 break;
366 uint32_t l1[SFUSE_PTRS_PER_BLOCK];
367 if (read_block(fs->backing_fd, inode.double_indirect, l1) < 0)
368 return -EIO;
369 uint32_t dbl_index = block_index - (12U + SFUSE_PTRS_PER_BLOCK);
370 uint32_t l1_idx = dbl_index / SFUSE_PTRS_PER_BLOCK;
371 uint32_t l2_idx = dbl_index % SFUSE_PTRS_PER_BLOCK;
372 if (l1_idx >= SFUSE_PTRS_PER_BLOCK || l1[l1_idx] == 0)
373 break;
374 uint32_t l2[SFUSE_PTRS_PER_BLOCK];
375 if (read_block(fs->backing_fd, l1[l1_idx], l2) < 0)
376 return -EIO;
377 disk_block = l2[l2_idx];
378 }
379
380 /* 할당되지 않은 블록이면 0으로 채움 */
381 if (disk_block == 0) {
382 memset(buf + bytes_read, 0, to_read);
383 } else {
384 /* 실제 디스크 읽기 */
385 if (read_block(fs->backing_fd, disk_block, block_buf) < 0)
386 return -EIO;
387 memcpy(buf + bytes_read, block_buf + block_offset, to_read);
388 }
389 bytes_read += to_read;
390 }
391
392 return bytes_read;
393}
394
407int fs_write(struct sfuse_fs *fs, const char *path, const char *buf,
408 size_t size, off_t offset) {
409 uint32_t ino;
410 if (fs_resolve_path(fs, path, &ino) < 0)
411 return -ENOENT;
412
413 struct sfuse_inode inode;
414 if (inode_load(fs->backing_fd, &fs->sb, ino, &inode) < 0)
415 return -EIO;
416
417 /*< 디렉터리에는 쓰기 불가 */
418 if ((inode.mode & S_IFDIR) == S_IFDIR)
419 return -EISDIR;
420
421 size_t bytes_written = 0;
422 uint8_t block_buf[SFUSE_BLOCK_SIZE];
423
424 /*< 요청한 크기만큼 반복 처리 */
425 while (bytes_written < size) {
426 off_t cur_offset = offset + bytes_written;
427 uint32_t block_index =
428 cur_offset / SFUSE_BLOCK_SIZE;
429 uint32_t block_offset =
430 cur_offset % SFUSE_BLOCK_SIZE;
431 size_t to_write =
432 SFUSE_BLOCK_SIZE - block_offset;
433 if (to_write > size - bytes_written)
434 to_write = size - bytes_written;
435
436 uint32_t *target = NULL;
437 uint32_t disk_block = 0;
438
439 /*< 직접 블록 */
440 if (block_index < 12U) {
441 target = &inode.direct[block_index];
442 disk_block = *target; /* direct 블록 포인터로 disk_block 초기화 */
443 }
444 /*< 단일 간접 블록 */
445 else if (block_index < 12U + SFUSE_PTRS_PER_BLOCK) {
446 if (inode.indirect == 0) {
447 /* 간접 블록이 없으면 새 할당 */
448 int new_block = alloc_block(&fs->sb, &fs->bmaps->block);
449 if (new_block < 0)
450 return -ENOSPC;
451 inode.indirect =
452 (uint32_t)(fs->sb.data_block_start +
453 new_block); /* 간접 블록 주소도 절대 번호로 변환 */
454 uint32_t tmp[SFUSE_PTRS_PER_BLOCK] = {0};
455 write_block(fs->backing_fd, inode.indirect, tmp);
456 }
457 /* 기존 간접 블록에서 포인터 읽기 */
458 uint32_t ptrs[SFUSE_PTRS_PER_BLOCK];
459 read_block(fs->backing_fd, inode.indirect, ptrs);
460
461 target = &ptrs[block_index - 12U];
462 disk_block = *target;
463
464 /* 새 데이터 블록 할당 */
465 if (disk_block == 0) {
466 int new_block = alloc_block(&fs->sb, &fs->bmaps->block);
467 if (new_block < 0)
468 return -ENOSPC;
469 disk_block = (uint32_t)(fs->sb.data_block_start +
470 new_block); /* 새 블록 인덱스를 데이터 영역
471 오프셋과 합산 */
472 *target = disk_block;
473 write_block(fs->backing_fd, inode.indirect, ptrs);
474 }
475 }
476 /*< 이중 간접 블록 */
477 else {
478 uint32_t dbl_index = block_index - (12U + SFUSE_PTRS_PER_BLOCK);
479 uint32_t l1_idx = dbl_index / SFUSE_PTRS_PER_BLOCK;
480 uint32_t l2_idx = dbl_index % SFUSE_PTRS_PER_BLOCK;
481
482 if (inode.double_indirect == 0) {
483 int new_block = alloc_block(&fs->sb, &fs->bmaps->block);
484 if (new_block < 0)
485 return -ENOSPC;
486 inode.double_indirect =
487 (uint32_t)(fs->sb.data_block_start +
488 new_block); /* 이중 간접 블록도 절대 번호로 변환 */
489 uint32_t tmp[SFUSE_PTRS_PER_BLOCK] = {0};
490 write_block(fs->backing_fd, inode.double_indirect, tmp);
491 }
492
493 uint32_t l1[SFUSE_PTRS_PER_BLOCK];
494 read_block(fs->backing_fd, inode.double_indirect, l1);
495
496 if (l1[l1_idx] == 0) {
497 int new_block = alloc_block(&fs->sb, &fs->bmaps->block);
498 if (new_block < 0)
499 return -ENOSPC;
500 l1[l1_idx] = (uint32_t)(fs->sb.data_block_start +
501 new_block); /* 레벨1 인덱스에도 데이터 영역 시작
502 오프셋 적용 */
503 uint32_t tmp[SFUSE_PTRS_PER_BLOCK] = {0};
504 write_block(fs->backing_fd, l1[l1_idx], tmp);
505 write_block(fs->backing_fd, inode.double_indirect, l1);
506 }
507
508 uint32_t l2[SFUSE_PTRS_PER_BLOCK];
509 read_block(fs->backing_fd, l1[l1_idx], l2);
510
511 if (l2[l2_idx] == 0) {
512 int new_block = alloc_block(&fs->sb, &fs->bmaps->block);
513 if (new_block < 0)
514 return -ENOSPC;
515 l2[l2_idx] = (uint32_t)(fs->sb.data_block_start +
516 new_block); /* 레벨2 인덱스에도 오프셋을 더해
517 절대 주소로 */
518 write_block(fs->backing_fd, l1[l1_idx], l2);
519 }
520
521 disk_block = l2[l2_idx];
522 target = &l2[l2_idx];
523 }
524
525 /*< 아직 할당되지 않았으면 새로 할당 */
526 if (target && *target == 0) {
527 int new_block = alloc_block(&fs->sb, &fs->bmaps->block);
528 if (new_block < 0)
529 return -ENOSPC;
530 *target = (uint32_t)(fs->sb.data_block_start +
531 new_block); /* 상대 인덱스에 데이터 영역 시작 블록
532 번호 더해 절대 블록 번호로 저장 */
533 disk_block = *target;
534 }
535
536 /*< 기존 블록 읽기 */
537 if (read_block(fs->backing_fd, disk_block, block_buf) < 0)
538 return -EIO;
539
540 /*< 데이터 쓰기 */
541 memcpy(block_buf + block_offset, buf + bytes_written, to_write);
542 if (write_block(fs->backing_fd, disk_block, block_buf) < 0)
543 return -EIO;
544
545 bytes_written += to_write;
546 }
547
548 /*< 파일 크기 갱신 */
549 if ((uint32_t)(offset + bytes_written) > inode.size)
550 inode.size = offset + bytes_written;
551 inode.mtime = time(NULL);
552 inode.ctime = inode.mtime;
553 if (inode_sync(fs->backing_fd, &fs->sb, ino, &inode) < 0)
554 return -EIO;
555
556 return bytes_written;
557}
558
570int fs_create(struct sfuse_fs *fs, const char *path, mode_t mode,
571 struct fuse_file_info *fi) {
572 (void)fi;
573
574 uint32_t dummy;
575 /* 이미 존재하면 실패 */
576 if (fs_resolve_path(fs, path, &dummy) == 0) {
577 return -EEXIST;
578 }
579
580 /* 상위 디렉터리와 새 파일 이름 분리 */
581 char *path_copy = strdup(path);
582 if (!path_copy)
583 return -ENOMEM;
584 char *name = strrchr(path_copy, '/');
585 if (!name || *(name + 1) == '\0') {
586 free(path_copy);
587 return -EINVAL;
588 }
589 *name = '\0';
590 char *parent_path = (*path_copy == '\0') ? "/" : path_copy;
591 name++;
592
593 /* 상위 디렉터리 inode 찾기 */
594 uint32_t parent_ino;
595 if (fs_resolve_path(fs, parent_path, &parent_ino) < 0) {
596 free(path_copy);
597 return -ENOENT;
598 }
599
600 struct sfuse_inode parent_inode;
601 inode_load(fs->backing_fd, &fs->sb, parent_ino, &parent_inode);
602 /* 상위가 디렉터리인지 확인 */
603 if ((parent_inode.mode & S_IFDIR) == 0) {
604 free(path_copy);
605 return -ENOTDIR;
606 }
607
608 /* 새 아이노드 할당 */
609 int new_ino = alloc_inode(&fs->sb, &fs->bmaps->inode);
610 if (new_ino < 0) {
611 free(path_copy);
612 return new_ino;
613 }
614
615 /* 새 아이노드 초기화 */
616 struct sfuse_inode new_inode;
617 memset(&new_inode, 0, sizeof(new_inode));
618 new_inode.mode = (mode & 0xFFF) | S_IFREG;
619 new_inode.uid = getuid();
620 new_inode.gid = getgid();
621 new_inode.size = 0;
622 time_t now = time(NULL);
623 new_inode.atime = (uint32_t)now;
624 new_inode.mtime = (uint32_t)now;
625 new_inode.ctime = (uint32_t)now;
626
627 /* 상위 디렉터리에 엔트리 추가 */
628 uint8_t dir_block[SFUSE_BLOCK_SIZE];
629 bool added = false;
630 for (int i = 0; i < 12 && !added; ++i) {
631 if (parent_inode.direct[i] == 0) {
632 /* 새 디렉터리 블록 할당 및 초기화 */
633 int new_dir_block = alloc_block(&fs->sb, &fs->bmaps->block);
634 if (new_dir_block < 0) {
635 free_inode(&fs->sb, &fs->bmaps->inode, new_ino);
636 free(path_copy);
637 return -ENOSPC;
638 }
639 parent_inode.direct[i] =
640 fs->sb.data_block_start + (uint32_t)new_dir_block;
641
642 memset(dir_block, 0, SFUSE_BLOCK_SIZE);
643 struct sfuse_dirent *entries = (struct sfuse_dirent *)dir_block;
644 entries[0].inode = new_ino;
645 strncpy(entries[0].name, name, SFUSE_NAME_MAX - 1);
646 entries[0].name[SFUSE_NAME_MAX - 1] = '\0';
647
648 write_block(fs->backing_fd, parent_inode.direct[i], dir_block);
649 parent_inode.size += SFUSE_BLOCK_SIZE;
650 added = true;
651 } else {
652 /* 기존 블록에서 빈 슬롯 검색 */
653 if (read_block(fs->backing_fd, parent_inode.direct[i], dir_block) < 0) {
654 free_inode(&fs->sb, &fs->bmaps->inode, new_ino);
655 free(path_copy);
656 return -EIO;
657 }
658 struct sfuse_dirent *entries = (struct sfuse_dirent *)dir_block;
659 for (uint32_t j = 0; j < DENTS_PER_BLOCK; ++j) {
660 if (entries[j].inode == 0) {
661 entries[j].inode = new_ino;
662 strncpy(entries[j].name, name, SFUSE_NAME_MAX - 1);
663 entries[j].name[SFUSE_NAME_MAX - 1] = '\0';
664 write_block(fs->backing_fd, parent_inode.direct[i], dir_block);
665 added = true;
666 break;
667 }
668 }
669 }
670 }
671
672 if (!added) {
673 /* 공간 부족 시 롤백 */
674 free_inode(&fs->sb, &fs->bmaps->inode, new_ino);
675 free(path_copy);
676 return -ENOSPC;
677 }
678
679 /* 새 아이노드를 디스크에 기록 */
680 inode_sync(fs->backing_fd, &fs->sb, new_ino, &new_inode);
681
682 /* 상위 디렉터리 메타데이터 갱신 */
683 parent_inode.mtime = (uint32_t)now;
684 parent_inode.ctime = (uint32_t)now;
685 inode_sync(fs->backing_fd, &fs->sb, parent_ino, &parent_inode);
686
687 free(path_copy);
688 return 0;
689}
690
702int fs_mkdir(struct sfuse_fs *fs, const char *path, mode_t mode) {
703 uint32_t dummy;
704 /* 이미 존재하면 실패 */
705 if (fs_resolve_path(fs, path, &dummy) == 0) {
706 return -EEXIST;
707 }
708
709 /* 상위 디렉터리와 새 이름 분리 */
710 char *path_copy = strdup(path);
711 if (!path_copy)
712 return -ENOMEM;
713 char *name = strrchr(path_copy, '/');
714 if (!name || *(name + 1) == '\0') {
715 free(path_copy);
716 return -EINVAL;
717 }
718 *name = '\0';
719 char *parent_path = (*path_copy == '\0') ? "/" : path_copy;
720 name++;
721
722 /* 상위 디렉터리 inode 조회 */
723 uint32_t parent_ino;
724 if (fs_resolve_path(fs, parent_path, &parent_ino) < 0) {
725 free(path_copy);
726 return -ENOENT;
727 }
728
729 struct sfuse_inode parent_inode;
730 inode_load(fs->backing_fd, &fs->sb, parent_ino, &parent_inode);
731 /* 상위가 디렉터리가 아니면 오류 */
732 if ((parent_inode.mode & S_IFDIR) == 0) {
733 free(path_copy);
734 return -ENOTDIR;
735 }
736
737 /* 새 아이노드 할당 */
738 int new_ino = alloc_inode(&fs->sb, &fs->bmaps->inode);
739 if (new_ino < 0) {
740 free(path_copy);
741 return new_ino;
742 }
743
744 /* 새 아이노드 초기화 */
745 struct sfuse_inode new_inode;
746 memset(&new_inode, 0, sizeof(new_inode));
747 new_inode.mode = (mode & 0xFFF) | S_IFDIR;
748 new_inode.uid = getuid();
749 new_inode.gid = getgid();
750 new_inode.size = 0;
751 time_t now = time(NULL);
752 new_inode.atime = (uint32_t)now;
753 new_inode.mtime = (uint32_t)now;
754 new_inode.ctime = (uint32_t)now;
755
756 /* 상위 디렉터리에 엔트리 추가 (메모리 안전성: 블록 전체 초기화) */
757 uint8_t dir_block[SFUSE_BLOCK_SIZE];
758 bool added = false;
759 for (int i = 0; i < 12 && !added; ++i) {
760 if (parent_inode.direct[i] == 0) {
761 /* 새 디렉터리 블록 할당 */
762 int new_dir_block = alloc_block(&fs->sb, &fs->bmaps->block);
763 if (new_dir_block < 0) {
764 free_inode(&fs->sb, &fs->bmaps->inode, new_ino);
765 free(path_copy);
766 return -ENOSPC;
767 }
768 parent_inode.direct[i] =
769 fs->sb.data_block_start + (uint32_t)new_dir_block;
770
771 memset(dir_block, 0, SFUSE_BLOCK_SIZE);
772 struct sfuse_dirent *entries = (struct sfuse_dirent *)dir_block;
773 entries[0].inode = new_ino;
774 strncpy(entries[0].name, name, SFUSE_NAME_MAX - 1);
775 entries[0].name[SFUSE_NAME_MAX - 1] = '\0';
776
777 write_block(fs->backing_fd, parent_inode.direct[i], dir_block);
778 parent_inode.size += SFUSE_BLOCK_SIZE;
779 added = true;
780 } else {
781 /* 기존 블록에서 빈 슬롯 검색 */
782 if (read_block(fs->backing_fd, parent_inode.direct[i], dir_block) < 0) {
783 free_inode(&fs->sb, &fs->bmaps->inode, new_ino);
784 free(path_copy);
785 return -EIO;
786 }
787 struct sfuse_dirent *entries = (struct sfuse_dirent *)dir_block;
788 for (uint32_t j = 0; j < DENTS_PER_BLOCK; ++j) {
789 if (entries[j].inode == 0) {
790 entries[j].inode = new_ino;
791 strncpy(entries[j].name, name, SFUSE_NAME_MAX - 1);
792 entries[j].name[SFUSE_NAME_MAX - 1] = '\0';
793 write_block(fs->backing_fd, parent_inode.direct[i], dir_block);
794 added = true;
795 break;
796 }
797 }
798 }
799 }
800
801 /* 공간 부족 시 롤백 */
802 if (!added) {
803 free_inode(&fs->sb, &fs->bmaps->inode, new_ino);
804 free(path_copy);
805 return -ENOSPC;
806 }
807
808 /* 새 아이노드 디스크에 기록 */
809 inode_sync(fs->backing_fd, &fs->sb, new_ino, &new_inode);
810
811 /* 상위 디렉터리 메타데이터 갱신 */
812 parent_inode.mtime = (uint32_t)now;
813 parent_inode.ctime = (uint32_t)now;
814 inode_sync(fs->backing_fd, &fs->sb, parent_ino, &parent_inode);
815
816 free(path_copy);
817 return 0;
818}
819
829int fs_unlink(struct sfuse_fs *fs, const char *path) {
830 uint32_t ino;
831 if (fs_resolve_path(fs, path, &ino) < 0) {
832 return -ENOENT;
833 }
834
835 struct sfuse_inode inode;
836 inode_load(fs->backing_fd, &fs->sb, ino, &inode);
837 /* 디렉터리는 삭제 불가 */
838 if ((inode.mode & S_IFDIR) == S_IFDIR) {
839 return -EISDIR;
840 }
841
842 /* 상위 디렉터리 및 파일 이름 분리 */
843 char *path_copy = strdup(path);
844 if (!path_copy)
845 return -ENOMEM;
846 char *name = strrchr(path_copy, '/');
847 *name = '\0';
848 char *parent_path = (*path_copy == '\0') ? "/" : path_copy;
849 name++;
850
851 /* 상위 디렉터리 inode 조회 */
852 uint32_t parent_ino;
853 fs_resolve_path(fs, parent_path, &parent_ino);
854
855 uint8_t dir_block[SFUSE_BLOCK_SIZE];
856 uint8_t zero_block[SFUSE_BLOCK_SIZE] = {0}; /* 블록 초기화용 제로 버퍼 */
857 struct sfuse_inode parent_inode;
858 inode_load(fs->backing_fd, &fs->sb, parent_ino, &parent_inode);
859
860 /* 상위 디렉터리에서 디렉터리 엔트리 제거 */
861 for (uint32_t i = 0; i < 12; ++i) {
862 if (parent_inode.direct[i] == 0)
863 continue;
864 if (read_block(fs->backing_fd, parent_inode.direct[i], dir_block) < 0)
865 continue;
866 struct sfuse_dirent *entries = (struct sfuse_dirent *)dir_block;
867 for (uint32_t j = 0; j < DENTS_PER_BLOCK; ++j) {
868 if (entries[j].inode == ino &&
869 strncmp(entries[j].name, name, SFUSE_NAME_MAX) == 0) {
870 /* 삭제 시 디렉터리 엔트리 전체를 0으로 초기화 */
871 memset(&entries[j], 0, sizeof(entries[j]));
872 write_block(fs->backing_fd, parent_inode.direct[i], dir_block);
873 goto found_entry;
874 }
875 }
876 }
877found_entry:
878
879 /* 직접 데이터 블록 해제: 내용 제로화 후 상대 인덱스로 비트맵 해제 */
880 for (int i = 0; i < 12; ++i) {
881 if (inode.direct[i] == 0)
882 continue;
883 write_block(fs->backing_fd, inode.direct[i],
884 zero_block); // 블록 내용 모두 0으로 덮어쓰기
885 free_block(&fs->sb, &fs->bmaps->block,
886 inode.direct[i] -
887 fs->sb.data_block_start); // 상대 블록 번호로 비트맵 해제
888 inode.direct[i] = 0;
889 }
890
891 /* 단일 간접 블록 해제: 데이터 블록과 포인터 블록 모두 제로화 후 해제 */
892 if (inode.indirect != 0) {
893 uint32_t ptrs[SFUSE_PTRS_PER_BLOCK];
894 read_block(fs->backing_fd, inode.indirect, ptrs);
895 for (uint32_t k = 0; k < SFUSE_PTRS_PER_BLOCK; ++k) {
896 if (ptrs[k] == 0)
897 continue;
898 write_block(fs->backing_fd, ptrs[k], zero_block);
899 free_block(&fs->sb, &fs->bmaps->block, ptrs[k] - fs->sb.data_block_start);
900 ptrs[k] = 0;
901 }
902 write_block(fs->backing_fd, inode.indirect,
903 zero_block); // 포인터 블록도 제로화
904 free_block(&fs->sb, &fs->bmaps->block,
905 inode.indirect - fs->sb.data_block_start);
906 inode.indirect = 0;
907 }
908
909 /* 이중 간접 블록 해제: 이중 레벨 순회하며 제로화 후 해제 */
910 if (inode.double_indirect != 0) {
911 uint32_t l1[SFUSE_PTRS_PER_BLOCK];
912 read_block(fs->backing_fd, inode.double_indirect, l1);
913 for (uint32_t i1 = 0; i1 < SFUSE_PTRS_PER_BLOCK; ++i1) {
914 if (l1[i1] == 0)
915 continue;
916 uint32_t l2[SFUSE_PTRS_PER_BLOCK];
917 read_block(fs->backing_fd, l1[i1], l2);
918 for (uint32_t i2 = 0; i2 < SFUSE_PTRS_PER_BLOCK; ++i2) {
919 if (l2[i2] == 0)
920 continue;
921 write_block(fs->backing_fd, l2[i2], zero_block);
922 free_block(&fs->sb, &fs->bmaps->block,
923 l2[i2] - fs->sb.data_block_start);
924 l2[i2] = 0;
925 }
926 write_block(fs->backing_fd, l1[i1], zero_block); // 2차 포인터 블록 제로화
927 free_block(&fs->sb, &fs->bmaps->block, l1[i1] - fs->sb.data_block_start);
928 l1[i1] = 0;
929 }
930 write_block(fs->backing_fd, inode.double_indirect,
931 zero_block); // 1차 포인터 블록 제로화
932 free_block(&fs->sb, &fs->bmaps->block,
933 inode.double_indirect - fs->sb.data_block_start);
934 inode.double_indirect = 0;
935 }
936
937 /* 아이노드 비트맵 해제 및 아이노드 초기화 */
938 free_inode(&fs->sb, &fs->bmaps->inode, ino);
939 struct sfuse_inode empty_inode;
940 memset(&empty_inode, 0, sizeof(empty_inode));
941 inode_sync(fs->backing_fd, &fs->sb, ino, &empty_inode);
942
943 /* 상위 디렉터리 메타데이터 갱신 */
944 time_t now_time = time(NULL);
945 parent_inode.mtime = (uint32_t)now_time;
946 parent_inode.ctime = (uint32_t)now_time;
947 inode_sync(fs->backing_fd, &fs->sb, parent_ino, &parent_inode);
948
949 free(path_copy);
950 return 0;
951}
952
963int fs_rmdir(struct sfuse_fs *fs, const char *path) {
964 uint32_t ino;
965 if (fs_resolve_path(fs, path, &ino) < 0) {
966 return -ENOENT;
967 }
968
969 struct sfuse_inode inode;
970 inode_load(fs->backing_fd, &fs->sb, ino, &inode);
971 /* 디렉터리인지 확인 */
972 if ((inode.mode & S_IFDIR) == 0) {
973 return -ENOTDIR;
974 }
975
976 /* 비어 있는지 확인 */
977 uint8_t block[SFUSE_BLOCK_SIZE];
978 for (int i = 0; i < 12; ++i) {
979 if (inode.direct[i] == 0)
980 continue;
981 if (read_block(fs->backing_fd, inode.direct[i], block) < 0)
982 continue;
983 struct sfuse_dirent *entries = (struct sfuse_dirent *)block;
984 for (uint32_t j = 0; j < DENTS_PER_BLOCK; ++j) {
985 if (entries[j].inode != 0) {
986 return -ENOTEMPTY;
987 }
988 }
989 }
990
991 /* fs_unlink 로직 재사용 */
992 char *dummy_path = strdup(path);
993 if (!dummy_path)
994 return -ENOMEM;
995 int res = fs_unlink(fs, path);
996 free(dummy_path);
997 return res;
998}
999
1011int fs_rename(struct sfuse_fs *fs, const char *from, const char *to) {
1012 uint32_t src_ino;
1013 if (fs_resolve_path(fs, from, &src_ino) < 0) {
1014 return -ENOENT;
1015 }
1016 uint32_t dummy;
1017 /* 대상이 이미 존재하면 실패 */
1018 if (fs_resolve_path(fs, to, &dummy) == 0) {
1019 return -EEXIST;
1020 }
1021
1022 /* 경로 복사 및 분할 */
1023 char *from_copy = strdup(from);
1024 char *to_copy = strdup(to);
1025 if (!from_copy || !to_copy) {
1026 free(from_copy);
1027 free(to_copy);
1028 return -ENOMEM;
1029 }
1030 char *from_name = strrchr(from_copy, '/');
1031 char *to_name = strrchr(to_copy, '/');
1032 *from_name = '\0';
1033 *to_name = '\0';
1034 char *from_parent_path = (*from_copy == '\0') ? "/" : from_copy;
1035 char *to_parent_path = (*to_copy == '\0') ? "/" : to_copy;
1036 from_name++;
1037 to_name++;
1038
1039 /* 부모 디렉터리 inode 조회 */
1040 uint32_t from_parent_ino, to_parent_ino;
1041 fs_resolve_path(fs, from_parent_path, &from_parent_ino);
1042 if (fs_resolve_path(fs, to_parent_path, &to_parent_ino) < 0) {
1043 free(from_copy);
1044 free(to_copy);
1045 return -ENOENT;
1046 }
1047
1048 struct sfuse_inode from_parent_inode, to_parent_inode;
1049 inode_load(fs->backing_fd, &fs->sb, from_parent_ino, &from_parent_inode);
1050 inode_load(fs->backing_fd, &fs->sb, to_parent_ino, &to_parent_inode);
1051 /* 디렉터리 여부 확인 */
1052 if ((from_parent_inode.mode & S_IFDIR) == 0 ||
1053 (to_parent_inode.mode & S_IFDIR) == 0) {
1054 free(from_copy);
1055 free(to_copy);
1056 return -ENOTDIR;
1057 }
1058
1059 uint8_t buf_block[SFUSE_BLOCK_SIZE];
1060 /* 원본 부모 디렉터리에서 엔트리 제거 */
1061 for (uint32_t i = 0; i < 12U; ++i) {
1062 if (from_parent_inode.direct[i] == 0)
1063 continue;
1064 read_block(fs->backing_fd, from_parent_inode.direct[i], buf_block);
1065 struct sfuse_dirent *entries = (struct sfuse_dirent *)buf_block;
1066 for (uint32_t j = 0; j < DENTS_PER_BLOCK; ++j) {
1067 if (entries[j].inode == src_ino &&
1068 strncmp(entries[j].name, from_name, SFUSE_NAME_MAX) == 0) {
1069 entries[j].inode = 0;
1070 entries[j].name[0] = '\0';
1071 write_block(fs->backing_fd, from_parent_inode.direct[i], entries);
1072 goto removed_src;
1073 }
1074 }
1075 }
1076removed_src:
1077
1078 /* 대상 부모 디렉터리에 엔트리 추가 */
1079 for (uint32_t i = 0; i < 12U; ++i) {
1080 if (to_parent_inode.direct[i] == 0) {
1081 int new_blk = alloc_block(&fs->sb, &fs->bmaps->block);
1082 if (new_blk < 0)
1083 break;
1084 to_parent_inode.direct[i] = new_blk;
1085 struct sfuse_dirent *entries = (struct sfuse_dirent *)buf_block;
1086 memset(entries, 0, sizeof(buf_block));
1087 entries[0].inode = src_ino;
1088 strncpy(entries[0].name, to_name, SFUSE_NAME_MAX - 1);
1089 entries[0].name[SFUSE_NAME_MAX - 1] = '\0';
1090 write_block(fs->backing_fd, to_parent_inode.direct[i], entries);
1091 to_parent_inode.size += SFUSE_BLOCK_SIZE;
1092 break;
1093 } else {
1094 read_block(fs->backing_fd, to_parent_inode.direct[i], buf_block);
1095 struct sfuse_dirent *entries = (struct sfuse_dirent *)buf_block;
1096 for (uint32_t k = 0; k < DENTS_PER_BLOCK; ++k) {
1097 if (entries[k].inode == 0) {
1098 entries[k].inode = src_ino;
1099 strncpy(entries[k].name, to_name, SFUSE_NAME_MAX - 1);
1100 write_block(fs->backing_fd, to_parent_inode.direct[i], entries);
1101 goto added_dst;
1102 }
1103 }
1104 }
1105 }
1106added_dst:
1107
1108 /* 메타데이터 갱신 */
1109 time_t now_time = time(NULL);
1110 from_parent_inode.mtime = from_parent_inode.ctime = (uint32_t)now_time;
1111 to_parent_inode.mtime = to_parent_inode.ctime = (uint32_t)now_time;
1112
1113 struct sfuse_inode src_inode;
1114 inode_load(fs->backing_fd, &fs->sb, src_ino, &src_inode);
1115 src_inode.ctime = (uint32_t)now_time;
1116
1117 inode_sync(fs->backing_fd, &fs->sb, src_ino, &src_inode);
1118 inode_sync(fs->backing_fd, &fs->sb, from_parent_ino, &from_parent_inode);
1119 inode_sync(fs->backing_fd, &fs->sb, to_parent_ino, &to_parent_inode);
1120
1121 free(from_copy);
1122 free(to_copy);
1123 return 0;
1124}
1125
1138int fs_truncate(struct sfuse_fs *fs, const char *path, off_t size) {
1139 uint32_t ino;
1140 if (fs_resolve_path(fs, path, &ino) < 0) {
1141 return -ENOENT;
1142 }
1143
1144 struct sfuse_inode inode;
1145 inode_load(fs->backing_fd, &fs->sb, ino, &inode);
1146
1147 /* 디렉터리인 경우 오류 반환 */
1148 if ((inode.mode & S_IFDIR) == S_IFDIR) {
1149 return -EISDIR;
1150 }
1151
1152 off_t old_size = inode.size;
1153 /* 변경할 크기가 동일하면 즉시 반환 */
1154 if (size == old_size) {
1155 return 0;
1156 }
1157 /* 크기 축소 */
1158 else if (size < old_size) {
1159 uint32_t keep_blocks =
1161 uint32_t old_blocks = (old_size + SFUSE_BLOCK_SIZE - 1) /
1163
1164 /* 축소되어야 할 블록 해제 */
1165 for (uint32_t i = keep_blocks; i < old_blocks; ++i) {
1166 if (i < 12) {
1167 if (inode.direct[i] != 0) {
1168 free_block(&fs->sb, &fs->bmaps->block, inode.direct[i]);
1169 inode.direct[i] = 0;
1170 }
1171 } else if (i < 12U + SFUSE_PTRS_PER_BLOCK) {
1172 if (inode.indirect != 0) {
1173 uint32_t ptrs[SFUSE_PTRS_PER_BLOCK];
1174 read_block(fs->backing_fd, inode.indirect, ptrs);
1175 int idx = i - 12;
1176 if (ptrs[idx] != 0) {
1177 free_block(&fs->sb, &fs->bmaps->block, ptrs[idx]);
1178 ptrs[idx] = 0;
1179 }
1180 write_block(fs->backing_fd, inode.indirect, ptrs);
1181 }
1182 } else {
1183 if (inode.double_indirect != 0) {
1184 uint32_t level1_arr[SFUSE_PTRS_PER_BLOCK];
1185 read_block(fs->backing_fd, inode.double_indirect, level1_arr);
1186 uint32_t idx = i - (12 + SFUSE_PTRS_PER_BLOCK);
1187 uint32_t l1_idx = idx / SFUSE_PTRS_PER_BLOCK;
1188 uint32_t l2_idx = idx % SFUSE_PTRS_PER_BLOCK;
1189
1190 if (level1_arr[l1_idx] != 0) {
1191 uint32_t level2_arr[SFUSE_PTRS_PER_BLOCK];
1192 read_block(fs->backing_fd, level1_arr[l1_idx], level2_arr);
1193 if (level2_arr[l2_idx] != 0) {
1194 free_block(&fs->sb, &fs->bmaps->block, level2_arr[l2_idx]);
1195 level2_arr[l2_idx] = 0;
1196 }
1197 write_block(fs->backing_fd, level1_arr[l1_idx], level2_arr);
1198 }
1199 }
1200 }
1201 }
1202
1203 /* 단일 간접 블록 전체가 비었는지 확인 후 해제 */
1204 if (inode.indirect != 0) {
1205 uint32_t ptrs[SFUSE_PTRS_PER_BLOCK];
1206 read_block(fs->backing_fd, inode.indirect, ptrs);
1207 int all_empty = 1;
1208 for (uint32_t j = 0; j < SFUSE_PTRS_PER_BLOCK; ++j) {
1209 if (ptrs[j] != 0) {
1210 all_empty = 0;
1211 break;
1212 }
1213 }
1214 if (all_empty) {
1215 free_block(&fs->sb, &fs->bmaps->block, inode.indirect);
1216 inode.indirect = 0;
1217 }
1218 }
1219
1220 /* 이중 간접 블록 전체가 비었는지 확인 후 해제 */
1221 if (inode.double_indirect != 0) {
1222 uint32_t level1[SFUSE_PTRS_PER_BLOCK];
1223 read_block(fs->backing_fd, inode.double_indirect, level1);
1224 int all_l1_empty = 1;
1225 for (uint32_t a = 0; a < SFUSE_PTRS_PER_BLOCK; ++a) {
1226 if (level1[a] != 0) {
1227 uint32_t level2[SFUSE_PTRS_PER_BLOCK];
1228 read_block(fs->backing_fd, level1[a], level2);
1229 int all_l2_empty = 1;
1230 for (uint32_t b = 0; b < SFUSE_PTRS_PER_BLOCK; ++b) {
1231 if (level2[b] != 0) {
1232 all_l2_empty = 0;
1233 break;
1234 }
1235 }
1236 if (all_l2_empty) {
1237 free_block(&fs->sb, &fs->bmaps->block, level1[a]);
1238 level1[a] = 0;
1239 } else {
1240 all_l1_empty = 0;
1241 }
1242 }
1243 }
1244 if (all_l1_empty) {
1245 free_block(&fs->sb, &fs->bmaps->block, inode.double_indirect);
1246 inode.double_indirect = 0;
1247 } else {
1248 write_block(fs->backing_fd, inode.double_indirect, level1);
1249 }
1250 }
1251
1252 inode.size = size;
1253 }
1254 /* 크기 확장 */
1255 else {
1256 char zero = 0;
1257 if (fs_write(fs, path, &zero, 1, size - 1) < 0) {
1258 return -EIO;
1259 }
1260 return 0;
1261 }
1262
1263 /* 시간 정보 갱신 및 동기화 */
1264 time_t now_time = time(NULL);
1265 inode.mtime = (uint32_t)now_time;
1266 inode.ctime = (uint32_t)now_time;
1267 inode_sync(fs->backing_fd, &fs->sb, ino, &inode);
1268 return 0;
1269}
1270
1280int fs_fsync(struct sfuse_fs *fs, const char *path, int datasync,
1281 struct fuse_file_info *fi) {
1282 (void)path;
1283 (void)fi;
1284 if (datasync) {
1285 if (fdatasync(fs->backing_fd) < 0)
1286 return -errno;
1287 } else {
1288 if (fsync(fs->backing_fd) < 0)
1289 return -errno;
1290 }
1291 return 0;
1292}
1293
1302int fs_flush(struct sfuse_fs *fs, const char *path, struct fuse_file_info *fi) {
1303 (void)path;
1304 (void)fi;
1305 if (fsync(fs->backing_fd) < 0)
1306 return -errno;
1307 return 0;
1308}
1309
1318int fs_utimens(struct sfuse_fs *fs, const char *path,
1319 const struct timespec tv[2]) {
1320 uint32_t ino;
1321 if (fs_resolve_path(fs, path, &ino) < 0) {
1322 return -ENOENT;
1323 }
1324 struct sfuse_inode inode;
1325 if (inode_load(fs->backing_fd, &fs->sb, ino, &inode) < 0) {
1326 return -EIO;
1327 }
1328 inode.atime = (uint32_t)tv[0].tv_sec;
1329 inode.mtime = (uint32_t)tv[1].tv_sec;
1330 inode.ctime = (uint32_t)time(NULL);
1331 inode_sync(fs->backing_fd, &fs->sb, ino, &inode);
1332 return 0;
1333}
1334
1343int fs_access(struct sfuse_fs *fs, const char *path, int mask) {
1344 uint32_t ino;
1345 /* 경로 → inode 변환 실패 시 ENOENT 반환 */
1346 if (fs_resolve_path(fs, path, &ino) < 0)
1347 return -ENOENT;
1348 /* mask에 따른 실제 권한 검사는 필요 시 구현 가능 */
1349 (void)mask;
1350 return 0;
1351}
int alloc_inode(struct sfuse_superblock *sb, struct sfuse_inode_bitmap *imap)
슈퍼블록 기반으로 아이노드 할당
Definition bitmap.c:95
int bitmap_sync(int fd, uint32_t start_blk, const struct sfuse_bitmaps *bmaps, uint32_t count)
메모리 비트맵을 디스크에 동기화
Definition bitmap.c:40
void free_inode(struct sfuse_superblock *sb, struct sfuse_inode_bitmap *imap, uint32_t ino)
슈퍼블록 기반으로 아이노드 해제
Definition bitmap.c:109
int alloc_block(struct sfuse_superblock *sb, struct sfuse_block_bitmap *bmap)
슈퍼블록 기반으로 데이터 블록 할당
Definition bitmap.c:121
void free_block(struct sfuse_superblock *sb, struct sfuse_block_bitmap *bmap, uint32_t blk)
슈퍼블록 기반으로 데이터 블록 해제
Definition bitmap.c:135
ssize_t read_block(int fd, uint32_t blk, void *out_buf)
지정한 블록 번호의 데이터를 읽어 버퍼에 저장
Definition block.c:15
ssize_t write_block(int fd, uint32_t blk, const void *buf)
버퍼의 내용을 지정한 블록 번호에 기록
Definition block.c:31
#define SFUSE_NAME_MAX
Definition dir.h:10
int dir_list(const struct sfuse_fs *fs, uint32_t dir_ino, void *buf, fuse_fill_dir_t filler, off_t offset)
FUSE용 디렉터리 목록 채우기 콜백 호출
Definition dir.c:58
int dir_lookup(const struct sfuse_fs *fs, uint32_t dir_ino, const char *name, uint32_t *out_ino)
디렉터리에서 이름으로 inode 번호를 검색
Definition dir.c:18
#define DENTS_PER_BLOCK
한 블록당 디렉터리 엔트리 수
Definition dir.h:14
int fs_getattr(struct sfuse_fs *fs, const char *path, struct stat *stbuf)
파일 또는 디렉터리 속성 가져오기 (stat)
Definition fs.c:237
int fs_mkdir(struct sfuse_fs *fs, const char *path, mode_t mode)
새 디렉터리 생성
Definition fs.c:702
struct sfuse_fs * fs_initialize(const char *path, int *error_out)
SFUSE FS 초기화
Definition fs.c:105
int fs_read(struct sfuse_fs *fs, const char *path, char *buf, size_t size, off_t offset)
파일 읽기
Definition fs.c:310
void fs_teardown(struct sfuse_fs *fs)
파일 시스템 해제
Definition fs.c:165
static int fs_format_filesystem(int fd, struct sfuse_superblock *sb)
빈 이미지 파일을 VSFS 구조로 포맷
Definition fs.c:35
int fs_create(struct sfuse_fs *fs, const char *path, mode_t mode, struct fuse_file_info *fi)
새 파일 생성
Definition fs.c:570
int fs_truncate(struct sfuse_fs *fs, const char *path, off_t size)
파일 크기 조정
Definition fs.c:1138
int fs_utimens(struct sfuse_fs *fs, const char *path, const struct timespec tv[2])
파일 접근/수정 시간 업데이트
Definition fs.c:1318
int fs_rmdir(struct sfuse_fs *fs, const char *path)
비어 있는 디렉터리 삭제
Definition fs.c:963
int fs_resolve_path(struct sfuse_fs *fs, const char *path, uint32_t *out_ino)
경로 문자열을 inode 번호로 변환
Definition fs.c:198
int fs_open(struct sfuse_fs *fs, const char *path, struct fuse_file_info *fi)
파일 열기 (존재 여부만 확인)
Definition fs.c:290
int fs_fsync(struct sfuse_fs *fs, const char *path, int datasync, struct fuse_file_info *fi)
파일 시스템 동기화 (flush/fsync)
Definition fs.c:1280
int fs_unlink(struct sfuse_fs *fs, const char *path)
파일 삭제
Definition fs.c:829
int fs_readdir(struct sfuse_fs *fs, const char *path, void *buf, fuse_fill_dir_t filler, off_t offset)
디렉터리 목록 가져오기
Definition fs.c:272
int fs_access(struct sfuse_fs *fs, const char *path, int mask)
파일 접근 권한 검사
Definition fs.c:1343
int fs_write(struct sfuse_fs *fs, const char *path, const char *buf, size_t size, off_t offset)
파일 쓰기
Definition fs.c:407
int fs_rename(struct sfuse_fs *fs, const char *from, const char *to)
파일 또는 디렉터리 이름 변경 (이동)
Definition fs.c:1011
int fs_flush(struct sfuse_fs *fs, const char *path, struct fuse_file_info *fi)
FUSE의 flush 호출 처리
Definition fs.c:1302
bool g_force_format
강제 포맷 옵션 플래그
Definition main.c:32
#define SFUSE_PTRS_PER_BLOCK
한 블록에 담을 수 있는 포인터 수 (32-bit)
Definition inode.h:17
int inode_load(int fd, const struct sfuse_superblock *sb, uint32_t ino, struct sfuse_inode *out)
디스크 이미지에서 아이노드를 읽어 구조체에 로드
Definition inode.c:32
int inode_sync(int fd, const struct sfuse_superblock *sb, uint32_t ino, const struct sfuse_inode *in)
아이노드 구조체 내용을 디스크 이미지에 동기화
Definition inode.c:51
아이노드 비트맵과 블록 비트맵을 함께 담는 구조체
Definition bitmap.h:30
struct sfuse_block_bitmap block
Definition bitmap.h:32
struct sfuse_inode_bitmap inode
Definition bitmap.h:31
디스크에 저장되는 디렉터리 엔트리 구조체
Definition dir.h:19
uint32_t inode
Definition dir.h:20
char name[256]
Definition dir.h:21
SFUSE 파일 시스템 컨텍스트 구조체
Definition fs.h:21
struct sfuse_bitmaps * bmaps
Definition fs.h:24
struct sfuse_superblock sb
Definition fs.h:23
struct sfuse_inode_block * inode_table
Definition fs.h:25
int backing_fd
Definition fs.h:22
uint8_t map[4096]
Definition bitmap.h:17
디스크에 저장되는 아이노드 구조체
Definition inode.h:22
uint32_t double_indirect
Definition inode.h:32
uint32_t mode
Definition inode.h:23
uint32_t direct[12]
Definition inode.h:30
uint32_t atime
Definition inode.h:27
uint32_t indirect
Definition inode.h:31
uint32_t size
Definition inode.h:26
uint32_t uid
Definition inode.h:24
uint32_t mtime
Definition inode.h:28
uint32_t gid
Definition inode.h:25
uint32_t ctime
Definition inode.h:29
슈퍼블록 구조체
Definition super.h:51
uint32_t total_inodes
Definition super.h:53
uint32_t inode_table_start
Definition super.h:59
uint32_t free_inodes
Definition super.h:55
uint32_t free_blocks
Definition super.h:56
uint32_t block_bitmap_start
Definition super.h:58
uint32_t data_block_start
Definition super.h:60
uint32_t inode_bitmap_start
Definition super.h:57
uint32_t magic
Definition super.h:52
uint32_t total_blocks
Definition super.h:54
#define SFUSE_BLOCK_SIZE
블록 크기 (바이트 단위)
Definition super.h:20
#define SFUSE_MAX_INODES
최대 아이노드 수
Definition super.h:27
int sb_sync(int fd, const struct sfuse_superblock *sb)
슈퍼블록을 디스크에 동기화
Definition super.c:40
#define SFUSE_MAGIC
SFUSE 매직 넘버
Definition super.h:13