# 간단한 ls
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
void do_ls(char []);
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; // 디렉토리를 열기 위한 포인터
struct dirent *direntp; // 파일의 정보를 받아오기 위한 구조체, 아래 dirent 구조체 참고
if((dir_ptr = opendir(dirname))==NULL) // 오류 처리
fprintf(stderr, "ls1: cannot open %s\n", dirname);
else
{
while((direntp=readdir(dir_ptr)) != NULL) // 현재 디렉토리의 파일을 하나씩 읽어온다. 더이상 읽을 파일이 없으면 NULL
printf("%s\n", direntp->d_name);
closedir(dir_ptr);
}
}

위에서 사용되는 dirent 구조체는 아래와 같이 구성되어 있다.
// dirent 구조체 참고
struct dirent{
long d_ino; // 파일이 가지고 있는 자신만의 번호 inode를 가리키는 숫자
off_t d_off; // dirent의 offset
unsigned short d_reclen; // d_name의 길이
char d_name [NAME_MAX+1]; //파일 혹은 디렉토리의 이름(없다면 NULL로 종료)
}
아래는 ls -l 구현이다.
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
void do_ls(char[]);
void dostat(char *);
void show_file_info(char *, struct stat *);
void mode_to_letters(int, char[]);
char *uid_to_name(uid_t);
char *gid_to_name(gid_t);
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;
struct dirent *direntp;
if ((dir_ptr = opendir(dirname)) == NULL)
fprintf(stderr, "ls1: cannot open %s\n", dirname);
else
{
while((direntp = readdir(dir_ptr)) != NULL)
dostat(direntp->d_name);
closedir(dir_ptr);
}
}
void dostat(char *filename)
{
struct stat info; // 파일의 상세 정보를 받아오는 stat 구조체
if (stat(filename, &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 ); // modestr 문자열에, 해당 파일의 사용자 권한 모드를 파악해 입력 ex) drwxrwxrwx
printf( "%s" , modestr);
printf( "%4d " , (int) info_p->st_nlink); // link 개수
printf( "%-8s " , uid_to_name(info_p->st_uid) ); // 소유 user id
printf( "%-8s " , gid_to_name(info_p->st_gid) ); // 소유 group id
printf( "%8ld " , (long)info_p->st_size); // 파일 size (byte)
printf( "%.12s ", 4+ctime(&info_p->st_mtime)); // 최종 수정시간
printf( "%s\n" , filename); // 파일 이름
}
void mode_to_letters(int mode, char str[])
{
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';
}
#include <pwd.h>
char *uid_to_name( uid_t 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;
}
#include <grp.h>
char *gid_to_name( gid_t 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;
}
위 코드에서 사용되는 stat 구조체의 멤버는 아래와 같아서 ls -l 출력에 필요한 정보들을 뽑아 쓰는 방식이다.
//stat 구조체 참고
struct stat {
dev_t st_dev; // 장치 정보(major number, minor number 등)
ino_t st_ino; // 파일의 inode 정보
mode_t st_mode; // 파일 허가권 모드
nlink_t st_nlink; // 파일 링크의 수
uid_t st_uid; // 파일 소유자의 사용자 식별번호(UID)
gid_t st_gid; // 파일 소유자가 속한 그룹 식별번호(GID)
dev_t st_rdev; // raw 장치의 정보(major num, minor num 등)
off_t st_size; // 파일 크기(Bytes 단위)
time_t st_atime; // 마지막으로 파일을 읽거나 실행한 시간 정보
time_t st_mtime; // 마지막으로 파일을 쓰기(변경)한 시간 정보
time_t st_xtime; // 마지막으로 inode 내용을 변경한 시간 정보
long st_blksize; // I/O 파일 시스템 블록의 크기 정보
long st_blocks; // 파일에 할당된 블록 수
};
