🔔 학교 강의를 바탕으로 개인적인 공부를 위해 정리한 글입니다. 혹여나 틀린 부분이 있다면 지적해주시면 감사드리겠습니다.
#include <unistd.h>
int readlink(const char *sympath, char* buffer, size_y bufsize);
argument
- const char *sympath : symbolic link 경로
- char* buffer : 저장할 buffer
- size_y bufsize : buffer size
return
- 성공 시 byte 개수 return
- error 발생 시 -1 return
readlink
는 sympath
를 따라가 실질적인 realname
을 보여주는 것이 아닌, sympath
그 자체를 읽어오는 역할을 한다.
#include <sys/stat.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
각 함수는 모두 동일하게 파일에 대한 정보를 출력하는 역할을 한다. 하지만 전달받는 인자에 차이가 있다.
argument
- const char *pathname :
stat
일 경우 파일의 경로,lstat
일 경우symbolic link
의 경로- struct stat *buf : 저장할 buffer
return
- 성공 시 0 return
- error 발생 시 -1 return
struct stat
은 아래와 같은 구조를 가지고 있다.
이에 대한 예시 코드는 아래와 같다.
// filedata -- 한 파일에 관한 정보를 출력
#include <stdio.h>
#include <sys/stat.h>
// 허가 비트가 설정되어 있는지 결정하기 위해 octarray를 사용
static short octarray[9] = {0400, 0200, 0100,
0040, 0020, 0010,
0004, 0002, 0001};
// 파일 허가에 대한 기호화 코드 끝부분의 null 때문에 길이가 10문자이다.
static char perms[10] = "rwxrwxrwx";
int filedata (const char *pathname) {
struct stat statbuf;
char descrip[10];
int j:
if(stat (pathname, &statbuf) == -1) {
fprintf (stderr, "Couldn't stat %s\n", pathname);
return (-1);
}
// 허가를 읽기 가능한 형태로 바꾼다.
for(j=0; j<9; j++) {
// 비트별 AND를 사용하여 허가가 설정되었는지 테스트
if (statbuf.st_mode & octarray[j])
descrip[j] = perms[j];
else
descrip[j] = '-';
}
descrip[9] = '\0'; // 하나의 문자열을 가지도록 확인
// 파일 정보를 출력한다.
printf ("\nFile %s :\n", pathname);
printf ("Size %ld bytes\n", statbuf.st_size);
printf ("User-id %d, Group-id %d\n\n", statbuf.st_uid, statbuf.st_gid);
printf ("Permissions: %s\n", descrip);
return (0);
}
파일 권한에 대한 정보를 stat
을 이용해 statbuf
에 저장한 이후, 해당 정보를 각 권한에 해당하는 bit와의 &
연산을 통해 문자열로 변경하여 출력해준다.
file system
은 file과 directory의 계층적 배열이며, 모든 것은 /
로 표기되는 root
에서부터 시작한다.
모든 process는 working directory
가 존재하며, 상대경로
를 판단하는 경로다.
우리가 로그인을 하면, working directory
가 우리의 home directory
를 설정해준다.
경로에는 2가지가 있으며, root
에서부터 시작하는 절대 경로
와 (/
로 시작함), working directory
에서 시작하는 상대 경로
가(/
로 시작하지 않음) 존재한다.
file에 사용되는 많은 system call들은 directory에도 사용될 수 있지만, 일반적인 file과 directory간의 차이는 존재한다.
create
나open
을 사용하여 directory 생성 불가O_WRONLY
나O_RDWR
flag가 설정된 경우에는 directory를 열 수 없음 (errno = EISDIR
)write
를 사용해서 directory를 update할 수 없음- kernel만 directory에 대해서 write이 가능함
directory는 그 안에 포함된 file이나 하위 directory의 항목들로 구성이 되며 아래의 요소들을 포함한다.
- i-node number
- character field (=string)
이전에 정리했던 link
의 경우, 동일한 i-node
번호를 가지면서 새로운 이름을 가지는 directory slot을 추가해주는 것에 해당하며, 이는 아래와 같다.
unlink
는 반대로 이 directory slot을 삭제해주는 역할이며, link count
가 0이 되면, 해당 i-node
전체를 삭제한다.
.
: 현 directory..
: 상위 directory이를 그림으로 나타내면 아래와 같다.
또한 directory의 구조를 그림으로 나타내면 아래와 같다.
directory의 권한 역시 file의 권한과 동일한 방식으로 구성되어 있지만, file의 권한과 의미하는 바가 다르다.
- Read permission : sub directory의 file name을 list화 가능
- Write permission : directory를 지우거나 새로 생성이 가능
- Execute permission : 해당 directory 안으로 이동하여 working directory로 지정이 가능
-> 앞에서 directory에 대해서write
이 불가능하다는 것은 system call을 이용해 directory 자체를 여는 것이 불가능하다는 의미
따라서 어떠한 파일 경로에 접근하기 위해서는, 해당 경로에 적힌 모든 directory에 대해서 execute permission
이 존재해야 한다는 의미가 된다. 또한 execute permission bit
를 search bit
이라고 부르기도 한다.
이전에 자세하게 다루지 않았던 permission 9bit
를 제외한 상위 3bit
중에서 S_ISVTX
는 save-text-image(sticky bit)
이라고도 부르며, directory에만 유효한 bit이다. 해당 bit가 설정되면 file 추가는 아무나 가능하나, file 삭제와 이름 변경은 아래 3개의 경우만 가능하다.
- file의 소유자일 경우
- directory의 소유자일 경우
- superuser (root)
#include <dirent.h>
struct dirent {
ino_t d_ino;
char d_name[NAME_MAX + 1];
}
dirent
는 자료형이며, i-node number
와 null로 끝나는 file 이름
을 포함하고 있다. d_ino
가 0이면 빈 슬롯임을 뜻하며, 이는 새로운 file을 만들 때 활용한다.
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
mkdir
는 pathname
에 해당하는 새로운 directory를 생성한다. mode
는 권한을 가리키며, umask
의 영향을 받는다. 또한 .
, ..
를 생성하고, i-node
를 부여한다.
argument
- const char *pathname : 생성할 새로운 directory
- mode_t mode : permission
return
- 성공 시 0 return
- error 발생 시 -1 return
directory 내의 file 이름들에 대해 접근하기 위해서는 적어도 하나의 execute bit
이 활성화되어야 한다.
#include <unistd.h>
int rmdir(const char *pathname);
rmdir
는 빈 directory를 제거하며, 여기서 빈 directory란 .
, ..
만 가지고 있는 directory를 뜻한다.
argument
- const char *pathname : 삭제할 directory
return
- 성공 시 0 return
- error 발생 시 -1 return
#include <dirent.h>
DIR *opendir(const char *dirname);
argument
- const char *dirname : open할 directory 이름
return
- 성공 시 해당 directory의
DIR
pointer return- error 발생 시
NULL
return
opendir
은 dirname
에 해당하는 directory를 open하는 함수이다. 여기서 return type인 DIR
은 standard I/O
에서 FILE
과 유사하게 작동한다. NULL
이 반환될 경우 error checking이 필요하다.
#include <dirent.h>
int closedir(DIR *dirptr);
argument
- DIR *dirptr : close할 directory pointer
return
- 성공 시 0 return
- error 발생 시 -1 return
closedir
은 전달받은 dirptr
에 해당하는 directory를 close하는 역할을 하며, directory는 program이 종료될때까지 닫기지 않으면, 종료 시에 자동으로 close된다.
#include <dirent.h>
struct dirent *readdir(DIR *dirptr);
argument
- DIR *dirptr : 읽고 싶은 directory pointer
return
- 성공 시
dirent
의 pointer return- error 발생 시
NULL
return
readdir
을 처음 실행하면, 첫 번째 directory entry가 dirent
로 읽혀지게 된다. readdir
이 성공하면, dirptr
은 다음 directory entry로 이동한다. 끝까지 이동한 경우에는 NULL
을 return한다.
#include <dirent.h>
void rewinddir(DIR *dirptr);
rewinddir
은 dirptr
를 directory의 가장 처음 entry로 이동시킨다. return값이 존재하지 않는다.
위에 대한 다양한 function들에 대한 예시 코드는 아래와 같다.
#include <dirent.h>
int my_double_ls (const char *name) {
struct dirent *d;
DIR *dp;
if ((dp=opendir(name))==NULL)
return (-1);
while (d=readdir(dp)) {
if (d->d_ino != 0)
printf(“%s\n”, d->d_name);
}
rewinddir(dp);
while (d=readdir(dp)) {
if (d->d_ino != 0)
printf(“%s\n”, d->d_name);
}
closedir(dp);
return 0;
}
중간에 d_ino
가 0이 아님을 확인하는 조건문은 유효성을 판단하는 것이며, 해당 코드는 ls
를 2번 실행하는 것과 유사하다.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
int match (const char *, const char*);
char *find_entry(char *dirname, char *suffix, int cont) {
static DIR *dp=NULL;
struct dirent *d;
if (dp == NULL || cont == 0) {
if (dp != NULL)
closedir (dp);
if ((dp = opendir(dirname)) == NULL)
return (NULL);
}
while (d = readdir(dp)) {
if (d->d_ino == 0)
continue;
if (match(d->d_name, suffix))
return (d->d_name);
}
closedir(dp);
dp = NULL;
return (NULL);
}
int match (const char *s1, const char *s2) {
int diff = strlen(s1) – strlen(s2);
if (stlen(s1) > strlen(s2))
return (strcmp(&s1[diff], s2) == 0);
else
return 0;
}
suffix
로 전달받은 file 이름과 동일한 file의 file entry
를 찾는 코드이다.
각 Linux(Unix) process는 각자의 working directory
를 가지고 있으며, 현재 실행되고 있는 process의 working directory
는 process가 시작된 working directory
인, 보통은 shell
로 설정된다.
int chdir(const char *path);
chdir
은 현재 process의 working directory
를 변경한다.
argument
- const char *path : working directory로 지정할 경로
return
- 성공 시 0 return
- error 발생 시 -1 return
error
가 발생하는 경우는 해당 path가 없는 경우, 혹은 path에 대해 execute permission이 없는 경우이며, 둘 중 하나라도 없으면 안된다.
특정 directory에 있는 file 여러개를 open해야할 경우, chdir
를 이용하여 해당 directory로 이동하여 작업하는 것이 더 효율적이다.
#include <unistd.h>
char *getcwd(char *name, size_t size);
getcwd
는 현 directory의 pathname
을 받아온다.
argument
- char *name : 현재 working directory 이름 저장
- size_t size : 현재 working directory를 받아오는 역할
return
- 성공 시 현재
working directory
이름 return- error 발생 시
NULL
return
항상 size
가 working directory
보다 1 이상 더 커야하며, 같거나 더 작은 경우 errno = ERANGE
와 함께 error가 발생한다.
이에 대한 예시 코드는 아래와 같다.
#include <stdio.h>
#include <unistd.h>
#define VERYBIG 200
void my_pwd ();
int main() {
my_pwd();
return 0;
}
void my_pwd () {
char dirname[VERYBIG];
if ( getcwd(dirname, VERYBIG) == NULL)
perror("getcwd error");
else
printf("%s\n", dirname);
}
위는 getcwd
를 활용하여 pwd
를 간단히 구현한 코드이다.
#include <unistd.h>
int ftw(const char *path, int(*func)(), int nopenfd);
int func(const char *name, const struct stat *sptr, int type) {
...
}
ftw
는 directory tree walk
, 즉 directory tree를 따라 반복적으로 모든 entry에 대해 func
을 수행하는 함수이다. func
의 형태는 정해져있다.
argument
- const char *path : 시작할 directory pathname
- int(*func)() : 실행할 함수
- int nopenfd : depth와 동일한 의미로, 동시에 열 directory의 개수를 의미 (1이어도 상관 없음)
종료되는 조건
- Bottom에 도달하거나, error이 발생한 경우
func
이 0이 아닌 값을 return한 경우
function
- const char *name : object 이름
- const struct stat *sptr : 해당 object에 대한
stat
- int type :
<ftw.h>
에 정의되어있음. 해당 파일의 type을 나타냄
- FTW_F : object가 file임
- FTW_D : object가 directory임
- FTW_DNR : object가 읽을 수 없는 directory임
- FTW_SL : object가 symbolic link임
- FTW_NS : object가 symbolic link가 아니지만stat
를 성공적으로 실행할 수 없음
이에 대한 예시 코드는 아래와 같다.
#include <sys/stat.h>
#include <ftw.h>
int list(const char *name, const struct stat *status, int type) {
if (type == FTW_NS)
return 0;
if(type == FTW_F)
printf("%-30s\t0%3o\n", name, status->st_mode&0777);
else
printf("%-30s*\t0%3o\n", name, status->st_mode&0777);
return 0;
}
int main (int argc, char **argv) {
int list(const char *, const struct stat *, int);
if (argc == 1)
ftw (".", list, 1);
else
ftw (argv[1], list, 1);
return 0;
}
file이면 그냥, 아닐 경우에는 *
를 붙여서 출력하며, ls -r
과 유사한 역할을 한다.