본문 바로가기
2022-2/시스템 프로그래밍

5. 파일 시스템

by 철없는민물장어 2022. 11. 2.
728x90
반응형
파일 시스템 구조
  • 부트 블록
  • 슈퍼 블록: 전체 파일 시스템에 대한 정보를 저장(총 블록 수, 사용 가능한 i-노드 수 등)
  • i-리스트 : 각 파일을 나타내는 모든 i-노드들의 리스트. 한 블록은 약 40개 정도의 i-노드를 포함함.(i-노드 하나가 하나의 파일을 가리킴)
  • 데이터 블록 : 실제 파일의 내용(데이터)을 저장하기 위한 블록들

 

i-노드

하나의 파일은 하나의 i-노드를 갖는다.

i-노드는 파일에 대한 모든 정보를 가지고 있음.(ls-l명령어의 출력에서 나오는 것들이 i-node에 저장되어있음)

 

데이터 블록 포인터

i-node 내부에 위치함.

파일의 내용을 저장하기 위해 할당된 데이터 블록의 주소.

하나의 i-node 내의 블록 포인터는

  • 직접 블록 포인터 12개
  • 간접 블록 포인터 1개
  • 이중 간접 블록 포인터 1개
  • 삼중 간접 블록 포인터 1개

가 있음(최대 파일의 크기는 대략 64테라바이트라고함)


파일 입출력 구현

파일 입출력 구현을 위한 커널 내부의 파일 시스템 자료구조

  • 파일 디스크립터 테이블(fd테이블)
  • 시스템 파일 테이블
  • (동적)i-노드 테이블

 

파일 디스크립터 테이블

프로세스당 하나씩 갖는다.

파일 디스크립터(fd)는 파일 디스크립터 테이블의 인덱스임(열린 파일을 나타내는 번호)

 

시스템 파일 테이블 (열린 파일 테이블)

열려진 모든 파일 목록을 저장하기 위한 공간

시스템 파일 테이블의 목록

  • 파일 상태 플래그(read,write,append...)
  • 파일의 현재 위치(current file offset)
  • Reference counter
  • 동적 i-node 테이블의 해당 엔트리를 가리킴

 

동적 i-노드 테이블

Open된 파일들의 i-node를 별도로 저장하기 위한 테이블

(파일을 열면 파일 시스템 내에서 i-node 내용을 가져와 메모리 상의 이 테이블 엔트리로 만든다)


fd2= dup(fd1);

dup2(fd2,fd1);

fd를 복제함.

결국 fd1과 fd2는 하나의 열린 파일 테이블을 가리키게 됨.


5.2 파일 상태 정보

파일 상태: 

파일에 대한 모든 정보. (블록 수, 파일 타입, 접근 권한, 링크 수, 파일 소유자의 사용자ID, 그룹ID, 파일 크기, 최종 수정시간 등)

 

stat 명령어
$ stat [옵션] 파일

파일의 자세한 상태 정보를 출력한다.

 

 

 

stat() 함수
#include <sys/types.h>
#include <sys/stat.h>

int stat(const char *filename, struct stat *buf);//파일이름으로 지정

int fstat(int fd, struct stat *buf);//대상 파일을 fd로 지정

int lstat(const char *filename, struct stat *buf);
//기본적으로 stat()과 동일하나, 대상 파일이 심볼릭 링크일 경우,
//링크가 가리키는 파일이 아니라 링크 자체에 대한 정보를 가져옴

파일의 상태 정보를 가져와서 stat 구조체 buf에 저장함. 성공하면 0, 실패하면 -1 리턴.

 

stat 구조체
struct stat{
	mode_t st_mode; //파일타입과 사용권한
    ino_t st_ino; //i-노드번호
    dev_t st_dev; //장치 번호
    
    nlink_t st_nlink;//링크 수
    uid_t st_uid;// 소유자의 id
    gid_t st_gid;
    off_t st_size//파일크기
    time_t st_atime; //최종접근시간
    .
    .
    .
    long st_blocks; //파일의 블록 수
};

st_mode는 권한도 나타내지만 파일타입도 저장함.

 

파일 타입 검사 함수

stat구조체 내의 st_mode필드 내부를 조사하는 대신 다음과 같은 매크로함수 사용가능

 

  • S_ISREG()
  • S_ISDIR()
  • S_ISCHR()
  • S_ISLNK()
  • ...

파일 타입 검사 함수 사용 예시

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

int main(int argc, char *argv[])
{
	int i;
    struct stat buf;
    for(i=1;i<argc;i++){
    	printf("%s: ",argv[i]);
        if(lstat(argv[i], &buf)<0){ //파일의 상태정보를 stat구조체에 저장
        	perror("lstat()");
            continue;
            }
        if(S_ISREG(buf.st_mode))
        	printf("%s \n","일반 파일");
        if(S_ISDIR(buf.st_mode))
        	printf("%s \n","디렉터리");
        if(S_ISCHR(buf.st_mode))
        	printf("%s \n","문자 장치 파일");
        if(S_ISBLK(buf.st_mode))
        	printf("%s \n","블록 장치 파일");
        if(S_ISFIFO(buf.st_mode))
        	printf("%s \n","FIFO 파일");
        if(S_ISLNK(buf.st_mode))
        	printf("%s \n","심볼릭 링크");
        if(S_ISSOCK(buf.st_mode))
        	printf("%s \n","소켓");
        }
    exit(0);
            
}

lstat(filename,&buf) 함수를 이용하여 stat구조체 buf에 파일상태를 저장하고

buf.st_mode를 S_ISREG 등의 매크로함수 인자로 넘겨준다.

 

 

