Cでディレクトリの中身を見る

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <limits.h>

#define INITSIZE 100


typedef struct entry {
    struct stat stat;
    char name[NAME_MAX];
} entry_t;

typedef struct dir {
    entry_t **entries;
    size_t count;
    size_t max_name_len;
    char *path;
} dir_t;


dir_t *dir = NULL;


dir_t* look_dir(const char* path) {
    DIR *dp;
    struct dirent *dirent;
    dir_t *dir;
    entry_t *entry;
    size_t n = INITSIZE;

    dir = malloc(sizeof(dir_t));
    dir->entries = malloc(sizeof(entry_t *) * n);
    dir->count = 0;
    dir->max_name_len = 0;
    dir->path = malloc(strlen(path)+1);
    strcpy(dir->path, path);

    dp = opendir(path);
    if (dp == NULL) {
        perror("opendir");
        exit(1);
    }
    while ((dirent = readdir(dp)) != NULL) {
        size_t len;

        len = strlen(dirent->d_name);
        if (len > dir->max_name_len) 
            dir->max_name_len = len;

        if (dir->count >= n) {
            n *= 2;
            dir->entries = realloc(dir->entries, sizeof(entry_t *) * n);
        }
        entry = malloc(sizeof(entry_t));
        strcpy(entry->name, dirent->d_name);
        if (stat(entry->name, &entry->stat) < 0) {
            perror("stat");
            exit(1);
        }
        dir->entries[dir->count++] = entry;
    }
    dir->entries[dir->count] = NULL;

    closedir(dp);
    return dir;
}

void free_dir(dir_t *dir) {
    if (dir == NULL) return;

    entry_t **pentry;
    for (pentry = dir->entries; *pentry != NULL; pentry++) {
        free(*pentry);
    }
    free(dir->entries);
    free(dir->path);
    free(dir);
}

int main(int argc, char **argv) {
    char *dirpath;
    entry_t **pentry;

    dirpath = getcwd(NULL, 0);
    dir = look_dir(dirpath);
    if (dir == NULL) {
        exit(1);
    }
    for (pentry = dir->entries; *pentry != NULL; pentry++) {
        entry_t *entry = *pentry;
        printf("%d\t%lld\t%s\n", entry->stat.st_mode, entry->stat.st_size, entry->name);
    }

    free_dir(dir);
    free(dirpath);

    return 0;
}

メモ

  • getcwd()でカレントディレクトリのパスを取得
    • バッファにNULLを渡すと、getcwdがメモリを確保して文字列を返す
      • 確保されたメモリは呼び出し側の責任でfreeしないと行けない
  • readdir()の返り値はfreeしてはいけない
  • NAME_MAXはシステムの最大のファイル名の長さ