summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2024-11-07 15:06:17 +0100
committerWerner Koch <wk@gnupg.org>2024-11-07 15:06:17 +0100
commit74e81f830dc26aa09f6ed3254f965d50c7f31d02 (patch)
tree690bacd47ca8cf1a0103c0b49da1fcbee9a2f4e6
parentgpg-mail-type: Assume text/plain for missing content-type. (diff)
downloadgnupg2-74e81f830dc26aa09f6ed3254f965d50c7f31d02.tar.xz
gnupg2-74e81f830dc26aa09f6ed3254f965d50c7f31d02.zip
gpgtar: Make sure to create upper directories for regular files.
* tools/gpgtar-extract.c (extract_directory): Factor parent directory creation out to .. (try_mkdir_p): new. (extract_regular): Create directory on ENOENT. * g10/pubkey-enc.c (get_it): Use log_info instead of log_error if the public key was not found for preference checking. -- If tarball was created with tar cf tarball file1.txt foo/file2.txt the tarball has no entry for foo/ and thus the extraction fails. This patch fixes this. GnuPG-bug-id: 7380 The second patch avoid a wrong exist status status line due to the use of log_error. But the actual cause needs stuill needs tobe investigated.
-rw-r--r--g10/pubkey-enc.c4
-rw-r--r--tools/gpgtar-extract.c101
2 files changed, 74 insertions, 31 deletions
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index a83d97495..4d2d6d46b 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -449,8 +449,8 @@ get_it (ctrl_t ctrl,
if (!pkb)
{
- err = -1;
- log_error ("oops: public key not found for preference check\n");
+ err = gpg_error (GPG_ERR_UNEXPECTED);
+ log_info ("oops: public key not found for preference check\n");
}
else if (pkb->pkt->pkt.public_key->selfsigversion > 3
&& dek->algo != CIPHER_ALGO_3DES
diff --git a/tools/gpgtar-extract.c b/tools/gpgtar-extract.c
index c6e3b6065..86e9c1812 100644
--- a/tools/gpgtar-extract.c
+++ b/tools/gpgtar-extract.c
@@ -67,6 +67,60 @@ check_suspicious_name (const char *name, tarinfo_t info)
}
+/* This is our version of mkdir -p. DIRECTORY is the full filename of
+ * the directory and PREFIXLEN is the length of an intial directory
+ * part which already exists. If STRIP is set filename is removed.
+ * If VERBOSE is set a diagnostic is printed to show the created
+ * directory. */
+static gpg_error_t
+try_mkdir_p (const char *directory, size_t prefixlen, int strip, int verbose)
+{
+ gpg_error_t err = 0;
+ char *fname;
+ char *p;
+
+ fname = xtrystrdup (directory);
+ if (!fname)
+ return gpg_error_from_syserror ();
+
+ if (strip) /* Strip last file name. */
+ {
+ p = strrchr (fname, '/');
+ if (p)
+ *p = 0;
+ }
+ else /* Remove a possible trailing slash. */
+ {
+ if (fname[strlen (fname)-1] == '/')
+ fname[strlen (fname)-1] = 0;
+ }
+
+ if (prefixlen >= strlen (fname))
+ goto leave; /* Nothing to create */
+
+ for (p = fname+prefixlen; (p = strchr (p, '/')); p++)
+ {
+ *p = 0;
+ err = gnupg_mkdir (fname, "-rwx------");
+ if (gpg_err_code (err) == GPG_ERR_EEXIST)
+ err = 0;
+ *p = '/';
+ if (err)
+ goto leave;
+ }
+ err = gnupg_mkdir (fname, "-rwx------");
+ if (gpg_err_code (err) == GPG_ERR_EEXIST)
+ err = 0;
+ if (!err && verbose)
+ log_info ("created '%s/'\n", fname);
+
+ leave:
+ xfree (fname);
+ return err;
+}
+
+
+
static gpg_error_t
extract_regular (estream_t stream, const char *dirname,
tarinfo_t info, tar_header_t hdr, strlist_t exthdr)
@@ -97,7 +151,6 @@ extract_regular (estream_t stream, const char *dirname,
}
fname = fname_buffer;
-
if (opt.dry_run)
outfp = es_fopen ("/dev/null", "wb");
else
@@ -105,8 +158,18 @@ extract_regular (estream_t stream, const char *dirname,
if (!outfp)
{
err = gpg_error_from_syserror ();
- log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
- goto leave;
+ /* On ENOENT, try afain after trying to create the directories. */
+ if (!opt.dry_run && gpg_err_code (GPG_ERR_ENOENT)
+ && !try_mkdir_p (fname, strlen (dirname) + 1, 1, opt.verbose))
+ {
+ outfp = es_fopen (fname, "wb,sysopen");
+ err = outfp? 0 : gpg_error_from_syserror ();
+ }
+ if (err)
+ {
+ log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
+ goto leave;
+ }
}
for (n=0; n < hdr->nrecords;)
@@ -179,40 +242,20 @@ extract_directory (const char *dirname, tarinfo_t info,
if (fname[strlen (fname)-1] == '/')
fname[strlen (fname)-1] = 0;
- if (! opt.dry_run && gnupg_mkdir (fname, "-rwx------"))
+ if (!opt.dry_run && gnupg_mkdir (fname, "-rwx------"))
{
err = gpg_error_from_syserror ();
+ /* Ignore existing directories while extracting. */
if (gpg_err_code (err) == GPG_ERR_EEXIST)
- {
- /* Ignore existing directories while extracting. */
- err = 0;
- }
-
- if (gpg_err_code (err) == GPG_ERR_ENOENT)
+ err = 0;
+ else 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. */
- int rc = 0;
- char *p;
- size_t prefixlen;
-
- /* (PREFIXLEN is the length of the new directory we use to
- * extract the tarball.) */
- prefixlen = strlen (dirname) + 1;
-
- for (p = fname+prefixlen; (p = strchr (p, '/')); p++)
- {
- *p = 0;
- rc = gnupg_mkdir (fname, "-rwx------");
- if (gpg_err_code (rc) == GPG_ERR_EEXIST)
- rc = 0;
- *p = '/';
- if (rc)
- break;
- }
- if (!rc && !gnupg_mkdir (fname, "-rwx------"))
+ if (!try_mkdir_p (fname, strlen (dirname) + 1, 0, 0))
err = 0;
}
+
if (err)
log_error ("error creating directory '%s': %s\n",
fname, gpg_strerror (err));