diff options
-rw-r--r-- | bpkg/archive.cxx | 14 | ||||
-rw-r--r-- | bpkg/auth.cxx | 8 | ||||
-rw-r--r-- | bpkg/buildfile | 3 | ||||
-rw-r--r-- | bpkg/checksum.cxx | 7 | ||||
-rw-r--r-- | bpkg/fetch.cxx | 42 | ||||
-rw-r--r-- | bpkg/pkg-unpack.cxx | 6 | ||||
-rw-r--r-- | bpkg/rep-create.cxx | 9 | ||||
-rwxr-xr-x | tests/test.sh | 84 |
8 files changed, 124 insertions, 49 deletions
diff --git a/bpkg/archive.cxx b/bpkg/archive.cxx index b0c7ab7..0edf09d 100644 --- a/bpkg/archive.cxx +++ b/bpkg/archive.cxx @@ -48,9 +48,21 @@ namespace bpkg // args.push_back ("-O"); + // An archive name that has a colon in it specifies a file or device on a + // remote machine. That makes it impossible to use absolute Windows paths + // unless we add the --force-local option. + // + args.push_back ("--force-local"); + args.push_back ("-xf"); args.push_back (a.string ().c_str ()); - args.push_back (f.string ().c_str ()); + + // MSYS tar doesn't find archived file if it's path is provided in Windows + // notation. + // + string fs (f.posix_string ()); + args.push_back (fs.c_str ()); + args.push_back (nullptr); if (verb >= 2) diff --git a/bpkg/auth.cxx b/bpkg/auth.cxx index 5296bc8..591c6a5 100644 --- a/bpkg/auth.cxx +++ b/bpkg/auth.cxx @@ -679,7 +679,9 @@ namespace bpkg try { - ofdstream os (pr.out_fd); + // Write the signature to the openssl process input in the binary mode. + // + ofdstream os (pr.out_fd, fdtranslate::binary); os.exceptions (ofdstream::badbit); for (const auto& c: sm.signature) @@ -763,7 +765,9 @@ namespace bpkg process pr (start_openssl ( co, "pkeyutl", {"-sign", "-inkey", key_name.c_str ()}, true, true)); - ifdstream is (pr.in_ofd); + // Read the signature from the openssl process output in the binary mode. + // + ifdstream is (pr.in_ofd, fdtranslate::binary); is.exceptions (ifdstream::badbit); try diff --git a/bpkg/buildfile b/bpkg/buildfile index dec1aa7..8436c7c 100644 --- a/bpkg/buildfile +++ b/bpkg/buildfile @@ -4,8 +4,9 @@ import libs = libbpkg%lib{bpkg} import libs += libbutl%lib{butl} -import libs += libodb%lib{odb} import libs += libodb-sqlite%lib{odb-sqlite} +import libs += libodb%lib{odb} +import libs += libsqlite3%lib{sqlite3} # @@ For now for static linking. exe{bpkg}: \ {hxx cxx}{ archive } \ diff --git a/bpkg/checksum.cxx b/bpkg/checksum.cxx index 95f2d80..3c9c4e5 100644 --- a/bpkg/checksum.cxx +++ b/bpkg/checksum.cxx @@ -269,7 +269,12 @@ namespace bpkg try { - return f (sha256_path, o.sha256_option ()); + process pr (f (sha256_path, o.sha256_option ())); + + // Prevent any data modifications on the way to the hashing program. + // + fdmode (pr.out_fd, fdtranslate::binary); + return pr; } catch (const process_error& e) { diff --git a/bpkg/fetch.cxx b/bpkg/fetch.cxx index 89c93e2..c4e441a 100644 --- a/bpkg/fetch.cxx +++ b/bpkg/fetch.cxx @@ -538,23 +538,26 @@ namespace bpkg try { - ifdstream is (pr.in_ofd); + // Unfortunately we cannot read from the original source twice as we do + // below for files. There doesn't seem to be anything better than reading + // the entire file into memory and then streaming it twice, once to + // calculate the checksum and the second time to actually parse. We need + // to read the original stream in the binary mode for the checksum + // calculation, then use the binary data to create the text stream for + // the manifest parsing. + // + ifdstream is (pr.in_ofd, fdtranslate::binary); is.exceptions (ifdstream::badbit | ifdstream::failbit); - // Unfortunately we cannot rewind STDOUT as we do below for files. There - // doesn't seem to be anything better than reading the entire file into - // memory and then streaming it twice, once to calculate the checksum - // and the second time to actually parse. - // - stringstream ss; - ss << is.rdbuf (); + stringstream bs (ios::in | ios::out | ios::binary); + bs << is.rdbuf (); is.close (); - string sha256sum (sha256 (o, ss)); + string sha256sum (sha256 (o, bs)); - ss.clear (); ss.seekg (0); // Rewind. + istringstream ts (bs.str ()); // Text mode. - manifest_parser mp (ss, url); + manifest_parser mp (ts, url); M m (mp, ignore_unknown); if (pr.wait ()) @@ -644,16 +647,17 @@ namespace bpkg try { - ifstream ifs; - ifs.exceptions (ofstream::badbit | ofstream::failbit); - ifs.open (f.string ()); - + // We can not use the same file stream for both calculating the checksum + // and reading the manifest. The file should be opened in the binary + // mode for the first operation and in the text mode for the second one. + // string sha256sum; if (o != nullptr) - { - sha256sum = sha256 (*o, ifs); - ifs.seekg (0); // Rewind the file stream. - } + sha256sum = sha256 (*o, f); // Read file in the binary mode. + + ifstream ifs; + ifs.exceptions (ofstream::badbit | ofstream::failbit); + ifs.open (f.string ()); // Open file in the text mode. manifest_parser mp (ifs, f.string ()); return make_pair (M (mp, ignore_unknown), move (sha256sum)); diff --git a/bpkg/pkg-unpack.cxx b/bpkg/pkg-unpack.cxx index 8eedb1c..4424017 100644 --- a/bpkg/pkg-unpack.cxx +++ b/bpkg/pkg-unpack.cxx @@ -172,6 +172,12 @@ namespace bpkg args.push_back ("-C"); args.push_back (c.string ().c_str ()); + // An archive name that has a colon in it specifies a file or device on a + // remote machine. That makes it impossible to use absolute Windows paths + // unless we add the --force-local option. + // + args.push_back ("--force-local"); + args.push_back ("-xf"); args.push_back (a.string ().c_str ()); args.push_back (nullptr); diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx index 2ab52fb..61e3f81 100644 --- a/bpkg/rep-create.cxx +++ b/bpkg/rep-create.cxx @@ -219,7 +219,12 @@ namespace bpkg { ofstream ofs; ofs.exceptions (ofstream::badbit | ofstream::failbit); - ofs.open (p.string ()); + + // While we can do nothing about repositories files edited on Windows + // and littered with the carriage return characters, there is no + // reason to litter the auto-generated packages and signature files. + // + ofs.open (p.string (), ofstream::out | ofstream::binary); manifest_serializer s (ofs, p.string ()); manifests.serialize (s); @@ -242,7 +247,7 @@ namespace bpkg ofstream ofs; ofs.exceptions (ofstream::badbit | ofstream::failbit); - ofs.open (p.string ()); + ofs.open (p.string (), ofstream::out | ofstream::binary); manifest_serializer s (ofs, p.string ()); m.serialize (s); diff --git a/tests/test.sh b/tests/test.sh index 3a56c10..4752698 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -32,6 +32,12 @@ trap 'exit 1' ERR +tmp_file=`mktemp` + +# Remove temporary file on exit. Cover the case when exit due to an error. +# +trap 'rm -f $tmp_file' EXIT + function error () { echo "$*" 1>&2 @@ -41,6 +47,10 @@ function error () bpkg="../bpkg/bpkg" cfg=/tmp/conf +if [ "${MSYSTEM:0:5}" = "MINGW" ]; then + msys=y +fi + verbose=n remote=n options= @@ -79,19 +89,16 @@ fi bpkg="$bpkg $options" -# Repository location, name, and absolute location prefixes. Note that the -# local path is carefully crafted so that we end up with the same repository -# names in both cases. This is necessary for the authentication tests to work -# in both cases. +# Repository location and name prefixes. Note that the local path is carefully +# crafted so that we end up with the same repository names in both cases. This +# is necessary for the authentication tests to work in both cases. # if [ "$remote" = "y" ]; then rep=https://build2.org/bpkg/1 repn=build2.org/ - repa=$rep else rep=pkg/1/build2.org repn=build2.org/ - repa=`pwd`/$rep fi # @@ -115,10 +122,8 @@ function test () if [ -t 0 ]; then $bpkg $cmd $ops $* else - # There is no way to get the exit code in process substitution - # so ruin the output. - # - diff -u - <($bpkg $cmd $ops $* || echo "<invalid output>") + $bpkg $cmd $ops $* >$tmp_file + diff --strip-trailing-cr -u - $tmp_file fi if [ $? -ne 0 ]; then @@ -196,6 +201,21 @@ function edit () mv $path.bak $path } +# Repository absolute location from a relative path. +# +function location () +{ + if [ "$remote" = "y" ]; then + echo $rep/$1 + elif [ "$msys" = "y" ]; then + # Convert Windows path like c:/abc/xyz to the c:\abc\xyz canonical form. + # + echo `pwd -W`/$rep/$1 | sed 's%/%\\%g' + else + echo `pwd`/$rep/$1 + fi +} + ## ## Low-level commands. ## @@ -233,13 +253,13 @@ test rep-create pkg/1/build2.org/common/bar/unstable fail rep-info # repository location expected test rep-info --trust-yes $rep/common/foo/testing <<EOF -${repn}common/foo/testing $repa/common/foo/testing -complement ${repn}common/foo/stable $repa/common/foo/stable +${repn}common/foo/testing `location common/foo/testing` +complement ${repn}common/foo/stable `location common/foo/stable` libfoo 1.1.0 EOF test rep-info -m -r -n --trust-yes $rep/common/bar/unstable <<EOF -${repn}common/bar/unstable $repa/common/bar/unstable +${repn}common/bar/unstable `location common/bar/unstable` : 1 location: ../../foo/testing : @@ -276,6 +296,26 @@ location: libbar-1.1.1.tar.gz sha256sum: d09700602ff78ae405b6d4850e34660e939d27676e015a23b549884497c8bb45 EOF +hello_fp=`rep_cert_fp pkg/1/build2.org/common/hello` +test rep-info -m -p --trust $hello_fp $rep/common/hello <<EOF +: 1 +sha256sum: 8d324fa7911038778b215d28805c6546e737e0092f79f7bd167cf2e28f4ad96f +: +name: libhello +version: 1.0.0+1 +summary: The "Hello World" example library +license: MIT +tags: c++, hello, world, example +description: \\ +A simple library that implements the "Hello World" example in C++. Its primary +goal is to show a canonical build2/bpkg project/package. +\\ +url: http://www.example.org/libhello +email: hello-users@example.org +requires: c++11 +location: libhello-1.0.0+1.tar.gz +sha256sum: ceff9f39dbff496ece817d6806ab3723b065dcdff1734683fe64a60c103f7f9b +EOF ## ## cfg-create @@ -321,7 +361,6 @@ fail cfg-fetch # no repositories # hello repository # -hello_fp=`rep_cert_fp pkg/1/build2.org/common/hello` test cfg-create --wipe test cfg-add $rep/common/hello test cfg-fetch --trust $hello_fp @@ -361,7 +400,6 @@ test cfg-add $rep/fetch/t1 fail pkg-fetch libfoo/1.0.0 # no packages test cfg-fetch --trust-yes fail pkg-fetch libfoo/2+1.0.0 # not available - test cfg-create --wipe test cfg-add $rep/fetch/t1 test cfg-fetch --trust-yes @@ -1539,44 +1577,44 @@ fail cfg-fetch --trust-yes # packages file signature:mismatch # test cfg-create --wipe test rep-info --trust-no --trust $signed_fp -d $cfg $rep/auth/signed <<EOF -${repn}auth/signed $repa/auth/signed +${repn}auth/signed `location auth/signed` libfoo 1.0.0 EOF test rep-info --trust-no -d $cfg $rep/auth/signed <<EOF -${repn}auth/signed $repa/auth/signed +${repn}auth/signed `location auth/signed` libfoo 1.0.0 EOF test cfg-create --wipe test rep-info --trust-yes $rep/auth/signed <<EOF -${repn}auth/signed $repa/auth/signed +${repn}auth/signed `location auth/signed` libfoo 1.0.0 EOF fail rep-info --trust-no $rep/auth/signed <<EOF -${repn}auth/signed $repa/auth/signed +${repn}auth/signed `location auth/signed` libfoo 1.0.0 EOF test cfg-create --wipe test rep-info --trust-yes -d $cfg $rep/auth/unsigned1 <<EOF -${repn}auth/unsigned1 $repa/auth/unsigned1 +${repn}auth/unsigned1 `location auth/unsigned1` libfoo 1.0.0 EOF test rep-info --trust-no -d $cfg $rep/auth/unsigned2 <<EOF -${repn}auth/unsigned2 $repa/auth/unsigned2 +${repn}auth/unsigned2 `location auth/unsigned2` libfoo 1.0.0 EOF test cfg-create --wipe test rep-info --trust-yes $rep/auth/unsigned1 <<EOF -${repn}auth/unsigned1 $repa/auth/unsigned1 +${repn}auth/unsigned1 `location auth/unsigned1` libfoo 1.0.0 EOF fail rep-info --trust-no $rep/auth/unsigned1 <<EOF -${repn}auth/unsigned1 $repa/auth/unsigned1 +${repn}auth/unsigned1 `location auth/unsigned1` libfoo 1.0.0 EOF |