source: MondoRescue/branches/3.3/mindi-busybox/libbb/copyfd.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 3.6 KB
Line 
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 source tree.
8 */
9
10#include "libbb.h"
11#if ENABLE_FEATURE_USE_SENDFILE
12# include <sys/sendfile.h>
13#else
14# define sendfile(a,b,c,d) (-1)
15#endif
16
17/*
18 * We were using 0x7fff0000 as sendfile chunk size, but it
19 * was seen to cause largish delays when user tries to ^C a file copy.
20 * Let's use a saner size.
21 * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB),
22 * or else "copy to eof" code will use neddlesly short reads.
23 */
24#define SENDFILE_BIGBUF (16*1024*1024)
25
26/* Used by NOFORK applets (e.g. cat) - must not use xmalloc.
27 * size < 0 means "ignore write errors", used by tar --to-command
28 * size = 0 means "copy till EOF"
29 */
30static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
31{
32 int status = -1;
33 off_t total = 0;
34 bool continue_on_write_error = 0;
35 ssize_t sendfile_sz;
36#if CONFIG_FEATURE_COPYBUF_KB > 4
37 char *buffer = buffer; /* for compiler */
38 int buffer_size = 0;
39#else
40 char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
41 enum { buffer_size = sizeof(buffer) };
42#endif
43
44 if (size < 0) {
45 size = -size;
46 continue_on_write_error = 1;
47 }
48
49 if (src_fd < 0)
50 goto out;
51
52 sendfile_sz = !ENABLE_FEATURE_USE_SENDFILE
53 ? 0
54 : SENDFILE_BIGBUF;
55 if (!size) {
56 size = SENDFILE_BIGBUF;
57 status = 1; /* copy until eof */
58 }
59
60 while (1) {
61 ssize_t rd;
62
63 if (sendfile_sz) {
64 rd = sendfile(dst_fd, src_fd, NULL,
65 size > sendfile_sz ? sendfile_sz : size);
66 if (rd >= 0)
67 goto read_ok;
68 sendfile_sz = 0; /* do not try sendfile anymore */
69 }
70#if CONFIG_FEATURE_COPYBUF_KB > 4
71 if (buffer_size == 0) {
72 if (size > 0 && size <= 4 * 1024)
73 goto use_small_buf;
74 /* We want page-aligned buffer, just in case kernel is clever
75 * and can do page-aligned io more efficiently */
76 buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
77 PROT_READ | PROT_WRITE,
78 MAP_PRIVATE | MAP_ANON,
79 /* ignored: */ -1, 0);
80 buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
81 if (buffer == MAP_FAILED) {
82 use_small_buf:
83 buffer = alloca(4 * 1024);
84 buffer_size = 4 * 1024;
85 }
86 }
87#endif
88 rd = safe_read(src_fd, buffer,
89 size > buffer_size ? buffer_size : size);
90 if (rd < 0) {
91 bb_perror_msg(bb_msg_read_error);
92 break;
93 }
94 read_ok:
95 if (!rd) { /* eof - all done */
96 status = 0;
97 break;
98 }
99 /* dst_fd == -1 is a fake, else... */
100 if (dst_fd >= 0 && !sendfile_sz) {
101 ssize_t wr = full_write(dst_fd, buffer, rd);
102 if (wr < rd) {
103 if (!continue_on_write_error) {
104 bb_perror_msg(bb_msg_write_error);
105 break;
106 }
107 dst_fd = -1;
108 }
109 }
110 total += rd;
111 if (status < 0) { /* if we aren't copying till EOF... */
112 size -= rd;
113 if (!size) {
114 /* 'size' bytes copied - all done */
115 status = 0;
116 break;
117 }
118 }
119 }
120 out:
121
122 if (buffer_size > 4 * 1024)
123 munmap(buffer, buffer_size);
124 return status ? -1 : total;
125}
126
127
128#if 0
129void FAST_FUNC complain_copyfd_and_die(off_t sz)
130{
131 if (sz != -1)
132 bb_error_msg_and_die("short read");
133 /* if sz == -1, bb_copyfd_XX already complained */
134 xfunc_die();
135}
136#endif
137
138off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size)
139{
140 if (size) {
141 return bb_full_fd_action(fd1, fd2, size);
142 }
143 return 0;
144}
145
146void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size)
147{
148 off_t sz = bb_copyfd_size(fd1, fd2, size);
149 if (sz == (size >= 0 ? size : -size))
150 return;
151 if (sz != -1)
152 bb_error_msg_and_die("short read");
153 /* if sz == -1, bb_copyfd_XX already complained */
154 xfunc_die();
155}
156
157off_t FAST_FUNC bb_copyfd_eof(int fd1, int fd2)
158{
159 return bb_full_fd_action(fd1, fd2, 0);
160}
Note: See TracBrowser for help on using the repository browser.