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
19static 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
70off_t bb_copyfd_size(int fd1, int fd2, off_t size)
71{
72	if (size) {
73		return bb_full_fd_action(fd1, fd2, size);
74	}
75	return 0;
76}
77
78void bb_copyfd_exact_size(int fd1, int fd2, off_t size)
79{
80	off_t sz = bb_copyfd_size(fd1, fd2, size);
81	if (sz == size)
82		return;
83	if (sz != -1)
84		bb_error_msg_and_die("short read");
85	/* if sz == -1, bb_copyfd_XX already complained */
86	xfunc_die();
87}
88
89off_t bb_copyfd_eof(int fd1, int fd2)
90{
91	return bb_full_fd_action(fd1, fd2, 0);
92}
93