파일 정보 다루기
inode
: 파일에 대한 정보를 저장하는 구조체

파일의 상태 정보
: i-node에 저장된 파일의 상태 정보 가져오기
- 심볼릭 링크의 경우 stat()은 링크가 가리키는 파일에 대한 정보를, lstat()은 링크 자체에 대한 정보를 가져옴
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char* pathname, struct stat* buf);
int fstat(int fd, struct stat* buf);
int lstat(const char* pathname, struct stat* buf);
// 파일의 상태 정보를 가져와서 buf에 저장
// 성공하면 0, 실패하면 -1을 저장
stat 구조체
struct stat {
dev_t st_dev; // 파일이 저장된 장치의 번호
ino_t st_ino; // i-node 번호
mode_t st_mode; // 파일 종류와 접근권한
nlink_t st_nlink; // 하드 링크 수
uid_t st_uid; // 소유자의 UID
gid_t st_gid; // 소유 그룹의 GID
dev_t st_rdiv; // 특수 파일 장치 번호
off_t st_size; // 파일 크기
long st_blksize; // 입출력 시 블럭 크기
long st_blocks; // 파일에 할당된 블럭 수
struct timespec st_atim; // 최종 내용 접근 시간
struct timespec st_mtim; // 최종 내용 수정 시간
struct timespec st_ctim; // 최종 상태 변경 시간
st_mode의 비트 구조

기호 상수를 이용한 파일의 종류 검색
: sys/stat.h


파일의 종류 판별 매크로

파일 접근 권한 확인
- 파일 접근 권한 검색 기호 상수(sys/stat.h)
- S_IREAD : 00400
- S_IWRITE : 00200
- S_IEXEC : 00100
- 기본적인 확인 방법
- st_mode & S_IREAD : 소유자의 읽기 권한
- st_mode & (S_IREAD >> 3) : 소유자의 읽기 권한
- st_mode & (S_IREAD >> 6) : 기타 사용자의 읽기 권한
파일 접근 권한 검색 상수

접근권한 검색
: 파일의 존재 여부나 접근 권한 확인
- mode :
F_OK,R_OK,W_OK,X_OK - errno 코드값
ENOENT: 존재하지 않거나 깨진 심벌릭 링크EACCESS: 접근 권한이 없는 경우
#include <unistd.h>
int access(const char* pathname, int mode);
// 권한이 있으면 0, 없으면 -1을 반환
파일 접근 권한의 변경
: 대상 파일의 접근 권한을 변경
- mode: 8진수 접근권한 (e. 0644)
- 성공하면 0, 실패하면 -1 반환
#include <sys/stat.h>
#include <sys/types.h>
int chmod(const char* pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
파일 소유자 변경
: 대상 파일의 소유자와 그룹 소유자를 변경
- 파일 소유자: super-user만 변경 가능
- 소유 그룹: 소유자가 자신이 속한 그룹으로 변경 가능
#include <sys/types.h>
#include <unistd.h>
int chown(const char* path, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char* path, uid_t owner, gid_t group); // 심볼릭 링크 자체를 변경
// 성공하면 0, 실패하면 -1 반환
링크의 생성과 삭제
하드 링크
: 기존 파일에 대한 새로운 이름(링크) 생성/삭제
#include <unistd.h>
int link(char* existing, char* new);
ink unlink(char* path);

실습(하드링크): myln.c, unlink.c
myln.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) // ./myln src new_file
{
if (argc < 3) {
fprintf(stderr, "usage: %s <target> <lnk_name>\n", argv[0]);
exit(1);
}
if (link(argv[1], argv[2]) == -1) { /* 하드링크 생성 */
perror(argv[0]);
exit(2);
}
return 0;
}
unlink.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) // ./unlink target
{
if (argc < 2) {
fprintf(stderr, "usage: %s <target>\n", argv[0]);
exit(1);
}
if (unlink(argv[1]) == -1) { /* 링크해제 */
perror(argv[1]);
exit(2);
}
return 0;
}
심볼릭 링크
- 심볼릭 링크의 생성
int symlink(const char* actualpath, const char* sympath);
// 성공하면 0, 실패하면 -1 반환
- 심볼릭 링크의 내용
#include <unistd.h>
int readlink(const char* path, char* buf, size_t bufsize);
// path 심볼릭 링크의 실제 내용을 읽어서 buf에 저장
// 성공하면 buf에 저장한 바이트 수를 반환, 실패하면 -1 반환
실습(심볼릭 링크) : myln_s.c
myln_s.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
if (argc < 3) {
fprintf(stderr, "usage: %s <target> <lnk_name>\n", argv[0]);
exit(1);
}
if (symlink(argv[1], argv[2])) == -1) { /* 심볼릭링크 생성 */
perror(argv[0]);
exit(2);
}
return 0;
}
rlink.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) // ./rlink /bin
{
if (argc < 2) {
fprintf(stderr, "usage: %s <symbolic_link_name>\n", argv[0]);
exit(1);
}
char buf[BUFSIZ + 1];
int nread = readlink(argv[1], buf, BUFSIZ); /* 심벌릭링크 파일의 내용 읽어오기 */
if (nread == -1) {
perror(argv[0]);
exit(2);
}
buf[nread] = '\0';
printf("%s -> %s\n", argv[1], buf);
return 0;
}
디렉터리 다루기
디렉터리 생성
: 새 디렉터리를 생성, .과 ..은 자동으로 만들어짐
- mode: 접근 권한. 8진수나 mode_t에서 선언된 기호 상수 사용
#inlcude <sys/stat.h>
#include <sys/types.h> // mode_t
int mkdir(const char* pathname, mode_t mode);
// 성공하면 0, 실패하면 -1을 반환
실습-디렉터리 생성: mymkdir.c
mymkdir.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#define PERMS 0755
int main(int argc, char* argv[])
{
if (argc < 2) {
fprintf(stderr, "usage: %s <directory>\n", argv[0]);
exit(1);
}
if (mkdir(argv[1], PERMS) == -1) { /* 디렉터리 생성 */
perror(argv[1]);
exit(2);
}
exit(0);
}
디렉터리 삭제
: 대상 디렉터리가 비어있으면 삭제
#include <unistd.h>
int rmdir(const char* pathname);
// 성공하면 0, 실패하면 -1 반환
실습-디렉터리 삭제: myrmdir.c
myrmdir.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
if (argc < 2) {
fprintf(stderr, "usage: %s <directory>\n", argv[0]);
exit(1);
}
if (rmdir(argv[1]) == -1) { /* 대상경로의 빈 디렉터리 삭제 */
perror(argv[1]);
exit(2);
}
exit(0);
}
현재 작업 디렉토리 확인
: 현재 작업 디렉토리의 절대 경로 반환
- buf: 경로를 저장할 문자 배열의 시작 주소. null이 전달되면 동적할당된 배열 반환
- size: 경로를 저장할 배열의 크기. buf == NULL && size = 0이면 자동으로 필요 크기 결정
#include <unistd.h>
char* getcwd(char* buf, size_t size);
// 성공하면 절대경로 문자열, 실패하면 NULL 반환
실습-pwd 확인: mypwd.c
mypwd.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
char* cwd;
char buf1[BUFSIZ]; // 표준 입출력에서 사용하는 버퍼의 크기
char buf2[10];
printf("BUFSIZ=%d\n", BUFSIZ); // 버퍼 크기 확인위한 출력
cwd = getcwd(buf1, BUFSIZ); /* buf1에 현재 작업 경로 얻기 */
printf("#1: [%s]\n", buf1);
printf("#1: [%s]\n", cwd);
cwd = getcwd(NULL, BUFSIZ); /* BUFSIZ 크기의 배열 동적할당하여 현재 작업 경로 저장후 반환 */
printf("#2: [%s]\n", cwd);
free(cwd);
cwd = getcwd(NULL, 0)/* 현재 작업 경로를 저장한 메모리를 동적할당하여 반환 */
printf("#3: [%s]\n", cwd);
free(cwd); /* free 하는 거 중요함!! */
cwd = getcwd(buf2, 10); /* 오류 상황 발생 (Out of range)*/
if (cwd == NULL) {
perror("mypwd");
exit(1);
}
printf("#4: [%s]\n", cwd);
return 0;
}
파일/디렉터리 이름 변경
: 대상 파일이나 디렉터리의 이름/위치를 변경. oldpath의 파일의 경로명을 newpath로 변경
#include <stdio.h>
int rename(const char* oldpath, const char* newpath);
// 성공하면 0, 실패하면 -1 반환
실습-파일/디렉토리 이름 변경: mymv.c
mymv.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
if (argc != 3) {
fprintf(stderr, "usage: %s <oldpath> <newpath>\n", argv[0]);
exit(1);
}
int rval = rename(argv[1], argv[2]); /* 이름 변경하기 */
if (rval == -1) {
perror(argv[0]);
exit(2);
}
return 0;
}
작업 디렉토리의 이동
: 현재 프로세스의 작업 디렉토리를 변경. 절대경로와 상대경로 모두 가능
- fd: 변경할 디렉터리에 대한 파일 디스크립터. open()으로부터 얻은 값
#include <unistd.h>
int chdir(const char* path);
실습-작업디렉토리 이동: mycd.c
mycd.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <pathname>\n", argv[0]);
exit(1);
}
char* cwd;
cwd = getcwd(NULL, 0);
printf("[%s]\n", cwd);
free(cwd);
/* 대상 디렉터리로 작업경로 변경 */
chdir(argv[1]);
cwd = getcwd(NULL, 0); /* 작업 경로 잘 바뀌었는지 확인*/
printf("[%s]\n", cwd);
free(cwd);
return 0;
}
mycd2.c
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <pathname>\n", argv[0]);
exit(1);
}
char* cwd;
cwd = getcwd(NULL, 0);
printf("[%s]\n", cwd);
free(cwd);
int fd = open(argv[1], O_RDONLY);
fchdir(fd); /* 대상 디렉터리로 작업경로 변경 */
cwd = getcwd(NULL, 0);
printf("[%s]\n", cwd);
free(cwd);
return 0;
}
디렉터리의 내용 접근
: 디렉터리 접근을 위해 편리한 함수 별도 제공
#include <sys/types.h>
#include <dirent.h>
struct DIR* opendir(const char* path);
// path 디렉터리를 열고 성공하면 DIR 구조체 포인터 반환
// 실패하면 NULL 반환
struct dirent* readdir(DIR* dp);
// 한 번에 디렉터리 엔트리를 하나씩 읽어서 반환
int closedir(DIR* dp);
// 성공하면 0, 실패하면 -1 반환
디렉터리 엔트리
: 디렉터리 내에 포함된 하나의 파일에 대한 정보 (node 번호 (e. d_ino), 파일 이름 (e. d_name))
#include <dirent.h>
struct dirent {
ino_t d_ino;
// ...
unsigned char d_type;
char d_name[NAME_MAX + 1];
};

실습-디렉토리 엔트리: myls_i.c
myls_i.c
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) // ./myls_i /home
{
char* dir;
if (argc == 1)
dir = ".";
else
dir = argv[1];
DIR* dp = opendir(dir); /* 디렉터리 열기 */
if (dp == NULL) {
perror(dir);
exit(1);
}
struct dirent* dent;
while ((dent = readdir(dp)) != NULL) { /* 디렉터리 엔트리 읽어들이기 */
printf("%d %s\n", (int) dent->d_ino, dent->d_name);
}
/* 디렉터리 닫기 */
closedir(dp);
return 0;
}