• 표준 유닉스 파일 시스템은 부트 블록, 슈퍼 블록, i-리스트, 데이터블록 부분으로 구성된다
• 파일 입출력 구현을 위해서 커널 내에 파일 디스크립터 배열, 파일테이블, 동적 i-노드 테이블 등의 자료구조를 사용한다.
• 파일 하나당 하나의 i-노드가 있으며 i-노드 내에 파일에 대한 모든 상태 정보가 저장되어 있다.
• 디렉터리는 일련의 디렉터리 엔트리들을 포함하고 각 디렉터리 엔트리는 파일 이름과 그 파일의 i-노드 번호로 구성된다.
• 링크는 기존 파일에 대한 또 다른 이름으로 하드 링크와 심볼릭(소프트) 링크가 있다.
부트 블록(Boot Block)
: 파일 시스템 시작부에 위치하고 보통 첫번째 섹터를 차지함.
: 리눅스 시작시 사용되는 부트스트랩 코드가 저장되는 블록.
슈퍼 블록(Super Block)
: 전체 파일 시스템에 대한 정보를 저장.
: 총 블록수, 사용가능한 i-노드 개수, 사용 가능한 블록 비트맵,
블록의 크기, 사용중인 블록 수, 사용 가능한 블록 수 등.
i-노드 리스트 (i-Node List)
: 각 파일을 나타내는 모든 i-노드들의 리스트
: 한 블록은 약 40 개 정도의 i-노드를 포함
데이터 블록(Data block)
: 파일의 내용(데이터)를 저장하기 위한 블록들
한 파일은 하나의 i-노드를 갖는다.
파일에 대한 상태 정보를 가지고 있음.
ex) 파일 타입 : 일반 파일, 디렉터리, 블록장치, 문자 장치 등
파일크기
사용권한
파일 소유자 및 그룹
접근 및 갱신 기간
데이터 블록에 대한 포인터(주소) 등
데이터 블록(파일의 내용(데이터)을 저장하는 블록) 에 대한 포인터
하나의 i-노드 내의 블록 포인터
직접 블록포인터 10개 -> 각 1개씩 10개의 데이터블록 가리킬 수 있음.
간접 블록포인터 1개 -> 1024개의 직접 블록포인터를 가리킬 수 있음
-> 1024개의 데이터블록을 가리킬 수 있음.
- 블록 포인터 크기 4바이트, 한 블록의 크기 4096바이트 일때 간접 블록 포인터가 가리키는 데이터 블록 내의 1024개의
직접 블록 포인터를 저장할 수 있음.
이중 간접 블록 포인터 -> 1024개의 간접 블록 포인터를 가리킬 수 있음 -> 1024*1024개의 데이터블록을 가리킬 수 있음.
▲ 1 ▲ 2 ▲ 3 ▲ 4
프로세스당 하나씩 갖는다.
파일 디스크립트 배열
: 프로세스 내의 자료구조
: 프로세스 내에서 열린 파일의 파일 디스크립터를 저장하기 위한 구조
: 열린 파일 테이블 엔트리를 가리킴.
파일 테이블(file table)
: 커널 내의 자료구조
: 열려진 모든 파일 목록
: 파일 테이블 엔트리로 구성
: 파일을 열 때 마다 파일 테이블 엔트리가 만들어짐
파일 테이블 엔트리(FIle table entry)
: 파일 상태 플래그 (read, write, append)
: 파일의 현재 위치 (current file position)
: 동적 i-node에 대한 포인터
동적 i-노드 테이블
: 커널 내의 자료구조
: 열린 파일들의 i노드를 저장하는 테이블
: 열린 파일의 i노드의 모든 정보를 가져옴
i-노드
: 하드디스크에 저장되어 있는 파일에 대한 자료구조
: 한 파일에 하나의 i-노드
: 하나의 파일에 대한 정보 저장
ex) 소유자, 크기, 파일이 위치한 장치, 파일 내용 디스크블록에 대한 포인터
fd배열 내에만 새로운 엔트리를 만듦.
열린 파일 테이블 내의 동일한 파일 엔트리를 가리키도록 함.
파일 상태(file status)
: 파일에 대한 모든 정보
: 블록 수, 파일 타입, 사용 권한, 링크 수, 사용자 ID, 그룹 ID, 파일 크기, 수정시간 등
ex) $ls -l hello.c
2 -rw-r--r-- 1 chang cs 617 11월17일15:53 hello
상태 정보 : stat()
: 파일 하나당 하나의 i-노드가 있으며
: i-노드 내에 파일에 대한 모든 상태 정보가 저장되어 있다.
: lstat()과 stat()의 차이는 lstat은 대상이 심볼릭 링크일 때 링크가 가리키는 파일이 아니라 링크 자체에 대한 정보
int stat(const char *filename, struct stat *buf);
int fstat(int fd, struct stat * buf);
int lstat(const char *filename, struct stat *buf);
// 파일의 상태정보를 가져와서 stat 구조체 buf에 저장한다.
성공하면 0, 실패하면 -1리턴
struct stat {
mode_t st_mode; // __파일 타입과 사용권한__
ino_t st_ino; // i-노드 번호
dev_t st_dev; // 장치 번호
dev_t st_rdev; // 특수 파일 장치 번호
nlink_t st_nlink; // 링크 수
uid_t st_uid; // 소유자의 사용자 ID
gid_t st_gid; // 소유자의 그룹 ID
off_t st_size; // 파일 크기
time_t st_atime; // 최종 접근 시간
time_t st_mtime; // 최종 수정 시간
time_t st_ctime; // 최종 상태 변경 시간
long st_blksize; // 최적 블록 크기
long st_blocks; // 파일의 블록 수
};
`
파일타입
파일 타입 검사 함수
맞으면 1 아니면 0 리턴
ex) 파일타입 검사함수 ftype.c
#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]);
// 파일정보를 가져오는데 실패하면 error메세지 출력
if (lstat(argv[i], &buf) < 0)
{
perror("lstat()");
continue;
}
if (S_ISREG(buf.st_mode)) // 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);
}
: 각파일에 대한 권한관리 (owner/ group / others) 로 구분해서 관리한다.
권한 종류 : 읽기 r , 쓰기 w, 실행 x
int chmod (const char *path, mode_t mode );
int fchmod (int fd, mode_t mode );
// 리턴 값 -1 실패, 0 성공
// mode : 8진수 형태의 세자리 정수 ex) 664
ex) fchmod.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
/* 파일 사용권한을 변경한다. */
int main(int argc, char *argv[])
{
long strtol( );
int newmode;
newmode = (int) strtol(argv[1], (char **) NULL, 8); // string to long (8진수)
if (chmod(argv[2], newmode) == -1) {
perror(argv[2]);
exit(1);
}
exit(0);
}
struct utimbuf {
time_t actime; /* access time */
time_t modtime; /* modification time */
}
루트 디렉터리부터 시작하여 트리 구조 형성
디렉터리 안의 디렉터리를 해당 디렉터리의 서브디렉터리라고 한다.
디렉터리 엔트리 : 각 엔트리는 디렉터리 내 하나의 파일을 나타냄
파일 이름과 그 파일의 i-노드 번호로 구성
opendir()
: 디렉터리 열기 함수
: dir 포인터 (열린 디렉터리를 가리키는 포인터) 리턴
readdir()
: 디렉터리 읽기 함수
dir 구조체 : 디렉터리에 대한 정보를 저장하기 위한 구조체
#include <dirent.h>
struct dirent
{
ino_t d_ino; // i-노드 번호
char d_name[NAME_MAX + 1]; // 파일 이름
}
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *path);
// path 디렉터리를 열고 성공하면 dir구조체 포인터를 리턴, 실패하면 NULL리턴
struct dirent *readdir(DIR *dp);
// 한번에 디렉터리 엔트리를 하나씩 읽어서리턴한다.
ex1 ) list1.c
#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; // dir 구조체 포인터
char *dir; // path 디렉터리 포인터
struct stat st; // 파일의 상태 정보를 담는 구조체 st
struct dirent *d; // dir구조체 포인터 d
char path[BUFSIZ+1];
if(argc==1) // 입력받은 인자가 없는경우
{
dir= ".";
}
else
{
dir = argv[1]; // 입력받은 인자가 있는경우
}
// dir !구조체! 포인터 변수 dp에 opendir(dir)수행후 dir구조체 포인터 리턴
// dp는 입력받은 디렉토리에 대한 정보를 저장한 구조체를 가리키는 포인터이다.
if(( dp = opendir(dir))== NULL) // 디렉터리를 열기
perror(dir);
//
while( (d=readdir(dp))!=NULL) // 각 디렉터리 엔트리에 대해
{
printf("%s\n", d->d_name); // 파일 이름 프린트
}
closedir(dp);
exit(0);
}
st
while((d = readdir(dp)) != NULL) // 디렉터리 내의 각 파일
{
// path = dir/d->name 저장
sprintf(path, "%s/%s", dir, d->d_name); // 파일 경로명 만들기
if(lstat(path, &st) < 0) // 파일 상태 가져오기
perror(path);
printf("%5d %s", st->st_blocks, d->name); // 블록 수, 파일 이름 출력
}
lstat() 시스템 호출
: 파일 타입과 사용권한 정보는 st->st_mode 필드에 함께 저장됨
st_mode 필드
#include <sys/types.h>
#include <sys/stat.h>
int mkdir (const char *path, mode_t mode );
새로운 디렉터리 만들기에 성공하면 0, 실패하면 -1을 리턴한다.
#include <unistd.h>
int rmdir(const char *path);
// 디렉터리가 비어있으면 삭제. 성공하면 0 ,실패시 -1리턴
: 디렉터리를 위한 구조는 따로 없음 ( 일종의 파일로 다른 파일처럼 구현됨)
: __디렉터리도 다른 파일처럼 하나의 i-노드로 표현됨.
: 디렉터리의 내용은 디렉터리 엔트리(파일이름, i-노드번호로 구성)
#include <unistd.h>
int link(char *existing, char *new);
// 기존 파일 이름 existing 에 대한 새로운 링크 new를 만든다.
// 성공하면 0 실패하면 -1 리턴
int unlink(char* path);
// 링크 path를 제거함
// 성공하면 0, 실패하면 -1 리턴
#include <unistd.h>
int main(int argc, char *argv[ ])
{
if (link(argv[1], argv[2]) == -1) {
exit(1);
}
exit(0);
}
$ link a.txt b.txt
// a.txt에 대한 링크 b.txt를 만듦
$ ls -l a.txt b.txt
// a.txt와 b.txt에 대한 정보 보기
->
-rw-rw-r-- 2 kdo6301 kdo6301 4 Sep 15 16:17 a.txt
-rw-rw-r-- 2 kdo6301 kdo6301 4 Sep 15 16:17 b.txt
$ ls -i a.txt b.txt
// a.txt와 b.txt에 대한 i-노드 인덱스 보기
->
675097 b.txt 675097 test.txt
#include <unistd.h>
main(int argc, char *argv[ ])
{
int unlink( );
if (unlink(argv[1]) == -1) {
perror(argv[1]);
exit(1);
}
exit(0);
}
$ unlink b.txt
// b.txt를 언링크
링크 수가 0 이되면 파일 삭제됨
하드 링크 (Hard link)
: 지금까지 살펴본 링크
: 파일 시스템 내의 i-노드를 가리킴
: 같은 파일 시스템 내에서만 사용가능
심볼릭 링크 (symbolic link)
: 소프트링크 라고도 한다.
: 실제 파일의 경로명 저장하고 있는 링크
: 파일에 대한 간접적인 포인터역할
: 다른 파일 시스템에서도 사용가능
심볼릭 링크
int symlink(const char* actualpath, const char* sympath);
// 심볼릭 링크를 만드는데 성공 -> 0리턴, 실패 -> -1리턴
#include <unistd.h>
int main(int argc, char* argv[])
{
if(symlink(argv[1],argv[2])==-1)
{
exit(1);
}
exit(0);
}
$ slink a.txt c.txt
-> a.txt에 대한 심볼릭 링크 c.txt를 만듦
$ ls -l c.txt
c.txt에 대한 리스트 출력
#include <unistd.h>
int readlink(const char* path, char *buf, size_t bufsize);
// path 심볼릭 링크의 실제 내용(경로명을 담고 있음)을 읽어서 buf에 저장한다.
// 성공하면 buf에 저장한 바이트 수를 반환하며 실패하면 -1을 반환한다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
char buffer[1024];
int nread;
nread = readlink(argv[1], buffer, 1024);
if(nread > 0)
{
write(1,buffer,nread);
exit(0);
}
else
{
fprintf(stderr,"오류 : 해당 링크 없음\n");
exit(1);
}
}