* Don't use fork() in copyPath(), but a string buffer.

This commit is contained in:
Eelco Dolstra 2005-03-03 13:58:02 +00:00
parent 9e6bca8765
commit 4bbdcfbb45
2 changed files with 17 additions and 47 deletions

View file

@ -1,7 +1,6 @@
#include <iostream>
#include <algorithm>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@ -126,20 +125,24 @@ void createStoreTransaction(Transaction & txn)
struct CopySink : DumpSink
{
int fd;
string s;
virtual void operator () (const unsigned char * data, unsigned int len)
{
writeFull(fd, data, len);
s.append((const char *) data, len);
}
};
struct CopySource : RestoreSource
{
int fd;
string & s;
unsigned int pos;
CopySource(string & _s) : s(_s), pos(0) { }
virtual void operator () (unsigned char * data, unsigned int len)
{
readFull(fd, data, len);
s.copy((char *) data, len, pos);
pos += len;
assert(pos <= s.size());
}
};
@ -148,52 +151,19 @@ void copyPath(const Path & src, const Path & dst)
{
debug(format("copying `%1%' to `%2%'") % src % dst);
/* Unfortunately C++ doesn't support coprocedures, so we have no
nice way to chain CopySink and CopySource together. Instead we
fork off a child to run the sink. (Fork-less platforms should
use a thread). */
/* Dump an archive of the path `src' into a string buffer, then
restore the archive to `dst'. This is not a very good method
for very large paths, but `copyPath' is mainly used for small
files. */
/* Create a pipe. */
Pipe pipe;
pipe.create();
/* Fork. */
Pid pid;
pid = fork();
switch (pid) {
case -1:
throw SysError("unable to fork");
case 0: /* child */
try {
pipe.writeSide.close();
CopySource source;
source.fd = pipe.readSide;
restorePath(dst, source);
_exit(0);
} catch (exception & e) {
cerr << "error: " << e.what() << endl;
}
_exit(1);
}
/* Parent. */
pipe.readSide.close();
CopySink sink;
sink.fd = pipe.writeSide;
{
SwitchToOriginalUser sw;
dumpPath(src, sink);
}
/* Wait for the child to finish. */
int status = pid.wait(true);
if (!statusOk(status))
throw Error(format("cannot copy `%1% to `%2%': child %3%")
% src % dst % statusToString(status));
CopySource source(sink.s);
restorePath(dst, source);
}
@ -619,9 +589,6 @@ Path addToStore(const Path & _srcPath)
if (pathExists(dstPath)) deletePath(dstPath);
/* !!! race: srcPath might change between hashPath() and
here! */
copyPath(srcPath, dstPath);
Hash h2 = hashPath(htSHA256, dstPath);

View file

@ -42,6 +42,7 @@
struct DumpSink
{
virtual ~DumpSink() { }
virtual void operator () (const unsigned char * data, unsigned int len) = 0;
};
@ -50,6 +51,8 @@ void dumpPath(const Path & path, DumpSink & sink);
struct RestoreSource
{
virtual ~RestoreSource() { }
/* The callee should store exactly *len bytes in the buffer
pointed to by data. It should block if that much data is not
yet available, or throw an error if it is not going to be