aboutsummaryrefslogtreecommitdiff
path: root/win32/dirent.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/dirent.c')
-rw-r--r--win32/dirent.c74
1 files changed, 62 insertions, 12 deletions
diff --git a/win32/dirent.c b/win32/dirent.c
index f0e8deae2..872f44fbc 100644
--- a/win32/dirent.c
+++ b/win32/dirent.c
@@ -8,26 +8,44 @@ struct DIR {
8 int got_dotdot; 8 int got_dotdot;
9}; 9};
10 10
11static inline unsigned char get_dtype(DWORD attr, DWORD reserved0)
12{
13 if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) &&
14 (reserved0 == IO_REPARSE_TAG_SYMLINK ||
15 reserved0 == IO_REPARSE_TAG_MOUNT_POINT ||
16 reserved0 == IO_REPARSE_TAG_APPEXECLINK))
17 return DT_LNK;
18 if (attr & FILE_ATTRIBUTE_DIRECTORY)
19 return DT_DIR;
20 return DT_REG;
21}
22
23#if !ENABLE_FEATURE_LONG_PATHS
11static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) 24static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
12{ 25{
13 /* copy file name from WIN32_FIND_DATA to dirent */ 26 /* copy file name from WIN32_FIND_DATA to dirent */
14 strcpy(ent->d_name, fdata->cFileName); 27 strcpy(ent->d_name, fdata->cFileName);
15 28 ent->d_type = get_dtype(fdata->dwFileAttributes, fdata->dwReserved0);
16 if ((fdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
17 (fdata->dwReserved0 == IO_REPARSE_TAG_SYMLINK ||
18 fdata->dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT ||
19 fdata->dwReserved0 == IO_REPARSE_TAG_APPEXECLINK))
20 ent->d_type = DT_LNK;
21 else if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
22 ent->d_type = DT_DIR;
23 else
24 ent->d_type = DT_REG;
25} 29}
30#else
31static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
32{
33 /* copy file name from WIN32_FIND_DATAW to dirent */
34 WideCharToMultiByte(CP_ACP, 0, fdata->cFileName, -1,
35 ent->d_name, PATH_MAX, NULL, NULL);
36 ent->d_type = get_dtype(fdata->dwFileAttributes, fdata->dwReserved0);
37}
38#endif
26 39
27DIR *opendir(const char *name) 40DIR *opendir(const char *name)
28{ 41{
42#if !ENABLE_FEATURE_LONG_PATHS
29 char pattern[MAX_PATH]; 43 char pattern[MAX_PATH];
30 WIN32_FIND_DATAA fdata; 44 WIN32_FIND_DATAA fdata;
45#else
46 wchar_t wpattern[32768];
47 WIN32_FIND_DATAW fdata;
48#endif
31 HANDLE h; 49 HANDLE h;
32 int len; 50 int len;
33 DIR *dir; 51 DIR *dir;
@@ -37,6 +55,8 @@ DIR *opendir(const char *name)
37 errno = EINVAL; 55 errno = EINVAL;
38 return NULL; 56 return NULL;
39 } 57 }
58
59#if !ENABLE_FEATURE_LONG_PATHS
40 /* check that the pattern won't be too long for FindFirstFileA */ 60 /* check that the pattern won't be too long for FindFirstFileA */
41 len = strlen(name); 61 len = strlen(name);
42 if (len + 2 >= MAX_PATH) { 62 if (len + 2 >= MAX_PATH) {
@@ -59,6 +79,30 @@ DIR *opendir(const char *name)
59 errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(); 79 errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix();
60 return NULL; 80 return NULL;
61 } 81 }
82#else /* ENABLE_FEATURE_LONG_PATHS */
83 /* Convert to wide string. CP_ACP is CP_UTF8 when the UTF-8 manifest
84 * is active, else the system ANSI code page. */
85 len = MultiByteToWideChar(CP_ACP, 0, name, -1, wpattern, 32760);
86 if (len == 0) {
87 errno = EINVAL;
88 return NULL;
89 }
90 len--; /* exclude null terminator from length */
91
92 /* append optional '\' and wildcard '*' */
93 if (len && wpattern[len - 1] != L'\\' && wpattern[len - 1] != L'/')
94 wpattern[len++] = L'\\';
95 wpattern[len++] = L'*';
96 wpattern[len] = 0;
97
98 /* open find handle using wide API */
99 h = FindFirstFileW(wpattern, &fdata);
100 if (h == INVALID_HANDLE_VALUE) {
101 DWORD err = GetLastError();
102 errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix();
103 return NULL;
104 }
105#endif
62 106
63 /* initialize DIR structure and copy first dir entry */ 107 /* initialize DIR structure and copy first dir entry */
64 dir = xzalloc(sizeof(DIR)); 108 dir = xzalloc(sizeof(DIR));
@@ -80,8 +124,14 @@ struct dirent *readdir(DIR *dir)
80 /* if first entry, dirent has already been set up by opendir */ 124 /* if first entry, dirent has already been set up by opendir */
81 if (dir->not_first) { 125 if (dir->not_first) {
82 /* get next entry and convert from WIN32_FIND_DATA to dirent */ 126 /* get next entry and convert from WIN32_FIND_DATA to dirent */
127#if !ENABLE_FEATURE_LONG_PATHS
83 WIN32_FIND_DATAA fdata; 128 WIN32_FIND_DATAA fdata;
84 if (FindNextFileA(dir->dd_handle, &fdata)) { 129 if (FindNextFileA(dir->dd_handle, &fdata))
130#else
131 WIN32_FIND_DATAW fdata;
132 if (FindNextFileW(dir->dd_handle, &fdata))
133#endif
134 {
85 finddata2dirent(&dir->dd_dir, &fdata); 135 finddata2dirent(&dir->dd_dir, &fdata);
86 } else if (!dir->got_dot) { 136 } else if (!dir->got_dot) {
87 strcpy(dir->dd_dir.d_name, "."); 137 strcpy(dir->dd_dir.d_name, ".");