리눅스에서는 파일을 일반 파일과 특수 파일, 디렉터리 세 가지로 구분한다
디렉터리는 해당 디렉터리에 속한 파일을 관리하는 특별한 파일이다
1. 일반 파일(-): 우리가 흔히 아는 데이터를 저장하는 파일
e.g. 텍스트 파일, 실행 파일, 프로그램 파일, 라이브러리, 이미지 파일 등과 같은 사용자가 읽거나 수정할 수 있는 파일들
2. 특수 파일: 하드웨어 장치나 프로세스와의 인터페이스를 제공하는 파일 (운영체제와 하드웨어 간의 인터페이스 역할)
하드웨어 장치(예: 키보드, 마우스, 디스크)와 상호작용할 수 있도록 시스템 자원에 대한 접근을 제공한다
리눅스에서는 주로 /dev 디렉터리에서 특수 파일들을 확인할 수 있다
- 블록 특수 파일(b): 디스크와 같은 장치에서 데이터를 블록 단위로 처리
- 문자 특수 파일(c): 키보드, 터미널 등에서 데이터를 문자 단위(바이트 단위)로 처리
- 심볼릭 링크, 소프트 링크(l): 특정 파일이나 디렉터리의 위치를 참조하는 특수 파일(파일 시스템 내에서 다른 파일의 경로를 가리키는 역할)
3. 디렉터리(d): 리눅스에서는 우리가 흔히 아는 폴더를 하나의 파일로 간주
디렉터리와 연관된 데이터 블록은 해당 디렉터리에 속한 파일의 목록과 inode를 저장한다
최상위 디렉터리는 루트 디렉터리(/) 이다
ㅇ파일의 종류 구분 방법: ls -l
(데이터 블록: 실제로 데이터가 저장되는 HDD 공간)
ㅇ inode(index node): 파일 시스템에서 파일과 디렉터리의 메타데이터가 저장되는 곳 (파일의 소유자나 크기 등의 정보와 실제 데이터를 저장하고 있는 데이터 블록의 위치를 나타내는 주소들이 저장)
리눅스 커널의 입장에서는 파일의 정보를 관리하는 자료구조로 사용된다
파일의 inode 번호는 ls -i 명령으로 알 수 있다
(리눅스 디렉터리 함수)
[리눅스 디렉터리 생성/삭제 함수]
ㅇ int mkdir(const char* pathname, mode_t mode): 디렉터리 생성
- pathname : 디렉터리가 포함된 경로
- mode : 접근 권한
mkdir() 함수는 성공하면 0, 실패하면 -1을 반환
#include <stdio.h> // perror() 함수
#include <stdlib.h> // exit() 함수
#include <sys/stat.h>
int main() {
// ha 라는 이름의 디렉터리를 생성하고 권한을 0755로 설정
if (mkdir("ha", 0755) == -1) {
perror("ha"); // 에러 메시지 출력
exit(1); // 0이 아닌 값은 에러를 의미
}
return 0;
}
ㅇ int rmdir(const char* pathname): 디렉터리 삭제
- pathname : 디렉터리가 포함된 경로
똑같이 성공하면 0, 실패하면 -1을 반환
#include <stdio.h>
#include <stdlib.h> // exit() 함수
#include <unistd.h>
int main() {
// ha 라는 이름의 디렉터리를 제거
if (rmdir("ha") == -1) {
perror("ha"); // 에러 메시지 출력
exit(1); // 0이 아닌 값은 에러를 의미
}
return 0;
}
[디렉터리 관리 함수]
ㅇ char* getcwd(char* buf, size_t size): 현재 위치 확인 (cwd: current working directory)
- buf : 현재 디렉터리의 절대 경로를 저장할 버퍼 주소
- size : 버퍼의 크기
getcwd() 함수는 경로를 저장할 버퍼의 주소와 버퍼의 크기를 인자로 받고 현재 디렉터리 값을 반환한다
[인자를 지정하는 방법]
① buf에 경로를 저장할 만큼 충분한 메모리를 할당하고, 그 크기를 size에 지정
② buf에 NULL을 지정하고 할당이 필요한 메모리 크기를 size에 지정
③ buf에 NULL을 지정하고 size는 0으로 지정
#include <stdio.h>
#include <stdlib.h> // exit() 함수
#include <unistd.h> // getcwd() 함수
// BUFSIZ 값은 stdio.h 파일에 8192(8KB)로 정의
int main() {
char* cwd; // 현재 작업 디렉터리(current working directory)
char wd1[BUFSIZ]; // 경로 저장 배열1
char wd2[10]; // 경로 저장 배열2
// 현재 작업 디렉터리 경로를 wd1에 저장
getcwd(wd1, BUFSIZ); // BUFSIZ 크기만큼 버퍼에 경로를 저장
printf("wd1 = %s\n", wd1); // 경로를 출력
// getcwd 함수에서 동적 메모리 할당하여 현재 작업 디렉터리 경로를 얻음
cwd = getcwd(NULL, BUFSIZ); // BUFSIZ 크기의 메모리를 자동으로 할당하여 경로를 얻음
printf("cwd1 = %s\n", cwd); // 얻은 경로 출력
free(cwd);
// getcwd 함수에서 메모리 크기를 0으로 설정하면 적절한 크기의 메모리를 자동 할당
cwd = getcwd(NULL, 0); // 0을 인자로 주면, 자동으로 메모리를 할당하여 경로를 반환
printf("cwd2 = %s\n", cwd); // 얻은 경로 출력
free(cwd);
// 크기가 10인 배열 wd2에 경로를 저장하려고 하므로, 오류가 발생할 가능성이 있음
if (getcwd(wd2, 10) == NULL) {
perror("getcwd"); // 에러 메시지 출력
exit(1); // 0이 아닌 값은 에러를 의미
}
return 0;
}
// 실행 결과: 경로를 정상적으로 출력하다가, 맨 마지막에 에러 메시지를 출력
// 에러 메시지는 결과가 메모리 범위를 벗어났다는 뜻
ㅇ char* get_current_dir_name(void): 현재 위치 확인
현재 디렉터리의 절대 경로를 반환
시스템이 메모리를 자동으로 할당해 경로를 저장하고 반환한다
#define _GNU_SOURCE // GNU 확장 함수들을 사용하기 위한 매크로 정의
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // get_current_dir_name() 함수
int main() {
char* cwd; // 현재 작업 디렉터리(current working directory)
// 현재 작업 디렉터리의 경로를 얻고, 그 경로에 대한 동적 메모리 할당
cwd = get_current_dir_name(); // 경로를 검색
printf("cwd = %s\n", cwd); // 경로를 출력
free(cwd);
return 0;
}
ㅇ int rename(const char* oldpath, const char* newpath): 디렉터리명 변경
- oldpath : 변경할 파일/디렉터리명
- newpath : 새 파일/디렉터리명
성공하면 0, 실패하면 -1을 반환
만약 두 번째 인자로 지정한 이름이 이미 있으면 해당 디렉터리를 삭제한다
실행 도중 오류가 발생하면 원본과 새로운 디렉터리명이 모두 남는다
+ rename() 함수는 파일명을 변경하는 데도 사용할 수가 있다
(rename() 함수의 매뉴얼을 보려면 man -s 2 rename을 이용하자)
#include <stdio.h> // rename() 함수
#include <stdlib.h> // exit() 함수
int main() {
// "ha" -> "dong" 디렉터리명 변경
if (rename("ha", "dong") == -1) {
perror("rename"); // 에러 메시지 출력
exit(1); // 비정상 종료를 의미
}
return 0;
}
ㅇ int chdir(const char* path): 디렉터리 이동 (change directory)
- path : 이동하려는 디렉터리 경로
성공하면 0, 실패하면 -1을 반환
(절대 경로와 상대 경로 모두 사용 가능)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // getcwd() 함수, chdir() 함수
int main() {
char* cwd; // 현재 작업 디렉터리(current working directory)
cwd = getcwd(NULL, BUFSIZ);
printf("1.Current Directory: %s\n", cwd);
chdir("dong"); // "dong" 디렉터리로 이동
cwd = getcwd(NULL, BUFSIZ);
printf("2.Current Directory: %s\n", cwd);
free(cwd);
return 0;
}
// 실행 결과: 디렉터리가 이동, 하지만 디렉터리 이동은 프로그램 내부에서만 진행된다
// 따라서 프로그램 종료 후, pwd 명령으로 보면 현재 디렉터리가 바뀐 것은 아님을 알 수 있음
ㅇ int fchdir(int fd): 디렉터리 이동
- fd : 이동하려는 디렉터리의 파일 디스크립터
※ 파일 디스크립터: open() 함수로 디렉터리를 열고 돌려받는 것, 따라서 fchdir() 함수를 사용하려면 open() 함수로 해당 디렉터리를 먼저 열어야 한다
성공하면 0, 실패하면 -1을 반환
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // getcwd() 함수, fchdir() 함수, close() 함수
#include <fcntl.h> // O_RDONLY: 읽기 전용으로 파일을 열기 위한 flag
int main() {
char* cwd; // 현재 작업 디렉터리(current working directory)
int fd;
cwd = getcwd(NULL, BUFSIZ);
printf("1.Current Directory: %s\n", cwd);
fd = open("dong", O_RDONLY); // open 함수로 dong 디렉터리를 실행
fchdir(fd); // fchdir 함수로 디렉터리를 이동
cwd = getcwd(NULL, BUFSIZ);
printf("2.Current Directory: %s\n", cwd);
close(fd);
free(cwd);
return 0;
}
// 실행 결과: 디렉터리가 이동, 하지만 디렉터리 이동은 프로그램 내부에서만 진행된다
// 따라서 pwd 명령으로 확인하면 프로그램 내부에서만(프로그램 실행 동안만) 디렉터리가 바뀐 것을 알 수 있다
[디렉터리 읽기 함수] (dirent: directory entry)
ㅇ DIR* opendir(const char* name): 디렉터리 열기
#include <sys/types.h>
#include <dirent.h>
ㅇ int closedir(DIR* dirp): 디렉터리 닫기
#include <sys/types.h>
#include <dirent.h>
ㅇ struct dirent* readdir(DIR* dirp): 디렉터리 내용 읽기
#include <dirent.h>
ㅇ long telldir(DIR* dirp), void seekdir(DIR* dirp, long loc), void rewinddir(DIR* dirp): 디렉터리의 내용을 읽는 위치 변경하기 (디렉터리 오프셋)
#include <sys/types.h>
#include <dirent.h>
참고 및 출처: 시스템 프로그래밍 리눅스&유닉스(이종원)
'Computer Science > UNIX & Linux' 카테고리의 다른 글
[UNIX/Linux] ep2+) 파일 함수 실습 (1) | 2024.09.26 |
---|---|
[UNIX/Linux] ep2) 파일 다루기 (0) | 2024.09.24 |
[UNIX/Linux] ep1+) 디렉터리 함수 실습 (1) | 2024.09.20 |
오픈소스 터미널 에뮬레이터(PuTTY, Termius, MobaXterm) (3) | 2024.09.04 |
[UNIX/Linux] ep0) 시스템 프로그래밍의 이해 (2) | 2024.09.04 |