FILE IO - fcntl, ioctl, stat, lstat, access, umask, chmod, chown

sesame·2021년 12월 16일
0

교육

목록 보기
2/46

fcntl

열려진 파일의 속성을 가져오거나 설정할 때 fcntl 함수를 사용합니다.

int fcntl(int fd, int cmd, /* int arg */);

cmd : 해당 fd에 할 작업을 의미
arg : 해당 fd에 할 작업(cmd에 따른)에 사용할 인수, 생략가능

F_DUPFD: 파일 디스크립터를 복제함
F_GETFD, F_SETFD: 파일 디스크립터 flags를 가져오거나 설정
F_GETFL, FSETFL: 파일의 status flags를 가져오가나 설정
F_GETOWN, F_SETOWN: SIGIO와 SIGUSR 시그널을 수신하는 프로세스 ID 혹은 프로세스 그룹 ID를 가져오거나 설정
F_GETLK, F_SETLK, F_SETLKW: 레코드 lock을 가져오거나 설정

#include <sys/types.h>
#include <fcntl.h>
#include "apue.h"

//fcntl 함수에 F_GETFL 인자를 전달하여 접근 모드를 확인하는 예제 코드입니다.
int main(int argc, char *argv[]){
        int accmode, val;
        //전달될 명령어 a.out 0 < /dev/tty
        //a.out 1 > temp.foo  새로 이거 생성해서 결과 standardout
        //전달된 갯수가 2개가 아니면 quit
        if(argc != 2)
                err_quit("usage: a.out <descriptor#>");
        //int fcntl(int fd, int cmd, .../*int arg*/);
        //fd에 전달된 데이터의 (두번째 값)넣고 open flag를 가져온다.
        //int arg는 무슨 역할??
        if((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
                err_sys("fcntl error for fd %d", atoi(argv[1]));

		//반환값&O_ACCMODE는 open flag값
        accmode = val & O_ACCMODE;
        if(accmode == O_RDONLY) printf("read only");
        else if(accmode == O_WRONLY) printf("write only");
        else if(accmode == O_RDWR) printf("read write");
        else err_dump("unknown access mode");

        if(val & O_APPEND) printf(", append");
        if(val & O_NONBLOCK) printf(", nonblocking");
#if !defined(_POSIX_SOURCE) && defined(O_SYNC)
        if(val&O_NONBLOCK) printf(", synchronous writes");
#endif
        putchar('\n');
        exit(0);
}

ioctl()

일반 파일, 파일 디스크립터, 네트워크 통신 모듈과 같은 디바이스와 관련된 속성의 연산을 위해 사용

디바이스를 제어하는 가장 적합한 방법으로 명령어(cmd)와 인자(arg)를 사용해서 디바이스를 설정하거나 설정된 값을 읽어오는데 주로 사용한다.

#include <sys/ioctl.h>

int ioctl(int fd, int cmd, int arg);

fd : 파일의 속성을 조회하거나 변경할 파일디스크립터 지정
cmd : 결과에 따른 여러 매개변수 사용 가능
arg : cmd에 의해 결정되는 선택적인 값으로 생략 가능
반환값 : 함수가 성공적으로 호출되면 0이나 0보다 큰수를 반환, 실패 시 -1 반환

ioctl() 함수가 입출력을 위한 제어를 위해 주로 사용하는 것을 제외하면, 기본적인 것은 fcntl() 함수와 동일하다.

/dev/fd

status flag change

#include <sys/types.h>
#include <fcntl.h>
#include "apue.h"

//access함수는 real userid 와 real groupid를 기반으로 테스트를 수행
int main(int argc, char *argv[]){
        if(argc != 2)
                err_quit("usage: a.out <pathname>");
        if(access(argv[1], R_OK) < 0)
                err_ret("access error for %s", argv[1]);
        else
                printf("read access OK\n");
        if(open(argv[1], O_RDONLY) < 0)
                err_ret("open error for %s", argv[1]);
        else
                printf("open for reading OK\n");
        exit(0);
}

4. File and Directories

stat

리눅스(유닉스) 시스템에서는 파일의 상태를 stat 구조체로 정의

int stat(const char *pathname, struct stat *buf);

int fstat(int filedes, struct stat *buf);

int lstat(const char *pathname, struct stat *buf);

lstat

#include <sys/types.h>
#include <sys/stat.h>
#include "apue.h"

//명령행 인자를 받아서 그 파일의 타입을 반환해주는 코드
int main(int argc, char *argv[]){
        int i;
        //파일의 상태를 stat에 저장
        struct stat buf;
        char *ptr;
        //받은 데이터 갯수동안
        for(i = 1; i < argc; i++){
                //받은 데이터 내용 출력
                printf("%s: ", argv[i]);
                //심볼릭 링크를 보기 위해 stat대신 lstat을 사용
                //첫번째 인수 fd, 두번째 인수 파일의 정보를 읽어온다
                if(lstat(argv[i], &buf) < 0){
                        err_ret("lstat error");
                        continue;
                }
                if(S_ISREG(buf.st_mode)) ptr = "regular";
                else if(S_ISDIR(buf.st_mode)) ptr = "directory";
                else if(S_ISCHR(buf.st_mode)) ptr = "character special";
                else if(S_ISBLK(buf.st_mode)) ptr = "block special";
                else if(S_ISFIFO(buf.st_mode)) ptr = "fifo";
        #ifdef S_ISLINK
                else if(S_ISLNK(buf.st_mode)) ptr = "symbolic link";
        #endif
        #ifdef S_ISSOCK
                else if(S_ISSOCK(buf.st_mode)) ptr = "socket";
        #endif
                else ptr = "unknown mode";
                printf("%sn", ptr);
        }
        exit(0);
}

file access permitions

st_mode 값은 또한 파일의 접근 권한을 저장하는데도 사용된다

Ownership of New Files and Directories

새 파일과 새 디렉터리의 권한에 대한 내용으로

  • 새파일의 user ID는 프로세스의 effective user ID로 세팅된다
  • 새파일의 group ID는 프로세스의 effective group ID로 세팅될 수 있다.
  • 새파일의 group ID는 그 파일이 생성되는 디렉토리의 group ID로 세팅될 수 있다.

access

사용자 계정에 따라 파일 접근 권한을 다르게 부여할 수 있다.

real userid: 단순히 실제 유저 아이디
effective userid: 일반적으로 userid와 동일하지만 권한이 없는 사용자가 루트와 같은 권한이 있는 사용자가 액세스 할 수 있는 파일에 액세스 할 수 있도록 변경되는 경우
saved set userid: 프로세스가 높은 권한으로 실행될 떄 일부 권한 부족 작업을 수행해야 할 때 사용되며, 이는 일시적으로 권한이 없는 계정으로 전환하여 달성할 수 있습니다.
권한 부족 작업이 수행하는 동안 효과적인 UID는 일부 낮은 권한 값으로 변경되고, 구저장된 userid에 터미널에서 id를 입력하기만 하면 uid를 인쇄할 수 있다.

int access(const char *pathname, int mode);
반환 값: 실패 시 -1, 성공 시 0

#include <sys/types.h>
#include <fcntl.h>
#include "apue.h"

//access함수는 real userid 와 real groupid를 기반으로 테스트를 수행
int main(int argc, char *argv[]){
        //다음 명령어 들어오지 않으면
        if(argc != 2)
                err_quit("usage: a.out <pathname>");
        //다음 읽기 권한이 있는지 확인해서 실패시
        if(access(argv[1], R_OK) < 0)
                err_ret("access error for %s", argv[1]);
        //성공시
        else
                printf("read access OK\n");
        //읽기 전용으로 파일 열기 실패시
        if(open(argv[1], O_RDONLY) < 0)
                err_ret("open error for %s", argv[1]);
        //성공시
        else
                printf("open for reading OK\n");
        exit(0);
}
// ls -l a.out
// -rwsrwxr-x 1 uucp 105216 Jan 18 08:48 a.out
// exit
// ./a.out /etc/uucp/Systems
// access error for /etc/uucp/Systems: Permission denied
// open for reading OK

umask

시스템 관리자는 파일의 접근 허가를 불허하는 최소한의 값을 설정할 수 있으며 이를 umask 값이라고 말합니다.

mode_t umask(mode_t cmask);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "apue.h"

int main(void){
        //unmask 0일때
        umask(0);
        //creat(const char *pathname, mode_t mode);
        if(creat("foo", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)<0)
                err_sys("creat error for foo");
        //unmask에 의해 모든 group과 other의 접근 권한을 막은 상태
        umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
        if(creat("bar", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)<0)
                err_sys("creat error for bar");
        exit(0);
}

chmod fchmod 함수

이미 존재하는 파일의 접근 권한을 바꾸는 2개의 함수가 있다.

  • chmod 함수는 지정한 파일에 대해
  • fchmod 함수는 이미 열려진 파일에 대해 작동한다.
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);
리턴값: 0이면 OK, -1이면 에러

#include <sys/types.h>
#include <sys/types.h>
#include "apue.h"

//chmode 예제
int main(void){
        struct stat statbuf;
        //접근권한을 현재상태와 관련지어 변경시킬 것이기 때문에
        //stat함수를 불러 현재의 퍼미션을 알아낸 뒤 그것을 변경
        //stat(const char *filename, struct stat *buf);
        if(stat("foo", &statbuf) < 0)
                err_sys("stat error for foo");
        //chmod(const char *pathname, mode_t mode);
        //chmod로 강제적으로 set-group-id 비트 키고, group execute 끈다
        //S_IXGRP: group-execute, S_ISGID: set-group-id
        if(chmod("foo", (statbuf.st_mode & -S_IXGRP) | S_ISGID)<0)
                err_sys("chmod error for foo");
        //set absolute mode to rw-r--r--
        if(chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)<0)
                err_sys("chmod error for bar");
        exit(0);
}

