aa8fbb967f61956c77ff4229cf487b9eb8db3498
[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 be very careful
18  * when calling xfuncs, allocating memory, with signals, termios, etc... */
19
20 static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
21 {
22         int status = -1;
23         off_t total = 0;
24         RESERVE_CONFIG_BUFFER(buffer, BUFSIZ);
25
26         if (src_fd < 0)
27                 goto out;
28
29         if (!size) {
30                 size = BUFSIZ;
31                 status = 1; /* copy until eof */
32         }
33
34         while (1) {
35                 ssize_t rd;
36
37                 rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ : size);
38
39                 if (!rd) { /* eof - all done */
40                         status = 0;
41                         break;
42                 }
43                 if (rd < 0) {
44                         bb_perror_msg(bb_msg_read_error);
45                         break;
46                 }
47                 /* dst_fd == -1 is a fake, else... */
48                 if (dst_fd >= 0) {
49                         ssize_t wr = full_write(dst_fd, buffer, rd);
50                         if (wr < rd) {
51                                 bb_perror_msg(bb_msg_write_error);
52                                 break;
53                         }
54                 }
55                 total += rd;
56                 if (status < 0) { /* if we aren't copying till EOF... */
57                         size -= rd;
58                         if (!size) {
59                                 /* 'size' bytes copied - all done */
60                                 status = 0;
61                                 break;
62                         }
63                 }
64         }
65  out:
66         RELEASE_CONFIG_BUFFER(buffer);
67         return status ? -1 : total;
68 }
69
70
71 #if 0
72 void complain_copyfd_and_die(off_t sz)
73 {
74         if (sz != -1)
75                 bb_error_msg_and_die("short read");
76         /* if sz == -1, bb_copyfd_XX already complained */
77         xfunc_die();
78 }
79 #endif
80
81 off_t bb_copyfd_size(int fd1, int fd2, off_t size)
82 {
83         if (size) {
84                 return bb_full_fd_action(fd1, fd2, size);
85         }
86         return 0;
87 }
88
89 void bb_copyfd_exact_size(int fd1, int fd2, off_t size)
90 {
91         off_t sz = bb_copyfd_size(fd1, fd2, size);
92         if (sz == size)
93                 return;
94         if (sz != -1)
95                 bb_error_msg_and_die("short read");
96         /* if sz == -1, bb_copyfd_XX already complained */
97         xfunc_die();
98 }
99
100 off_t bb_copyfd_eof(int fd1, int fd2)
101 {
102         return bb_full_fd_action(fd1, fd2, 0);
103 }