Linux 파일시스템프로그래밍 File System Programming - 파일시스템내부구조 - File Descriptor - File 기본작업시스템호출 - File 정보관리시스템호출 - Directory 관리시스템호출 이제부터는 시스템사용에만머물지않는다. 내부로들어가서건드려보고나만의시스템을만들자. 시스템호출 ( 또는표준 API) 을이용하여운영체제기능을프로그램에서사용 시스템호출 (System Calls) 프로세스와운영체제간의인터페이스제공 운영체제마다다른것이원칙 Library 함수와다르다. 사용자명령결과프로그래머 응용프로그램, 명령해석기, 시스템프로그램 시스템호출 결과 운영체제 ( 서비스, 자원관리 ) 2
파일관련시스템호출 파일기본동작 함수 의미 open 이미존재하는파일을읽기또는쓰기용으로열거나, 새로운파일을생성하여연다. creat 새로운파일을생성하여연다. close open 또는 creat 로열려진파일을닫는다. read 열려진파일로부터데이터를읽어들인다. write 열려진파일에데이터를쓴다. lseek 파일안에서읽기 / 쓰기포인터를지정한바이트위치로이동한다. unlink/remove 파일을삭제한다. 3 파일관련시스템호출 파일정보관리작업 함수 의미 umask 파일생성마스크를설정한다. access 파일에대한사용자의접근권한을확인한다. chmod/fchmod 파일에대한접근권한을변경한다. chown/fchown 파일의소유주와그룹을변경한다. link 파일의새로운이름을생성한다. (hard-link) rename 파일의이름이나위치를변경한다. symlink 파일의새로운이름을생성한다. (soft-link, symbolic link) readlink 심볼형링크의값 ( 실제내용 ) 을읽어온다. stat/fstat 파일의상태정보를가져온다. 4
파일관련시스템호출 디렉터리작업 함수의미 mkdir 새로운디렉터리를작성한다. rmdir 디렉터리를삭제한다. opendir 디렉터리를파일처럼개방한다. closedir 개방한디렉터리를닫는다. readdir 개방된디렉터리로부터디렉터리항목을읽어온다. rewinddir 개방된디렉터리스트림을초기화한다. chdir 디렉터리경로를변경한다. getcwd 현재작업디렉터리를구한다. 5 파일시스템 파일 정보의논리적저장단위 FCB (File Control Block) - 파일에대한정보를구성하는저장구조로서운영체제에서사용 운영체제에서파일시스템제공 파일의물리적의미, 구조, 속성, 연산정의 논리적파일시스템을물리적보조저장장치에매핑하는알고리즘과자료구조 기본적으로디스크기반파일시스템제공 UFS, VFS, FAT, NTFS, ext3, JFS, ReiserFS, XFS, 계층적구조사용 6
파일시스템 디스크내기본정보 운영체제부트방법, 블록의수, 자유블록의수와위치, 디렉터리구조, 개별파일정보등 디스크구조 부트제어블록 시스템부팅에필요한정보 UFS boot block, NTFS partition boot sector 파티션제어블록 ( 또는 Volume Control Block) 파티션의블록수, 크기, 자유블록수와포인터, 자유 FCB 수와포인터등의파티션정보 UFS Superblock, NTFS Master File Table 디렉터리구조 파일제어블록 (FCB) 파일허가, 소유, 크기등자세한파일정보 UFS inode, NTFS Master File Table 안에저장 7 유닉스파일시스템 유닉스파일시스템구조 부트블록 (Boot Block) 수퍼블록 (Super Block) 아이노드블록 (Inode Blocks) 데이터블록 (Data Blocks) 부트블록 (boot block) 운영체제당하나 운영체제를부팅시키기위한코드가저장되어있다. 수퍼블록 (super block) 파일시스템 ( 파티션 ) 당하나 파일시스템과관련된정보를저장하고있다. 아이노드블록 (inode blocks) 파일당하나 파일에대한정보를저장하고있다. 소유자, 크기, 접근권한, 접근시간등 데이터블록 (data blocks) 파일이보관해야하는데이터를저장하고있다. 보관하는데이터의크기에따라여러개일수있다. 8
아이노드와데이터 유닉스파일시스템 파일 아이노드블록에저장됨 $ cat > temp apple is red banana is yellow $ ls -l temp 데이터블록에 -rw-r--r-- 1 juyoon juyoon 30 Oct 18 16:54 temp $ 블록에저장됨 9 유닉스파일시스템 수퍼블록정보보기 디렉터리정보는어디? 디렉터리도파일이다. 아이노드번호 (ID) 와파일명으로구성된목록파일 추가정보필요시아이노드번호를이용해해당파일의아이노드정보를가져온다. 항상.( 자기자신 ) 와..( 부모디렉터리 ) 을포함한다. 10
프로세스와파일 프로그램전에프로그램수행시파일관련정보는어떻게관리되는지알아보자. File Descriptor Read/Write Pointer 11 프로세스와파일 파일기술자 (File Descriptor) 실행중인프로그램 ( 프로세스 ) 가관리하는파일들의포인터배열에대한인덱스 음수가아닌정수값 - 시스템 ( 커널 ) 이결정 파일개방이실패하면 -1 여러개의프로그램이동시에하나의파일을개방할수있다. 12
프로세스와파일 읽기 / 쓰기포인터 개방된파일내에서읽기나쓰기작업을수행할바이트단위의위치 특정위치를기준으로한상대적인위치를의미 오프셋 (offset) 파일을개방한직후에읽기 / 쓰기포인터는 0 파일의첫번째바이트를가리킨다. 파일의내용을읽거나파일에새로운데이터를작성하면그만큼증가한다. 파일기술자마다하나씩존재 한파일이여러프로세스에서사용되어도무방 13 프로세스와파일 프로세스와파일기술자 14
시스템호출 시스템호출사용시필수요소 기능 이름 전달인자 반환타입 자세한사용법은 man 을활용하자! 15 open 파일을개방 이미존재하는파일개방 새로운파일개방 open 또는 creat 오류가발생해도그대로진행 프로그래머가체크 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *pathname, int flags, [mode_t mode]); pathname 개방할파일의경로이름을가지고있는문자열의포인터 flags 파일의개방방식지정 : O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_APPEND, mode 대부분의경우생략할수있는값으로새롭게생성하는파일의초기접근권한을지정정상적으로파일을개방하게되면파일기술자반환파일개방이실패할경우 -1 반환 16
open 주요플래그 O_RDONLY O_WRONLY O_RDWR O_CREAT O_EXCL O_APPEND O_TRUNC 읽기전용쓰기전용읽기와쓰기가동시에가능한상태로개방지정한경로의파일이존재하지않으면새롭게생성한후개방한다. 지정한경로의파일이존재하면지정한상태로개방한다. 지정한경로의파일이존재하지않으면새롭게생성하나, 지정한경로의파일이존재하면 open 호출을실패한다. ( O_CREAT 플래그와함께사용해야한다.) 파일을개방한직후에읽기 / 쓰기포인터의위치를파일내용의마지막바로뒤로이동파일을개방한직후에읽기 / 쓰기포인터의위치를파일내용의첫부분으로이동 17 open open 사용예 여러플래그를동시에사용할때는 (bitwise OR) 사용 int fd1, fd2, fd3, fd4; char *filename = data.txt ; fd1 = open( data1.txt, O_RDONLY); fd2 = open( data2.txt, O_WRONLY O_APPEND); fd3 = open( data3.txt, O_RDWR O_CREAT); fd4 = open(filename, O_RDWR O_CREAT O_EXCL, 0644); 18
creat 새로운파일생성 O_WRONLY O_CREAT O_TRUNC 설정으로개방하는것과같은효과 기존파일이있으면데이터를모두삭제 (O_TRUNC) 하고개방 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat (const char *pathname, mode_t mode); pathname 개방할파일의경로이름을가지고있는문자열의포인터 mode 새롭게생성하는파일의초기접근권한을지정. open과달리생략할수없다. 정상적으로파일을개방하게되면파일기술자반환파일개방이실패할경우 -1 반환 19 close 개방상태의파일닫기 사용이끝나면반드시닫아주어야한다. 하나의프로세스가동시에개방할수있는파일의수와전체시스템에서동시에개방할수있는파일의수가제한되어있음. 프로세스정상종료시자동폐쇄 프로그램내에서처리하는습관이좋다! int close (int filedes); filedes 이전에 open이나 creat에의해개방된파일의파일기술자작업이성공할경우 0이반환되며, 실패할경우 -1 반환 20
read/write 파일에서데이터읽기 / 쓰기 ssize_t read (int filedes, void *buf, size_t count); ssize_t write (int filedes, const void *buf, size_t count); filedes buf count 읽기 / 쓰기작업을수행할파일의파일기술자읽거나쓸내용을저장하는공간. 일반적으로배열을사용하게되는데배열의데이터형식은어느것이라도상관없다. 읽거나쓸내용의크기를지정. 바이트단위. 버퍼 (buf) 크기와상관없다. 파일로부터읽기 / 쓰기작업이성공할경우 1) 읽거나쓴내용의바이트크기반환 (1 이상의값 ) ( 일반적으로 count 값과같다.) 2) 읽거나쓴내용이없을경우 (EOF일경우 ) 0을반환읽기작업이실패한경우 : -1을반환쓰기작업이실패한경우 : count 값과이다르다. 21 read/write read/write 사용예 ssize_t nread, nwrite; if ((nread = read(fd, buf, BUFSIZE)) > 0) // 읽기가정상적으로수행되면 if ((write(fd, buf, nwrite) < nwrite) // 쓰기가정상적으로수행되면 22
lseek 읽기 / 쓰기포인터위치변경 #include <sys/types.h> off_t lseek (int filedes, off_t offset, int whence); filedes 읽기 / 쓰기포인터를변경할파일을지정 offset 새롭게지정할읽기 / 쓰기포인터의위치. 오프셋이기때문에기준에따라음수가될수도있으며, 바이트단위로이동한다. whence offset의기준. 파일의맨처음 (SEEK_SET), 현재포인터의위치 (SEEK_CUR) 또는파일의맨마지막 (SEEK_END) 작업이성공하면파일의첫부분을기준으로한포인터의오프셋을반환. 작업이실패할경우 (off_t)-1 반환. 23 lseek lseek 사용예 off_t newpos; newpos = lseek (fd, (off_t) 3, SEEK_SET); --- (1) newpos = lseek (fd, (off_t) -2, SEEK_CUR); --- (2) newpos = lseek (fd, (off_t) 0, SEEK_END); --- (3) newpos = lseek (fd, (off_t) -3, SEEK_CUR); --- (4) (2) (1) (4) (3) 0 1 2 3 4 5 6 7 8 EOF 24
unlink/remove 경로명으로지정한파일삭제 디렉터리삭제 비어있지않으면삭제할수없다. 비어있는디렉터리는 remove 로삭제 int unlink (const char *pathname); #include <stdio.h> int remove (const char *pathname); pathname 삭제할파일의경로이름작업이성공할경우 0이반환되며, 실패할경우 -1이반환된다. 25 예제 1 실행결과 : 26
umask 새로운파일생성시적용하는접근권한중일부를제한 명령어로존재 파일생성시접근권한을설정할때디폴트로사용할마스크지정 $ umask 077 mask XOR 777 ( 또는 ~mask & 777) 새파일의접근권한 시스템에서 022 로지정되어있다. 항상적용하고싶으면.bashrc 등의설정파일에기록해서사용 27 umask umask 시스템호출 #include <sys/types.h> #include <sys/stat.h> mode_t umask (mode_t mask); mask 새로생성하는파일의접근권한설정을위한마스크. (open 의 mode & ~mask) 로실제접근권한이설정됨. umask 의실행은항상성공하며이전 mask 값을반환한다. 프로그램에서설정한 umask 는프로세스실행중일때만유지됨. 예 mode_t oldmask; oldmask = umask (022); fd = open ( data.txt, O_CREAT, 0777); 실제로는 (777 & ~022 = 055) 로접근권한이설정됨. 28
access 지정한파일에대해특정접근권한을가지고있는지검사 int access (const char *pathname, int mode); pathname mode 파일의경로이름검사하려는접근권한 : R_OK, W_OK, X_OK, F_OK 등성공하면 0을반환, 실패하면 -1을반환 사용예 if (access( data.txt, R_OK) == -1) { printf( User cannot read file data.txt\n ); exit(1); } 29 chmod/fchmod 파일의접근권한변경 chmod: 파일경로명이용 fchmod: 파일기술자이용 8 진수또는매크로상수로이루어진 mode 를이용해접근권한변경 #include <sys/types.h> #include <sys/stat.h> int chmod (const char *path, mode_t mode); int fchmod (int filedes, mode_t mode); path filedes mode 파일의경로이름개방된파일의파일기술자파일에새롭게적용하려는접근권한성공하면 0을반환, 실패하면 -1을반환 30
chmod/fchmod 접근권한을나타내는매크로상수 8진수값 상수이름 의미 0400 S_IRUSR 소유자에대한읽기권한 0200 S_IWUSR 소유자에대한쓰기권한 0100 S_IXUSR 소유자에대한실행권한 0040 S_IRGRP 그룹사용자에대한읽기권한 0020 S_IWGRP 그룹사용자에대한쓰기권한 0010 S_IXGRP 그룹사용자에대한실행권한 0004 S_IROTH 기타사용자에대한읽기권한 0002 S_IWOTH 기타사용자에대한쓰기권한 0001 S_IXOTH 기타사용자에대한실행권한 사용예 : mode_t mode; mode = S_IRUSR S_IWUSR S_IRGRP S_IROTH; chmod( test.txt, mode); 31 chown/fchown 지정한경로의파일이나이미개방된파일의소유주변경 시스템관리자만수행할수있다. #include <sys/types.h> int chown (const char *path, uid_t owner, gid_t group); int fchown (int fd, uid_t owner, gid_t group); path fd owner group 파일의경로이름개방된파일의파일기술자새로운소유주의사용자식별번호 (UID) 새로운소유주의그룹식별번호 (GID) 성공하면 0을반환, 실패하면 -1을반환 UID, GID 는 id 명령으로알수있다. 32
link/symlink 파일의하드 / 심볼릭링크생성 int link (const char *oldpath, const char *newpath); int symlink (const char *oldpath, const char *newpath); oldpath newpath 원본파일의경로이름하드링크 / 소프트링크의경로이름성공하면 0을반환, 실패하면 -1을반환 33 readlink 소프트링크파일의내용을읽는다. 내용 == 원본파일의경로이름 int readlink (const char *path, char *buf, size_t bufsize); path 소프트링크의경로이름 buf 소프트링크의실제내용을담을공간 bufsize buf의크기읽기가성공하면 buf에저장한바이트수를반환하며, 실패할경우 -1을반환 사용예 char buffer[1024]; int nread; nread = readlink( link, buffer, 1024); write = (1, buffer, nread); 34
rename 지정한경로의파일이름을새로운이름으로변경 #include <stdio.h> int rename (const char *oldpath, const char *newpath); oldpath newpath 이름을바꾸려는파일의경로이름파일의새로운이름성공하면 0을반환하고, 실패하면 -1을반환 oldpath == newpath 이면성공으로간주 newpath 와같은이름의파일이이미존재할경우, 이를삭제한다. 즉, overwrite 한다. newpath 와같은이름의디렉터리가존재할경우, 비어있으면 overwrite 하고비어있지않으면실패한다. 35 stat/fstat 파일의상세정보를읽어온다. 아이노드에저장된메타정보 #include <sys/types.h> #include <sys/stat.h> int stat (const char *filename, struct stat *buf); int fstat (int filedes, struct stat *buf); filename filedes buf 사용예 파일의경로이름개방된파일의파일기술자파일의정보를담기위한 struct stat 타입구조체의포인터성공하면 0을반환하고, 실패하면 -1을반환 struct stat fileinfo; if (stat( data.txt, &fileinfo) == -1) { printf( 파일정보읽기실패 \n ); exit(1); } 36
stat/fstat struct stat 구조체 struct stat { dev_t st_dev; // 장치식별번호 ino_t st_ino; // 아이노드블록번호 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; // 바이트단위파일크기 timestruc_t st_atim; // 마지막접근시간 timestruc_t st_mtim; // 마지막수정시간 timestruc_t st_ctim; // 마지막상태변경시간 blksize_t st_blksize; // 할당된블록크기 blkcnt_t st_blocks; // 할당된데이터블록수 char st_fstype[_st_fstypsz]; // 파일시스템의종류 }; 37 예제 2 실행결과 : 38
mkdir/rmdir 새디렉터리생성또는삭제 #include <sys/types.h> #include <sys/stat.h> int mkdir (const char *pathname, mode_t mode); int rmdir (const char *pathname); pathname mode 디렉터리의경로이름생성하려는디렉터리의초기접근권한성공하면 0을반환하고, 실패하면 -1을반환 rmdir 은비어있는디렉터리만삭제가능 39 opendir/closedir 디렉터리개방폐쇄 디렉터리도파일 특수형태 open 으로개방할수있으나내용을읽기어렵다. 별도의시스템호출사용 #include <sys/types.h> #include <dirent.h> DIR *opendir (const char *name); int closedir (DIR *dir); name 개방하려는디렉터리의경로이름 dir 닫으려고하는개방된디렉터리에대한포인터 [opendir] 성공하면디렉터리스트림에대한 DIR형포인터를반환, 실패하면 NULL을반환 [closedir] 호출이성공하면 0을반환, 실패하면 -1을반환 40
readdir 개방된디렉터리 ( 파일 ) 에서하나의디렉터리항 (directory entry) 을읽어온다. #include <sys/types.h> #include <dirent.h> struct dirent *readdir(dir *dirp); dirp opendir로개방한디렉터리에대한포인터호출이성공하면 struct dirent 포인터형의디렉터리항을반환하고, 호출이실패하면 NULL을반환한다. 더이상읽을디렉터리항이없을경우에도 NULL을반환한다. 사용예 DIR *dirp; struct dirent *dentry; if ((dirp = opendir(. )) == NULL) exit (1); while (dentry = readdir(dirp)) { if (dentry->d_ino!= 0) printf( %s\n, dentry->d_name); } // 항이남아있는동안 // 0은삭제된파일 41 readdir 디렉터리항 (directory entry) 구조 dirent 자료구조 struct dirent { long d_ino; char d_name[name_max + 1]; } 디렉터리파일의내용 1020. \0 907.. \0 1507 t e s t 1 \0 0 t e m p \0 1347 a p p l e \0 아이노드블록번호 파일이름 42
rewinddir 디렉터리파일에서읽기포인터의위치초기화 lseek(fd, 0, SEEK_SET) 과같은효과 디렉터리파일의읽기포인터는항단위로이동 #include <sys/types.h> #include <dirent.h> void rewinddir (DIR *dir); dir 읽기포인터를초기화하려는개방된파일의포인터없음 43 chdir 작업디렉터리변경 int chdir (const char *path); path 변경하려는새로운디렉터리경로성공하면 0을반환, 실패하면 -1을반환한 프로그램내디렉터리변경은프로세스실행동안에만적용되며, 프로세스종료후쉘에영향을주지않는다. 44
getcwd 현재작업디렉터리를알아본다. Current Working Directory 절대경로가버퍼에저장된다. char *getcwd(char *buf, size_t size); buf size 사용예 현재작업디렉터리의경로를저장할버퍼버퍼의최대크기성공하면 buf의포인터를반환하고, 실패할경우 NULL을반환 char buffer[256]; if (getcwd(buffer, 256) == NULL) exit(1); printf( %s\n, buffer); 45 예제 3 실행결과 : 46