이번에 dirent 와 stat 을 이용하여 작업을 하면서 알게된 내용들을 간단하게 정리했다.
dirent
dirent 는 디렉토리 정보를 담는 구조체이다.
dirent 와 scandir() 을 사용하면 디렉토리에 어떤 파일들이 있는지 간략하게 알 수 있는 속성과 파일 리스트 포인터를 이용할 수 있다.
struct dirent
{
#ifndef __USE_FILE_OFFSET64
__ino_t d_ino;
__off_t d_off;
#else
__ino64_t d_ino;
__off64_t d_off;
#endif
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
구조체 내용 중, d_type 으로 파일의 속성을 파악할 수 있는데, 종류는 다음과 같다.
#ifdef __USE_BSD
/* File types for `d_type'. */
enum
{
DT_UNKNOWN = 0,
# define DT_UNKNOWN DT_UNKNOWN
DT_FIFO = 1,
# define DT_FIFO DT_FIFO
DT_CHR = 2,
# define DT_CHR DT_CHR
DT_DIR = 4,
# define DT_DIR DT_DIR
DT_BLK = 6,
# define DT_BLK DT_BLK
DT_REG = 8,
# define DT_REG DT_REG
DT_LNK = 10,
# define DT_LNK DT_LNK
DT_SOCK = 12,
# define DT_SOCK DT_SOCK
DT_WHT = 14
# define DT_WHT DT_WHT
};
/* Convert between stat structure types and directory types. */
# define IFTODT(mode) (((mode) & 0170000) >> 12)
# define DTTOIF(dirtype) ((dirtype) << 12)
#endif
stat
stat 은 파일 속성을 가져오는 함수이며, 구조체이다. stat 을 호출하면, 입력한 파일에 대한 속성들이 struct stat 구조체에 입력된다.
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
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 bytes */
blksize_t st_blksize; /* blocksize for filesystem 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_ctime; /* time of last status change */
};
Eaxmple
아래는 stat 과 scandir 을 이용한 예제 프로그램이다.
현재 디렉토리 내에 있는 모든 파일들을 최근 수정한 순서대로 검색하며 각각의 파일명과 사이즈(Byte)를 표시한다.
만약, 디렉토리 안에 있는 파일들의 용량의 10M가 넘어가면, 그 이후부터는 파일을 삭제한다.
즉, 디렉토리에 있는 파일들의 용량이 10M가 넘어가면 오래된 파일부터 삭제하는 것이다.
그리고 파일을 검색하는 도중 파일명에 .wav(wav 파일)이 들어있으면 “Found wav file” 을 표시한다.
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define TARGET_DIR "."
#define LIMIT_SIZE 10485760 // 10M
int file_select( const struct dirent *d );
int cmp_time(const struct dirent **e1, const struct dirent **e2);
int main(int argc, char** argv)
{
struct dirent **namelist;
struct stat tmp_stat;
unsigned long total_size;
char* pszFilename;
int iCnt;
int i;
int iRet;
char* pRet;
iCnt = scandir(TARGET_DIR, &namelist, file_select, cmp_time);
if(iCnt < 0)
{
printf("Could not scanning.. err:%d, msg:%s\n", errno, strerror(errno));
return 0;
}
total_size = 0;
printf("Scan files:%d\n", iCnt);
for(i = 0; i < iCnt; i++)
{
asprintf(&pszFilename, "%s/%s", TARGET_DIR, namelist[i]->d_name);
stat(pszFilename, &tmp_stat);
printf("filename: %s, size:%ld\n", pszFilename, tmp_stat.st_size);
pRet = strstr(namelist[i]->d_name, ".wav");
if(pRet != NULL)
{
printf("Found wav file!\n");
}
total_size += tmp_stat.st_size;
if(total_size > LIMIT_SIZE)
{
total_size -= tmp_stat.st_size;
printf("Delete limit overed files... name: %s\n", pszFilename);
iRet = remove(pszFilename);
if(iRet == -1)
{
printf("Err! Could not delete file. name:%s, err:%d, msg:%s\n", pszFilename, errno, strerror(errno));
}
}
free(pszFilename);
free(namelist[i]);
}
free(namelist);
printf("totalSize %lu\n", total_size);
return 0;
}
/**
*
*/
int file_select(const struct dirent *entry)
{
if(entry->d_type == DT_DIR)
{
return 0;
}
return 1;
}
/**
*
*/
int cmp_time(const struct dirent **e1, const struct dirent **e2)
{
int iRet;
struct stat sb1;
struct stat sb2;
char* filename_e1;
char* filename_e2;
asprintf(&filename_e1, "%s/%s", TARGET_DIR, (*e1)->d_name);
asprintf(&filename_e2, "%s/%s", TARGET_DIR, (*e2)->d_name);
iRet = stat(filename_e1, &sb1);
if(iRet == -1)
{
printf("Error occured! name:%s, err:%d, msg:%s\n", filename_e1, errno, strerror(errno));
free(filename_e1);
free(filename_e2);
return -1;
}
iRet = stat(filename_e2, &sb2);
if(iRet == -1)
{
printf("Error occured! Err:%d, Msg:%s\n", errno, strerror(errno));
free(filename_e1);
free(filename_e2);
return -1;
}
free(filename_e1);
free(filename_e2);
return sb1.st_mtime < sb2.st_mtime;
}