Enable use of sendfile on FreeBSD
[exim.git] / src / src / dkim_transport.c
index 552e1beb17dc2377be89b74658cd4e295dba6582..95e750e5edd630edbb6292a9df444f6feebc648d 100644 (file)
 
 #ifndef DISABLE_DKIM   /* rest of file */
 
-#ifdef HAVE_LINUX_SENDFILE
-# include <sys/sendfile.h>
-#endif
-
 
 static BOOL
 dkt_sign_fail(struct ob_dkim * dkim, int * errp)
@@ -38,17 +34,16 @@ if (dkim->dkim_strict)
 return TRUE;
 }
 
+/* Send the file at in_fd down the output fd */
+
 static BOOL
 dkt_send_file(int out_fd, int in_fd, off_t off, size_t size)
 {
-DEBUG(D_transport) debug_printf("send file fd=%d size=%d\n", out_fd, size - off);
+DEBUG(D_transport) debug_printf("send file fd=%d size=%u\n", out_fd, (unsigned)(size - off));
 
 /*XXX should implement timeout, like transport_write_block_fd() ? */
 
-/* Rewind file */
-lseek(in_fd, off, SEEK_SET);
-
-#ifdef HAVE_LINUX_SENDFILE
+#ifdef OS_SENDFILE
 /* We can use sendfile() to shove the file contents
    to the socket. However only if we don't use TLS,
    as then there's another layer of indirection
@@ -58,7 +53,7 @@ if (tls_out.active != out_fd)
   ssize_t copied = 0;
 
   while(copied >= 0 && off < size)
-    copied = sendfile(tctx->u.fd, dkim_fd, &off, size - off);
+    copied = os_sendfile(out_fd, in_fd, &off, size - off);
   if (copied < 0)
     return FALSE;
   }
@@ -69,8 +64,11 @@ else
   {
   int sread, wwritten;
 
+  /* Rewind file */
+  if (lseek(in_fd, off, SEEK_SET) < 0) return FALSE;
+
   /* Send file down the original fd */
-  while((sread = read(in_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) >0)
+  while((sread = read(in_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) > 0)
     {
     uschar * p = deliver_out_buffer;
     /* write the chunk */
@@ -118,14 +116,16 @@ dkt_direct(transport_ctx * tctx, struct ob_dkim * dkim,
 {
 int save_fd = tctx->u.fd;
 int save_options = tctx->options;
+BOOL save_wireformat = spool_file_wireformat;
 uschar * hdrs, * dkim_signature;
-int siglen, hsize;
+int siglen = 0, hsize;
 const uschar * errstr;
 BOOL rc;
 
 DEBUG(D_transport) debug_printf("dkim signing direct-mode\n");
 
-/* Get headers in string for signing and transmission */
+/* Get headers in string for signing and transmission.  Do CRLF
+and dotstuffing (but no body nor dot-termination) */
 
 tctx->u.msg = NULL;
 tctx->options = tctx->options & ~(topt_end_dot | topt_use_bdat)
@@ -155,14 +155,18 @@ else if (!(rc = dkt_sign_fail(dkim, &errno)))
 /* Write the signature and headers into the deliver-out-buffer.  This should
 mean they go out in the same packet as the MAIL, RCPT and (first) BDAT commands
 (transport_write_message() sizes the BDAT for the buffered amount) - for short
-messages, the BDAT LAST command.  We want no CRLF or dotstuffing expansion */
+messages, the BDAT LAST command.  We want no dotstuffing expansion here, it
+having already been done - but we have to say we want CRLF output format, and
+temporarily set the marker for possible already-CRLF input. */
 
-tctx->options &= ~(topt_use_crlf | topt_escape_headers);
+tctx->options &= ~topt_escape_headers;
+spool_file_wireformat = TRUE;
 transport_write_reset(0);
-if (  !write_chunk(tctx, dkim_signature, siglen)
+if (  siglen > 0 && !write_chunk(tctx, dkim_signature, siglen)
    || !write_chunk(tctx, hdrs, hsize))
   return FALSE;
 
+spool_file_wireformat = save_wireformat;
 tctx->options = save_options | topt_no_headers | topt_continuation;
 
 if (!(transport_write_message(tctx, 0)))
@@ -196,7 +200,7 @@ int dkim_fd;
 int save_errno = 0;
 BOOL rc;
 uschar * dkim_spool_name, * dkim_signature;
-int sread = 0, wwritten = 0, siglen, options;
+int sread = 0, wwritten = 0, siglen = 0, options;
 off_t k_file_size;
 const uschar * errstr;
 
@@ -247,10 +251,14 @@ else if (!(rc = dkt_sign_fail(dkim, &save_errno)))
   goto CLEANUP;
   }
 
-#ifndef HAVE_LINUX_SENDFILE
+#ifndef OS_SENDFILE
 if (options & topt_use_bdat)
 #endif
-  k_file_size = lseek(dkim_fd, 0, SEEK_END); /* Fetch file size */
+  if ((k_file_size = lseek(dkim_fd, 0, SEEK_END)) < 0)
+    {
+    *err = string_sprintf("dkim spoolfile seek: %s", strerror(errno));
+    goto CLEANUP;
+    }
 
 if (options & topt_use_bdat)
   {
@@ -286,7 +294,7 @@ if (!dkt_send_file(tctx->u.fd, dkim_fd, 0, k_file_size))
 
 CLEANUP:
   /* unlink -K file */
-  (void)close(dkim_fd);
+  if (dkim_fd >= 0) (void)close(dkim_fd);
   Uunlink(dkim_spool_name);
   errno = save_errno;
   return rc;