5 장파일시스템 상지대학교컴퓨터공학과고광만 kkman@sangji.ac.kr http://compiler.sangji.ac.kr 2018
5.1 파일시스템구현
파일시스템구조 0 1 2 3 200 201 부트블록슈퍼블록 i-노드 1..40 i-노드 41..80... 데이터블록데이터블록... i- 리스트 데이터블록 데이터블록 3
파일시스템구조 부트블록 (Boot block) 파일시스템시작부에위치하고보통첫번째섹터를차지 부트스트랩코드가저장되는블록 슈퍼블록 (Super block) 전체파일시스템에대한정보를저장 총블록수, 사용가능한 i- 노드개수, 사용가능한블록비트맵, 블록의크기, 사용중인블록수, 사용가능한블록수등 i- 리스트 (i-list) 각파일을나타내는모든 i- 노드들의리스트 한블록은약 40 개정도의 i- 노드를포함 데이터블록 (Data block) 파일의내용 ( 데이터 ) 을저장하기위한블록들 4
i- 노드 (i-node) 한파일은하나의 i-노드를갖는다. 파일에대한모든정보를가지고있음 파일타입 : 일반파일, 디렉터리, 블록장치, 문자장치등 파일크기 사용권한 파일소유자및그룹 접근및갱신시간 데이터블록에대한포인터 ( 주소 ) 등 5
블록포인터
블록포인터 데이터블록에대한포인터 파일의내용을저장하기위해할당된데이터블록의주소 하나의 i-노드내의블록포인터 직접블록포인터 10개 간접블록포인터 1개 이중간접블록포인터 1개 최대몇개의데이터블록을가리킬수있을까? 7
파일입출력구현 파일입출력구현을위한커널내자료구조 파일디스크립터배열 (Fd array) 열린파일테이블 (Open File Table) 동적 i-노드테이블 (Active i-node table) 8
파일을위한커널자료구조 fd = open( file, O_RDONLY); fd 테이블 ( 프로세스당하나 ) 열린파일테이블 동적 i- 노드테이블 파일시스템 0 1 i- 리스트 2 3 4 현재파일위치 refcnt=1 파일타입파일크기접근권한 데이터블록...
파일디스크립터배열 (Fd Array) 프로세스당하나씩갖는다. 파일디스크립터배열 열린파일테이블의엔트리를가리킨다. 파일디스크립터 파일디스크립터배열의인덱스 열린파일을나타내는번호 10
열린파일테이블 (Open File Table) 파일테이블 (file table) 커널자료구조 열려진모든파일목록 열려진파일 파일테이블의항목 파일테이블항목 (file table entry) 파일상태플래그 (read, write, append, sync, nonblocking, ) 파일의현재위치 (current file offset) i-node에대한포인터 11
동적 i- 노드테이블 (Active i-node table) 동적 i- 노드테이블 커널내의자료구조 Open 된파일들의 i-node 를저장하는테이블 i- 노드 하드디스크에저장되어있는파일에대한자료구조 한파일에하나의 i-node 하나의파일에대한정보저장 소유자, 크기 파일이위치한장치 파일내용디스크블럭에대한포인터 i-node table vs. i-node 12
파일을위한커널자료구조 fd = open( file, O_RDONLY); // 두번 open fd 테이블 ( 프로세스당하나 ) 열린파일테이블 동적 i- 노드테이블 파일시스템 0 1 i- 리스트 2 3 4 현재파일위치 refcnt=1 파일타입 현재파일위치 파일크기접근권한... 데이터블록 refcnt=1
파일을위한커널자료구조 fd = dup(3); 혹은 fd = dup2(3,4); fd 테이블 ( 프로세스당하나 ) 열린파일테이블 동적 i- 노드테이블 파일시스템 0 1 i- 리스트 2 3 4 현재파일위치 refcnt=1 파일타입파일크기접근권한 데이터블록...
5.2 파일상태정보
파일상태 (file status) 파일상태 파일에대한모든정보 블록수, 파일타입, 접근권한, 링크수, 파일소유자의사용자 ID, 그룹 ID, 파일크기, 최종수정시간등 예 $ ls -l hello.c 2 -rw-r--r-- 1 chang cs 617 11월 17일 15:53 hello.c 블록수 ^ 사용권한링크수사용자ID 그룹ID 파일크기최종수정시간파일이름 파일타입 16
상태정보 : stat() 파일하나당하나의 i- 노드가있으며 i- 노드내에파일에대한모든상태정보가저장되어있다. #include <sys/types.h> #include <sys/stat.h> 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을리턴한다. 17
stat 구조체 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; // 파일의블록수 }; 18
파일타입 파일타입일반파일디렉터리파일문자장치파일블록장치파일 FIFO 파일소켓심볼릭링크 설명데이터를갖고있는텍스트파일또는이진화일파일의이름들과파일정보에대한포인터를포함하는파일문자단위로데이터를전송하는장치를나타내는파일블록단위로데이터를전송하는장치를나타내는파일프로세스간통신에사용되는파일로이름있는파이프네트워크를통한프로세스간통신에사용되는파일다른파일을가리키는포인터역할을하는파일 19
파일타입검사함수 파일타입을검사하기위한매크로함수 파일타입일반파일디렉터리파일문자장치파일블록장치파일 FIFO 파일소켓심볼릭링크 파일타입을검사하기위한매크로함수 S_ISREG() S_ISDIR() S_ISCHR() S_ISBLK() S_ISFIFO() S_ISSOCK() S_ISLNK() 20
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]); if (lstat(argv[i], &buf) < 0) { perror("lstat()"); continue; 21
ftype.c } 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); 22
파일사용권한 (File Permissions) 각파일에대한권한관리 각파일마다사용권한이있다. 소유자 (owner)/ 그룹 (group)/ 기타 (others) 로구분해서관리한다. 파일에대한권한 읽기 r 쓰기 w 실행 x 23
사용권한 read 권한이있어야 O_RDONLY O_RDWR 을사용하여파일을열수있다 write 권한이있어야 O_WRONLY O_RDWR O_TRUNC 을사용하여파일을열수있다 디렉토리에 write 권한과 execute 권한이있어야 그디렉토리에파일을생성할수있고 그디렉토리의파일을삭제할수있다 삭제할때그파일에대한 read write 권한은없어도됨 24
파일사용권한 파일사용권한 (file access permission) stat 구조체의 st_mode 의값 #include <sys/stat.h> st_mode mask S_IRUSR S_IWUSR S_IXUSR Meaning user-read user-write user-execute st_mode 파일타입특수용도 사용권한 소유자그룹 기타 사용자 S_IRGRP S_IWGRP S_IXGRP group-read group-write group-execute 4 비트 3 비트 9 비트 S_IROTH other-read S_IWOTH other-write S_IXOTH other-execute 25
chmod(), fchmod() #include <sys/stat.h> #include <sys/types.h> int chmod (const char *path, mode_t mode ); int fchmod (int fd, mode_t mode ); 파일의접근권한 (access permission) 을변경한다 리턴값 성공하면 0, 실패하면 -1 mode : bitwise OR S_ISUID, S_ISGID S_IRUSR, S_IWUSR, S_IXUSR S_IRGRP, S_IWGRP, S_IXGRP S_IROTH, S_IWOTH, S_IXOTH 26
fchmod.c #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> /* 파일사용권한을변경한다. */ main(int argc, char *argv[]) { long strtol( ); int newmode; newmode = (int) strtol(argv[1], (char **) NULL, 8); if (chmod(argv[2], newmode) == -1) { } perror(argv[2]); exit(1); exit(0); } 27
chown() #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, gid_t group ); int lchown (const char *path, uid_t owner, gid_t group ); 파일의 user ID 와 group ID 를변경한다. 리턴 성공하면 0, 실패하면 -1 lchown() 은심볼릭링크자체를변경한다 super-user만변환가능 28
utime() #include <sys/types.h> #include <utime.h> int utime (const char *filename, const struct utimbuf *times ); 파일의최종접근시간과최종변경시간을조정한다. times가 NULL 이면, 현재시간으로설정된다. 리턴값 성공하면 0, 실패하면 -1 UNIX 명령어 touch 참고 29
utime() struct utimbuf { time_t actime; /* access time */ time_t modtime; /* modification time */ } 각필드는 1970-1-1 00:00 부터현재까지의경과시간을초로환산한값 30
예제 : cptime.c #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <utime.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { struct stat buf; // 파일상태저장을위한변수 struct utimbuf time; if (argc < 3) { fprintf(stderr, " 사용법 : cptime file1 file2\n"); exit(1); } if (stat(argv[1], &buf) <0) { // 상태가져오기 perror("stat()"); exit(-1); } time.actime = buf.st_atime; time.modtime = buf.st_mtime; if (utime(argv[2], &time)) // 접근, 수정시간복사 perror("utime"); else exit(0); Lecture } 05: 파일시스템프로그래밍, kkman@sangji.ac.kr 숙대창병모 31
5.3 디렉터리
디렉터리구현 디렉터리내에는무엇이저장되어있을까? 디렉터리엔트리 #include <dirent.h> struct dirent { ino_t d_ino; // i-노드번호 char d_name[name_max + 1]; // 파일이름 } 33
디렉터리리스트 opendir() 디렉터리열기함수 DIR 포인터 ( 열린디렉터리를가리키는포인터 ) 리턴 readdir() 디렉터리읽기함수 #include <sys/types.h> #include <dirent.h> DIR *opendir (const char *path); path 디렉터리를열고성공하면 DIR 구조체포인터를, 실패하면 NULL을리턴 struct dirent *readdir(dir *dp); 한번에디렉터리엔트리를하나씩읽어서리턴한다. 34
list1.c 1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <dirent.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 7 /* 디렉터리내의파일이름들을리스트한다. */ 8 int main(int argc, char **argv) 9 { 10 DIR *dp; 11 char *dir; 12 struct dirent *d; 13 struct stat st; 14 char path[bufsiz+1]; 15 35
list1.c 16 if (argc == 1) 17 dir = "."; // 현재디렉터리를대상으로 18 else dir = argv[1]; 19 20 if ((dp = opendir(dir)) == NULL) // 디렉터리열기 21 perror(dir); 22 23 while ((d = readdir(dp))!= NULL) // 각디렉터리엔트리에대해 24 printf("%s \n", d->d_name); // 파일이름프린트 25 26 closedir(dp); 27 exit(0); 28 } 36
파일이름 / 크기프린트 디렉터리내에있는파일이름과그파일의크기 ( 블록의수 ) 를프린트하도록확장 while ((d = readdir(dp))!= NULL) { sprintf(path, "%s/%s", dir, d->d_name); if (lstat(path, &st) < 0) perror(path); printf("%5d %s", st->st_blocks, d->name); putchar('\n'); } // 디렉터리내의각파일 // 파일경로명만들기 // 파일상태정보가져오기 // 블록수, 파일이름출력 37
st_mode lstat() 시스템호출 파일타입과사용권한정보는 st->st_mode 필드에함께저장됨. st_mode 필드 4비트 : 파일타입 3비트 : 특수용도 9비트 : 사용권한 3비트 : 파일소유자의사용권한 3비트 : 그룹의사용권한 3비트 : 기타사용자의사용권한 st_mode 파일타입특수용도 사용권한 소유자그룹 4 비트 3 비트 9 비트 기타 사용자 38
디렉터리리스트 : 예 list2.c ls l 명령어처럼파일의모든상태정보를프린트 프로그램구성 main() 메인프로그램 printstat() 파일상태정보프린트 type() 파일타입리턴 perm() 파일사용권한리턴 39
list2.c 1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <dirent.h> 4 #include <pwd.h> 5 #include <grp.h> 6 #include <stdio.h> 7 8 char type(mode_t); 9 char *perm(mode_t); 10 void printstat(char*, char*, struct stat*); 11 12 /* 디렉터리내용을자세히리스트한다. */ 13 int main(int argc, char **argv) 14 { 15 DIR *dp; 16 char *dir; 17 struct stat st; 18 struct dirent *d; 19 char path[bufsiz+1]; 40
list2.c 21 if (argc == 1) 22 dir = "."; 23 else dir = argv[1]; 24 25 if ((dp = opendir(dir)) == NULL) // 디렉터리열기 26 perror(dir); 27 28 while ((d = readdir(dp))!= NULL) { // 디렉터리의각파일에대해 29 sprintf(path, "%s/%s", dir, d->d_name); // 파일경로명만들기 30 if (lstat(path, &st) < 0) // 파일상태정보가져오기 31 perror(path); 32 printstat(path, d->d_name, &st); // 상태정보출력 33 putchar('\n'); 34 } 35 36 closedir(dp); 37 exit(0); 38 } 41
list2.c 40 /* 파일상태정보를출력 */ 41 void printstat(char *pathname, char *file, struct stat *st) { 42 43 printf("%5d ", st->st_blocks); 44 printf("%c%s ", type(st->st_mode), perm(st->st_mode)); 45 printf("%3d ", st->st_nlink); 46 printf("%s %s ", getpwuid(st->st_uid)->pw_name, getgrgid(st->st_gid)->gr_name); 47 printf("%9d ", st->st_size); 48 printf("%.12s ", ctime(&st->st_mtime)+4); 49 printf("%s", file); 50 } 42
list2.c 52 /* 파일타입을리턴 */ 53 char type(mode_t mode) { 54 55 if (S_ISREG(mode)) 56 return('-'); 57 if (S_ISDIR(mode)) 58 return('d'); 59 if (S_ISCHR(mode)) 60 return('c'); 61 if (S_ISBLK(mode)) 62 return('b'); 63 if (S_ISLNK(mode)) 64 return('l'); 65 if (S_ISFIFO(mode)) 66 return('p'); 67 if (S_ISSOCK(mode)) 68 return('s'); 69 Lecture } 05: 파일시스템프로그래밍, kkman@sangji.ac.kr 43
list2.c 71 /* 파일사용권한을리턴 */ 72 char* perm(mode_t mode) { 73 int i; 74 static char perms[10] = "---------"; 75 76 for (i=0; i < 3; i++) { 77 if (mode & (S_IREAD >> i*3)) 78 perms[i*3] = 'r'; 79 if (mode & (S_IWRITE >> i*3)) 80 perms[i*3+1] = 'w'; 81 if (mode & (S_IEXEC >> i*3)) 82 perms[i*3+2] = 'x'; 83 } 84 return(perms); 85 } 44
디렉터리만들기 mkdir() 시스템호출 path가나타내는새로운디렉터리를만든다. "." 와 ".." 파일은자동적으로만들어진다 #include <sys/types.h> #include <sys/stat.h> int mkdir (const char *path, mode_t mode ); 새로운디렉터리만들기에성공하면 0, 실패하면 -1을리턴한다. 45
디렉터리삭제 rmdir() 시스템호출 path 가나타내는디렉터리가비어있으면삭제한다. #include <unistd.h> int rmdir (const char *path); 디렉터리가비어있으면삭제한다. 성공하면 0, 실패하면 -1 을리턴 46
디렉터리구현 그림 5.1 의파일시스템구조를보자. 디렉터리를위한구조는따로없다. 파일시스템내에서디렉터리를어떻게구현할수있을까? 디렉터리도일종의파일로다른파일처럼구현된다. 디렉터리도다른파일처럼하나의 i-노드로표현된다. 디렉터리의내용은디렉터리엔트리 ( 파일이름, i-노드번호 ) 47
디렉토리구현 bin 3 usr 4 ls 5 cp 7 test.c 6 /usr/test.c 2 i-노드번호 1 2 3 4 5 6 블록번호 200 201 202 203 204 205 206 블록포인터 200 dr-xr-xr-x 201 dr-xr-xr-x 202 dr-xr-xr-x 203 -r-xr-xr-x 204,206-r-xr-xr-x... 2 bin 3 usr 4. 3.. 2 ls 5 cp 7. 4.. 2 test.c 6 ls 실행파일 test.c : 첫번째블록 cp 실행파일 사용권한 test.c : 두 번째숙대블록창병모
5.4 링크
링크 링크는기존파일에대한또다른이름으로 하드링크와심볼릭 ( 소프트 ) 링크가있다. #include <unistd.h> int link(char *existing, char *new); int unlink(char *path); 50
링크의구현 link() 시스템호출 기존파일 existing 에대한새로운이름 new 즉링크를만든다. 51
link.c #include <unistd.h> int main(int argc, char *argv[ ]) { if (link(argv[1], argv[2]) == -1) { exit(1); } exit(0); } 52
unlink.c #include <unistd.h> main(int argc, char *argv[ ]) { int unlink( ); if (unlink(argv[1]) == -1 { perror(argv[1]); exit(1); } exit(0); } 53
하드링크 vs 심볼릭링크 하드링크 (hard link) 지금까지살펴본링크 파일시스템내의 i-노드를가리키므로 같은파일시스템내에서만사용될수있다 심볼릭링크 (symbolic link) 소프트링크 (soft link) 실제파일의경로명저장하고있는링크 파일에대한간접적인포인터역할을한다. 다른파일시스템에있는파일도링크할수있다. 54
심볼릭링크 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); } 55
심볼릭링크내용 #include <unistd.h> int readlink (const char *path, char *buf, size_t bufsize); path 심볼릭링크의실제내용을읽어서 buf에저장한다. 성공하면 buf에저장한바이트수를반환하며실패하면 1을반환한다. 56
rlink.c #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); } 57
핵심개념 표준유닉스파일시스템은부트블록, 슈퍼블록, i- 리스트, 데이터블록부분으로구성된다 파일입출력구현을위해서커널내에파일디스크립터배열, 파일테이블, 동적 i- 노드테이블등의자료구조를사용한다. 파일하나당하나의 i- 노드가있으며 i- 노드내에파일에대한모든상태정보가저장되어있다. 디렉터리는일련의디렉터리엔트리들을포함하고각디렉터리엔트리는파일이름과그파일의 i- 노드번호로구성된다. 링크는기존파일에대한또다른이름으로하드링크와심볼릭 ( 소프트 ) 링크가있다. 58