compat / win32 / dirent.con commit Merge branch 'jc/fix-clone-single-starting-at-a-tag' (3d77f72)
   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};
   8
   9static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
  10{
  11        /* copy file name from WIN32_FIND_DATA to dirent */
  12        memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
  13
  14        /* Set file type, based on WIN32_FIND_DATA */
  15        if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  16                ent->d_type = DT_DIR;
  17        else
  18                ent->d_type = DT_REG;
  19}
  20
  21DIR *opendir(const char *name)
  22{
  23        char pattern[MAX_PATH];
  24        WIN32_FIND_DATAA fdata;
  25        HANDLE h;
  26        int len;
  27        DIR *dir;
  28
  29        /* check that name is not NULL */
  30        if (!name) {
  31                errno = EINVAL;
  32                return NULL;
  33        }
  34        /* check that the pattern won't be too long for FindFirstFileA */
  35        len = strlen(name);
  36        if (len + 2 >= MAX_PATH) {
  37                errno = ENAMETOOLONG;
  38                return NULL;
  39        }
  40        /* copy name to temp buffer */
  41        memcpy(pattern, name, len + 1);
  42
  43        /* append optional '/' and wildcard '*' */
  44        if (len && !is_dir_sep(pattern[len - 1]))
  45                pattern[len++] = '/';
  46        pattern[len++] = '*';
  47        pattern[len] = 0;
  48
  49        /* open find handle */
  50        h = FindFirstFileA(pattern, &fdata);
  51        if (h == INVALID_HANDLE_VALUE) {
  52                DWORD err = GetLastError();
  53                errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
  54                return NULL;
  55        }
  56
  57        /* initialize DIR structure and copy first dir entry */
  58        dir = xmalloc(sizeof(DIR));
  59        dir->dd_handle = h;
  60        dir->dd_stat = 0;
  61        finddata2dirent(&dir->dd_dir, &fdata);
  62        return dir;
  63}
  64
  65struct dirent *readdir(DIR *dir)
  66{
  67        if (!dir) {
  68                errno = EBADF; /* No set_errno for mingw */
  69                return NULL;
  70        }
  71
  72        /* if first entry, dirent has already been set up by opendir */
  73        if (dir->dd_stat) {
  74                /* get next entry and convert from WIN32_FIND_DATA to dirent */
  75                WIN32_FIND_DATAA fdata;
  76                if (FindNextFileA(dir->dd_handle, &fdata)) {
  77                        finddata2dirent(&dir->dd_dir, &fdata);
  78                } else {
  79                        DWORD lasterr = GetLastError();
  80                        /* POSIX says you shouldn't set errno when readdir can't
  81                           find any more files; so, if another error we leave it set. */
  82                        if (lasterr != ERROR_NO_MORE_FILES)
  83                                errno = err_win_to_posix(lasterr);
  84                        return NULL;
  85                }
  86        }
  87
  88        ++dir->dd_stat;
  89        return &dir->dd_dir;
  90}
  91
  92int closedir(DIR *dir)
  93{
  94        if (!dir) {
  95                errno = EBADF;
  96                return -1;
  97        }
  98
  99        FindClose(dir->dd_handle);
 100        free(dir);
 101        return 0;
 102}