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