# # # patch "ChangeLog" # from [872b01844de77889d8db88bc71181daf8bac1b46] # to [64a209e3f6cbfdc02a87df7e0b01447edb95bf49] # # patch "win32/fs.cc" # from [6cf4bc46e555a714ee4f6ed96e8d266b546eb575] # to [bf1ed69810fd107a33cf9c8ea8327574f2271bfe] # ============================================================ --- ChangeLog 872b01844de77889d8db88bc71181daf8bac1b46 +++ ChangeLog 64a209e3f6cbfdc02a87df7e0b01447edb95bf49 @@ -1,3 +1,13 @@ +2005-12-14 Matthew Gregan + + * win32/fs.cc: Handle the fact that the MoveFileEx symbol might + exist in kernel32.dll even though it doesn't actually work. It + turns out that Win9x implements a bunch of NT-only symbols as + stubs that return ERROR_CALL_NOT_IMPLEMENTED, so it's not + sufficient to detect feature availability by doing symbol lookups + at runtime. Also add a missing parameter to the final error + message. Fixes #15063. + 2005-12-13 Derek Scherger * commands.cc (update): remove \n from F() string ============================================================ --- win32/fs.cc 6cf4bc46e555a714ee4f6ed96e8d266b546eb575 +++ win32/fs.cc bf1ed69810fd107a33cf9c8ea8327574f2271bfe @@ -139,18 +139,26 @@ // more compatible DeleteFile/MoveFile pair as a compatibility fall-back. typedef BOOL (*MoveFileExFun)(LPCTSTR, LPCTSTR, DWORD); static MoveFileExFun MoveFileEx = 0; + static bool MoveFileExAvailable = false; if (MoveFileEx == 0) { HMODULE hModule = LoadLibrary("kernel32"); if (hModule) MoveFileEx = reinterpret_cast (GetProcAddress(hModule, "MoveFileExA")); - if (MoveFileEx) + if (MoveFileEx) { L(F("using MoveFileEx for renames")); + MoveFileExAvailable = true; + } else + L(F("using DeleteFile/MoveFile fallback for renames")); } - if (MoveFileEx) { + if (MoveFileExAvailable) { if (MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)) return true; + else if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + MoveFileExAvailable = false; + L(F("MoveFileEx failed with CALL_NOT_IMPLEMENTED, using fallback")); + } } else { // This is not even remotely atomic, but what can you do? DeleteFile(to); @@ -167,6 +175,7 @@ const char* szTo = to.as_external().c_str(); static const int renameAttempts = 16; DWORD sleepTime = 1; + DWORD lastError = 0; // If a clobbering rename attempt fails, we wait and try again, up to an // (arbitrary) maximum of 16 attempts. This is a gross hack to work @@ -175,11 +184,13 @@ for (int i = 0; i < renameAttempts; ++i) { if (rename_clobberingly_impl(szFrom, szTo)) return; + lastError = GetLastError(); L(F("attempted rename of '%s' to '%s' failed: %d") - % szFrom % szTo % GetLastError()); + % szFrom % szTo % lastError); Sleep(sleepTime); if (sleepTime < 250) sleepTime *= 2; } - E(false, F("renaming '%s' to '%s' failed: %d") % from % to); + E(false, F("renaming '%s' to '%s' failed: %d") % from % to % lastError); } +