Chapter.3: Directories and File Properties : Looking through ls
ls의 Main logic
opendir
while(readdir)
print d_name
closedir
ls -l
파일에 대한 상세정보를 보여준다.
상세정보는 stat()이라는 system call을 통해 얻어올 수 있다.
Masking
st_mode: 파일 타입과 권한을 의미하는 16-bit.
- masking
- st_mode를 위 그림의 mode처럼 rwx 형태로 나타내기 위해서
- &연산으로 st_mode의 파일타입과 권한을 각각 decode한다.
ls -l 구현
- main 함수:
- 프로그램의 진입점입니다. 사용자로부터 명령행 인수를 받고 주어진 디렉터리 또는 파일에 따라 다른 함수를 호출합니다.
- do_ls 함수:
- 주어진 디렉터리 내의 파일과 디렉터리를 나열합니다.
- opendir 함수로 디렉터리를 열고 readdir 함수로 디렉터리 내의 항목들을 읽어옵니다.
- do_ls_al 함수:
- 주어진 파일에 대한 상세 정보를 표시합니다.
- stat 함수를 사용하여 파일의 상태 정보를 얻어옵니다.
- do_ls_alR 함수:
- 주어진 디렉터리 내의 파일과 디렉터리를 재귀적으로 나열하고 상세 정보를 표시합니다.
- do_ls_al 함수와 유사하지만 재귀적으로 하위 디렉터리를 처리합니다.
- dostat 함수:
- stat 함수를 사용하여 파일 또는 디렉터리의 상태 정보를 얻고, 그 정보를 show_file_info 함수에 전달합니다.
- show_file_info 함수:
- 파일 또는 디렉터리의 상세 정보를 표시합니다. 이 정보에는 파일 유형, 권한, 링크 수, 소유자, 그룹, 파일 크기 및 수정 시간이 포함됩니다.
- mode_to_letters 함수:
- 파일 권한 모드를 문자열로 변환합니다. 예를 들어, "drwxr-xr-x"와 같이 표현된 파일 권한을 생성합니다.
- uid_to_name 및 gid_to_name 함수:
- 사용자 ID (UID) 및 그룹 ID (GID)를 사용자 이름과 그룹 이름으로 변환하는 함수입니다.
- print_curDIR 함수:
- 현재 디렉터리 내의 파일 크기 합계를 계산하고 블록 단위로 출력합니다. 이 함수는 디렉터리의 내용을 보기 전에 디렉터리의 크기를 표시합니다.
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
void dostat(char path[], char *filename);
void show_file_info(char *filename, struct stat *info_p);
void mode_to_letters(int mode, char str[]);
char *uid_to_name(uid_t uid);
char *gid_to_name(gid_t gid);
void print_curDIR(char dirname[]);
void do_ls(char dirname[]);
void do_ls_al(char *filename);
void do_ls_alR(char dirname[]);
int main(int argc, char* argv[]) {
if (argc == 1) { // 명령어만 입력한 경우
do_ls("."); // 현재 디렉터리의 항목들을 나열함
}
else {
struct stat info;
for (int i=1; i<argc; i++) {
if(stat(argv[i], &info) == 0){
if(S_ISDIR(info.st_mode)){ // 디렉터리명이 주어지면 -alR
do_ls_alR(argv[i]);
}
else if(S_ISREG(info.st_mode)){ // 파일명이 주어지면 -al
do_ls_al(argv[i]);
}
}
}
}
return 0;
}
void do_ls(char dirname[]) {
DIR *dir_ptr;
struct dirent *direntp;
if ((dir_ptr = opendir(dirname)) == NULL) {
fprintf(stderr, "lsl: cannot open %s\n", dirname);
return;
}
while((direntp = readdir(dir_ptr)) != NULL)
printf("%s\n", direntp->d_name);
closedir(dir_ptr);
}
void do_ls_al(char *filename) {
struct stat info;
if (stat(filename, &info) == -1)
perror(filename);
else {
show_file_info(filename, &info);
}
}
void do_ls_alR(char dirname[]) {
//주어진 디렉터리 내의 파일 및 디렉터리를 나열하고 출력하는 함수
DIR *dir_ptr;
struct dirent *direntp;
//opendir: 디렉터리 열기, 실패하면 오류메시지 출력
if ((dir_ptr = opendir(dirname)) == NULL) {
fprintf(stderr, "lsl: cannot open %s\n", dirname);
return;
}
// 주어진 디렉터리명과 항목들의 총 크기를 출력함
print_curDIR(dirname);
// 다음 탐색을 위해 하위 디렉터리를 저장할 배열
char* nextdirs[1024];
int dir_cnt = 0;
// readdir: 디렉터리 내의 항목 읽기
while ((direntp = readdir(dir_ptr)) != NULL) {
char fullpath[1024]; // 파일 및 디렉터리의 전체 경로
snprintf(fullpath, sizeof(fullpath), "%s/%s", dirname, direntp->d_name);
// 현재 디렉터리 또는 상위 디렉터리인 경우
if (strcmp(direntp->d_name, ".") == 0 || strcmp(direntp->d_name, "..") == 0) {
dostat(dirname, direntp->d_name);
}
// 하위 디렉터리거나 파일인 경우
else if (strcmp(direntp->d_name, ".") != 0 && strcmp(direntp->d_name, "..") != 0) {
if (direntp->d_type == DT_DIR) {
// 하위 디렉터리인 경우
nextdirs[dir_cnt] = strdup(fullpath); // 다음 탐색을 위해 저장
dostat(fullpath, direntp->d_name);
dir_cnt++;
}
else { //파일인 경우
dostat(fullpath, direntp->d_name);
}
}
}
printf("\n");
closedir(dir_ptr); // 디렉터리 닫기
// 하위 디렉터리 탐색
for (int i = 0; i < dir_cnt; i++) {
do_ls_alR(nextdirs[i]);
}
}
void dostat(char path[], char *filename) {
//stat()이 파일 정보를 가져와서 info구조체에 저장하는 함수
struct stat info;
if (stat(path, &info) == -1)
perror(filename);
else {
show_file_info(filename, &info);
}
}
void show_file_info(char *filename, struct stat *info_p) {
//파일 또는 디렉터리의 상세 정보 출력하는 함수
char *uid_to_name(), *ctime(), *gid_to_name(), *filemode();
void mode_to_letters();
char modestr[11];
mode_to_letters(info_p->st_mode, modestr);
printf("%s", modestr);
printf("%4d ", (int) info_p->st_nlink);
printf("%-8s ", uid_to_name(info_p->st_uid));
printf("%-8s ", gid_to_name(info_p->st_gid));
printf("%8ld ", (long) info_p->st_size);
printf("%.12s ", 4+ctime(&info_p->st_mtime));
printf("%s\n", filename);
}
void mode_to_letters(int mode, char str[]) {
//st_mode 값을 문자열로 변환하는 함수
strcpy(str, "----------");
if (S_ISDIR(mode)) str[0] = 'd';
if (S_ISCHR(mode)) str[0] = 'c';
if (S_ISBLK(mode)) str[0] = 'b';
if (mode & S_IRUSR) str[1] = 'r';
if (mode & S_IWUSR) str[2] = 'w';
if (mode & S_IXUSR) str[3] = 'x';
if (mode & S_IRGRP) str[4] = 'r';
if (mode & S_IWGRP) str[5] = 'w';
if (mode & S_IXGRP) str[6] = 'x';
if (mode & S_IROTH) str[7] = 'r';
if (mode & S_IWOTH) str[8] = 'w';
if (mode & S_IXOTH) str[9] = 'x';
}
char *uid_to_name(uid_t uid) {
// getpwuid 함수를 사용하여 uid를 사용자 이름으로 변환하는 함수
struct passwd *getpwuid(), *pw_ptr;
static char numstr[10];
if((pw_ptr = getpwuid(uid)) == NULL) {
sprintf(numstr, "%d", uid);
return numstr;
}
else
return pw_ptr->pw_name;
}
char *gid_to_name(gid_t gid) {
// getgrgid 함수를 사용하여 gid를 그룹 이름으로 변환하는 함수
struct group *getgrgid(), *grp_ptr;
static char numstr[10];
if((grp_ptr = getgrgid(gid)) == NULL) {
sprintf(numstr, "%d", gid);
return numstr;
}
else
return grp_ptr->gr_name;
}
void print_curDIR(char dirname[]) {
// 디렉터리 내의 파일 크기 합계를 계산하여 블록 단위로 출력하는 함수
DIR *dir_ptr;
struct dirent *direntp;
long long total_blocks = 0;
if ((dir_ptr = opendir(dirname)) == NULL) {
fprintf(stderr, "lsl: cannot open %s\n", dirname);
return;
}
while ((direntp = readdir(dir_ptr)) != NULL) {
char subpath[1024];
snprintf(subpath, sizeof(subpath), "%s/%s", dirname, direntp->d_name);
struct stat info;
if (stat(subpath, &info) != -1) {
// st_blocks: 파일의 크기
total_blocks += info.st_blocks;
}
}
printf("%s:\n", dirname);
printf("합계 %lld\n", total_blocks / 2);
closedir(dir_ptr);
}
'C' 카테고리의 다른 글
[시스템프로그래밍] ch.4 pwd 복습 (0) | 2023.10.26 |
---|---|
[시스템프로그래밍] File Handling, Files in multi-user environment (0) | 2023.10.13 |