Download presentation
Presentation is loading. Please wait.
1
11장 파일
2
11.1 시스템 호출
3
유닉스/리눅스 커널(kernel) 하드웨어를 운영 관리하여 다음과 같은 서비스를 제공
프로세스 관리(Process management) 파일 관리(File management) 메모리 관리(Memory management) 통신 관리(Communication management) 주변장치 관리(Device management)
4
시스템 호출(system call) 시스템 호출은 유닉스/리눅스 커널에 서비스를 요청하기 위한 프로 그래밍 인터페이스
응용 프로그램은 시스템 호출을 통해서 유닉스/리눅스 커널에 서비 스를 요청한다 /usr/include/asm/unistd_32.h 참조
5
11.2 파일
6
유닉스/리눅스에서 파일 연속된 바이트의 나열 특별한 다른 포맷을 정하지 않음
디스크 파일뿐만 아니라 외부 장치에 대한 인터페이스
7
파일 열기: open() 파일을 사용하기 위해서는 먼저 open() 시스템 호출을 이용하여 파일을 열어야 한다
파일 디스크립터는 열린 파일을 나타내는 번호 oflag, mode : 교재 331~332 쪽, /usr/include/bits/fcntl.h 참조 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *path, int oflag, [ mode_t mode ]); 파일 열기에 성공하면 파일 디스크립터를 리턴, 실패하면 -1을 리턴
8
파일 열기: 예 fd = open("account",O_RDONLY); fd = open(argv[1], O_RDWR);
fd = open(argv[1], O_RDWR | O_CREAT, 0600); fd = open("tmpfile", O_WRONLY|O_CREAT|O_TRUNC, 0600); fd = open("/sys/log", O_WRONLY|O_APPEND|O_CREAT, 0600); if ((fd = open("tmpfile", O_WRONLY|O_CREAT|O_EXCL, 0666))==-1)
9
fopen.c #include <stdio.h> #include <stdlib.h>
#include <fcntl.h> #include <errno.h> int main(int argc, char *argv[]) { int fd; if ((fd = open(argv[1], O_RDWR)) == -1) perror(argv[1]); printf("파일 %s 열기 성공\n", argv[1]); close(fd); exit(0); } fd 번호를 출력해보세요! 매개변수 없을 경우도 잘 처리하도록 debug 해보세요!
10
파일 생성: creat() creat() 시스템 호출 path가 나타내는 파일을 생성하고 쓰기 전용으로 연다
생성된 파일의 사용권한은 mode로 정한다 기존 파일이 있는 경우에는 그 내용을 삭제하고 연다 다음 시스템 호출과 동일 open(path, WRONLY | O_CREAT | O_TRUNC, mode); #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat (const char *path, mode_t mode ); 파일 생성에 성공하면 생성된 파일의 파일 디스크립터, 실패하면 -1을 리턴
11
파일 닫기: close() close() 시스템 호출은 fd가 나타내는 파일을 닫는다
#include <unistd.h> int close( int fd ); fd가 나타내는 파일을 닫는다. 성공하면 0, 실패하면 -1을 리턴한다.
12
데이터 읽기: read() read() 시스템 호출 fd가 나타내는 파일에서 nbytes 만큼의 데이터를 읽고
읽은 데이터는 buf에 저장한다 #include <unistd.h> ssize_t read ( int fd, void *buf, size_t nbytes ); 파일 읽기에 성공하면 읽은 바이트 수, 파일 끝을 만나면 0, 실패하면 -1을 리턴
13
fsize.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> //#include <unistd.h> #define BUFSIZE 512 /* 파일 크기를 계산한다 */ int main(int argc, char *argv[]) { char buffer[BUFSIZE]; int fd; ssize_t nread; long total = 0; if ((fd = open(argv[1], O_RDONLY)) == -1) perror(argv[1]); /* 파일의 끝에 도달할 때까지 반복해서 읽으면서 파일 크기 계산 */ while((nread = read(fd, buffer, BUFSIZE)) > 0) total += nread; close(fd); printf ("%s 파일 크기 : %ld 바이트 \n", argv[1], total); exit(0); } $ gcc –o fsize fsize.c $ fsize xx 매개변수 없을 경우도 잘 처리하도록 debug 해보세요!
14
데이터 쓰기: write() write() 시스템 호출 buf에 있는 nbytes 만큼의 데이터를 fd가 나타내는 파일에 쓴다
#include <unistd.h> ssize_t write (int fd, void *buf, size_t nbytes); 파일에 쓰기를 성공하면 실제 쓰여진 데이터의 바이트 수를 리턴하고, 실패하면 -1을 리턴
15
fcp.c BUFSIZ 값 출력해보기 $ grep BUFSIZ /usr/include/*
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> /* 파일 복사 프로그램 */ main(int argc, char *argv[]) { int fd1, fd2, n; char buf[BUFSIZ]; if (argc != 3) { fprintf(stderr,"사용법: %s file1 file2\n", argv[0]); exit(1); } if ((fd1 = open(argv[1], O_RDONLY)) == -1) { perror(argv[1]); exit(2); if ((fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) { perror(argv[2]); exit(3); while ((n = read(fd1, buf, BUFSIZ)) > 0) write(fd2, buf, n); // 읽은 내용을 쓴다 exit(0); BUFSIZ 값 출력해보기 $ grep BUFSIZ /usr/include/* O_APPEND
16
(보충) $ man $ man read $ whatis read $ man –f read (Unix) $ man –l read
read (1p) - read a line from standard input read (2) - read from a file descriptor read (3p) - read from a file read [builtins] (1) - bash built-in commands, see bash(1) $ man –s 2 read 또는 $ man 2 read $ man –M /usr/share/man 2 read (목록의 man page가 나오지 않을 경우) $ man man 1절 명령어 2절 시스템 호출 3절 라이브러리 함수 4절 특수화일 5절 파일 형식 6절 게임 7절 기타 정보 8절 유지보수 명령어 9절 커널 루틴 1 Executable programs or shell commands 2 System calls (functions provided by the kernel) 3 Library calls (functions within program libraries) 4 Special files (usually found in /dev) 5 File formats and conventions eg /etc/passwd 6 Games 7 Miscellaneous (including macro packages and conven-tions 8 System administration commands (usually only for root) 9 Kernel routines [Non standard]
17
(보충) set-user-id set-group-id set-sticky-bit
Symbolic File Access Modes $ chmod a=rw xx $ chmod g+x xx $ chmod g-rwx xx $ chmod g=u xx Octal File Access Modes $ chmod xx $ chmod xx $ chmod xx 실행파일에 대하여 4000 set user ID : $ chmod xx $ chmod u+s myfile 2000 set group ID : $ chmod xx $ chmod g+s myfile 1000 set sticky bit : $ chmod xx $ chmod o+t myfile $ find / -perm ls > result $ find / -perm ls > result 디렉터리에 대하여 1000 set sticky bit : $ chmod /share 그 디렉터리 안의 파일 제거 또는 이름 변경은 파일 소유자, 디렉터리 소유자, 수퍼유저만 가능 디렉터리 소유자 아닌 다른 사용자는 그 안에 자기파일 생성만 가능 umask (user mask) : file 생성시 허가권 제한 - rws r-x --x - rwx r-s --x - rwx r-x --t
18
(보충) IA-32(Intel Architecture, 32-bit) 정수 표현
Q:IA-32(Intel Architecture, 32-bit) 정수형 데이터 음수 표현 방법은? signed & unsigned char(8bit), short(16bit), int(32bit), long(64bit), long long(128bit) 리틀 엔디안(Little-Endian) 사용 고정 소수점 (Fixed-Point) 표현 첫 번째 비트는 부호 비트 양수(+)는 0, 음수(-)는 1로 표시 나머지는 정수부가 저장되고, 소수점은 맨 오른쪽에 있는 것으로 가정 고정 소수점 음수 표현 방법 부호와 절대치(signed-magnitude) 양수 표현에 대하여 부호 비트만 1로 변경 1의 보수(1’s complement) 양수 표현에 대하여 1의 보수 계산 2의 보수(2’s complement) 양수 표현에 대하여 2의 보수 계산 (reverse+1) (예) short score = 99; 99 = 6* = 0x63 (예) short score = -99; -99 = -6* = -0x63 (부호와 절대치) (2의 보수)
19
(보충) 비트단위 정수 출력 bitwise.c
#include <stdio.h> #include <limits.h> void bit_print(short); main(int arc, char *argv[]) { short i=atoi(argv[1]), mask=1; bit_print(i); printf("\n정수: %d\n", i); } void bit_print(short a) int i; int n=sizeof(short) * CHAR_BIT; /* /usr/include/limits.h 55행 */ printf("n=%d, sizeof(short)=%d, CHAR_BIT=%d\n", n, sizeof(short), CHAR_BIT); int mask = 1 << (n-1); for (i=1; i<=n; ++i) putchar(((a & mask) == 0) ? '0' : '1'); a <<= 1; if(i % (CHAR_BIT/2) == 0 && i < n) putchar(' '); $ gcc –o bitwise bitwise.c $ bitwise -99 short 형을 int 형으로 수정하세요! 매개변수 없을 경우도 잘 처리하도록 debug 하세요!
20
11.3 현재 파일 위치
21
파일 위치 포인터(file position pointer)
파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일 위치 (current file position)를 가리킨다.
22
파일 위치 포인터 이동: lseek() lseek() 시스템 호출 임의의 위치로 파일 위치 포인터를 이동시킬 수 있다.
#include <unistd.h> off_t lseek (int fd, off_t offset, int whence ); 이동에 성공하면 현재 위치를 리턴하고 실패하면 -1을 리턴한다.
23
파일 위치 포인터이동: 예 파일 위치 이동 레코드 단위로 이동 파일끝 이후로 이동
lseek(fd, 0L, SEEK_SET); 파일 시작으로 이동(rewind) lseek(fd, 100L, SEEK_SET); 파일 시작에서 100바이트 위치로 lseek(fd, 0L, SEEK_END); 파일 끝으로 이동(append) 레코드 단위로 이동 lseek(fd, n * sizeof(record), SEEK_SET); n+1번째 레코드 시작위치로 lseek(fd, sizeof(record), SEEK_CUR); 다음 레코드 시작위치로 lseek(fd, -sizeof(record), SEEK_CUR); 전 레코드 시작위치로 파일끝 이후로 이동 lseek(fd, sizeof(record), SEEK_END); 파일끝에서 한 레코드 다음 위치로
24
레코드 저장 예 $ vi student.h write(fd, &record1, sizeof(record));
#define MAX 20 struct student { int id; char name[MAX]; int score; }; write(fd, &record1, sizeof(record)); write(fd, &record2, sizeof(record)); lseek(fd, sizeof(record), SEEK_END); write(fd, &record3, sizeof(record)); 레코드 #1 레코드 #2 레코드 #3
25
dbcreate.c $ gcc –o dbcreate.c dbcreate.c $ dbcreate stdb
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include "student.h" #define START_ID /* 학생 정보를 입력받아 데이터베이스 파일에 저장한다 */ int main(int argc, char *argv[]) { int fd; struct student record; if (argc < 2) { fprintf(stderr, "사용법 : %s file\n", argv[0]); exit(1); } if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_EXCL, 0640)) == -1) { perror(argv[1]); exit(2); } printf("%7s %6s %4s\n", "학번", "이름", "점수"); while (scanf("%d %s %d", &record.id, record.name, &record.score) == 3) { lseek(fd, (record.id - START_ID) * sizeof(record), SEEK_SET); write(fd, (char *) &record, sizeof(record) ); close(fd); exit(0); $ gcc –o dbcreate.c dbcreate.c $ dbcreate stdb
26
dbquery.c $ gcc –o dbquery.c dbquery.c $ dbcreate stdb
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include "student.h" #define START_ID /* 학번을 입력받아 해당 학생의 레코드를 파일에서 읽어 출력한다 */ int main(int argc, char *argv[]) { int fd, id; char c; struct student record; if (argc < 2) { fprintf(stderr, "사용법 : %s file\n", argv[0]); exit(1); } if ((fd = open(argv[1], O_RDONLY)) == -1) { perror(argv[1]); exit(2); do { printf("검색할 학생의 학번 입력: "); if (scanf("%d", &id) == 1) { lseek(fd, (id-START_ID)*sizeof(record), SEEK_SET); if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0)) printf("이름:%s\t 학번:%d\t 점수:%d\n", record.name, record.id, record.score); else printf("레코드 %d 없음\n", id); } else printf("입력 오류"); printf("계속하겠습니까?(Y/N) "); scanf(" %c", &c); } while (c=='Y'); close(fd); exit(0); } $ gcc –o dbquery.c dbquery.c $ dbcreate stdb
27
레코드 수정 과정 (1) 파일로부터 해당 레코드를 읽어서 (2) 이 레코드를 수정한 후에
(3) 수정된 레코드를 다시 파일 내의 원래 위치에 써야 한다
28
dbupdate.c $ gcc –o dbupdate.c dbupdate.c $ dbupdate stdb
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include "student.h" #define START_ID /* 학번을 입력받아 해당 학생 레코드를 수정한다 */ int main(int argc, char *argv[]) { int fd, id; char c; struct student record; if (argc < 2) { fprintf(stderr, "사용법 : %s file\n", argv[0]); exit(1); } if ((fd = open(argv[1], O_RDWR)) == -1) { perror(argv[1]); exit(2); do { printf("수정할 학생의 학번 입력: "); if (scanf("%d", &id) == 1) { lseek(fd, (long) (id-START_ID)*sizeof(record), SEEK_SET); if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0)) { printf("학번:%8d\t 이름:%4s\t 점수:%4d\n", record.id, record.name, record.score); printf("새로운 점수: "); scanf("%d", &record.score); lseek(fd, (long) -sizeof(record), SEEK_CUR); write(fd, (char *) &record, sizeof(record)); } else printf("레코드 %d 없음\n", id); } else printf("입력오류\n"); printf("계속하겠습니까?(Y/N)"); scanf(" %c",&c); } while (c == 'Y'); close(fd); exit(0); } $ gcc –o dbupdate.c dbupdate.c $ dbupdate stdb
29
11.4 파일 상태 정보
30
파일 상태(file status) 파일 상태 예 $ ls -sl hello
파일에 대한 모든 정보 블록수, 파일 타입, 접근 권한, 링크수, 파일 소유자의 사용자 ID, 그룹 ID, 파일 크기, 최종 수정 시간 등 예 $ ls -sl hello 2 -rw-r--r mysung other 월 26일 15:59 hello.c 블록수 사용권한 링크수 사용자ID 그룹ID 파일크기 최종 수정 시간 파일이름 파일 타입 Linux: $ getconf PAGESIZE 또는 PAGE_SIZE (4096) Solaris: $ pagesize –a (4096, )
31
상태 정보: stat() 파일 하나당 하나의 i-노드가 있으며 i-노드 내에 파일에 대한 모든 상태 정보가 저장되어 있다
Q: stat()과 lstat()의 차이점은? $ man –s 2 stat #include <sys/types.h> #include <sys/stat.h> int stat (const char *pathname, struct stat *buf); int fstat (int fd, struct stat *buf); int lstat (const char *pathname, struct stat *buf); 파일의 상태 정보를 가져와서 stat 구조체 buf에 저장한다. 성공하면 0, 실패하면 -1을 리턴한다.
32
stat 구조체 /usr/include/sys/stat.h 107행 /usr/include/bits/stat.h 39행 참조 struct stat { dev_t st_dev; /* 장치 */ ino_t st_ino; /* inode 번호 */ mode_t st_mode; /* 파일타입과 사용권한 */ nlink_t st_nlink; /* 하드 링크 수 */ uid_t st_uid; /* 소유자의 사용자 ID */ gid_t st_gid; /* 소유자의 그룹 ID */ dev_t st_rdev; /* 장치이면 장치 번호 */ off_t st_size; /* 파일의 바이트 크기 */ unsigned long st_blksize; /* 파일시스템 I/O 최적 블록 크기 */ unsigned long st_blocks; /* 파일에 할당 된 512-byte 블록 수 */ time_t st_atime; /* 최종 접근 시간 */ time_t st_mtime; /* 최종 수정 시간 */ time_t st_ctime; /* 최종 상태 변경 시간 */ };
33
파일 타입과 매크로 함수 /usr/include/sys/stat.h 127행 참조
/usr/include/bits/stat.h 142행 참조 파일 타입 설명 파일 타입을 검사하기 위한 매크로 함수 일반 파일 데이터를 갖고 있는 텍스트 파일 또는 이진 파일 S_ISREG() 디렉터리 파일 파일의 이름들과 파일 정보에 대한 포인터를 포함하는 파일 S_ISDIR() 문자 장치 파일 문자 단위로 데이터를 전송하는 장치를 나타내는 파일 S_ISCHR() 블록 장치 파일 블록 단위로 데이터를 전송하는 장치를 나타내는 파일 S_ISBLK() FIFO 파일 프로세스 간 통신에 사용되는 파일로 이름 있는 파이프 S_ISFIFO() 소켓 네트워크를 통한 프로세스 간 통신에 사용되는 파일 S_ISSOCK() 심볼릭 링크 다른 파일을 가리키는 포인터 역할을 하는 파일 S_ISLNK()
34
ftype.c $ gcc –o ftype ftype.c $ ln -s xx yy $ ftype xx yy $ ftype *
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.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; } 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); ftype.c $ gcc –o ftype ftype.c $ ln -s xx yy $ ftype xx yy $ ftype * $ ftype /dev/* | more st_ino와 st_size 출력해 보세요! Q: stat()과 lstat()의 차이점은?
35
파일 상태 정보 변경 chmod() 시스템 호출 파일의 상태 정보를 변경 #include <sys/types.h>
#include <sys/stat.h> int chmod(const char *path, mode_t mode); path가 나타내는 파일의 사용권한을 mode로 변경한다
36
fchmod.c #include <stdio.h> #include <stdlib.h> /* 파일 사용권한을 변경한다 */ main(int argc, char *argv[]) { long int strtol( ); int newmode; newmode = (int) strtol(argv[1],(char **) NULL, 8); if (chmod(argv[2], newmode) == -1) { perror(argv[2]); exit(1); } exit(0); $ gcc –o fchmod fchmod.c $ fchmod xx $ ls –asl xx $ man atoi int atoi(const char *nptr); = strtol(nptr, (char **)NULL, 10); # include <sys/types.h> /usr/include/stdlib.h 320행 typedef __mode_t mode_t; /usr/include/sys/types.h 71행 # define __STD_TYPE typedef /usr/include/bits/types.h 127행 __STD_TYPE __MODE_T_TYPE __mode_t; /usr/include/bits/types.h 139행 #include <bits/typesizes.h> /usr/include/bits/types.h 131행 #define __MODE_T_TYPE __U32_TYPE /usr/include/bits/typesizes.h 35행 #define __U32_TYPE unsigned int /usr/include/bits/types.h 102행
37
11.5 디렉터리
38
디렉터리 구현 디렉터리 내에는 무엇이 저장되어 있을까? 디렉터리 엔트리 #include <dirent.h>
/usr/include/dirent.h 30행 #include <bits/dirent.h> /usr/include/bits/dirent.h 23행 struct dirent { #ifndef __USE_FILE_OFFSET64 __ino_t d_ino; __off_t d_off; #else __ino64_t d_ino; __off64_t d_off; #endif unsigned short int d_reclen; unsigned char d_type; char d_name[256]; /* We must not include limits.h! */ }; DIR
39
디렉터리 리스트 opendir() readdir() 디렉터리 열기 함수 DIR 포인터(열린 디렉터리를 가리키는 포인터) 리턴
디렉터리 읽기 함수 #include <sys/types.h> #include <dirent.h> DIR *opendir (const char *path); path 디렉터리를 열고 성공하면 DIR 구조체 포인터를, 실패하면 NULL을 리턴한다. struct dirent *readdir(DIR *dp); 한 번에 디렉터리 엔트리를 하나씩 읽어서 리턴한다. typedef struct __dirstream DIR; /usr/include/dirent.h 128행
40
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; 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) // 각 디렉터리 엔트리에 대해 printf("%s \n", d->d_name); // 파일 이름 프린트 closedir(dp); exit(0); } $ gcc –o list1 list1.c $ list1 $ list1 /usr
41
파일 이름/크기 프린트 디렉터리 내에 있는 파일 이름과 그 파일의 크기(블록의 수)를 프린트하도 록 확장
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'); }
42
디렉터리 리스트: 예 list2.c 프로그램 구성 ls –l 명령어처럼 파일의 모든 상태 정보를 프린트
main() 메인 프로그램 printStat() 파일 상태 정보 프린트 type() 파일 타입 리턴 perm() 파일 접근권한 리턴 Q: 한 블록의 크기는? Linux: $ getconf PAGESIZE 또는 PAGE_SIZE (4096) Solaris: $ pagesize –a (4096, )
43
list2.c $ gcc –o list2 list2.c $ list2 $ list2 | sort +9 -10 $ ls -asl
#include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <pwd.h> #include <grp.h> #include <stdio.h> #include <stdlib.h> char type(mode_t); char *perm(mode_t); void printStat(char*, char*, struct stat*); int main(int argc, char **argv) /* 디렉터리 내용을 자세히 리스트한다 */ { DIR *dp; char *dir; struct stat st; struct dirent *d; 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); printStat(path, d->d_name, &st); /* 상태 정보 출력 */ putchar('\n'); } closedir(dp); exit(0); list2.c $ gcc –o list2 list2.c $ list2 $ list2 | sort $ ls -asl $ list2 /bin (/bin/su 파일로 확인)
44
list2.c (계속) 교재 코드 Debug 채워 넣으세요 st_ino 출력해 보세요
Q: 파일시스템 I/O 최적 블록 크기는? /* 파일 상태 정보를 출력 */ void printStat(char *pathname, char *file, struct stat *st) { printf("%5d ", st->st_blocks); printf("%c%s ", type(st->st_mode), perm(st->st_mode)); printf("%3d ", st->st_nlink); printf("%s %s ", getpwuid(st->st_uid)->pw_name, getgrgid(st->st_gid)->gr_name); printf("%9d ", st->st_size); printf("%.12s ", ctime(&st->st_mtime)+4); printf("%s", file); } /* 파일 타입을 리턴 */ char type(mode_t mode) { if (S_ISREG(mode)) return('-'); if (S_ISDIR(mode)) return('d'); if (S_ISCHR(mode)) return('c'); if (S_ISBLK(mode)) return('b'); if (S_ISLNK(mode)) return('l'); if (S_ISFIFO(mode)) return('p'); if (S_ISSOCK(mode)) return('s'); char* perm(mode_t mode) { int i; static char perms[10] = " "; for (i=0; i < 3; i++) { if (mode & (S_IREAD >> i*3)) perms[i*3] = 'r'; if (mode & (S_IWRITE >> i*3)) perms[i*3+1] = 'w'; if (mode & (S_IEXEC >> i*3)) perms[i*3+2] = 'x'; } /* set user ID * * set group ID * set sticky bit */ return(perms); /usr/include/bits/stat.h 161행 참조 #define __S_ISUID /* Set user ID on execution. */ #define __S_ISGID /* Set group ID on execution. */ #define __S_ISVTX /* Save swapped text after use (sticky). #define __S_IREAD /* Read by owner. */ #define __S_IWRITE /* Write by owner. */ #define __S_IEXEC /* Execute by owner. */
45
디렉터리 만들기 mkdir() 시스템 호출 path가 나타내는 새로운 디렉터리를 만든다
"." 와 ".." 파일은 자동적으로 만들어진다 #include <sys/types.h> #include <sys/stat.h> int mkdir (const char *path, mode_t mode ); 새로운 디렉터리 만들기에 성공하면 0, 실패하면 -1을 리턴한다
46
디렉터리 삭제 rmdir() 시스템 호출 path가 나타내는 디렉터리가 비어 있으면 삭제한다
#include <unistd.h> int rmdir (const char *path); 디렉터리가 비어 있으면 삭제한다. 성공하면 0, 실패하면 -1을 리턴
47
링크 링크는 기존 파일에 대한 또 다른 이름으로 하드 링크와 심볼릭(소프트) 링크가 있다
#include <unistd.h> int link(char *existing, char *new); 하드 링크를 만드는데 성공하면 0, 실패하면 -1을 리턴한다 int unlink(char *path); 링크를 제거하는데 성공하면 0, 실패하면 -1을 리턴한다 int symlink (const char *actualpath, const char *sympath ); 심볼릭 링크를 만드는데 성공하면 0, 실패하면 -1을 리턴한다
48
링크의 구현 link() 시스템 호출 기존 파일 existing에 대한 새로운 이름 new 즉 링크를 만든다
49
하드 링크 vs 심볼릭 링크 하드 링크(hard link) 심볼릭 링크(symbolic link) 지금까지 살펴본 링크
같은 파일 시스템 내에서만 사용될 수 있다 심볼릭 링크(symbolic link) 소프트 링크(soft link) 실제 파일의 경로명 저장하고 있는 링크 파일에 대한 간접적인 포인터 역할을 한다 다른 파일 시스템에 있는 파일도 링크할 수 있다
50
link.c #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[ ]) { if (link(argv[1], argv[2]) == -1) { exit(1); } exit(0);
51
unlink.c #include <unistd.h> #include <stdlib.h> main(int argc, char *argv[ ]) { int unlink( ); if (unlink(argv[1]) == -1) { perror(argv[1]); exit(1); } exit(0);
52
slink.c #include <unistd.h> #include <stdlib.h>
int main(int argc, char *argv[ ]) { if (symlink(argv[1], argv[2]) == -1) { exit(1); } exit(0);
53
핵심 개념 시스템 호출은 유닉스 커널에 서비스를 요청하기 위한 프로그래밍 인 터페이스로 응용 프로그램은 시스템 호출을 통해서 유닉스 커널에 서 비스를 요청한다 파일 디스크립터는 열린 파일을 나타낸다 파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일 위치를 가 리킨다 파일 하나당 하나의 i-노드가 있으며 i-노드 내에 파일에 대한 모든 상태 정보가 저장되어 있다 디렉터리는 일련의 디렉터리 엔트리들을 포함하고 각 디렉터리 엔트 리는 파일 이름과 그 파일의 i-노드 번호로 구성된다 링크는 기존 파일에 대한 또 다른 이름으로 하드 링크와 심볼릭(소프트 ) 링크가 있다
Similar presentations