gpgtar,w32: Handle Unicode file names.

* tools/gpgtar.c (oUtf8Strings): New.
(opts): Add option --utf8-strings.
(parse_arguments): Set option.
* tools/gpgtar.h (opt): Add field utf8strings.
* tools/gpgtar-create.c (name_to_utf8): New.
(fillup_entry_w32): Use that.
(scan_directory): Ditto.
(scan_directory) [W32]: Convert file name to utf8.
(gpgtar_create): Convert pattern.
--

Note that this works only with file names read from a file or if the
specified files on the command line are plain ascii.  When recursing
into a directory Unicode file names work again.  This limitation is
due to  main(int, char**) which can't get the wchar version.  We could
fix that but is needs a bit more work in our init code.

GnuPG-bug-id: 4083
Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-08-21 21:28:28 +02:00
parent eec70e539e
commit 34e7703a96
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
4 changed files with 68 additions and 10 deletions

View File

@ -2093,6 +2093,12 @@ line.
Modify option @option{--files-from} to use a binary nul instead of a Modify option @option{--files-from} to use a binary nul instead of a
linefeed to separate file names. linefeed to separate file names.
@item --utf8-strings
@opindex utf8-strings
Assume that the file names read by @option{--files-from} are UTF-8
encoded. This option has an effect only on Windows where the active
code page is otherwise assumed.
@item --openpgp @item --openpgp
@opindex openpgp @opindex openpgp
This option has no effect because OpenPGP encryption and signing is This option has no effect because OpenPGP encryption and signing is

View File

