ls

윤강훈·2024년 10월 12일

System Programming

목록 보기
4/12

ls

  • 디렉토리, 파일 유형 및 다양한 파일 속성을 확인
  • -l example
ExampleAction
-llong format
/tmp/tmp 디렉토리 내부의 파일들의 목록 출력
-l docs현재 작업 디렉토리 하위에 있는 docs 디렉토리에 있는 파일들의 속성 출력
-l ../Makefile현재 작업 디렉토리의 상위 디렉토리에 있는 Makefile의 속성 출력
*.c파일 확장자가 'c'로 끝나는 파일들의 목록 출력
  • options
CommandAction
-a".", "..", 및 파일 목록(숨겨진 파일) 모두 출력
-lu파일 목록 및 마지막으로 읽은 시간 출력
-s파일에 할당된 크기를 블록 단위로 출력
-t파일 생성 시간 순서로 정렬 후 출력(newest first)
-F파일의 타입 출력 (ll = 'ls -alF')

directory

  1. opendir
#include <dirent.h>

DIR *opendir(char *)
	creates a connection,
    returns a DIR * (first entry)
  1. readdir
#include <dirent.h>

struct dirent *readdir(DIR *)
	reads next records,
    returns a pointer to a struct dirent
    returns NULL (end of directory)
  1. closedir
#include <dirent.h>

int closedir(DIR *)
	close a connection

stat

  • 특정 파일에 대한 정보를 가져옴
  • usage: stat(char fname, struct stat buf)
struct stat {
  dev_t st_dev; /* ID of device containing file */
  ino_t st_ino; /* inode number */
  mode_t st_mode; /* type and permission */
  nlink_t st_nlink; /* number of hard links */
  uid_t st_uid; /* user ID of owner */
  gid_t st_gid; /* group ID of owner */
  dev_t st_rdev; /* device ID (if special file) */
  off_t st_size; /* total size, in byte */
  blksize_t st_blksize; /* blocksize for file system I/O */
  blkcnt_t st_blocks; /* number of 512B blocks allocated */
  time_t st_atime; /* time of last access */
  time_t st_mtime; /* time of last modification */
  time_t st_xtime; /* time of last status change */
};

show stat info

  • code
#include <stdio.h>
#include <sys/stat.h>
void show_stat_info(char *fname, struct stat *buf)
{
  printf(" mode: %o\n", buf->st_mode);
  printf(" mode: 0x%x\n", buf->st_mode);
  printf(" links: %ld\n", buf->st_nlink);
  printf(" user: %d\n", buf->st_uid);
  printf(" group: %d\n", buf->st_gid);
  printf(" size: %ld\n", buf->st_size);
  printf(" modtime: %ld\n", buf->st_mtime);
  printf(" name: %s\n", fname);
}

int main(int ac, char *av[]){
	struct stat buf;
    if (ac > 1){
    	if (stat(av[1], &buf) != -1)
  			show_stat_info(av[1], &buf);
  	}
  	else
  		return -1;
    return 0;
}
  • result
$ gcc fileinfo.c -o fileinfo
$ ./fileinfo fileinfo.c
mode: 100666
mode: 0x81b6
links: 1
user: 1001
group: 1001
size: 791
modtime: 1726020963
name: fileinfo.c

st_mode

/etc/passwd

  • 사용자들의 목록을 저장
  • stat에는 사용자 정보가 int로 저장, 사용자 이름을 사용하기 위해서는 passwd->pw_name에서 사용

getpwuid

  • uid에 해당하는 사용자의 상세 정보를 얻음
struct passwd *getpwuid(uid_t uid); // function prototype
struct passwd
{
  char *pw_name; /* Username. */
  char *pw_passwd; /* Hashed passphrase, if shadow database not in use (see shadow.h). */

  __uid_t pw_uid; /* User ID. (unsigned int) */
  __gid_t pw_gid; /* Group ID. (unsigned int) */
  char *pw_gecos; /* Real name. */
  char *pw_dir; /* Home directory. */
  char *pw_shell; /* Shell program. */
};

