aboutsummaryrefslogtreecommitdiff
path: root/bpkg/archive.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/archive.cxx')
-rw-r--r--bpkg/archive.cxx165
1 files changed, 135 insertions, 30 deletions
diff --git a/bpkg/archive.cxx b/bpkg/archive.cxx
index c096701..c41c4e3 100644
--- a/bpkg/archive.cxx
+++ b/bpkg/archive.cxx
@@ -31,22 +31,45 @@ namespace bpkg
}
#endif
+ // Only the extract ('x') and list ('t') operations are supported.
+ //
static pair<cstrings, size_t>
- start_extract (const common_options& co, const path& a)
+ start (const common_options& co, char op, const path& a)
{
+ assert (op == 'x' || op == 't');
+
cstrings args;
// On Windows we default to libarchive's bsdtar with auto-decompression
// (though there is also bsdcat which we could have used).
//
- const char* tar (co.tar_specified ()
- ? co.tar ().string ().c_str ()
+ // OpenBSD tar does not support -O|--to-stdout and so far the best
+ // solution seems to require bsdtar (libarchive) or gtar (GNU tar).
+ //
+ const char* tar;
+
+ if (co.tar_specified ())
+ tar = co.tar ().string ().c_str ();
+ else
+ {
#ifdef _WIN32
- : "bsdtar"
+ tar = "bsdtar";
+#elif defined(__OpenBSD__)
+ // A bit wasteful to do this every time (and throw away the result).
+ // Oh, well, the user can always "optimize" this away by passing
+ // explicit --tar.
+ //
+ if (!process::try_path_search ("bsdtar", true).empty ())
+ tar = "bsdtar";
+ else if (!process::try_path_search ("gtar", true).empty ())
+ tar = "gtar";
+ else
+ fail << "bsdtar or gtar required on OpenBSD for -O|--to-stdout support"
+ << endf;
#else
- : "tar"
+ tar = "tar";
#endif
- );
+ }
// See if we need to decompress.
//
@@ -91,7 +114,7 @@ namespace bpkg
args.push_back ("--force-local");
#endif
- args.push_back ("-xf");
+ args.push_back (op == 'x' ? "-xf" : "-tf");
args.push_back (i == 0 ? a.string ().c_str () : "-");
return make_pair (move (args), i);
@@ -100,7 +123,7 @@ namespace bpkg
pair<process, process>
start_extract (const common_options& co, const path& a, const dir_path& d)
{
- pair<cstrings, size_t> args_i (start_extract (co, a));
+ pair<cstrings, size_t> args_i (start (co, 'x', a));
cstrings& args (args_i.first);
size_t i (args_i.second);
@@ -171,31 +194,20 @@ namespace bpkg
}
}
- pair<process, process>
- start_extract (const common_options& co,
- const path& a,
- const path& f,
- bool diag)
+ // Only the extract ('x') and list ('t') operations are supported.
+ //
+ static pair<process, process>
+ start (const common_options& co,
+ char op,
+ const path& a,
+ const cstrings& tar_args,
+ bool diag)
{
- assert (!f.empty () && f.relative ());
-
- pair<cstrings, size_t> args_i (start_extract (co, a));
+ pair<cstrings, size_t> args_i (start (co, op, a));
cstrings& args (args_i.first);
size_t i (args_i.second);
- // -O/--to-stdout -- extract to stdout.
- //
- args.push_back ("-O");
-
- // On Windows neither MSYS GNU tar nor BSD tar will find the archived file
- // if its path is provided in the Windows notation.
- //
-#ifdef _WIN32
- string fs (f.posix_string ());
- args.push_back (fs.c_str ());
-#else
- args.push_back (f.string ().c_str ());
-#endif
+ args.insert (args.end (), tar_args.begin (), tar_args.end ());
args.push_back (nullptr);
args.push_back (nullptr); // Pipe end.
@@ -245,6 +257,34 @@ namespace bpkg
}
}
+ pair<process, process>
+ start_extract (const common_options& co,
+ const path& a,
+ const path& f,
+ bool diag)
+ {
+ assert (!f.empty () && f.relative ());
+
+ cstrings args;
+ args.reserve (2);
+
+ // -O/--to-stdout -- extract to stdout.
+ //
+ args.push_back ("-O");
+
+ // On Windows neither MSYS GNU tar nor BSD tar will find the archived file
+ // if its path is provided in the Windows notation.
+ //
+#ifdef _WIN32
+ string fs (f.posix_string ());
+ args.push_back (fs.c_str ());
+#else
+ args.push_back (f.string ().c_str ());
+#endif
+
+ return start (co, 'x', a, args, diag);
+ }
+
string
extract (const common_options& o, const path& a, const path& f, bool diag)
try
@@ -253,7 +293,7 @@ namespace bpkg
try
{
- // Do not throw when eofbit is set (end of stream reached), and
+ // Do not throw when eofbit is set (end of stream is reached), and
// when failbit is set (getline() failed to extract any character).
//
ifdstream is (move (pr.second.in_ofd), ifdstream::badbit);
@@ -290,4 +330,69 @@ namespace bpkg
//
fail << "unable to extract " << f << " from " << a << ": " << e << endf;
}
+
+ paths
+ archive_contents (const common_options& o, const path& a, bool diag)
+ try
+ {
+ pair<process, process> pr (start (o, 't', a, cstrings (), diag));
+
+ try
+ {
+ paths r;
+
+ // 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.second.in_ofd), ifdstream::badbit);
+
+ for (string l; !eof (getline (is, l)); )
+ r.emplace_back (move (l));
+
+ is.close ();
+
+ if (pr.second.wait () && pr.first.wait ())
+ return r;
+
+ // Fall through.
+ }
+ catch (const invalid_path& e)
+ {
+ // Just fall through if the pipeline has failed.
+ //
+ if (pr.second.wait () && pr.first.wait ())
+ {
+ if (diag)
+ error << "unable to obtain contents for " << a
+ << ": invalid path '" << e.path << "'";
+
+ throw failed ();
+ }
+
+ // Fall through.
+ }
+ catch (const io_error&)
+ {
+ // Child exit status doesn't matter. Just wait for the process
+ // completion and fall through.
+ //
+ pr.second.wait (); pr.first.wait (); // Check throw.
+ }
+
+ // While it is reasonable to assuming the child process issued diagnostics
+ // if exited with an error status, tar, specifically, doesn't mention the
+ // archive name. So print the error message whatever the child exit status
+ // is, if the diagnostics is requested.
+ //
+ if (diag)
+ error << "unable to obtain contents for " << a;
+
+ throw failed ();
+ }
+ catch (const process_error& e)
+ {
+ // Note: this is not a tar error, so no diag check.
+ //
+ fail << "unable to obtain contents for " << a << ": " << e << endf;
+ }
}