본문 바로가기
컴퓨터공학기초 개념/시스템 프로그래밍

37. 시스템 프로그래밍 - 파일시스템 관련 시스템 콜

by devraphy 2021. 9. 27.

0. 시작하기전에

- 이번 포스팅에서는 파일 시스템과 관련된 시스템 콜에 대해서 알아보자. 


1. inode 파일 시스템 

- 리눅스는 inode라는 파일 시스템을 사용한다.

- 이 파일 시스템을 이해하는데 가장 큰 도움이 되는 것은 inode의 구조체를 이해하는 것이다. 

- 다음 사진에서 빨간색 네모로 표시된 inode의 구조체를 살펴보자. 

- 프로세스는 pid로 구분되고, 프로세스의 상태를 나타내는 pcb를 가지고 있다.

- 이처럼 파일도 inode번호로 구분되고, 각 inode번호에 대응하는 구조체를 갖고 있다. 

 

▶ Mode

   - 파일 종류, 권한

 

▶ Owner Info

   - 소유자, 소유 그룹

 

▶ Size

   - 파일의 사이즈

 

▶ Timestamps

   - 파일의 생성, 수정 등의 시간정보 

 

▶ Direct Blocks

   - 파일은 가변적인 크기를 갖는다. 어떤 파일은 1바이트, 어떤 파일은 몇 기가의 크기를 가질 수 있다. 

   - 이처럼 가변적인 크기를 갖는 파일이 저장위치를 나타내는 직접주소(데이터 위치)를 표현한다.

 

▶ Single, Double, Triple indirect

  - 파일의 간접주소를 표현를 표현한다. 

 

 

a) stat() - inode 메타 데이터를 가져오는 시스템 콜

- 위에서 설명했듯이, 각 파일에는 inode 구조체를 가지고 있다. 

- 이 inode 구조체가 가진 정보를 inode 메타데이터라고 부른다. 

- stat() 함수는 이 inode 메타데이터를 한번에 불러오는 시스템 콜이다.

- 다음 stat() 함수의 원문을 살펴보자. 

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *path, struct stat *buf); // 파일 이름(경로)를 이용해 inode 메타데이터를 가져온다
int fstat(int filedes, struct stat *buf); // file descriptor를 이용해 inode 메타데이터를 가져온다.

 

 

b) stat 구조체

- stat 구조체는 다음과 같은 inode의 메타데이터를 가져온다.

 

 

c) 실습예제 - inode 메타 데이터 출력하기 

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

int main() {
        int ret = 0;
        struct stat buf;
        ret = stat("link.txt", &buf);
        if(ret < 0) {
                printf("ERROR\n");
                return 0;
        }
        printf("deviceID[%ld], inodenum[%ld], hardlinkcount[%ld], filesize[%ld], blocksize[%ld], blockcount[%ld] \n", buf.st_dev, buf.st_ino, buf.st_nlink, buf.st_size, buf.st_blksize, buf.st_blocks);
        return 0;
}

* 참고로 filesize의 경우, 실제 파일이 차지하고 있는 영역과 추가될 것을 대비하여 예약되어 있는 영역을 포함하여 계산된다. 

* 참고로 blockcount의 경우, 1개의 블럭을 512Byte로 기준으로 하여 몇개의 블럭이 사용되는지를 계산한다.

 


2. 표준 입출력 관련 시스템 콜 

- 앞서 표준 입출력은 다음 세가지 스트림으로 구분된다는 것을 배웠다.

 

▶ 표준 입력 스트림(Standard Input Stream) - stdin

▶ 표준 출력 스트림(Standard Output Stream) - stdout

▶ 오류 출력 스트림(Standard Error Stream) - stderr

 

- 이 세가지 스트림이 프로그램에서 어떻게 사용되는지 예제를 통해 알아보자. 

 

 

a) 실습예제

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char** argv) {
        char buf[255];
        FILE* fp;
        if(argc == 2) { // 인자가 들어오는 경우
                fp = fopen(argv[1], "r"); // 인자를 오픈해서 fp에 저장한다.
                if(fp == NULL) {
                        fputs("file open error", stderr);
                        exit(0);
                }
        } else {
                fp = stdin; // 인자가 없는 경우, 인자를 받는다.(표준입력)
        }

        while(fgets(buf, 255, fp) != NULL) { // 인자를 255만큼의 크기를 입력 받은 경우
                fputs(buf, stdout); // 인자를 출력한다. (표준출력)
        }
}

- 이처럼 파일 디스크립터를 이용하여 표준 입출력이 작동한다는 것을 확인할 수 있다. 

댓글