opendir・readdir・closedirをエミュレートする

空のディレクトリの動作が違いそうな…。

#include <stdio.h>
#include <errno.h>
#include "dirent.h"

int main() {
  DIR *dir;
  struct dirent *entry;

  if ((dir = opendir("/usr/local")) == NULL) {
    perror("opendir(3)");
    exit(1);
  }

  entry = readdir(dir);

  while (entry) {
    puts(entry->d_name);
    entry = readdir(dir);
  }

  closedir(dir);

  return 0;
}


.
..
bin
CollabNet Subversion
etc
iconv-1.8.win32


dirent.c

#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include "dirent.h"

DIR *opendir(const char *name) {
  char *path;
  HANDLE h;
  WIN32_FIND_DATAA *fd;
  DIR *dir;
  int namlen;

  if (name == NULL) {
    return NULL;
  }

  if ((namlen = strlen(name)) == -1) {
    return NULL;
  }

  if (name[namlen -1] == '\\' || name[namlen -1] == '/') {
    path = _alloca(namlen + 2);
    strcpy_s(path, namlen + 2, name);
    path[namlen] = '*';
    path[namlen + 1] = '\0';
  } else {
    path = _alloca(namlen + 3);
    strcpy_s(path, namlen + 3, name);

    path[namlen] = (strchr(name, '/') != NULL) ? '/' : '\\';
    path[namlen + 1] = '*';
    path[namlen + 2] = '\0';
  }

  if ((fd = malloc(sizeof(WIN32_FIND_DATA))) == NULL) {
    return NULL;
  }

  if ((h = FindFirstFileA(path, fd)) == INVALID_HANDLE_VALUE) {
    free(fd);
    return NULL;
  }

  if ((dir = malloc(sizeof(DIR))) == NULL) {
    FindClose(h);
    free(fd);
    return NULL;
  }

  dir->h = h;
  dir->fd = fd;
  dir->has_next = TRUE;

  return dir;
}

struct dirent *readdir(DIR *dir) {
  char *cFileName;
  char *d_name;

  if (dir == NULL) {
    return NULL;
  }

  if (dir->fd == NULL) {
    return NULL;
  }

  if (!dir->has_next) {
    return NULL;
  }

  cFileName = dir->fd->cFileName;
  d_name = dir->entry.d_name;
  strcpy_s(d_name, _MAX_PATH, cFileName);
  dir->has_next = FindNextFileA(dir->h, dir->fd);

  return &dir->entry;
}

int closedir(DIR *dir) {
  if (dir == NULL) {
    return -1;
  }

  if (dir->h && dir->h != INVALID_HANDLE_VALUE) {
    FindClose(dir->h);
  }

  if (dir->fd) {
    free(dir->fd);
  }

  free(dir);

  return 0;
}

dirent.h

#ifndef __DIRENT_H__
#define __DIRENT_H__

#include <windows.h>

typedef unsigned int ino_t;

struct dirent {
  ino_t          d_ino;
  char           d_name[_MAX_PATH];
};

typedef struct {
  HANDLE h;
  WIN32_FIND_DATAA *fd;
  BOOL has_next;
  struct dirent entry;
} DIR;

DIR *opendir(const char *name);
struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);

#endif