티스토리 뷰

공부

Unix programming - 2

Bluesion 2022. 10. 18. 23:08

File

- Unix OS 차원에서 확장자는 존재하지 않는다.

- 바이트 별로 주소가 있어서 file direct access가 가능하다.

 

System call

open, creat, close, read, write, lseek, unlink, remove, fcntl

이때, block device들은 1 block씩 읽어야하기 때문에 버퍼 캐시가 따로 필요하다. (Character file은 1 바이트씩 읽으니 굳이 버퍼가 필요하지 않음)

 

File descriptor

- File descriptor는 integer 값을 가진다. (0~2가 아닌 가장 작은 양의 정수)- open 함수로 파일을 열면 file descriptor 값이 return되며, 이 값은 read와 write 함수의 인자로 활용된다.- 0은 stdin(키보드), 1은 stdout(모니터), 2는 stderr(모니터)이다.

 

open system call

#include <fcntl.h>
int open(const char* pathname, int flags, [mode_t mode]);

pathname: Relative pathname

flags: O_RDONLY, O_WRONLY, O_RDWR 중 1개 무조건 쓰기 + O_APPEND, O_CREAT, O_EXCL, O_TRUNC, O_NONBLOCK랑 섞어서 써도 OK

mode: O_CREAT flag가 있다면 해당 파일의 권한을 설정할 수 있다.

 

int fd;

// 파일이 없다면 만들고, 쓰기 모드로 열어라
// 새로 만들 때의 파일 퍼미션은 644이다.
fd = open("myfile", O_WRONLY | O_CREAT, 0644);

// 파일이 없으면 새롭게 만들되, 이미 파일이 존재한다면 error를 뱉어라 (최초 1회만 만들고 열어라)
// 새로 만들 때의 파일 퍼미션은 644이다.
fd = open("/home/bluesion/myfile.txt", O_RDWR | O_CREAT | O_EXCL, 0644);

// 파일이 없다면 새로 만들고, 있다면 해당 파일의 내용을 다 지우고 열어라
// 새로 만들 때의 파일 퍼미션은 644이다.
fd = open("asdf", O_WRONLY | O_CREAT | O_TRUNC, 0644);

한 process당 20개의 파일을 열 수 있다. (시간이 지나고 많이 발전하여 최근 유닉스는 20개 이상의 파일을 열 수 있다.)

 

Permissions

chmod 명령어를 통해 파일의 권한을 바꿀 수 있다.

# test 파일의 group에 write 퍼미션 추가
chmod g+w test

# test 파일의 permission을 777로 변경
chmod 777 test

mode의 symbolic name들은 다음이 있다. (open의 argument에 해당 symbol을 줘도 된다)

 

S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXU: User mode symbol

S_IRGRP, S_IWGRP, S_IXGRP, S_IRWXG: Group mode symbol

S_IROTH, S_IWOTH, S_IXOTH, S_IRWXO: Other mode symbol

S_ISUID, S_ISGID: Set user/group ID on execution

 

creat system call

#include <fcntl.h>
int creat(const char* pathname, mode_t mode);

아래와 같이 사용한다.

int fd;

// 아래 두 문장은 똑같은 역할을 한다.
fd = open("test", O_WRONLY | O_CREAT | O_TRUNC, 0644);
fd = creat("test", 0644);

 

Owner and permission of a new file

- open이나 creat system call을 사용하여 새로운 파일을 만드는 경우, effective user id와 effective group id가 부여된다. effective id의 경우 보통 해당 프로세스를 실행시킨 사람을 따라간다. 물론 아닐 때도 있다.

 

close system call

#include <fcntl.h>
int close(int filedes);

 

인자에는 닫고 싶은 file descriptor 값이 들어간다.

close를 명시적으로 사용하지 않아도, 모든 파일들은 프로그램이 종료되면 알아서 닫힌다.

 

read system call

