fac7f2504731c8494a63a41dc3ba035a081c472c
   1#include "../../git-compat-util.h"
   2
   3struct DIR {
   4        struct dirent dd_dir; /* includes d_type */
   5        HANDLE dd_handle;     /* FindFirstFile handle */
   6        int dd_stat;          /* 0-based index */
   7        char dd_name[1];      /* extend struct */
   8};
   9
  10DIR *opendir(const char *name)
  11{
  12        DWORD attrs = GetFileAttributesA(name);
  13        int len;
  14        DIR *p;
  15
  16        /* check for valid path */
  17        if (attrs == INVALID_FILE_ATTRIBUTES) {
  18                errno = ENOENT;
  19                return NULL;
  20        }
  21
  22        /* check if it's a directory */
  23        if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
  24                errno = ENOTDIR;
  25                return NULL;
  26        }
  27
  28        /* check that the pattern won't be too long for FindFirstFileA */
  29        len = strlen(name);
  30        if (is_dir_sep(name[len - 1]))
  31                len--;
  32        if (len + 2 >= MAX_PATH) {
  33                errno = ENAMETOOLONG;
  34                return NULL;
  35        }
  36
  37        p = malloc(sizeof(DIR) + len + 2);
  38        if (!p)
  39                return NULL;
  40
  41        memset(p, 0, sizeof(DIR) + len + 2);
  42        strcpy(p->dd_name, name);
  43        p->dd_name[len] = '/';
  44        p->dd_name[len+1] = '*';
  45
  46        p->dd_handle = INVALID_HANDLE_VALUE;
  47        return p;
  48}
  49
  50struct dirent *readdir(DIR *dir)
  51{
  52        WIN32_FIND_DATAA buf;
  53        HANDLE handle;
  54
  55        if (!dir || !dir->dd_handle) {
  56                errno = EBADF; /* No set_errno for mingw */
  57                return NULL;
  58        }
  59
  60        if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
  61                DWORD lasterr;
  62                handle = FindFirstFileA(dir->dd_name, &buf);
  63                lasterr = GetLastError();
  64                dir->dd_handle = handle;
  65                if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
  66                        errno = err_win_to_posix(lasterr);
  67                        return NULL;
  68                }
  69        } else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
  70                return NULL;
  71        } else if (!FindNextFileA(dir->dd_handle, &buf)) {
  72                DWORD lasterr = GetLastError();
  73                FindClose(dir->dd_handle);
  74                dir->dd_handle = INVALID_HANDLE_VALUE;
  75                /* POSIX says you shouldn't set errno when readdir can't
  76                   find any more files; so, if another error we leave it set. */
  77                if (lasterr != ERROR_NO_MORE_FILES)
  78                        errno = err_win_to_posix(lasterr);
  79                return NULL;
  80        }
  81
  82        /* We get here if `buf' contains valid data.  */
  83        strcpy(dir->dd_dir.d_name, buf.cFileName);
  84        ++dir->dd_stat;
  85
  86        /* Set file type, based on WIN32_FIND_DATA */
  87        dir->dd_dir.d_type = 0;
  88        if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  89                dir->dd_dir.d_type |= DT_DIR;
  90        else
  91                dir->dd_dir.d_type |= DT_REG;
  92
  93        return &dir->dd_dir;
  94}
  95
  96int closedir(DIR *dir)
  97{
  98        if (!dir) {
  99                errno = EBADF;
 100                return -1;
 101        }
 102
 103        if (dir->dd_handle != INVALID_HANDLE_VALUE)
 104                FindClose(dir->dd_handle);
 105        free(dir);
 106        return 0;
 107}