diff options
author | Werner Koch <wk@gnupg.org> | 2010-07-16 15:19:45 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2010-07-16 15:19:45 +0200 |
commit | 8b8925a2bdbb12dd537dde20a27cdb1416c2f1ae (patch) | |
tree | 366acb6bb52e61242bb39682ddddb76615c3ba34 /tools | |
parent | Make it build on W32 again. (diff) | |
download | gnupg2-8b8925a2bdbb12dd537dde20a27cdb1416c2f1ae.tar.xz gnupg2-8b8925a2bdbb12dd537dde20a27cdb1416c2f1ae.zip |
Some work on porting dirmngr (unfinished)
Ported gpgtar to W32.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/ChangeLog | 8 | ||||
-rw-r--r-- | tools/Makefile.am | 3 | ||||
-rw-r--r-- | tools/gpgtar-create.c | 258 | ||||
-rw-r--r-- | tools/gpgtar-extract.c | 84 | ||||
-rw-r--r-- | tools/gpgtar-list.c | 3 | ||||
-rw-r--r-- | tools/gpgtar.c | 20 | ||||
-rw-r--r-- | tools/gpgtar.h | 3 |
7 files changed, 325 insertions, 54 deletions
diff --git a/tools/ChangeLog b/tools/ChangeLog index d3238b28c..5599ff578 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,11 @@ +2010-07-16 Werner Koch <wk@g10code.com> + + * gpgtar-create.c: Rewrite to better support W32. + +2010-07-01 Werner Koch <wk@g10code.com> + + * gpgtar.c: Add option --set-filename. + 2010-06-24 Werner Koch <wk@g10code.com> * gpgconf-comp.c (gpg_agent_runtime_change) diff --git a/tools/Makefile.am b/tools/Makefile.am index fc9725a72..73913de44 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -128,7 +128,8 @@ gpgtar_SOURCES = \ gpgtar-list.c \ no-libgcrypt.c gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS) -gpgtar_LDADD = $(commonpth_libs) $(PTH_LIBS) $(GPG_ERROR_LIBS) +#gpgtar_LDADD = $(commonpth_libs) $(PTH_LIBS) $(GPG_ERROR_LIBS) +gpgtar_LDADD = $(common_libs) $(GPG_ERROR_LIBS) $(W32SOCKLIBS) # Make sure that all libs are build before we use them. This is diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c index c7a75f90f..2b2c441fe 100644 --- a/tools/gpgtar-create.c +++ b/tools/gpgtar-create.c @@ -25,14 +25,14 @@ #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> -/* #ifdef HAVE_W32_SYSTEM */ -/* # define WIN32_LEAN_AND_MEAN */ -/* # include <windows.h> */ -/* #else /\*!HAVE_W32_SYSTEM*\/ */ +#ifdef HAVE_W32_SYSTEM +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#else /*!HAVE_W32_SYSTEM*/ # include <unistd.h> # include <pwd.h> # include <grp.h> -/* #endif /\*!HAVE_W32_SYSTEM*\/ */ +#endif /*!HAVE_W32_SYSTEM*/ #include <assert.h> #include "i18n.h" @@ -58,9 +58,83 @@ struct scanctrl_s /* Given a fresh header object HDR with only the name field set, try - to gather all available info. */ + to gather all available info. This is the W32 version. */ +#ifdef HAVE_W32_SYSTEM static gpg_error_t -fillup_entry (tar_header_t hdr) +fillup_entry_w32 (tar_header_t hdr) +{ + char *p; + wchar_t *wfname; + WIN32_FILE_ATTRIBUTE_DATA fad; + DWORD attr; + + for (p=hdr->name; *p; p++) + if (*p == '/') + *p = '\\'; + wfname = utf8_to_wchar (hdr->name); + for (p=hdr->name; *p; p++) + if (*p == '\\') + *p = '/'; + if (!wfname) + { + log_error ("error utf8-ing `%s': %s\n", hdr->name, w32_strerror (-1)); + return gpg_error_from_syserror (); + } + if (!GetFileAttributesExW (wfname, GetFileExInfoStandard, &fad)) + { + log_error ("error stat-ing `%s': %s\n", hdr->name, w32_strerror (-1)); + xfree (wfname); + return gpg_error_from_syserror (); + } + xfree (wfname); + + attr = fad.dwFileAttributes; + + if ((attr & FILE_ATTRIBUTE_NORMAL)) + hdr->typeflag = TF_REGULAR; + else if ((attr & FILE_ATTRIBUTE_DIRECTORY)) + hdr->typeflag = TF_DIRECTORY; + else if ((attr & FILE_ATTRIBUTE_DEVICE)) + hdr->typeflag = TF_NOTSUP; + else if ((attr & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_TEMPORARY))) + hdr->typeflag = TF_NOTSUP; + else + hdr->typeflag = TF_REGULAR; + + /* Map some attributes to USTAR defined mode bits. */ + hdr->mode = 0640; /* User may read and write, group only read. */ + if ((attr & FILE_ATTRIBUTE_DIRECTORY)) + hdr->mode |= 0110; /* Dirs are user and group executable. */ + if ((attr & FILE_ATTRIBUTE_READONLY)) + hdr->mode &= ~0200; /* Clear the user write bit. */ + if ((attr & FILE_ATTRIBUTE_HIDDEN)) + hdr->mode &= ~0707; /* Clear all user and other bits. */ + if ((attr & FILE_ATTRIBUTE_SYSTEM)) + hdr->mode |= 0004; /* Make it readable by other. */ + + /* Only set the size for a regular file. */ + if (hdr->typeflag == TF_REGULAR) + hdr->size = (fad.nFileSizeHigh * (unsigned long long)(MAXDWORD+1) + + fad.nFileSizeLow); + + hdr->mtime = (((unsigned long long)fad.ftLastWriteTime.dwHighDateTime << 32) + | fad.ftLastWriteTime.dwLowDateTime); + if (!hdr->mtime) + hdr->mtime = (((unsigned long long)fad.ftCreationTime.dwHighDateTime << 32) + | fad.ftCreationTime.dwLowDateTime); + hdr->mtime -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */ + hdr->mtime /= 10000000; /* Convert from 0.1us to seconds. */ + + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + +/* Given a fresh header obje`<ct HDR with only the name field set, try + to gather all available info. This is the POSIX version. */ +#ifndef HAVE_W32_SYSTEM +static gpg_error_t +fillup_entry_posix (tar_header_t hdr) { gpg_error_t err; struct stat sbuf; @@ -132,38 +206,36 @@ fillup_entry (tar_header_t hdr) hdr->mtime = sbuf.st_mtime; - return 0; } +#endif /*!HAVE_W32_SYSTEM*/ - +/* Add a new entry. The name of a director 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. */ static gpg_error_t -add_entry (const char *dname, size_t dnamelen, struct dirent *de, - scanctrl_t scanctrl) +add_entry (const char *dname, const char *entryname, scanctrl_t scanctrl) { gpg_error_t err; tar_header_t hdr; char *p; + size_t dnamelen = strlen (dname); assert (dnamelen); hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1 - + (de? strlen (de->d_name) : 0)); + + (entryname? strlen (entryname) : 0) + 1); if (!hdr) - { - err = gpg_error_from_syserror (); - log_error (_("error reading directory `%s': %s\n"), - dname, gpg_strerror (err)); - return err; - } + return gpg_error_from_syserror (); p = stpcpy (hdr->name, dname); - if (de) + if (entryname) { if (dname[dnamelen-1] != '/') *p++ = '/'; - strcpy (p, de->d_name); + strcpy (p, entryname); } else { @@ -171,11 +243,10 @@ add_entry (const char *dname, size_t dnamelen, struct dirent *de, hdr->name[dnamelen-1] = 0; } #ifdef HAVE_DOSISH_SYSTEM - for (p=hdr->name; *p; p++) - if (*p == '\\') - *p = '/'; + err = fillup_entry_w32 (hdr); +#else + err = fillup_entry_posix (hdr); #endif - err = fillup_entry (hdr); if (err) xfree (hdr); else @@ -194,12 +265,101 @@ static gpg_error_t scan_directory (const char *dname, scanctrl_t scanctrl) { gpg_error_t err = 0; - size_t dnamelen; + +#ifdef HAVE_W32_SYSTEM + WIN32_FIND_DATAW fi; + HANDLE hd = INVALID_HANDLE_VALUE; + char *p; + + if (!*dname) + return 0; /* An empty directory name has no entries. */ + + { + char *fname; + wchar_t *wfname; + + fname = xtrymalloc (strlen (dname) + 2 + 2 + 1); + if (!fname) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (!strcmp (dname, "/")) + strcpy (fname, "/*"); /* Trailing slash is not allowed. */ + else if (!strcmp (dname, ".")) + strcpy (fname, "*"); + else if (*dname && dname[strlen (dname)-1] == '/') + strcpy (stpcpy (fname, dname), "*"); + else if (*dname && dname[strlen (dname)-1] != '*') + strcpy (stpcpy (fname, dname), "/*"); + else + strcpy (fname, dname); + + for (p=fname; *p; p++) + if (*p == '/') + *p = '\\'; + wfname = utf8_to_wchar (fname); + xfree (fname); + if (!wfname) + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, gpg_strerror (err)); + goto leave; + } + hd = FindFirstFileW (wfname, &fi); + if (hd == INVALID_HANDLE_VALUE) + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, w32_strerror (-1)); + xfree (wfname); + goto leave; + } + xfree (wfname); + } + + do + { + char *fname = wchar_to_utf8 (fi.cFileName); + if (!fname) + { + err = gpg_error_from_syserror (); + log_error ("error utf8-ing filename: %s\n", w32_strerror (-1)); + break; + } + for (p=fname; *p; p++) + if (*p == '\\') + *p = '/'; + if (!strcmp (fname, "." ) || !strcmp (fname, "..")) + err = 0; /* Skip self and parent dir entry. */ + else if (!strncmp (dname, "./", 2) && dname[2]) + err = add_entry (dname+2, fname, scanctrl); + else + err = add_entry (dname, fname, scanctrl); + xfree (fname); + } + while (!err && FindNextFileW (hd, &fi)); + if (err) + ; + else if (GetLastError () == ERROR_NO_MORE_FILES) + err = 0; + else + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, w32_strerror (-1)); + } + + leave: + if (hd != INVALID_HANDLE_VALUE) + FindClose (hd); + +#else /*!HAVE_W32_SYSTEM*/ DIR *dir; struct dirent *de; - dnamelen = strlen (dname); - if (!dnamelen) + if (!*dname) return 0; /* An empty directory name has no entries. */ dir = opendir (dname); @@ -216,13 +376,14 @@ scan_directory (const char *dname, scanctrl_t scanctrl) if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, "..")) continue; /* Skip self and parent dir entry. */ - err = add_entry (dname, dnamelen, de, scanctrl); + err = add_entry (dname, de->d_name, scanctrl); if (err) goto leave; } leave: closedir (dir); +#endif /*!HAVE_W32_SYSTEM*/ return err; } @@ -343,6 +504,9 @@ store_uname (char *buffer, size_t length, unsigned long uid) if (!initialized || uid != lastuid) { +#ifdef HAVE_W32_SYSTEM + mem2str (lastuname, uid? "user":"root", sizeof lastuname); +#else struct passwd *pw = getpwuid (uid); lastuid = uid; @@ -354,6 +518,7 @@ store_uname (char *buffer, size_t length, unsigned long uid) log_info ("failed to get name for uid %lu\n", uid); *lastuname = 0; } +#endif } mem2str (buffer, lastuname, length); } @@ -368,6 +533,9 @@ store_gname (char *buffer, size_t length, unsigned long gid) if (!initialized || gid != lastgid) { +#ifdef HAVE_W32_SYSTEM + mem2str (lastgname, gid? "users":"root", sizeof lastgname); +#else struct group *gr = getgrgid (gid); lastgid = gid; @@ -379,6 +547,7 @@ store_gname (char *buffer, size_t length, unsigned long gid) log_info ("failed to get name for gid %lu\n", gid); *lastgname = 0; } +#endif } mem2str (buffer, lastgname, length); } @@ -446,6 +615,7 @@ build_header (void *record, tar_header_t hdr) store_uname (raw->uname, sizeof raw->uname, hdr->uid); store_gname (raw->gname, sizeof raw->gname, hdr->gid); +#ifndef HAVE_W32_SYSTEM if (hdr->typeflag == TF_SYMLINK) { int nread; @@ -460,7 +630,7 @@ build_header (void *record, tar_header_t hdr) } raw->linkname[nread] = 0; } - +#endif /*HAVE_W32_SYSTEM*/ /* Compute the checksum. */ memset (raw->checksum, ' ', sizeof raw->checksum); @@ -520,6 +690,8 @@ write_file (estream_t stream, tar_header_t hdr) while (hdr->nrecords--) { nbytes = hdr->nrecords? RECORDSIZE : (hdr->size % RECORDSIZE); + if (!nbytes) + nbytes = RECORDSIZE; nread = es_fread (record, 1, nbytes, infp); if (nread != nbytes) { @@ -572,24 +744,40 @@ gpgtar_create (char **inpattern) struct scanctrl_s scanctrl_buffer; scanctrl_t scanctrl = &scanctrl_buffer; tar_header_t hdr, *start_tail; - estream_t outstream; + estream_t outstream = NULL; memset (scanctrl, 0, sizeof *scanctrl); scanctrl->flist_tail = &scanctrl->flist; for (; (pattern = *inpattern); inpattern++) { + char *pat, *p; + if (!*pattern) continue; + + pat = xtrystrdup (pattern); + if (!pat) + { + err = gpg_error_from_syserror (); + log_error ("memory allocation problem: %s\n", gpg_strerror (err)); + goto leave; + } + for (p=pat; *p; p++) + if (*p == '\\') + *p = '/'; + if (opt.verbose > 1) - log_info ("scanning `%s'\n", pattern); + log_info ("scanning `%s'\n", pat); start_tail = scanctrl->flist_tail; - if (!pattern_valid_p (pattern)) - log_error ("skipping invalid name `%s'\n", pattern); - else if (!add_entry (pattern, strlen (pattern), NULL, scanctrl) + if (!pattern_valid_p (pat)) + log_error ("skipping invalid name `%s'\n", pat); + else if (!add_entry (pat, NULL, scanctrl) && *start_tail && ((*start_tail)->typeflag & TF_DIRECTORY)) - scan_recursive (pattern, scanctrl); + scan_recursive (pat, scanctrl); + + xfree (pat); } if (opt.outfile) diff --git a/tools/gpgtar-extract.c b/tools/gpgtar-extract.c index 002215c5d..028ac0df4 100644 --- a/tools/gpgtar-extract.c +++ b/tools/gpgtar-extract.c @@ -32,7 +32,6 @@ #include "gpgtar.h" - static gpg_error_t extract_regular (estream_t stream, const char *dirname, tar_header_t hdr) @@ -79,6 +78,8 @@ extract_regular (estream_t stream, const char *dirname, /* Fixme: Set permissions etc. */ leave: + if (!err && opt.verbose) + log_info ("extracted `%s/'\n", fname); es_fclose (outfp); if (err && fname && outfp) { @@ -96,7 +97,9 @@ extract_directory (const char *dirname, tar_header_t hdr) { gpg_error_t err; char *fname; - + size_t prefixlen; + + prefixlen = strlen (dirname) + 1; fname = strconcat (dirname, "/", hdr->name, NULL); if (!fname) { @@ -107,14 +110,40 @@ extract_directory (const char *dirname, tar_header_t hdr) else err = 0; + if (fname[strlen (fname)-1] == '/') + fname[strlen (fname)-1] = 0; + + /* Note that we don't need to care about EEXIST because we always + extract into a new hierarchy. */ if (gnupg_mkdir (fname, "-rwx------")) { err = gpg_error_from_syserror (); - log_error ("error creating directory `%s': %s\n", - fname, gpg_strerror (err)); + if (gpg_err_code (err) == GPG_ERR_ENOENT) + { + /* Try to create the directory with parents but keep the + original error code in case of a failure. */ + char *p; + int rc = 0; + + for (p = fname+prefixlen; (p = strchr (p, '/')); p++) + { + *p = 0; + rc = gnupg_mkdir (fname, "-rwx------"); + *p = '/'; + if (rc) + break; + } + if (!rc && !gnupg_mkdir (fname, "-rwx------")) + err = 0; + } + if (err) + log_error ("error creating directory `%s': %s\n", + fname, gpg_strerror (err)); } leave: + if (!err && opt.verbose) + log_info ("created `%s/'\n", fname); xfree (fname); return err; } @@ -155,7 +184,8 @@ extract (estream_t stream, const char *dirname, tar_header_t hdr) { char record[RECORDSIZE]; - log_info ("unsupported file type for `%s' - skipped\n", hdr->name); + log_info ("unsupported file type %d for `%s' - skipped\n", + (int)hdr->typeflag, hdr->name); for (err = 0, n=0; !err && n < hdr->nrecords; n++) err = read_record (stream, record); } @@ -171,9 +201,31 @@ static char * create_directory (const char *dirprefix) { gpg_error_t err = 0; + char *prefix_buffer = NULL; char *dirname = NULL; + size_t n; int idx; + /* Remove common suffixes. */ + n = strlen (dirprefix); + if (n > 4 && (!compare_filenames (dirprefix + n - 4, EXTSEP_S "gpg") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "pgp") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "asc") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "pem") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "p7e"))) + { + prefix_buffer = xtrystrdup (dirprefix); + if (!prefix_buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } + prefix_buffer[n-4] = 0; + dirprefix = prefix_buffer; + } + + + for (idx=1; idx < 5000; idx++) { xfree (dirname); @@ -184,14 +236,14 @@ create_directory (const char *dirprefix) goto leave; } if (!gnupg_mkdir (dirname, "-rwx------")) - goto leave; + goto leave; /* Ready. */ if (errno != EEXIST && errno != ENOTDIR) { err = gpg_error_from_syserror (); goto leave; } } - err = gpg_error_from_syserror (); + err = gpg_error (GPG_ERR_LIMIT_REACHED); leave: if (err) @@ -201,6 +253,7 @@ create_directory (const char *dirprefix) xfree (dirname); dirname = NULL; } + xfree (prefix_buffer); return dirname; } @@ -217,9 +270,6 @@ gpgtar_extract (const char *filename) if (filename) { - dirprefix = strrchr (filename, '/'); - if (dirprefix) - dirprefix++; stream = es_fopen (filename, "rb"); if (!stream) { @@ -231,6 +281,20 @@ gpgtar_extract (const char *filename) else stream = es_stdin; /* FIXME: How can we enforce binary mode? */ + + if (filename) + { + dirprefix = strrchr (filename, '/'); + if (dirprefix) + dirprefix++; + } + else if (opt.filename) + { + dirprefix = strrchr (opt.filename, '/'); + if (dirprefix) + dirprefix++; + } + if (!dirprefix || !*dirprefix) dirprefix = "GPGARCH"; diff --git a/tools/gpgtar-list.c b/tools/gpgtar-list.c index 82711c19e..1de15b58c 100644 --- a/tools/gpgtar-list.c +++ b/tools/gpgtar-list.c @@ -89,8 +89,7 @@ parse_header (const void *record, const char *filename) for (namelen=0; namelen < sizeof raw->name && raw->name[namelen]; namelen++) ; if (namelen == sizeof raw->name) - log_info ("%s: warning: name not terminated by a nul byte\n", - filename); + log_info ("%s: warning: name not terminated by a nul byte\n", filename); for (n=namelen+1; n < sizeof raw->name; n++) if (raw->name[n]) { diff --git a/tools/gpgtar.c b/tools/gpgtar.c index 555fe39dc..8a9aaaf9b 100644 --- a/tools/gpgtar.c +++ b/tools/gpgtar.c @@ -59,6 +59,7 @@ enum cmd_and_opt_values aSignEncrypt, oSkipCrypto, + oSetFilename, aList }; @@ -82,6 +83,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")), ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")), + ARGPARSE_s_s (oSetFilename, "set-filename", "@"), ARGPARSE_end () }; @@ -175,6 +177,7 @@ main (int argc, char **argv) switch (pargs.r_opt) { case oOutput: opt.outfile = pargs.r.ret_str; break; + case oSetFilename: opt.filename = pargs.r.ret_str; break; case oQuiet: opt.quiet = 1; break; case oVerbose: opt.verbose++; break; case oNoVerbose: opt.verbose = 0; break; @@ -208,6 +211,8 @@ main (int argc, char **argv) if (argc > 1) usage (1); fname = argc ? *argv : NULL; + if (opt.filename) + log_info ("note: ignoring option --set-filename\n"); if (skip_crypto) gpgtar_list (fname); else @@ -217,6 +222,8 @@ main (int argc, char **argv) case aEncrypt: if (!argc) usage (1); + if (opt.filename) + log_info ("note: ignoring option --set-filename\n"); if (skip_crypto) gpgtar_create (argv); else @@ -298,6 +305,7 @@ write_record (estream_t stream, const void *record) /* Return true if FP is an unarmored OpenPGP message. Note that this fucntion reads a few bytes from FP but pushes them back. */ +#if 0 static int openpgp_message_p (estream_t fp) { @@ -332,7 +340,7 @@ openpgp_message_p (estream_t fp) } return 0; } - +#endif @@ -340,7 +348,8 @@ openpgp_message_p (estream_t fp) static void tar_and_encrypt (char **inpattern) { - + (void)inpattern; + log_error ("tar_and_encrypt has not yet been implemented\n"); } @@ -348,8 +357,8 @@ tar_and_encrypt (char **inpattern) static void decrypt_and_untar (const char *fname) { - - + (void)fname; + log_error ("decrypt_and_untar has not yet been implemented\n"); } @@ -357,5 +366,6 @@ decrypt_and_untar (const char *fname) static void decrypt_and_list (const char *fname) { - + (void)fname; + log_error ("decrypt_and_list has not yet been implemented\n"); } diff --git a/tools/gpgtar.h b/tools/gpgtar.h index 57fb34a48..08dfcf8b7 100644 --- a/tools/gpgtar.h +++ b/tools/gpgtar.h @@ -27,8 +27,9 @@ struct { int verbose; int quiet; - char *outfile; + const char *outfile; int symmetric; + const char *filename; } opt; |