#include <unistd.h>
ssize_t read(int filedes, void* buffer, size_t n);

filedes의 파일의 n 바이트를 buffer에 넣으라는 의미. buffer에 저장된 값을 읽으면 된다. 실제로 읽은 바이트 수가 return 된다.

 

write system call

#include <unistd.h>
ssize_t write(int fd, const void* buffer, size_t n);

- read와 상당히 비슷하다. fd 파일의 n 바이트를 buffer에 쓰라는 의미. 실제로 쓴 바이트 수가 return 된다.

- 이미 있는 파일을 write 하는 경우, character 단위로 overwrite 된다. Truncate를 하지 않으면 이전 데이터와 새로운 데이터가 겹쳐서 보일 수 있다는 것을 의미한다.

- write system call은 상당히 빠른데, 그 이유는 커널 안에 있는 buffer에 있다. Kernel buffer에 4KB가 모여야 I/O 작업을 진행한다. (Delayed writing)

 

lseek system call

#include <unistd.h>
off_t lseek(int fd, off_t offset, int start_flag);

off_t는 음수가 될 수도 있다. start_flag에서 offset만큼 이동한 곳에 커서를 놓으라는 의미.

 

<start_flag>

SEEK_SET(0): 파일의 처음에서 offset만큼 이동하여 커서를 놓아라

SEEK_CUR(1): 현재 커서 위치에서 offset만큼 이동하여 커서를 놓아라

SEEK_END(2): 파일의 맨 끝에서 offset만큼 이동하여 커서를 놓아라

 

EX) lseek을 이용하여 파일 사이즈를 측정하는 법

off_t filesize;
int fd;

filesize = lseek(fd, (off_t)0, SEEK_END);

파일의 맨 끝에 커서를 가져다 놓으면 그게 바로 파일 사이즈가 되니까...

 

File share

- 모든 프로세스는 커널이 프로세스 테이블로 관리한다. 프로세스 테이블에는 fd flag와 file table pointer가 있다.

- file table pointer를 따라가보면 file table이 존재한다. file table에는 status, offset, v-node pointer가 존재한다.

- v-node에는 해당 파일의 모든 것들이 적혀 있다. v-node는 무조건 파일당 1개씩만 존재한다.

- 같은 파일을 열었을 때, 파일을 여는 방식(status), offset에 따라 file table은 다를 수도 있지만, 결국 최종적으로는 동일한 v-node로 연결된다.

- close system call을 호출하면 file table이 사라진다.

 

dup2 system call

#include <unistd.h>
int dup2(int fd, int fd2);

file descriptor를 복사하는 system call이다. dup도 있지만, dup2가 훨씬 더 많이 사용된다. fd를 fd2로 복사한다.

fd와 fd2가 각각 다른 file table을 가리키고 있었다고 가정하자. dup2를 사용한다면 fd2 역시 fd가 가리키는 file table을 가리키게 되는 것이다.

 

Error handling

#include <errno.h>
int main() {
    int fd;
    fd = open("nothing", O_RDONLY);
    
    if (fd == -1) {
    	fprintf(stderr, "error %d\n", errno);
        perror("Error message");
    }

    return 0;
}

- system call은 실패하면 -1을 return한다.

- 이때 커널은 마지막으로 실패한 system call에 대한 정보를 가지고 있는데, errno.h 헤더를 사용하면 그 정보를 읽을 수 있다.

- 위 코드를 실행하면 아래와 같은 결과가 나온다.

error 2
Error message : There is no such files

'공부' 카테고리의 다른 글

시스템 프로그래밍 - Modular programming  (0) 2022.10.20
시스템 프로그래밍 - GCC & GDB 주요 정리  (0) 2022.10.20
Unix Programming - 1  (0) 2022.10.18
컴퓨터네트워크 Chapter 15  (0) 2022.10.11
컴퓨터네트워크 Chapter 2  (0) 2022.10.11
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함