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

View file

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