파일 사용권한 변경

파일 사용권한은 stat구조체의 st_mode의 값으로 저장됨.

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

int chmod(const char *path, mode_t mode); //파일 이름 사용

int fchmod(int fd, mode_t mode): //fd사용

파일의 사용권한을 변경한다. 성공하면 0, 실패하면 -1 리턴

더보기
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
long strtol();
int main(int argc,char *argv[])
{
    int newmode;
    newmode=(int)strtol(argv[1],(char**)NULL,8);
    if(chmod(argv[2],newmode)==-1){
        perror(argv[2]);
        exit(1);
    }
    exit(0);
}

 

파일 소유자 변경

파일의 UID,GID변경하기.

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

int chown(const char *path, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, git_t group);
int lchown(const char *path, uid_t owner, gid_t group);

성공하면 0, 실패하면 -1을 리턴한다.

lchown()은 심볼릭 링크 자체의 소유자를 변경한다.(링크가 가리키는 원본이 아님)

파일 소유자는 super user만 변경가능

 

(참고)utime()

더보기

파일의 최종 접근 시간과 최종 변경 시간을 조정한다.

#include <sys/types.h>
#include <utime.h>

int utime(const char *filename, const struct utimbuf *times);

times가 NULL이면 현재시간으로 설정된다.

성공하면 0, 실패하면 -1 리턴.

 


디렉터리

디렉터리 구현

디렉터리 엔트리에는 파일이름과 i-노드 번호가 저장되어 있다.

#include <dirent.h>
struct dirent{
	ino_t d_ino;//i노드번호
    char d_name[NAME_MAX+1];//파일이름
}

디렉터리를 위한 별도의 구조는 없다

  • 디렉터리도 일종의 파일로 다른 파일처럼 구현된다
  • 디렉터리도 다른 파일처럼 하나의 i-노드로 표현된다
  • 디렉터리의 내용은 디렉터리 엔트리(파일이름, i-노드 번호)

 

디렉터리도 파일이므로 기본적으로 open(), read(), close() 함수를 사용할 수 있으나 별도의 콜 함수가 존재함

디렉터리 리스트

opendir() : 디렉터리 열기 함수

readdir() :디렉터리 읽기 함수

#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *path);
//path디렉터리를 열고 서공하면 DIR구조체 포인터를, 실패하면 NULL 리턴

struct dirent *readdir(DIR *dp);
//한 번에 디렉터리 엔트리를 하나씩 읽어서 리턴한다.

 

디렉터리를 열어 안의 파일을 출력하는 프로그램

더보기
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char**argv)
{
    DIR *dp;
    char *dir;
    struct dirent *d;
    struct stat st;
    char path[BUFSIZ+1];
    if(argc==1)
        dir="."; //인자 없이 사용할 경우 현재 디렉터리를 대상으로함
    else dir=argv[1];
    if((dp=opendir(dir))==NULL)
        perror(dir);
    while ((d=readdir(dp))!=NULL)
         sprintf(path, "%s/%s", dir, d->d_name);
        if(lstat(path, &st)<0)
            perror(path);
        if(S_ISREG(st.st_mode))
            printf("%s \n","일반 파일");
        if(S_ISDIR(st.st_mode))
            printf("%s \n","디렉터리");
        if(S_ISCHR(st.st_mode))
            printf("%s \n","문자 장치 파일");
        if(S_ISBLK(st.st_mode))
            printf("%s \n","블록 장치 파일");
        if(S_ISFIFO(st.st_mode))
            printf("%s \n","FIFO 파일");
        if(S_ISLNK(st.st_mode))
            printf("%s \n","심볼릭 링크");
        if(S_ISSOCK(st.st_mode))
            printf("%s \n","소켓");
        printf("%10s %5lld %5lld %5lld %5lld %10lld",d->d_name, st.st_dev, s    t.st_nlink, st.st_size,st.st_blocks,st.st_atime);
        putchar('\n');
    printf("%s \n",d->d_name);
    closedir(dp);
    exit(0);
}

 

 

 

디렉터리 생성하기

mkdir()

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

int mkdir(const char *path, mode_t mode);

새로운 디렉터리 생성을 성공하면 0, 실패하면 -1을 리턴한다.

 

디렉터리 삭제하기

rmdir()

#include <unistd.h>

int rmdir(const char *path);

디렉터리가 비어 있으면 삭제한다.

 


링크

 

ln명령어

ln [-s] 파일1 파일2 
//파일1의 새로운이름으로 파일2생성

ln [-s] 파일1 디렉터리
//파일1의 링크를 지정 디렉터리에 같은이름으로 생성

 

#include <unistd.h>

int link(char *existing, char *new);
int unlink(char *path);

 

하드링크시 원본과 링크는 둘 다 같은 i-node값을 가지고

 

심볼릭링크는 원본과 링크가 서로 다른 i-node값을 가진다.

심볼릭링크의 i-node포인터가 가리키는 데이터블록에는 실제파일의 경로명이 있다.

원본이 삭제되면 접근불가하다.

 

int symlink(const char* actualpath, const char* sympath);
//심볼릭링크 생성

int readlink(const char* path, char* buf, size_t bufsize);
//심볼릭 링크의 실제 내용=> 원본파일의 경로를 읽어 buf에 저장
728x90
반응형

'2022-2 > 시스템 프로그래밍' 카테고리의 다른 글

10장 메모리 관리  (0) 2022.11.11
8장 프로세스  (1) 2022.11.08
4장 파일 입출력  (0) 2022.10.30
gdb 디버거  (3) 2022.10.14
make 시스템  (0) 2022.10.11

댓글