diff options
Diffstat (limited to 'win32/dirent.c')
| -rw-r--r-- | win32/dirent.c | 74 |
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 | ||
| 11 | static 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 | ||
| 11 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) | 24 | static 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 | ||
| 31 | static 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 | ||
| 27 | DIR *opendir(const char *name) | 40 | DIR *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, "."); |
