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*/
#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 ());

View File

@ -41,22 +41,166 @@
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#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:
*/