aboutsummaryrefslogtreecommitdiff
path: root/nix/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'nix/libutil')
-rw-r--r--nix/libutil/hash.cc101
-rw-r--r--nix/libutil/util.cc62
-rw-r--r--nix/libutil/util.hh6
3 files changed, 75 insertions, 94 deletions
diff --git a/nix/libutil/hash.cc b/nix/libutil/hash.cc
index 050446610f..2da00a53de 100644
--- a/nix/libutil/hash.cc
+++ b/nix/libutil/hash.cc
@@ -84,7 +84,7 @@ string printHash(const Hash & hash)
return string(buf, hash.hashSize * 2);
}
-
+
Hash parseHash(HashType ht, const string & s)
{
Hash hash(ht);
@@ -92,7 +92,7 @@ Hash parseHash(HashType ht, const string & s)
throw Error(format("invalid hash `%1%'") % s);
for (unsigned int i = 0; i < hash.hashSize; i++) {
string s2(s, i * 2, 2);
- if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
+ if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
throw Error(format("invalid hash `%1%'") % s);
std::istringstream str(s2);
int n;
@@ -103,24 +103,6 @@ Hash parseHash(HashType ht, const string & s)
}
-static unsigned char divMod(unsigned char * bytes, unsigned char y)
-{
- unsigned int borrow = 0;
-
- int pos = Hash::maxHashSize - 1;
- while (pos >= 0 && !bytes[pos]) --pos;
-
- for ( ; pos >= 0; --pos) {
- unsigned int s = bytes[pos] + (borrow << 8);
- unsigned int d = s / y;
- borrow = s % y;
- bytes[pos] = d;
- }
-
- return borrow;
-}
-
-
unsigned int hashLength32(const Hash & hash)
{
return (hash.hashSize * 8 - 1) / 5 + 1;
@@ -136,19 +118,19 @@ string printHash32(const Hash & hash)
Hash hash2(hash);
unsigned int len = hashLength32(hash);
- const char * chars = base32Chars.data();
-
- string s(len, '0');
-
- int pos = len - 1;
- while (pos >= 0) {
- unsigned char digit = divMod(hash2.hash, 32);
- s[pos--] = chars[digit];
+ string s;
+ s.reserve(len);
+
+ for (int n = len - 1; n >= 0; n--) {
+ unsigned int b = n * 5;
+ unsigned int i = b / 8;
+ unsigned int j = b % 8;
+ unsigned char c =
+ (hash.hash[i] >> j)
+ | (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j));
+ s.push_back(base32Chars[c & 0x1f]);
}
- for (unsigned int i = 0; i < hash2.maxHashSize; ++i)
- assert(hash2.hash[i] == 0);
-
return s;
}
@@ -159,51 +141,24 @@ string printHash16or32(const Hash & hash)
}
-static bool mul(unsigned char * bytes, unsigned char y, int maxSize)
-{
- unsigned char carry = 0;
-
- for (int pos = 0; pos < maxSize; ++pos) {
- unsigned int m = bytes[pos] * y + carry;
- bytes[pos] = m & 0xff;
- carry = m >> 8;
- }
-
- return carry;
-}
-
-
-static bool add(unsigned char * bytes, unsigned char y, int maxSize)
-{
- unsigned char carry = y;
-
- for (int pos = 0; pos < maxSize; ++pos) {
- unsigned int m = bytes[pos] + carry;
- bytes[pos] = m & 0xff;
- carry = m >> 8;
- if (carry == 0) break;
- }
-
- return carry;
-}
-
-
Hash parseHash32(HashType ht, const string & s)
{
Hash hash(ht);
+ unsigned int len = hashLength32(ht);
+ assert(s.size() == len);
- const char * chars = base32Chars.data();
-
- for (unsigned int i = 0; i < s.length(); ++i) {
- char c = s[i];
+ for (unsigned int n = 0; n < len; ++n) {
+ char c = s[len - n - 1];
unsigned char digit;
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
- if (chars[digit] == c) break;
+ if (base32Chars[digit] == c) break;
if (digit >= 32)
- throw Error(format("invalid base-32 hash `%1%'") % s);
- if (mul(hash.hash, 32, hash.hashSize) ||
- add(hash.hash, digit, hash.hashSize))
- throw Error(format("base-32 hash `%1%' is too large") % s);
+ throw Error(format("invalid base-32 hash '%1%'") % s);
+ unsigned int b = n * 5;
+ unsigned int i = b / 8;
+ unsigned int j = b % 8;
+ hash.hash[i] |= digit << j;
+ if (i < hash.hashSize - 1) hash.hash[i + 1] |= digit >> (8 - j);
}
return hash;
@@ -299,7 +254,7 @@ Hash hashFile(HashType ht, const Path & path)
if (n == -1) throw SysError(format("reading file `%1%'") % path);
update(ht, ctx, buf, n);
}
-
+
finish(ht, ctx, hash.hash);
return hash;
}
@@ -311,7 +266,7 @@ HashSink::HashSink(HashType ht) : ht(ht)
bytes = 0;
start(ht, *ctx);
}
-
+
HashSink::~HashSink()
{
bufPos = 0;
@@ -369,7 +324,7 @@ HashType parseHashType(const string & s)
else return htUnknown;
}
-
+
string printHashType(HashType ht)
{
if (ht == htMD5) return "md5";
@@ -378,5 +333,5 @@ string printHashType(HashType ht)
else throw Error("cannot print unknown hash type");
}
-
+
}
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index a4a1ddb12a..dab4235b04 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -19,6 +19,10 @@
#include <sys/syscall.h>
#endif
+#ifdef __linux__
+#include <sys/prctl.h>
+#endif
+
extern char * * environ;
@@ -189,8 +193,12 @@ Path readLink(const Path & path)
if (!S_ISLNK(st.st_mode))
throw Error(format("`%1%' is not a symlink") % path);
char buf[st.st_size];
- if (readlink(path.c_str(), buf, st.st_size) != st.st_size)
- throw SysError(format("reading symbolic link `%1%'") % path);
+ ssize_t rlsize = readlink(path.c_str(), buf, st.st_size);
+ if (rlsize == -1)
+ throw SysError(format("reading symbolic link '%1%'") % path);
+ else if (rlsize > st.st_size)
+ throw Error(format("symbolic link ‘%1%’ size overflow %2% > %3%")
+ % path % rlsize % st.st_size);
return string(buf, st.st_size);
}
@@ -260,8 +268,8 @@ void writeFile(const Path & path, const string & s)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
if (fd == -1)
- throw SysError(format("opening file `%1%'") % path);
- writeFull(fd, (unsigned char *) s.data(), s.size());
+ throw SysError(format("opening file '%1%'") % path);
+ writeFull(fd, s);
}
@@ -288,7 +296,7 @@ string readLine(int fd)
void writeLine(int fd, string s)
{
s += '\n';
- writeFull(fd, (const unsigned char *) s.data(), s.size());
+ writeFull(fd, s);
}
@@ -478,18 +486,13 @@ void warnOnce(bool & haveWarned, const FormatOrString & fs)
}
-static void defaultWriteToStderr(const unsigned char * buf, size_t count)
-{
- writeFull(STDERR_FILENO, buf, count);
-}
-
-
void writeToStderr(const string & s)
{
try {
- auto p = _writeToStderr;
- if (!p) p = defaultWriteToStderr;
- p((const unsigned char *) s.data(), s.size());
+ if (_writeToStderr)
+ _writeToStderr((const unsigned char *) s.data(), s.size());
+ else
+ writeFull(STDERR_FILENO, s);
} catch (SysError & e) {
/* Ignore failing writes to stderr if we're in an exception
handler, otherwise throw an exception. We need to ignore
@@ -501,7 +504,7 @@ void writeToStderr(const string & s)
}
-void (*_writeToStderr) (const unsigned char * buf, size_t count) = defaultWriteToStderr;
+void (*_writeToStderr) (const unsigned char * buf, size_t count) = 0;
void readFull(int fd, unsigned char * buf, size_t count)
@@ -535,6 +538,12 @@ void writeFull(int fd, const unsigned char * buf, size_t count)
}
+void writeFull(int fd, const string & s)
+{
+ writeFull(fd, (const unsigned char *) s.data(), s.size());
+}
+
+
string drainFD(int fd)
{
string result;
@@ -867,6 +876,10 @@ pid_t startProcess(std::function<void()> fun,
if (pid == 0) {
_writeToStderr = 0;
try {
+#if __linux__
+ if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
+ throw SysError("setting death signal");
+#endif
restoreAffinity();
fun();
} catch (std::exception & e) {
@@ -884,16 +897,19 @@ pid_t startProcess(std::function<void()> fun,
}
+std::vector<const char *> stringsToCharPtrs(const Strings & ss)
+{
+ std::vector<const char *> res;
+ for (auto & s : ss) res.push_back(s.c_str());
+ res.push_back(0);
+ return res;
+}
+
+
string runProgram(Path program, bool searchPath, const Strings & args)
{
checkInterrupt();
- std::vector<const char *> cargs; /* careful with c_str()! */
- cargs.push_back(program.c_str());
- for (Strings::const_iterator i = args.begin(); i != args.end(); ++i)
- cargs.push_back(i->c_str());
- cargs.push_back(0);
-
/* Create a pipe. */
Pipe pipe;
pipe.create();
@@ -903,6 +919,10 @@ string runProgram(Path program, bool searchPath, const Strings & args)
if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
throw SysError("dupping stdout");
+ Strings args_(args);
+ args_.push_front(program);
+ auto cargs = stringsToCharPtrs(args_);
+
if (searchPath)
execvp(program.c_str(), (char * *) &cargs[0]);
else
diff --git a/nix/libutil/util.hh b/nix/libutil/util.hh
index 0ad0026711..6a84ed8851 100644
--- a/nix/libutil/util.hh
+++ b/nix/libutil/util.hh
@@ -171,6 +171,7 @@ extern void (*_writeToStderr) (const unsigned char * buf, size_t count);
requested number of bytes. */
void readFull(int fd, unsigned char * buf, size_t count);
void writeFull(int fd, const unsigned char * buf, size_t count);
+void writeFull(int fd, const string & s);
MakeError(EndOfFile, Error)
@@ -280,6 +281,11 @@ string runProgram(Path program, bool searchPath = false,
MakeError(ExecError, Error)
+/* Convert a list of strings to a null-terminated vector of char
+ *'s. The result must not be accessed beyond the lifetime of the
+ list of strings. */
+std::vector<const char *> stringsToCharPtrs(const Strings & ss);
+
/* Close all file descriptors except stdin, stdout, stderr, and those
listed in the given set. Good practice in child processes. */
void closeMostFDs(const set<int> & exceptions);