more generic. Now i can share it with other programs (for example, my
portable install(1)).
-/* Copy the message from stdin to fd. */
-/* buf is passed only as an (early, evil) space optimization). */
+/* Copy the file from INFD to OUTFD in blocks of BUFSIZE bytes (stored
+ * in BUF). BUF must point to a buffer of at least BUFSIZE bytes;
+ * we're not dealing with null-terminated strings here.
+ *
+ * Note that OUTFD is closed before returning; this is necessary to
+ * ensure the file was fully written on some filesystems, such as NFS.
+ */
-copy_message(int fd, char *buf, char *fn)
+copy_file(int infd, int outfd, char *buf, size_t bufsize, char *fn)
- while ((r = read(STDIN_FILENO, buf, BUFSIZ)) > 0
+ while ((r = read(infd, buf, bufsize)) > 0
|| (r == -1 && errno == EINTR)) {
|| (r == -1 && errno == EINTR)) {
- if (full_write(fd, buf, r) != r) {
+ if (full_write(outfd, buf, r) != r) {
save_errno( unlink(fn) );
err(MDELIVER_EXITCODE, "Failed write(%s)", fn);
}
save_errno( unlink(fn) );
err(MDELIVER_EXITCODE, "Failed write(%s)", fn);
}
if (r == -1) {
save_errno( unlink(fn) );
if (r == -1) {
save_errno( unlink(fn) );
- err(MDELIVER_EXITCODE, "Failed read from stdin");
+ err(MDELIVER_EXITCODE, "Failed read");
+ if (fsync(outfd) < 0) {
save_errno( unlink(fn) );
err(MDELIVER_EXITCODE, "Failed fsync(%s)", fn);
}
save_errno( unlink(fn) );
err(MDELIVER_EXITCODE, "Failed fsync(%s)", fn);
}
+ if (close(outfd) < 0) {
save_errno( unlink(fn) );
err(MDELIVER_EXITCODE, "Failed close(%s)", fn);
}
save_errno( unlink(fn) );
err(MDELIVER_EXITCODE, "Failed close(%s)", fn);
}
* must try to unlink it before bombing. */
strip_from(fd, buf, fn);
* must try to unlink it before bombing. */
strip_from(fd, buf, fn);
- copy_message(fd, buf, fn);
+ copy_file(STDIN_FILENO, fd, buf, BUFSIZ, fn);
strcpy(newfn, fn);
memcpy(newfn, "new", 3);
strcpy(newfn, fn);
memcpy(newfn, "new", 3);