Sticky 비트

만일 이것이 실행 가능한 프로그램에서 세팅되어 있고, 그 프로그램이 처음으로 실행되면, 프로그램의 텍스트는 프로세스가 종료할 때 스왑영역에 남게 된다. 이것은 프로그램으로 하여금 다음번에 메모리로 더 빠르게 로드될 수 있도록 한다. 왜냐하면 유닉스의 파일 시스템은 일반적으로 임의의 위치에 있는 데이터 블록들로 이루어지지만, 스왑 영역은 연속적인 파일로 다루어지기 때문이다.

shown, fchown, lchown 함수

chdown 함수들은 파일의 사용자 ID와 그룹 ID를 바꾸는 일을 한다.

int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
  • lchown의 경우에는 심볼릭 링크가 가리키고 있는 파일이 아니라, 심볼릭 링크 그 자체의 소유자를 변경

    만일 _POSIX_CHOWN_RESTRICTED가 주어진 파일에서 효력이 있으면,

  1. 단지 슈퍼유저 프로세스만이 파일의 유저 ID를 바꿀 수 있다.
  2. 슈퍼유저가 아닌 프로세스는 다음과 같은 경우에 group ID를 바꿀 수 있다.
    a. 프로세스가 파일의 주인일 때(effective user ID가 파일의 유저 ID와 같을 때)
    b. owner 인자가 파일의 유저 ID와 같고, group ID가 그 프로세스의 effective group ID와 같거나, 프로세스의 supplementary group ID와 같을 때

