about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-08-16T14·15+0200
committerGitHub <noreply@github.com>2019-08-16T14·15+0200
commitf435634a29551754d5f7303b0a60cd8fe2df2079 (patch)
treef0c33d03dc692f5d2108b78f2bd898206bf4dfe7
parentb7ea98bf3409a29bb6412c6a17a896ba1c1f524a (diff)
parentb226b5cd976ca71abb3c0861b56d5e5940430924 (diff)
Merge pull request #3041 from zimbatm/nix-store-error-13
Fix for `unknown serve command 13`
-rw-r--r--src/libutil/serialise.hh30
-rw-r--r--src/nix-store/nix-store.cc12
2 files changed, 40 insertions, 2 deletions
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index 969e4dff383d..a344a5ac7520 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -179,6 +179,36 @@ struct TeeSource : Source
     }
 };
 
+/* A reader that consumes the original Source until 'size'. */
+struct SizedSource : Source
+{
+    Source & orig;
+    size_t remain;
+    SizedSource(Source & orig, size_t size)
+        : orig(orig), remain(size) { }
+    size_t read(unsigned char * data, size_t len)
+    {
+        if (this->remain <= 0) {
+            throw EndOfFile("sized: unexpected end-of-file");
+        }
+        len = std::min(len, this->remain);
+        size_t n = this->orig.read(data, len);
+        this->remain -= n;
+        return n;
+    }
+
+    /* Consume the original source until no remain data is left to consume. */
+    size_t drainAll()
+    {
+        std::vector<unsigned char> buf(8192);
+        size_t sum = 0;
+        while (this->remain > 0) {
+            size_t n = read(buf.data(), buf.size());
+            sum += n;
+        }
+        return sum;
+    }
+};
 
 /* Convert a function into a sink. */
 struct LambdaSink : Sink
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index f324056bb3a1..0cbceb02f31e 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -950,8 +950,16 @@ static void opServe(Strings opFlags, Strings opArgs)
                 info.sigs = readStrings<StringSet>(in);
                 in >> info.ca;
 
-                // FIXME: race if addToStore doesn't read source?
-                store->addToStore(info, in, NoRepair, NoCheckSigs);
+                if (info.narSize == 0) {
+                    throw Error("narInfo is too old and missing the narSize field");
+                }
+
+                SizedSource sizedSource(in, info.narSize);
+
+                store->addToStore(info, sizedSource, NoRepair, NoCheckSigs);
+
+                // consume all the data that has been sent before continuing.
+                sizedSource.drainAll();
 
                 out << 1; // indicate success