|
6 | 6 | #include "simpletimer.h" |
7 | 7 | #include "logging.h" |
8 | 8 | #include "spmiutil.h" |
| 9 | +#include "config.h" |
9 | 10 | #include <stdio.h> |
10 | 11 | #ifdef TARGET_UNIX |
11 | 12 | #include <sys/types.h> |
12 | 13 | #include <dirent.h> |
13 | 14 | #include <fnmatch.h> |
14 | | -#endif |
| 15 | +#if !HAVE_DIRENT_D_TYPE |
| 16 | +#define DT_UNKNOWN 0 |
| 17 | +#define DT_DIR 4 |
| 18 | +#define DT_REG 8 |
| 19 | +#define DT_LNK 10 |
| 20 | +#endif // !HAVE_DIRENT_D_TYPE |
| 21 | +#endif // TARGET_UNIX |
15 | 22 |
|
16 | 23 | #include <utility> |
17 | 24 |
|
@@ -187,9 +194,9 @@ bool verbMerge::DirectoryFilterDirectories(FilterArgType* findData) |
187 | 194 | #else // TARGET_WINDOWS |
188 | 195 | if (findData->d_type == DT_DIR) |
189 | 196 | { |
190 | | - if (strcmp(findData->d_name, ".") == 0) |
| 197 | + if (u16_strcmp(findData->cFileName, W(".")) == 0) |
191 | 198 | return false; |
192 | | - if (strcmp(findData->d_name, "..") == 0) |
| 199 | + if (u16_strcmp(findData->cFileName, W("..")) == 0) |
193 | 200 | return false; |
194 | 201 |
|
195 | 202 | return true; |
@@ -277,18 +284,58 @@ int verbMerge::FilterDirectory(LPCWSTR dir, |
277 | 284 | DIR* pDir = opendir(dirUtf8.c_str()); |
278 | 285 | if (pDir != nullptr) |
279 | 286 | { |
280 | | - errno = 0; |
281 | | - dirent *pEntry = readdir(pDir); |
282 | | - while (pEntry != nullptr) |
| 287 | + while (true) |
283 | 288 | { |
284 | | - if ((fnmatch(searchPatternUtf8.c_str(), pEntry->d_name, 0) == 0) && filter(pEntry)) |
| 289 | + dirent *pEntry; |
| 290 | + int dirEntryType; |
| 291 | + |
| 292 | + errno = 0; |
| 293 | + pEntry = readdir(pDir); |
| 294 | + if (pEntry == nullptr) |
| 295 | + break; |
| 296 | + |
| 297 | +#if HAVE_DIRENT_D_TYPE |
| 298 | + dirEntryType = pEntry->d_type; |
| 299 | +#else |
| 300 | + dirEntryType = DT_UNKNOWN; |
| 301 | +#endif |
| 302 | + // On some systems, dirent contains a d_type field, but note: |
| 303 | + // some file systems MAY leave d_type == DT_UNKNOWN, |
| 304 | + // expecting the consumer to stat the file. On systems |
| 305 | + // without a d_type simply always stat the file. |
| 306 | + |
| 307 | + if (dirEntryType == DT_UNKNOWN) |
285 | 308 | { |
286 | | - FindData findData(pEntry->d_type, ConvertMultiByteToWideChar(pEntry->d_name)); |
| 309 | + struct stat sb; |
| 310 | + |
| 311 | + if (fstatat(dirfd(pDir), pEntry->d_name, &sb, 0) == -1) |
| 312 | + continue; |
| 313 | + |
| 314 | + if (S_ISDIR(sb.st_mode)) |
| 315 | + dirEntryType = DT_DIR; |
| 316 | + else if (S_ISREG(sb.st_mode)) |
| 317 | + dirEntryType = DT_REG; |
| 318 | + else if (S_ISLNK(sb.st_mode)) |
| 319 | + dirEntryType = DT_LNK; |
| 320 | + else |
| 321 | + dirEntryType = DT_UNKNOWN; |
| 322 | + |
| 323 | + } |
| 324 | + |
| 325 | + if (dirEntryType == DT_UNKNOWN) |
| 326 | + continue; |
| 327 | + |
| 328 | + if (fnmatch(searchPatternUtf8.c_str(), pEntry->d_name, 0) != 0) |
| 329 | + continue; |
| 330 | + |
| 331 | + // Call the filter with &FindData like the Windows code below. |
| 332 | + FindData findData(dirEntryType, ConvertMultiByteToWideChar(pEntry->d_name)); |
| 333 | + if (filter(&findData)) |
| 334 | + { |
| 335 | + // Prepend it to the list. |
287 | 336 | first = new findDataList(&findData, first); |
288 | 337 | ++elemCount; |
289 | 338 | } |
290 | | - errno = 0; |
291 | | - pEntry = readdir(pDir); |
292 | 339 | } |
293 | 340 |
|
294 | 341 | if (errno != 0) |
|
0 commit comments