File size

stat 구조체의 st_size 멤버는 파일의 크기를 바이트 단위로 저장

  • 심볼릭 링크의 경우에는 파일 사이즈는 파일 이름의 길이가 된다. 예를 들면 다음과 같다.
    lrwxrwxrwx 1 root 7 sep 25 07:14 lib -> usr/lib
    파일 사이즈 7은 경로명 usr/lib의 길이와 같다.
    (심볼릭 링크는 일반적인 C의 널 바이트를 경로명의 끝에 가지지 않음에 유의하라, 길이는 항상 st_size로부터 얻어진다.)

  • 구멍이 있는 코드
    cat core>core.copy하면
    272 core
    16592 core.copy가 된다
    read함수는 null공간을 0으로 읽기 때문에 빈공간에 데이터가 들어가서 차이가 생겼다. 이것은 파일시스템에서 사용되는 블록은 실제 데이터를 가리키는 포인터만을 유지하기 때문에 생긴 것이다.

File Truncation

O_TRUNC 플래그로 파일을 open 하여 파일의 모든 내용을 완전히 지우는 것이 그 예

int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);

리턴값: 0이면 OK, -1이면 에러

이 두 함수는 현재 존재하는 파일을 length 바이트만큼 잘라낸다. 이전의 파일 사이즈가 length바이트 이상이면, length 바이트 이상은 접근할 수 없게 된다. 만일 이전 파일 사이즈가 length 이하이면, 그 효과는 시스템에 따라 다르다. 만일 그 구현이 파일을 확장하는 것이면, 이전의 end-of-file부터 새 end-of-file 까지는 0으로 읽혀진다.(즉 아마 파일 내부에 구멍이 생길 것이다)

File Systems

0개의 댓글