@ -58,6 +58,38 @@ struct scanctrl_s
/* On Windows convert name to UTF8 and return it; caller must release
* the result. On Unix or if ALREADY_UTF8 is set, this function is a
* mere xtrystrcopy. On failure NULL is returned and ERRNO set. */
static char *
name_to_utf8 (const char *name, int already_utf8)
{
#ifdef HAVE_W32_SYSTEM
wchar_t *wstring;
char *result;
if (already_utf8)
result = xtrystrdup (name);
else
{
wstring = native_to_wchar (name);
if (!wstring)
return NULL;
result = wchar_to_utf8 (wstring);
xfree (wstring);
}
return result;
#else /*!HAVE_W32_SYSTEM */
(void)already_utf8;
return xtrystrdup (name);
#endif /*!HAVE_W32_SYSTEM */
}
/* Given a fresh header object HDR with only the name field set, try /* Given a fresh header object HDR with only the name field set, try
to gather all available info. This is the W32 version. */ to gather all available info. This is the W32 version. */
@ -73,7 +105,7 @@ fillup_entry_w32 (tar_header_t hdr)
for (p=hdr->name; *p; p++) for (p=hdr->name; *p; p++)
if (*p == '/') if (*p == '/')
*p = '\\'; *p = '\\';
wfname = native_to_wchar (hdr->name); wfname = utf8_to_wchar (hdr->name);
for (p=hdr->name; *p; p++) for (p=hdr->name; *p; p++)
if (*p == '\\') if (*p == '\\')
*p = '/'; *p = '/';
@ -213,7 +245,7 @@ fillup_entry_posix (tar_header_t hdr)
#endif /*!HAVE_W32_SYSTEM*/ #endif /*!HAVE_W32_SYSTEM*/
/* Add a new entry. The name of a director entry is ENTRYNAME; if /* Add a new entry. The name of a directory entry is ENTRYNAME; if
that is NULL, DNAME is the name of the directory itself. Under that is NULL, DNAME is the name of the directory itself. Under
Windows ENTRYNAME shall have backslashes replaced by standard Windows ENTRYNAME shall have backslashes replaced by standard
slashes. */ slashes. */
@ -225,7 +257,7 @@ add_entry (const char *dname, const char *entryname, scanctrl_t scanctrl)
char *p; char *p;
size_t dnamelen = strlen (dname); size_t dnamelen = strlen (dname);
assert (dnamelen); log_assert (dnamelen);
hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1 hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1
+ (entryname? strlen (entryname) : 0) + 1); + (entryname? strlen (entryname) : 0) + 1);
@ -300,7 +332,7 @@ scan_directory (const char *dname, scanctrl_t scanctrl)
for (p=fname; *p; p++) for (p=fname; *p; p++)
if (*p == '/') if (*p == '/')
*p = '\\'; *p = '\\';
wfname = native_to_wchar (fname); wfname = utf8_to_wchar (fname);
xfree (fname); xfree (fname);
if (!wfname) if (!wfname)
{ {
@ -323,7 +355,7 @@ scan_directory (const char *dname, scanctrl_t scanctrl)
do do
{ {
char *fname = wchar_to_native (fi.cFileName); char *fname = wchar_to_utf8 (fi.cFileName);
if (!fname) if (!fname)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
@ -760,6 +792,19 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
estream_t cipher_stream = NULL; estream_t cipher_stream = NULL;
int eof_seen = 0; int eof_seen = 0;
memset (scanctrl, 0, sizeof *scanctrl);
scanctrl->flist_tail = &scanctrl->flist;
/* { unsigned int cpno, cpno2, cpno3; */
/* cpno = GetConsoleOutputCP (); */
/* cpno2 = GetACP (); */
/* cpno3 = GetOEMCP (); */
/* log_debug ("Codepages: Console: %u ANSI: %u OEM: %u\n", */
/* cpno, cpno2, cpno3); */
/* } */
if (!inpattern) if (!inpattern)
{ {
if (!files_from || !strcmp (files_from, "-")) if (!files_from || !strcmp (files_from, "-"))
@ -778,8 +823,6 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
} }
} }
memset (scanctrl, 0, sizeof *scanctrl);
scanctrl->flist_tail = &scanctrl->flist;
if (opt.directory && gnupg_chdir (opt.directory)) if (opt.directory && gnupg_chdir (opt.directory))
{ {
@ -805,7 +848,7 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
if (!*pattern) if (!*pattern)
continue; continue;
pat = xtrystrdup (pattern); pat = name_to_utf8 (pattern, 0);
} }
else /* Read Nul or LF delimited pattern from files_from_stream. */ else /* Read Nul or LF delimited pattern from files_from_stream. */
{ {
@ -871,7 +914,7 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
if (skip_this || n < 2) if (skip_this || n < 2)
continue; continue;
pat = xtrystrdup (namebuf); pat = name_to_utf8 (namebuf, opt.utf8strings);
} }
if (!pat) if (!pat)

View File

@ -75,6 +75,7 @@ enum cmd_and_opt_values
oCMS, oCMS,
oSetFilename, oSetFilename,
oNull, oNull,
oUtf8Strings,
/* Compatibility with gpg-zip. */ /* Compatibility with gpg-zip. */
oGpgArgs, oGpgArgs,
@ -120,6 +121,12 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oFilesFrom, "files-from", ARGPARSE_s_s (oFilesFrom, "files-from",
N_("|FILE|get names to create from FILE")), N_("|FILE|get names to create from FILE")),
ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")), ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
#ifdef HAVE_W32_SYSTEM
ARGPARSE_s_n (oUtf8Strings, "utf8-strings",
N_("-T reads UTF-8 encoded names")),
#else
ARGPARSE_s_n (oUtf8Strings, "utf8-strings", "@"),
#endif
ARGPARSE_s_s (oGpgArgs, "gpg-args", "@"), ARGPARSE_s_s (oGpgArgs, "gpg-args", "@"),
ARGPARSE_s_s (oTarArgs, "tar-args", "@"), ARGPARSE_s_s (oTarArgs, "tar-args", "@"),
@ -325,6 +332,7 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts)
case oNoVerbose: opt.verbose = 0; break; case oNoVerbose: opt.verbose = 0; break;
case oFilesFrom: files_from = pargs->r.ret_str; break; case oFilesFrom: files_from = pargs->r.ret_str; break;
case oNull: null_names = 1; break; case oNull: null_names = 1; break;
case oUtf8Strings: opt.utf8strings = 1; break;
case aList: case aList:
case aDecrypt: case aDecrypt:

View File

@ -32,6 +32,7 @@ struct
unsigned int debug_level; unsigned int debug_level;
int quiet; int quiet;
int dry_run; int dry_run;
int utf8strings;
const char *gpg_program; const char *gpg_program;
strlist_t gpg_arguments; strlist_t gpg_arguments;
const char *outfile; const char *outfile;
@ -121,7 +122,7 @@ struct tar_header_s
unsigned long long nrecords; /* Number of data records. */ unsigned long long nrecords; /* Number of data records. */
char name[1]; /* Filename (dynamically extended). */ char name[1]; /* Filename (UTF-8, dynamically extended). */
}; };