이번에 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;
}

Tags: , ,

Leave a Reply