From b47c355b18d9537ccc3dd3e80cc1825b018ecff7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 20 Oct 2020 13:38:11 +0200 Subject: [PATCH] w32: Allow Unicode filenames for dotlock * common/dotlock.c (any8bitchar) [W32]: New. (dotlock_create_w32): Use strconcat and CreateFileW. * common/t-dotlock.c: Source include dotlock.c and modify to allow manual testing on Windows. -- GnuPG-bug-id: 5098 Signed-off-by: Werner Koch --- common/dotlock.c | 53 +++++++++------ common/t-dotlock.c | 166 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 192 insertions(+), 27 deletions(-) diff --git a/common/dotlock.c b/common/dotlock.c index 8d9ee5139..f3e4bac28 100644 --- a/common/dotlock.c +++ b/common/dotlock.c @@ -471,6 +471,21 @@ map_w32_to_errno (DWORD w32_err) } #endif /*HAVE_DOSISH_SYSTEM*/ + +#ifdef HAVE_W32_SYSTEM +static int +any8bitchar (const char *string) +{ + if (string) + for ( ; *string; string++) + if ((*string & 0x80)) + return 1; + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + + /* Entirely disable all locking. This function should be called before any locking is done. It may be called right at startup of @@ -794,7 +809,7 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock) h->next = all_lockfiles; all_lockfiles = h; - h->lockname = xtrymalloc ( strlen (file_to_lock) + 6 ); + h->lockname = strconcat (file_to_lock, EXTSEP_S "lock", NULL); if (!h->lockname) { all_lockfiles = h->next; @@ -802,7 +817,6 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock) xfree (h); return NULL; } - strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock"); /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE along with FILE_SHARE_DELETE but that does not work due to a race @@ -812,25 +826,24 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock) reasons why a lock file can't be created and thus the process would not stop as expected but spin until Windows crashes. Our solution is to keep the lock file open; that does not harm. */ - { -#ifdef HAVE_W32CE_SYSTEM - wchar_t *wname = utf8_to_wchar (h->lockname); + if (any8bitchar (h->lockname)) + { + wchar_t *wname = utf8_to_wchar (h->lockname); - if (wname) - h->lockhd = CreateFile (wname, - GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_ALWAYS, 0, NULL); - else - h->lockhd = INVALID_HANDLE_VALUE; - xfree (wname); -#else - h->lockhd = CreateFile (h->lockname, - GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_ALWAYS, 0, NULL); -#endif - } + if (wname) + h->lockhd = CreateFileW (wname, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_ALWAYS, 0, NULL); + else + h->lockhd = INVALID_HANDLE_VALUE; + xfree (wname); + } + else + h->lockhd = CreateFileA (h->lockname, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_ALWAYS, 0, NULL); if (h->lockhd == INVALID_HANDLE_VALUE) { int saveerrno = map_w32_to_errno (GetLastError ()); diff --git a/common/t-dotlock.c b/common/t-dotlock.c index f7aee09d3..e2d22f66d 100644 --- a/common/t-dotlock.c +++ b/common/t-dotlock.c @@ -41,22 +41,166 @@ #include #include #include +#ifdef HAVE_W32_SYSTEM +# include "windows.h" +#endif #include "dotlock.h" +#ifdef HAVE_W32_SYSTEM +#define DIM(v) (sizeof(v)/sizeof((v)[0])) + +const char * +w32_strerror (int ec) +{ + static char strerr[256]; + + if (ec == -1) + ec = (int)GetLastError (); +#ifdef HAVE_W32CE_SYSTEM + /* There is only a wchar_t FormatMessage. It does not make much + sense to play the conversion game; we print only the code. */ + snprintf (strerr, sizeof strerr, "ec=%d", (int)GetLastError ()); +#else + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + strerr, DIM (strerr)-1, NULL); + { + /* Strip the CR,LF - we want just the string. */ + size_t n = strlen (strerr); + if (n > 2 && strerr[n-2] == '\r' && strerr[n-1] == '\n' ) + strerr[n-2] = 0; + } +#endif + return strerr; +} + +static wchar_t * +cp_to_wchar (const char *string, unsigned int codepage) +{ + int n; + size_t nbytes; + wchar_t *result; + + n = MultiByteToWideChar (codepage, 0, string, -1, NULL, 0); + if (n < 0) + { + return NULL; + } + + nbytes = (size_t)(n+1) * sizeof(*result); + if (nbytes / sizeof(*result) != (n+1)) + { + return NULL; + } + result = malloc (nbytes); + if (!result) + return NULL; + + n = MultiByteToWideChar (codepage, 0, string, -1, result, n); + if (n < 0) + { + free (result); + result = NULL; + } + return result; +} + +wchar_t * +utf8_to_wchar (const char *string) +{ + return cp_to_wchar (string, CP_UTF8); +} + +char * +stpcpy(char *a,const char *b) +{ + while( *b ) + *a++ = *b++; + *a = 0; + + return (char*)a; +} + +static char * +do_strconcat (const char *s1, va_list arg_ptr) +{ + const char *argv[48]; + size_t argc; + size_t needed; + char *buffer, *p; + + argc = 0; + argv[argc++] = s1; + needed = strlen (s1); + while (((argv[argc] = va_arg (arg_ptr, const char *)))) + { + needed += strlen (argv[argc]); + if (argc >= DIM (argv)-1) + { + return NULL; + } + argc++; + } + needed++; + buffer = malloc (needed); + if (buffer) + { + for (p = buffer, argc=0; argv[argc]; argc++) + p = stpcpy (p, argv[argc]); + } + return buffer; +} + +/* Concatenate the string S1 with all the following strings up to a + NULL. Returns a malloced buffer with the new string or NULL on a + malloc error or if too many arguments are given. */ +char * +strconcat (const char *s1, ...) +{ + va_list arg_ptr; + char *result; + + if (!s1) + result = calloc (1, 1); + else + { + va_start (arg_ptr, s1); + result = do_strconcat (s1, arg_ptr); + va_end (arg_ptr); + } + return result; +} +#endif /*HAVE_W32_SYSTEM*/ + + +#include "dotlock.c" + #define PGM "t-dotlock" - -static volatile int ctrl_c_pending; - +#ifndef HAVE_W32_SYSTEM +static volatile int ctrl_c_pending_flag; static void control_c_handler (int signo) { (void)signo; - ctrl_c_pending = 1; + ctrl_c_pending_flag = 1; } +#endif +static int +ctrl_c_pending (void) +{ +#if HAVE_W32_SYSTEM + static int count; + + return (++count > 9); +#else + return ctrl_c_pending_flag; +#endif +} + static void die (const char *format, ...) @@ -95,7 +239,7 @@ lock_and_unlock (const char *fname) die ("error creating lock file for '%s': %s", fname, strerror (errno)); inf ("lock created"); - while (!ctrl_c_pending) + while (!ctrl_c_pending ()) { if (dotlock_take (h, -1)) die ("error taking lock"); @@ -119,8 +263,15 @@ main (int argc, char **argv) if (argc > 1) fname = argv[1]; else - fname = "t-dotlock.tmp"; + { +#ifdef HAVE_W32_SYSTEM + fname = "t-dotâ’¶lock.tmp"; +#else + fname = "t-dotlock.tmp"; +#endif + } +#ifndef HAVE_W32_SYSTEM { struct sigaction nact; @@ -128,6 +279,7 @@ main (int argc, char **argv) nact.sa_flags = 0; sigaction (SIGINT, &nact, NULL); } +#endif dotlock_create (NULL, 0); /* Initialize (optional). */ @@ -140,6 +292,6 @@ main (int argc, char **argv) /* Local Variables: -compile-command: "cc -Wall -O2 -D_FILE_OFFSET_BITS=64 -o t-dotlock t-dotlock.c dotlock.c" +compile-command: "cc -Wall -O2 -D_FILE_OFFSET_BITS=64 -o t-dotlock t-dotlock.c" End: */