/etc/group

  • 그룹 목록을 저장
  • 사용자는 하나 이상의 그룹에 속할 수 있음
  • 그룹도 마찬가지로 stat에 int로 저장

getgrgid

  • 그룹의 상세 정보를 확인
#include <pwd.h>
struct group *getgrgid(gid_t gid); // function prototype

struct group
{
  char *gr_name; /* Group name. */
  char *gr_passwd; /* Password. */
  __gid_t gr_gid; /* Group ID. */
  char **gr_mem; /* Member list. */
};

code

#include <stdio.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <ctype.h>
#include <sys/types.h>

void do_ls(char[]);
void do_stat(char *);
void mode_to_letters(mode_t mode, char mode_str[]);
char *uid_to_name(uid_t);
char *gid_to_name(gid_t);
void show_file_info(char *, struct stat *);

int main(int ac, char *av[]){
    if (ac == 1){
        do_ls(".");
    }
    else{
        while (--ac){
            printf("%s: \n", *++av);
            do_ls(*av);
        }
    }
    return 0;
}

void do_ls(char dirname[]){
    DIR *dir_ptr = NULL;
    struct dirent *dirent_ptr = NULL;

    if ((dir_ptr = opendir(dirname)) == NULL){
        fprintf(stderr, "ls2: cannot open %s\n", dirname);
    }
    else{
        while((dirent_ptr = readdir(dir_ptr)) != NULL){
            do_stat(dirent_ptr->d_name);
        }
    }
    closedir(dir_ptr);
}

void do_stat(char *filename){
    struct stat buf;
    if (stat(filename, &buf) == -1){
        perror(filename);
    }
    else{
        show_file_info(filename, &buf);
    }
}

void show_file_info(char *filename, struct stat *info_p){
    char mode[10];
    mode_to_letters(info_p->st_mode, mode);
    printf("%s", mode);
    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(mode_t mode, char mode_str[]){
    strcpy(mode_str,"----------"); // default = no permission
    // file type
    if (S_ISDIR(mode)) mode_str[0] = 'd';
    if (S_ISCHR(mode)) mode_str[0] = 'c';
    if (S_ISBLK(mode)) mode_str[0] = 'b';
    // permission
    if (mode & S_IRUSR) mode_str[1] = 'r';
    if (mode & S_IWUSR) mode_str[2] = 'w';
    if (mode & S_IXUSR) mode_str[3] = 'x';
    if (mode & S_IRGRP) mode_str[4] = 'r';
    if (mode & S_IWGRP) mode_str[5] = 'w';
    if (mode & S_IXGRP) mode_str[6] = 'x';
    if (mode & S_IROTH) mode_str[7] = 'r';
    if (mode & S_IWOTH) mode_str[8] = 'w';
    if (mode & S_IXOTH) mode_str[9] = 'x';
}

char *uid_to_name(uid_t uid){
    struct passwd *pw_ptr = NULL;
    static char uid_str[10];
    if ((pw_ptr = getpwuid(uid)) == NULL){
        sprintf(uid_str, "%d", uid);
        return uid_str;
    }
    else{
        return pw_ptr->pw_name;
    }
}

char *gid_to_name(gid_t gid){
    struct group *gp_ptr = NULL;
    static char gid_str[10];
    if ((gp_ptr = getgrgid(gid)) == NULL){
        sprintf(gid_str, "%d", gid);
        return gid_str;
    }
    else{
        return gp_ptr->gr_name;
    }
}

함수 설명

  1. do_ls: 디렉토리를 열고 차례로 파일을 하나씩 읽어옴

  2. do_stat: 파일 정보를 buf에 저장

  3. show_file_info: buf에 저장된 정보들을 출력

  4. mode_to_letters: st_mode를 문자열로 변환

  5. uid_to_name: uid를 통해 /etc/passwd에서 user_name을 가져옴

  6. gid_to_name: uid를 통해 /etc/group에서 user_name을 가져옴

  • 문제점: 디렉토리는 처리 불가능
profile
Just do it.

0개의 댓글