aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/db.cc57
-rw-r--r--src/db.hh8
-rw-r--r--src/fix.cc2
-rw-r--r--src/fstate.cc8
-rw-r--r--src/shared.cc3
-rw-r--r--src/store.cc93
-rw-r--r--src/store.hh9
-rw-r--r--src/test.cc15
-rw-r--r--src/util.cc17
-rw-r--r--src/util.hh7
11 files changed, 172 insertions, 49 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5488e133a..b22a56e3a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,7 +14,7 @@ fix_LDADD = libnix.a -ldb_cxx-4 -lATerm
TESTS = test
-test_SOURCES = test.cc
+test_SOURCES = test.cc shared.cc
test_LDADD = libnix.a -ldb_cxx-4 -lATerm
noinst_LIBRARIES = libnix.a
diff --git a/src/db.cc b/src/db.cc
index b33591c8b..89cee32ba 100644
--- a/src/db.cc
+++ b/src/db.cc
@@ -73,6 +73,40 @@ bool queryDB(const string & filename, const string & dbname,
}
+bool queryListDB(const string & filename, const string & dbname,
+ const string & key, Strings & data)
+{
+ string d;
+
+ if (!queryDB(filename, dbname, key, d))
+ return false;
+
+ string::iterator it = d.begin();
+
+ while (it != d.end()) {
+
+ if (it + 4 > d.end())
+ throw Error(format("short db entry: `%1%'") % d);
+
+ unsigned int len;
+ len = (unsigned char) *it++;
+ len |= ((unsigned char) *it++) << 8;
+ len |= ((unsigned char) *it++) << 16;
+ len |= ((unsigned char) *it++) << 24;
+
+ if (it + len > d.end())
+ throw Error(format("short db entry: `%1%'") % d);
+
+ string s;
+ while (len--) s += *it++;
+
+ data.push_back(s);
+ }
+
+ return true;
+}
+
+
void setDB(const string & filename, const string & dbname,
const string & key, const string & data)
{
@@ -85,6 +119,29 @@ void setDB(const string & filename, const string & dbname,
}
+void setListDB(const string & filename, const string & dbname,
+ const string & key, const Strings & data)
+{
+ string d;
+
+ for (Strings::const_iterator it = data.begin();
+ it != data.end(); it++)
+ {
+ string s = *it;
+ unsigned int len = s.size();
+
+ d += len & 0xff;
+ d += (len >> 8) & 0xff;
+ d += (len >> 16) & 0xff;
+ d += (len >> 24) & 0xff;
+
+ d += s;
+ }
+
+ setDB(filename, dbname, key, d);
+}
+
+
void delDB(const string & filename, const string & dbname,
const string & key)
{
diff --git a/src/db.hh b/src/db.hh
index 0054dbec1..aee6ce9bf 100644
--- a/src/db.hh
+++ b/src/db.hh
@@ -4,6 +4,8 @@
#include <string>
#include <list>
+#include "util.hh"
+
using namespace std;
typedef pair<string, string> DBPair;
@@ -14,9 +16,15 @@ void createDB(const string & filename, const string & dbname);
bool queryDB(const string & filename, const string & dbname,
const string & key, string & data);
+bool queryListDB(const string & filename, const string & dbname,
+ const string & key, Strings & data);
+
void setDB(const string & filename, const string & dbname,
const string & key, const string & data);
+void setListDB(const string & filename, const string & dbname,
+ const string & key, const Strings & data);
+
void delDB(const string & filename, const string & dbname,
const string & key);
diff --git a/src/fix.cc b/src/fix.cc
index fdf12ffef..eb77a4942 100644
--- a/src/fix.cc
+++ b/src/fix.cc
@@ -29,7 +29,7 @@ static bool isFState(Expr e, string & path)
}
else if (ATmatch(e, "Include(<str>)", &s1))
{
- string fn = queryFromStore(parseHash(s1));
+ string fn = queryPathByHash(parseHash(s1));
return isFState(evalFile(fn), path);
}
else return false;
diff --git a/src/fstate.cc b/src/fstate.cc
index 8003a1b38..2e3ffd639 100644
--- a/src/fstate.cc
+++ b/src/fstate.cc
@@ -167,7 +167,7 @@ struct RStatus
static ATerm termFromHash(const Hash & hash)
{
- string path = queryFromStore(hash);
+ string path = queryPathByHash(hash);
ATerm t = ATreadFromNamedFile(path.c_str());
if (!t) throw Error(format("cannot read aterm %1%") % path);
return t;
@@ -183,7 +183,7 @@ Hash writeTerm(ATerm t)
string path2 = nixStore + "/" + (string) hash + ".nix";
if (rename(path.c_str(), path2.c_str()) == -1)
throw SysError(format("renaming %1% to %2%") % path % path2);
- setDB(nixDB, dbRefs, hash, path2);
+ registerPath(path2, hash);
return hash;
}
@@ -259,7 +259,7 @@ static FState realise(RStatus & status, FState fs)
}
/* Do we know a path with that hash? If so, copy it. */
- string path2 = queryFromStore(hash);
+ string path2 = queryPathByHash(hash);
copyPath(path2, path);
return nf;
@@ -318,7 +318,7 @@ static FState realise(RStatus & status, FState fs)
/* Register targetHash -> targetPath. !!! this should be in
values.cc. */
- setDB(nixDB, dbRefs, outHash, outPath);
+ registerPath(outPath, outHash);
/* Register the normal form of fs. */
FState nf = ATmake("Path(<str>, Hash(<str>), <term>)",
diff --git a/src/shared.cc b/src/shared.cc
index 6d157766e..bd165ce97 100644
--- a/src/shared.cc
+++ b/src/shared.cc
@@ -54,6 +54,9 @@ int main(int argc, char * * argv)
"Try `%2% --help' for more information.\n")
% e.what() % programId;
return 1;
+ } catch (Error & e) {
+ cerr << format("error: %1%\n") % e.msg();
+ return 1;
} catch (exception & e) {
cerr << format("error: %1%\n") % e.what();
return 1;
diff --git a/src/store.cc b/src/store.cc
index 68a1cd1e2..73713201d 100644
--- a/src/store.cc
+++ b/src/store.cc
@@ -83,25 +83,89 @@ void copyPath(string src, string dst)
}
+Hash registerPath(const string & _path, Hash hash)
+{
+ string path(canonPath(_path));
+
+ if (hash == Hash()) hash = hashPath(path);
+
+ Strings paths;
+ queryListDB(nixDB, dbRefs, hash, paths); /* non-existence = ok */
+
+ for (Strings::iterator it = paths.begin();
+ it != paths.end(); it++)
+ if (*it == path) goto exists;
+
+ paths.push_back(path);
+
+ setListDB(nixDB, dbRefs, hash, paths);
+
+ exists:
+ return hash;
+}
+
+
+bool isInPrefix(const string & path, const string & _prefix)
+{
+ string prefix = canonPath(_prefix + "/");
+ return string(path, 0, prefix.size()) == prefix;
+}
+
+
+static string queryPathByHashPrefix(Hash hash, const string & prefix)
+{
+ Strings paths;
+
+ if (!queryListDB(nixDB, dbRefs, hash, paths))
+ throw Error(format("no paths known with hash `%1%'") % (string) hash);
+
+ /* Arbitrarily pick the first one that exists and still hash the
+ right hash. */
+
+ for (Strings::iterator it = paths.begin();
+ it != paths.end(); it++)
+ {
+ debug(*it);
+ string path = *it;
+ try {
+ debug(path);
+ debug(prefix);
+ if (isInPrefix(path, prefix) && hashPath(path) == hash)
+ return path;
+ } catch (Error & e) {
+ debug(format("checking hash: %1%") % e.msg());
+ /* try next one */
+ }
+ }
+
+ throw Error(format("all paths with hash `%1%' are stale") % (string) hash);
+}
+
+
+string queryPathByHash(Hash hash)
+{
+ return queryPathByHashPrefix(hash, "/");
+}
+
+
void addToStore(string srcPath, string & dstPath, Hash & hash)
{
srcPath = absPath(srcPath);
hash = hashPath(srcPath);
- string path;
- if (queryDB(nixDB, dbRefs, hash, path)) {
- debug((string) hash + " already known");
- dstPath = path;
+ try {
+ dstPath = queryPathByHashPrefix(hash, nixStore);
return;
+ } catch (...) {
}
-
+
string baseName = baseNameOf(srcPath);
dstPath = nixStore + "/" + (string) hash + "-" + baseName;
copyPath(srcPath, dstPath);
- setDB(nixDB, dbRefs, hash, dstPath);
+ registerPath(dstPath, hash);
}
@@ -113,20 +177,3 @@ void deleteFromStore(const string & path)
deletePath(path);
// delDB(nixDB, dbRefs, hash);
}
-
-
-string queryFromStore(Hash hash)
-{
- string fn, url;
-
- if (queryDB(nixDB, dbRefs, hash, fn)) {
-
- /* Verify that the file hasn't changed. !!! race !!! slow */
- if (hashPath(fn) != hash)
- throw Error("file " + fn + " is stale");
-
- return fn;
- }
-
- throw Error(format("don't know a path with hash `%1%'") % (string) hash);
-}
diff --git a/src/store.hh b/src/store.hh
index b96fa30ba..a83fa0304 100644
--- a/src/store.hh
+++ b/src/store.hh
@@ -10,6 +10,12 @@ using namespace std;
void copyPath(string src, string dst);
+/* Register a path keyed on its hash. */
+Hash registerPath(const string & path, Hash hash = Hash());
+
+/* Query a path (any path) through its hash. */
+string queryPathByHash(Hash hash);
+
/* Copy a file to the nixStore directory and register it in dbRefs.
Return the hash code of the value. */
void addToStore(string srcPath, string & dstPath, Hash & hash);
@@ -17,8 +23,5 @@ void addToStore(string srcPath, string & dstPath, Hash & hash);
/* Delete a value from the nixStore directory. */
void deleteFromStore(const string & path);
-/* !!! */
-string queryFromStore(Hash hash);
-
#endif /* !__VALUES_H */
diff --git a/src/test.cc b/src/test.cc
index fb7900ca9..b30a5b0e9 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -191,15 +191,10 @@ void runTests()
}
-int main(int argc, char * * argv)
+void run(Strings args)
{
- ATerm bottomOfStack;
- ATinit(argc, argv, &bottomOfStack);
-
- try {
- runTests();
- } catch (exception & e) {
- cerr << "error: " << e.what() << endl;
- return 1;
- }
+ runTests();
}
+
+
+string programId = "test";
diff --git a/src/util.cc b/src/util.cc
index 65ceea938..2f9c43e55 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -33,13 +33,18 @@ string absPath(string path, string dir)
dir = buf;
}
path = dir + "/" + path;
- /* !!! canonicalise */
- char resolved[PATH_MAX];
- if (!realpath(path.c_str(), resolved))
- throw SysError(format("cannot canonicalise path %1%") % path);
- path = resolved;
}
- return path;
+ return canonPath(path);
+}
+
+
+string canonPath(const string & path)
+{
+ char resolved[PATH_MAX];
+ if (!realpath(path.c_str(), resolved))
+ throw SysError(format("cannot canonicalise path `%1%'") % path);
+ /* !!! check that this removes trailing slashes */
+ return resolved;
}
diff --git a/src/util.hh b/src/util.hh
index 6242fcb11..a8f801b30 100644
--- a/src/util.hh
+++ b/src/util.hh
@@ -21,6 +21,7 @@ public:
Error(const format & f);
~Error() throw () { };
const char * what() const throw () { return err.c_str(); }
+ const string & msg() const throw () { return err; }
};
class SysError : public Error
@@ -44,9 +45,13 @@ extern string thisSystem;
/* Return an absolutized path, resolving paths relative to the
- specified directory, or the current directory otherwise. */
+ specified directory, or the current directory otherwise. The path
+ is also canonicalised. */
string absPath(string path, string dir = "");
+/* Canonicalise a path (as in realpath(3)). */
+string canonPath(const string & path);
+
/* Return the directory part of the given path, i.e., everything
before the final `/'. */
string dirOf(string path);