aboutsummaryrefslogtreecommitdiff
path: root/bpkg/archive.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-05-01 11:02:36 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-05-01 11:02:36 +0200
commit5fb0df6f63e02c141e8a0e5ad4543dea525df3fc (patch)
tree5063cce50ab142650ae8090f95bc5a4ed6f308bf /bpkg/archive.cxx
parent7263a091971f42a611f5b03239135e8c3ef9bb47 (diff)
Reimplement tar invocations to do manual decompression
This is needed to prevent tar from forking, which doesn't work reliably on MSYS2.
Diffstat (limited to 'bpkg/archive.cxx')
-rw-r--r--bpkg/archive.cxx64
1 files changed, 54 insertions, 10 deletions
diff --git a/bpkg/archive.cxx b/bpkg/archive.cxx
index 4e12e28..54ab8ea 100644
--- a/bpkg/archive.cxx
+++ b/bpkg/archive.cxx
@@ -26,7 +26,7 @@ namespace bpkg
return path_cast<dir_path> (d);
}
- process
+ pair<process, process>
start_extract (const common_options& co,
const path& a,
const path& f,
@@ -34,7 +34,30 @@ namespace bpkg
{
assert (!f.empty () && f.relative ());
- cstrings args {co.tar ().string ().c_str ()};
+ cstrings args;
+
+ // See if we need to decompress.
+ //
+ {
+ string e (a.extension ());
+
+ if (e == "gz") args.push_back ("gzip");
+ else if (e == "bzip2") args.push_back ("bzip2");
+ else if (e == "xz") args.push_back ("xz");
+ else if (e != "tar")
+ fail << "unknown compression method in " << a;
+ }
+
+ size_t i (0); // The tar command line start.
+ if (!args.empty ())
+ {
+ args.push_back ("-dc");
+ args.push_back (a.string ().c_str ());
+ args.push_back (nullptr);
+ i = args.size ();
+ }
+
+ args.push_back (co.tar ().string ().c_str ());
// Add extra options.
//
@@ -55,7 +78,7 @@ namespace bpkg
#endif
args.push_back ("-xf");
- args.push_back (a.string ().c_str ());
+ args.push_back (i == 0 ? a.string ().c_str () : "-");
// MSYS tar doesn't find archived file if it's path is provided in Windows
// notation.
@@ -64,21 +87,42 @@ namespace bpkg
args.push_back (fs.c_str ());
args.push_back (nullptr);
+ args.push_back (nullptr); // Pipe end.
+ size_t what;
try
{
- process_path pp (process::path_search (args[0]));
+ process_path dpp;
+ process_path tpp;
+
+ process dpr;
+ process tpr;
+
+ if (i != 0)
+ dpp = process::path_search (args[what = 0]);
+
+ tpp = process::path_search (args[what = i]);
if (verb >= 2)
print_process (args);
// If err is false, then redirect STDERR to STDOUT.
//
- return process (pp, args.data (), 0, -1, (err ? 2 : 1));
+ auto_fd nfd (err ? nullfd : fdnull ());
+
+ if (i != 0)
+ {
+ dpr = process (dpp, &args[what = 0], 0, -1, (err ? 2 : nfd.get ()));
+ tpr = process (tpp, &args[what = i], dpr, -1, (err ? 2 : nfd.get ()));
+ }
+ else
+ tpr = process (tpp, &args[what = 0], 0, -1, (err ? 2 : nfd.get ()));
+
+ return make_pair (move (dpr), move (tpr));
}
catch (const process_error& e)
{
- error << "unable to execute " << args[0] << ": " << e;
+ error << "unable to execute " << args[what] << ": " << e;
if (e.child)
exit (1);
@@ -91,20 +135,20 @@ namespace bpkg
extract (const common_options& o, const path& a, const path& f)
try
{
- process pr (start_extract (o, a, f));
+ pair<process, process> pr (start_extract (o, a, f));
try
{
// Do not throw when eofbit is set (end of stream reached), and
// when failbit is set (getline() failed to extract any character).
//
- ifdstream is (move (pr.in_ofd), ifdstream::badbit);
+ ifdstream is (move (pr.second.in_ofd), ifdstream::badbit);
string s;
getline (is, s, '\0');
is.close ();
- if (pr.wait ())
+ if (pr.second.wait () && pr.first.wait ())
return s;
// Fall through.
@@ -114,7 +158,7 @@ namespace bpkg
// Child exit status doesn't matter. Just wait for the process
// completion and fall through.
//
- pr.wait (); // Check throw.
+ pr.second.wait (); pr.first.wait (); // Check throw.
}
// While it is reasonable to assuming the child process issued diagnostics