diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2020-06-21 16:43:17 +0000 |
---|---|---|
committer | John Ericson <John.Ericson@Obsidian.Systems> | 2020-06-21 16:43:17 +0000 |
commit | fdeabf71601e4ec9ff797e0283d06f9b5b9d8aa5 (patch) | |
tree | 51cfb1a7b05b0641fc7c3bb755210f6cd053c395 /src/libutil | |
parent | 02928f76fdf8ab991da404d4216e97d54af19976 (diff) | |
parent | 984e521392b3f41f7cdab203e5c00f3e00e27a28 (diff) |
Merge remote-tracking branch 'upstream/master' into multi-output-hashDerivationModulo
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/ansicolor.hh | 2 | ||||
-rw-r--r-- | src/libutil/args.cc | 14 | ||||
-rw-r--r-- | src/libutil/args.hh | 1 | ||||
-rw-r--r-- | src/libutil/hash.cc | 71 | ||||
-rw-r--r-- | src/libutil/hash.hh | 18 | ||||
-rw-r--r-- | src/libutil/json.cc | 2 | ||||
-rw-r--r-- | src/libutil/tests/compression.cc | 78 | ||||
-rw-r--r-- | src/libutil/tests/hash.cc | 5 | ||||
-rw-r--r-- | src/libutil/util.cc | 4 |
9 files changed, 156 insertions, 39 deletions
diff --git a/src/libutil/ansicolor.hh b/src/libutil/ansicolor.hh index 8ae07b092..a38c2d798 100644 --- a/src/libutil/ansicolor.hh +++ b/src/libutil/ansicolor.hh @@ -11,5 +11,7 @@ namespace nix { #define ANSI_GREEN "\e[32;1m" #define ANSI_YELLOW "\e[33;1m" #define ANSI_BLUE "\e[34;1m" +#define ANSI_MAGENTA "\e[35m;1m" +#define ANSI_CYAN "\e[36m;1m" } diff --git a/src/libutil/args.cc b/src/libutil/args.cc index ce6580119..1f0e4f803 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -162,8 +162,18 @@ Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht) .labels = {"hash-algo"}, .handler = {[ht](std::string s) { *ht = parseHashType(s); - if (*ht == htUnknown) - throw UsageError("unknown hash type '%1%'", s); + }} + }; +} + +Args::Flag Args::Flag::mkHashTypeOptFlag(std::string && longName, std::optional<HashType> * oht) +{ + return Flag { + .longName = std::move(longName), + .description = "hash algorithm ('md5', 'sha1', 'sha256', or 'sha512'). Optional as can also be gotten from SRI hash itself.", + .labels = {"hash-algo"}, + .handler = {[oht](std::string s) { + *oht = std::optional<HashType> { parseHashType(s) }; }} }; } diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 154d1e6aa..433d26bba 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -85,6 +85,7 @@ protected: Handler handler; static Flag mkHashTypeFlag(std::string && longName, HashType * ht); + static Flag mkHashTypeOptFlag(std::string && longName, std::optional<HashType> * oht); }; std::map<std::string, Flag::ptr> longFlags; diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index 460d479a3..e49eb4569 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -4,6 +4,7 @@ #include <openssl/md5.h> #include <openssl/sha.h> +#include "args.hh" #include "hash.hh" #include "archive.hh" #include "util.hh" @@ -18,11 +19,13 @@ namespace nix { void Hash::init() { - if (type == htMD5) hashSize = md5HashSize; - else if (type == htSHA1) hashSize = sha1HashSize; - else if (type == htSHA256) hashSize = sha256HashSize; - else if (type == htSHA512) hashSize = sha512HashSize; - else abort(); + if (!type) abort(); + switch (*type) { + case htMD5: hashSize = md5HashSize; break; + case htSHA1: hashSize = sha1HashSize; break; + case htSHA256: hashSize = sha256HashSize; break; + case htSHA512: hashSize = sha512HashSize; break; + } assert(hashSize <= maxHashSize); memset(hash, 0, maxHashSize); } @@ -102,11 +105,18 @@ string printHash16or32(const Hash & hash) } +HashType assertInitHashType(const Hash & h) { + if (h.type) + return *h.type; + else + abort(); +} + std::string Hash::to_string(Base base, bool includeType) const { std::string s; if (base == SRI || includeType) { - s += printHashType(type); + s += printHashType(assertInitHashType(*this)); s += base == SRI ? '-' : ':'; } switch (base) { @@ -124,8 +134,10 @@ std::string Hash::to_string(Base base, bool includeType) const return s; } +Hash::Hash(std::string_view s, HashType type) : Hash(s, std::optional { type }) { } +Hash::Hash(std::string_view s) : Hash(s, std::optional<HashType>{}) { } -Hash::Hash(std::string_view s, HashType type) +Hash::Hash(std::string_view s, std::optional<HashType> type) : type(type) { size_t pos = 0; @@ -136,17 +148,17 @@ Hash::Hash(std::string_view s, HashType type) sep = s.find('-'); if (sep != string::npos) { isSRI = true; - } else if (type == htUnknown) + } else if (! type) throw BadHash("hash '%s' does not include a type", s); } if (sep != string::npos) { string hts = string(s, 0, sep); this->type = parseHashType(hts); - if (this->type == htUnknown) + if (!this->type) throw BadHash("unknown hash type '%s'", hts); - if (type != htUnknown && type != this->type) - throw BadHash("hash '%s' should have type '%s'", s, printHashType(type)); + if (type && type != this->type) + throw BadHash("hash '%s' should have type '%s'", s, printHashType(*type)); pos = sep + 1; } @@ -202,14 +214,16 @@ Hash::Hash(std::string_view s, HashType type) } else - throw BadHash("hash '%s' has wrong length for hash type '%s'", s, printHashType(type)); + throw BadHash("hash '%s' has wrong length for hash type '%s'", s, printHashType(*type)); } -Hash newHashAllowEmpty(std::string hashStr, HashType ht) +Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht) { if (hashStr.empty()) { - Hash h(ht); - warn("found empty hash, assuming '%s'", h.to_string(SRI, true)); + if (!ht) + throw BadHash("empty hash requires explicit hash type"); + Hash h(*ht); + warn("found empty hash, assuming '%s'", h.to_string(Base::SRI, true)); return h; } else return Hash(hashStr, ht); @@ -328,24 +342,35 @@ Hash compressHash(const Hash & hash, unsigned int newSize) } -HashType parseHashType(const string & s) +std::optional<HashType> parseHashTypeOpt(const string & s) { if (s == "md5") return htMD5; else if (s == "sha1") return htSHA1; else if (s == "sha256") return htSHA256; else if (s == "sha512") return htSHA512; - else return htUnknown; + else return std::optional<HashType> {}; } +HashType parseHashType(const string & s) +{ + auto opt_h = parseHashTypeOpt(s); + if (opt_h) + return *opt_h; + else + throw UsageError("unknown hash algorithm '%1%'", s); +} string printHashType(HashType ht) { - if (ht == htMD5) return "md5"; - else if (ht == htSHA1) return "sha1"; - else if (ht == htSHA256) return "sha256"; - else if (ht == htSHA512) return "sha512"; - else abort(); + switch (ht) { + case htMD5: return "md5"; break; + case htSHA1: return "sha1"; break; + case htSHA256: return "sha256"; break; + case htSHA512: return "sha512"; break; + } + // illegal hash type enum value internally, as opposed to external input + // which should be validated with nice error message. + abort(); } - } diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh index 180fb7633..0d9916508 100644 --- a/src/libutil/hash.hh +++ b/src/libutil/hash.hh @@ -10,7 +10,7 @@ namespace nix { MakeError(BadHash, Error); -enum HashType : char { htUnknown, htMD5, htSHA1, htSHA256, htSHA512 }; +enum HashType : char { htMD5, htSHA1, htSHA256, htSHA512 }; const int md5HashSize = 16; @@ -29,7 +29,7 @@ struct Hash unsigned int hashSize = 0; unsigned char hash[maxHashSize] = {}; - HashType type = htUnknown; + std::optional<HashType> type = {}; /* Create an unset hash object. */ Hash() { }; @@ -40,14 +40,18 @@ struct Hash /* Initialize the hash from a string representation, in the format "[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a Subresource Integrity hash expression). If the 'type' argument - is htUnknown, then the hash type must be specified in the + is not present, then the hash type must be specified in the string. */ - Hash(std::string_view s, HashType type = htUnknown); + Hash(std::string_view s, std::optional<HashType> type); + // type must be provided + Hash(std::string_view s, HashType type); + // hash type must be part of string + Hash(std::string_view s); void init(); /* Check whether a hash is set. */ - operator bool () const { return type != htUnknown; } + operator bool () const { return (bool) type; } /* Check whether two hash are equal. */ bool operator == (const Hash & h2) const; @@ -95,7 +99,7 @@ struct Hash }; /* Helper that defaults empty hashes to the 0 hash. */ -Hash newHashAllowEmpty(std::string hashStr, HashType ht); +Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht); /* Print a hash in base-16 if it's MD5, or base-32 otherwise. */ string printHash16or32(const Hash & hash); @@ -118,6 +122,8 @@ Hash compressHash(const Hash & hash, unsigned int newSize); /* Parse a string representing a hash type. */ HashType parseHashType(const string & s); +/* Will return nothing on parse error */ +std::optional<HashType> parseHashTypeOpt(const string & s); /* And the reverse. */ string printHashType(HashType ht); diff --git a/src/libutil/json.cc b/src/libutil/json.cc index 74e37b4c4..01331947e 100644 --- a/src/libutil/json.cc +++ b/src/libutil/json.cc @@ -173,7 +173,7 @@ JSONObject JSONPlaceholder::object() JSONPlaceholder::~JSONPlaceholder() { - assert(!first || std::uncaught_exception()); + assert(!first || std::uncaught_exceptions()); } } diff --git a/src/libutil/tests/compression.cc b/src/libutil/tests/compression.cc new file mode 100644 index 000000000..5b7a2c5b9 --- /dev/null +++ b/src/libutil/tests/compression.cc @@ -0,0 +1,78 @@ +#include "compression.hh" +#include <gtest/gtest.h> + +namespace nix { + + /* ---------------------------------------------------------------------------- + * compress / decompress + * --------------------------------------------------------------------------*/ + + TEST(compress, compressWithUnknownMethod) { + ASSERT_THROW(compress("invalid-method", "something-to-compress"), UnknownCompressionMethod); + } + + TEST(compress, noneMethodDoesNothingToTheInput) { + ref<std::string> o = compress("none", "this-is-a-test"); + + ASSERT_EQ(*o, "this-is-a-test"); + } + + TEST(decompress, decompressXzCompressed) { + auto method = "xz"; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + ref<std::string> o = decompress(method, *compress(method, str)); + + ASSERT_EQ(*o, str); + } + + TEST(decompress, decompressBzip2Compressed) { + auto method = "bzip2"; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + ref<std::string> o = decompress(method, *compress(method, str)); + + ASSERT_EQ(*o, str); + } + + TEST(decompress, decompressBrCompressed) { + auto method = "br"; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + ref<std::string> o = decompress(method, *compress(method, str)); + + ASSERT_EQ(*o, str); + } + + TEST(decompress, decompressInvalidInputThrowsCompressionError) { + auto method = "bzip2"; + auto str = "this is a string that does not qualify as valid bzip2 data"; + + ASSERT_THROW(decompress(method, str), CompressionError); + } + + /* ---------------------------------------------------------------------------- + * compression sinks + * --------------------------------------------------------------------------*/ + + TEST(makeCompressionSink, noneSinkDoesNothingToInput) { + StringSink strSink; + auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto sink = makeCompressionSink("none", strSink); + (*sink)(inputString); + sink->finish(); + + ASSERT_STREQ((*strSink.s).c_str(), inputString); + } + + TEST(makeCompressionSink, compressAndDecompress) { + StringSink strSink; + auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto decompressionSink = makeDecompressionSink("bzip2", strSink); + auto sink = makeCompressionSink("bzip2", *decompressionSink); + + (*sink)(inputString); + sink->finish(); + decompressionSink->finish(); + + ASSERT_STREQ((*strSink.s).c_str(), inputString); + } + +} diff --git a/src/libutil/tests/hash.cc b/src/libutil/tests/hash.cc index 5334b046e..412c03030 100644 --- a/src/libutil/tests/hash.cc +++ b/src/libutil/tests/hash.cc @@ -72,9 +72,4 @@ namespace nix { "7299aeadb6889018501d289e4900f7e4331b99dec4b5433a" "c7d329eeb6dd26545e96e55b874be909"); } - - TEST(hashString, hashingWithUnknownAlgoExits) { - auto s = "unknown"; - ASSERT_DEATH(hashString(HashType::htUnknown, s), ""); - } } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 667dd2edb..1268b146a 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -35,7 +35,7 @@ #endif -extern char * * environ; +extern char * * environ __attribute__((weak)); namespace nix { @@ -1199,7 +1199,7 @@ void _interrupted() /* Block user interrupts while an exception is being handled. Throwing an exception while another exception is being handled kills the program! */ - if (!interruptThrown && !std::uncaught_exception()) { + if (!interruptThrown && !std::uncaught_exceptions()) { interruptThrown = true; throw Interrupted("interrupted by the user"); } |