summaryrefslogtreecommitdiff
path: root/src/tipideed/send_file.c
blob: 2ee122ae72f8652f6f8629199caad6ae757410e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* ISC license. */

#include <skalibs/sysdeps.h>

#ifdef SKALIBS_HASSPLICE

#include <skalibs/nonposix.h>

#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>

#include <skalibs/strerr.h>
#include <skalibs/djbunix.h>
#include <skalibs/unix-timed.h>

#include "tipideed-internal.h"

void init_splice_pipe (void)
{
  if (pipenbcoe(g.p) == -1)
    strerr_diefu1sys(111, "pipe2") ;
}

struct spliceinfo_s
{
  ssize_t n ;
  uint32_t last : 1 ;
} ;

static int getfd (void *b)
{
  (void)b ;
  return 1 ;
}

static int isnonempty (void *b)
{
  struct spliceinfo_s *si = b ;
  return !!si->n ;
}

static int flush (void *b)
{
  struct spliceinfo_s *si = b ;
  while (si->n)
  {
    ssize_t r = splice(g.p[0], 0, 1, 0, si->n, SPLICE_F_NONBLOCK | (si->last ? 0 : SPLICE_F_MORE)) ;
    if (r == -1) return 0 ;
    if (!r) return 1 ;
    si->n -= r ;
  }
  return 1 ;
}

void send_file (int fd, uint64_t n, char const *fn)
{
  tain deadline ;
  struct spliceinfo_s si = { .last = 0 } ;
  tain_add_g(&deadline, &g.writetto) ;
  if (!buffer_timed_flush_g(buffer_1, &deadline))
    strerr_diefu2sys(111, "write", " to stdout") ;
  while (n)
  {
    si.n = splice(fd, 0, g.p[1], 0, n, 0) ;
    if (si.n == -1) strerr_diefu2sys(111, "read from ", fn) ;
    else if (!si.n) strerr_diefu3x(111, "serve ", fn, ": file was truncated") ;
    else if (si.n > n)
    {
      si.n = n ;
      if (g.verbosity >= 2)
        strerr_warnw2x("serving elongated file: ", fn) ;
    }
    n -= si.n ;
    if (!n) si.last = 1 ;
    tain_add_g(&deadline, &g.writetto) ;
    if (!timed_flush_g(&si, &getfd, &isnonempty, &flush, &deadline))
      strerr_diefu2sys(111, "splice", " to stdout") ;
  }
}

#else

#include <sys/uio.h>

#include <skalibs/allreadwrite.h>
#include <skalibs/buffer.h>
#include <skalibs/strerr.h>
#include <skalibs/tai.h>

#include "tipideed-internal.h"

void init_splice_pipe (void)
{
}

void send_file (int fd, uint64_t n, char const *fn)
{
  tain deadline ;
  struct iovec v[2] ;
  while (n)
  {
    ssize_t r ;
    buffer_rpeek(buffer_1, v) ;
    r = allreadv(fd, v, 2) ;
    if (r == -1) strerr_diefu2sys(111, "read from ", fn) ;
    if (!r) strerr_diefu3x(111, "serve ", fn, ": file was truncated") ;
    if (r > n)
    {
      r = n ;
      if (g.verbosity >= 2)
        strerr_warnw2x("serving elongated file: ", fn) ;
    }
    buffer_rseek(buffer_1, r) ;
    tain_add_g(&deadline, &g.writetto) ;
    if (!buffer_timed_flush_g(buffer_1, &deadline))
      strerr_diefu1sys(111, "write to stdout") ;
    n -= r ;
  }
}

#endif