diff --git a/doc/tools.texi b/doc/tools.texi index 7779af43d..8eb77401e 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -2093,6 +2093,12 @@ line. Modify option @option{--files-from} to use a binary nul instead of a 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 @opindex openpgp This option has no effect because OpenPGP encryption and signing is diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c index 9921074a3..8a54c70ee 100644 --- a/tools/gpgtar-create.c +++ b/tools/gpgtar-create.c @@ -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 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++) if (*p == '/') *p = '\\'; - wfname = native_to_wchar (hdr->name); + wfname = utf8_to_wchar (hdr->name); for (p=hdr->name; *p; p++) if (*p == '\\') *p = '/'; @@ -213,7 +245,7 @@ fillup_entry_posix (tar_header_t hdr) #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 Windows ENTRYNAME shall have backslashes replaced by standard slashes. */ @@ -225,7 +257,7 @@ add_entry (const char *dname, const char *entryname, scanctrl_t scanctrl) char *p; size_t dnamelen = strlen (dname); - assert (dnamelen); + log_assert (dnamelen); hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1 + (entryname? strlen (entryname) : 0) + 1); @@ -300,7 +332,7 @@ scan_directory (const char *dname, scanctrl_t scanctrl) for (p=fname; *p; p++) if (*p == '/') *p = '\\'; - wfname = native_to_wchar (fname); + wfname = utf8_to_wchar (fname); xfree (fname); if (!wfname) { @@ -323,7 +355,7 @@ scan_directory (const char *dname, scanctrl_t scanctrl) do { - char *fname = wchar_to_native (fi.cFileName); + char *fname = wchar_to_utf8 (fi.cFileName); if (!fname) { 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; 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 (!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)) { @@ -805,7 +848,7 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names, if (!*pattern) continue; - pat = xtrystrdup (pattern); + pat = name_to_utf8 (pattern, 0); } 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) continue; - pat = xtrystrdup (namebuf); + pat = name_to_utf8 (namebuf, opt.utf8strings); } if (!pat) diff --git a/tools/gpgtar.c b/tools/gpgtar.c index 4a5a00a1f..a06e870ad 100644 --- a/tools/gpgtar.c +++ b/tools/gpgtar.c @@ -75,6 +75,7 @@ enum cmd_and_opt_values oCMS, oSetFilename, oNull, + oUtf8Strings, /* Compatibility with gpg-zip. */ oGpgArgs, @@ -120,6 +121,12 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oFilesFrom, "files-from", N_("|FILE|get names to create from FILE")), 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 (oTarArgs, "tar-args", "@"), @@ -325,6 +332,7 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts) case oNoVerbose: opt.verbose = 0; break; case oFilesFrom: files_from = pargs->r.ret_str; break; case oNull: null_names = 1; break; + case oUtf8Strings: opt.utf8strings = 1; break; case aList: case aDecrypt: diff --git a/tools/gpgtar.h b/tools/gpgtar.h index 3e7aa5ed6..c931b8247 100644 --- a/tools/gpgtar.h +++ b/tools/gpgtar.h @@ -32,6 +32,7 @@ struct unsigned int debug_level; int quiet; int dry_run; + int utf8strings; const char *gpg_program; strlist_t gpg_arguments; const char *outfile; @@ -121,7 +122,7 @@ struct tar_header_s unsigned long long nrecords; /* Number of data records. */ - char name[1]; /* Filename (dynamically extended). */ + char name[1]; /* Filename (UTF-8, dynamically extended). */ };