From 83ff08f9db58e516f81e948e8256b50940145d30 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 11 Mar 2022 18:07:50 +0000 Subject: [PATCH] Remove hard dependency on GetFileAttributesEx. This fixes a load-time failure on versions of Windows too old to have that function in kernel32.dll. We use it to determine whether a file was safe to overwrite in the context of PuTTY session logging: if it's safe, we skip the 'do you want to overwrite or append?' dialog box. On earlier Windows you can use FindFirstFile to get a similar effect, so that's what we fall back to. It's not quite the same, though - if you pass a wildcard then it will succeed when you'd rather it had failed. But it's good enough to at least work in normal cases. --- .../utils/open_for_write_would_lose_data.c | 66 +++++++++++++++---- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/windows/utils/open_for_write_would_lose_data.c b/windows/utils/open_for_write_would_lose_data.c index 3891f51e..2aef5c5a 100644 --- a/windows/utils/open_for_write_would_lose_data.c +++ b/windows/utils/open_for_write_would_lose_data.c @@ -4,20 +4,19 @@ #include "putty.h" -bool open_for_write_would_lose_data(const Filename *fn) +/* + * This is slightly fiddly because we want to be backwards-compatible + * with systems too old to have GetFileAttributesEx. The next best + * thing is FindFirstFile, which will return a different data + * structure, but one that also contains the fields we want. (But it + * will behave more unhelpfully - for this application - in the + * presence of wildcards, so we'd prefer to use GFAE if we can.) + */ + +static inline bool open_for_write_would_lose_data_impl( + DWORD dwFileAttributes, DWORD nFileSizeHigh, DWORD nFileSizeLow) { - WIN32_FILE_ATTRIBUTE_DATA attrs; - if (!GetFileAttributesEx(fn->path, GetFileExInfoStandard, &attrs)) { - /* - * Generally, if we don't identify a specific reason why we - * should return true from this function, we return false, and - * let the subsequent attempt to open the file for real give a - * more useful error message. - */ - return false; - } - if (attrs.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE | - FILE_ATTRIBUTE_DIRECTORY)) { + if (dwFileAttributes & (FILE_ATTRIBUTE_DEVICE|FILE_ATTRIBUTE_DIRECTORY)) { /* * File is something other than an ordinary disk file, so * opening it for writing will not cause truncation. (It may @@ -25,7 +24,7 @@ bool open_for_write_would_lose_data(const Filename *fn) */ return false; } - if (attrs.nFileSizeHigh == 0 && attrs.nFileSizeLow == 0) { + if (nFileSizeHigh == 0 && nFileSizeLow == 0) { /* * File is zero-length (or may be a named pipe, which * dwFileAttributes can't tell apart from a regular file), so @@ -36,3 +35,42 @@ bool open_for_write_would_lose_data(const Filename *fn) } return true; } + +bool open_for_write_would_lose_data(const Filename *fn) +{ + static HMODULE kernel32_module; + DECL_WINDOWS_FUNCTION(static, BOOL, GetFileAttributesExA, + (LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID)); + + if (!kernel32_module) { + kernel32_module = load_system32_dll("kernel32.dll"); + GET_WINDOWS_FUNCTION(kernel32_module, GetFileAttributesExA); + } + + if (p_GetFileAttributesExA) { + WIN32_FILE_ATTRIBUTE_DATA attrs; + if (!p_GetFileAttributesExA(fn->path, GetFileExInfoStandard, &attrs)) { + /* + * Generally, if we don't identify a specific reason why we + * should return true from this function, we return false, and + * let the subsequent attempt to open the file for real give a + * more useful error message. + */ + return false; + } + return open_for_write_would_lose_data_impl( + attrs.dwFileAttributes, attrs.nFileSizeHigh, attrs.nFileSizeLow); + } else { + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(fn->path, &fd); + if (h == INVALID_HANDLE_VALUE) { + /* + * As above, if we can't find the file at all, return false. + */ + return false; + } + CloseHandle(h); + return open_for_write_would_lose_data_impl( + fd.dwFileAttributes, fd.nFileSizeHigh, fd.nFileSizeLow); + } +}