From 87abf9d2de4c75539b9ba7cb400f4baae35936ba Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 28 Aug 2011 19:07:17 +0000 Subject: Use "more standard" Windows API functions FindFirstFileW and FindNextFileW for directory enumeration instead of _wfindfirst and _wfindnext. Ignore reparse points when enumerating directories to avoid infinite loops. Convert VSS paths back to real paths when notifying users about backup progress. --- lib/win32/emu.cpp | 48 ++++++++++++++++++++++++++++++------------------ lib/win32/emu.h | 38 ++++++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 34 deletions(-) (limited to 'lib/win32') diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 2c1fb0df..ef237671 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1,8 +1,5 @@ // Box Backup Win32 native port by Nick Knight -// Need at least 0x0500 to use GetFileSizeEx on Cygwin/MinGW -#define WINVER 0x0500 - #include "emu.h" #ifdef WIN32 @@ -1080,9 +1077,10 @@ DIR *opendir(const char *name) return NULL; } - pDir->fd = _wfindfirst((const wchar_t*)pDir->name, &(pDir->info)); + pDir->fd = FindFirstFileW(pDir->name, &pDir->info); + DWORD tmp = GetLastError(); - if (pDir->fd == -1) + if (pDir->fd == INVALID_HANDLE_VALUE) { delete [] pDir->name; delete pDir; @@ -1111,26 +1109,37 @@ struct dirent *readdir(DIR *dp) { struct dirent *den = NULL; - if (dp && dp->fd != -1) + if (dp && dp->fd != INVALID_HANDLE_VALUE) { - if (!dp->result.d_name || - _wfindnext(dp->fd, &dp->info) != -1) + // first time around, when dp->result.d_name == NULL, use + // the values returned by FindFirstFile. After that, call + // FindNextFileW to return new ones. + if (!dp->result.d_name || + FindNextFileW(dp->fd, &dp->info) != 0) { den = &dp->result; - std::wstring input(dp->info.name); + std::wstring input(dp->info.cFileName); memset(tempbuff, 0, sizeof(tempbuff)); - WideCharToMultiByte(CP_UTF8, 0, dp->info.name, + WideCharToMultiByte(CP_UTF8, 0, dp->info.cFileName, -1, &tempbuff[0], sizeof (tempbuff), NULL, NULL); //den->d_name = (char *)dp->info.name; den->d_name = &tempbuff[0]; - if (dp->info.attrib & FILE_ATTRIBUTE_DIRECTORY) + den->d_type = dp->info.dwFileAttributes; + } + else // FindNextFileW failed + { + // Why did it fail? No more files? + winerrno = GetLastError(); + den = NULL; + + if (winerrno == ERROR_NO_MORE_FILES) { - den->d_type = S_IFDIR; + errno = 0; // no more files } else { - den->d_type = S_IFREG; + errno = ENOSYS; } } } @@ -1138,6 +1147,7 @@ struct dirent *readdir(DIR *dp) { errno = EBADF; } + return den; } catch (...) @@ -1159,24 +1169,26 @@ int closedir(DIR *dp) { try { - int finres = -1; + BOOL finres = false; + if (dp) { - if(dp->fd != -1) + if(dp->fd != INVALID_HANDLE_VALUE) { - finres = _findclose(dp->fd); + finres = FindClose(dp->fd); } delete [] dp->name; delete dp; } - if (finres == -1) // errors go to EBADF + if (finres == FALSE) // errors go to EBADF { + winerrno = GetLastError(); errno = EBADF; } - return finres; + return (finres == TRUE) ? 0 : -1; } catch (...) { diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 1ebd45c2..151fa2cb 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -50,22 +50,30 @@ #define __MSVCRT_VERSION__ 0x0601 #endif +// We need WINVER at least 0x0500 to use GetFileSizeEx on Cygwin/MinGW, +// and 0x0501 for FindFirstFile(W) for opendir/readdir. +// // WIN32_WINNT versions 0x0600 (Vista) and higher enable WSAPoll() in // winsock2.h, whose struct pollfd conflicts with ours below, so for -// now we just set it lower than that, to Windows 2000. +// now we just set it lower than that, to Windows XP (0x0501). + #ifdef WINVER - #if WINVER != 0x0500 - #error Must include emu.h before setting WINVER - #endif +# if WINVER != 0x0501 +// provoke a redefinition warning to track down the offender +# define WINVER 0x0501 +# error Must include emu.h before setting WINVER +# endif #endif -#define WINVER 0x0500 +#define WINVER 0x0501 #ifdef _WIN32_WINNT - #if _WIN32_WINNT != 0x0500 - #error Must include emu.h before setting _WIN32_WINNT - #endif +# if _WIN32_WINNT != 0x0501 +// provoke a redefinition warning to track down the offender +# define _WIN32_WINNT 0x0501 +# error Must include emu.h before setting _WIN32_WINNT +# endif #endif -#define _WIN32_WINNT 0x0500 +#define _WIN32_WINNT 0x0501 // Windows headers @@ -237,17 +245,15 @@ inline int strcasecmp(const char *s1, const char *s2) struct dirent { char *d_name; - unsigned long d_type; + DWORD d_type; // file attributes }; struct DIR { - intptr_t fd; // filedescriptor - // struct _finddata_t info; - struct _wfinddata_t info; - // struct _finddata_t info; - struct dirent result; // d_name (first time null) - wchar_t *name; // null-terminated byte string + HANDLE fd; // the HANDLE returned by FindFirstFile + WIN32_FIND_DATAW info; + struct dirent result; // d_name (first time null) + wchar_t* name; // null-terminated byte string }; DIR *opendir(const char *name); -- cgit v1.2.3