httpd: fix CGI handling bug (we were closing wrong fd).
[oweals/busybox.git] / libbb / copyfd.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Utility routines.
4  *
5  * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */
9
10 #include "libbb.h"
11
12 #if BUFSIZ < 4096
13 #undef BUFSIZ
14 #define BUFSIZ 4096
15 #endif
16
17 /* Used by NOFORK applets (e.g. cat) - must not use xmalloc */
18
19 static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
20 {
21         int status = -1;
22         off_t total = 0;
23         char buffer[BUFSIZ];
24
25         if (src_fd < 0)
26                 goto out;
27
28         if (!size) {
29                 size = BUFSIZ;
30                 status = 1; /* copy until eof */
31         }
32
33         while (1) {
34                 ssize_t rd;
35
36                 rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ : size);
37
38                 if (!rd) { /* eof - all done */
39                         status = 0;
40                         break;
41                 }
42                 if (rd < 0) {
43                         bb_perror_msg(bb_msg_read_error);
44                         break;
45                 }
46                 /* dst_fd == -1 is a fake, else... */
47                 if (dst_fd >= 0) {
48                         ssize_t wr = full_write(dst_fd, buffer, rd);
49                         if (wr < rd) {
50                                 bb_perror_msg(bb_msg_write_error);
51                                 break;
52                         }
53                 }
54                 total += rd;
55                 if (status < 0) { /* if we aren't copying till EOF... */
56                         size -= rd;
57                         if (!size) {
58                                 /* 'size' bytes copied - all done */
59                                 status = 0;
60                                 break;
61                         }
62                 }
63         }
64  out:
65         return status ? -1 : total;
66 }
67
68
69 #if 0
70 void complain_copyfd_and_die(off_t sz)
71 {
72         if (sz != -1)
73                 bb_error_msg_and_die("short read");
74         /* if sz == -1, bb_copyfd_XX already complained */
75         xfunc_die();
76 }
77 #endif
78
79 off_t bb_copyfd_size(int fd1, int fd2, off_t size)
80 {
81         if (size) {
82                 return bb_full_fd_action(fd1, fd2, size);
83         }
84         return 0;
85 }
86
87 void bb_copyfd_exact_size(int fd1, int fd2, off_t size)
88 {
89         off_t sz = bb_copyfd_size(fd1, fd2, size);
90         if (sz == size)
91                 return;
92         if (sz != -1)
93                 bb_error_msg_and_die("short read");
94         /* if sz == -1, bb_copyfd_XX already complained */
95         xfunc_die();
96 }
97
98 off_t bb_copyfd_eof(int fd1, int fd2)
99 {
100         return bb_full_fd_action(fd1, fd2, 0);
101 }