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 <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-10-20 13:38:11 +02:00
parent 390497ea11
commit b47c355b18
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 192 additions and 27 deletions

View File

@ -471,6 +471,21 @@ map_w32_to_errno (DWORD w32_err)
} }
#endif /*HAVE_DOSISH_SYSTEM*/ #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 /* Entirely disable all locking. This function should be called
before any locking is done. It may be called right at startup of 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; h->next = all_lockfiles;
all_lockfiles = h; all_lockfiles = h;
h->lockname = xtrymalloc ( strlen (file_to_lock) + 6 ); h->lockname = strconcat (file_to_lock, EXTSEP_S "lock", NULL);
if (!h->lockname) if (!h->lockname)
{ {
all_lockfiles = h->next; all_lockfiles = h->next;
@ -802,7 +817,6 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
xfree (h); xfree (h);
return NULL; 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 /* 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 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 reasons why a lock file can't be created and thus the process
would not stop as expected but spin until Windows crashes. Our would not stop as expected but spin until Windows crashes. Our
solution is to keep the lock file open; that does not harm. */ solution is to keep the lock file open; that does not harm. */
{ if (any8bitchar (h->lockname))
#ifdef HAVE_W32CE_SYSTEM {
wchar_t *wname = utf8_to_wchar (h->lockname); wchar_t *wname = utf8_to_wchar (h->lockname);
if (wname) if (wname)
h->lockhd = CreateFile (wname, h->lockhd = CreateFileW (wname,
GENERIC_READ|GENERIC_WRITE, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, 0, NULL); NULL, OPEN_ALWAYS, 0, NULL);
else else
h->lockhd = INVALID_HANDLE_VALUE; h->lockhd = INVALID_HANDLE_VALUE;
xfree (wname); xfree (wname);
#else }
h->lockhd = CreateFile (h->lockname, else
GENERIC_READ|GENERIC_WRITE, h->lockhd = CreateFileA (h->lockname,
FILE_SHARE_READ|FILE_SHARE_WRITE, GENERIC_READ|GENERIC_WRITE,
NULL, OPEN_ALWAYS, 0, NULL); FILE_SHARE_READ|FILE_SHARE_WRITE,
#endif NULL, OPEN_ALWAYS, 0, NULL);
}
if (h->lockhd == INVALID_HANDLE_VALUE) if (h->lockhd == INVALID_HANDLE_VALUE)
{ {
int saveerrno = map_w32_to_errno (GetLastError ()); int saveerrno = map_w32_to_errno (GetLastError ());

View File

@ -41,22 +41,166 @@
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#ifdef HAVE_W32_SYSTEM
# include "windows.h"
#endif
#include "dotlock.h" #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" #define PGM "t-dotlock"
#ifndef HAVE_W32_SYSTEM
static volatile int ctrl_c_pending; static volatile int ctrl_c_pending_flag;
static void static void
control_c_handler (int signo) control_c_handler (int signo)
{ {
(void)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 static void
die (const char *format, ...) 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)); die ("error creating lock file for '%s': %s", fname, strerror (errno));
inf ("lock created"); inf ("lock created");
while (!ctrl_c_pending) while (!ctrl_c_pending ())
{ {
if (dotlock_take (h, -1)) if (dotlock_take (h, -1))
die ("error taking lock"); die ("error taking lock");
@ -119,8 +263,15 @@ main (int argc, char **argv)
if (argc > 1) if (argc > 1)
fname = argv[1]; fname = argv[1];
else 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; struct sigaction nact;
@ -128,6 +279,7 @@ main (int argc, char **argv)
nact.sa_flags = 0; nact.sa_flags = 0;
sigaction (SIGINT, &nact, NULL); sigaction (SIGINT, &nact, NULL);
} }
#endif
dotlock_create (NULL, 0); /* Initialize (optional). */ dotlock_create (NULL, 0); /* Initialize (optional). */
@ -140,6 +292,6 @@ main (int argc, char **argv)
/* /*
Local Variables: 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: End:
*/ */