From 4c139229611631a3497c224a61107b6b6918e3bf Mon Sep 17 00:00:00 2001
From: Denis Vlasenko <vda.linux@googlemail.com>
Date: Sun, 2 Dec 2007 03:27:42 +0000
Subject: Introduce FEATURE_COPYBUF_KB. People who want smaller stack at any
 cost may use it to reduce cp's stack usage (FEATURE_COPYBUF_KB=1). Desktop
 people may get faster copy of big files (FEATURE_COPYBUF_KB=32 is ~30% faster
 than 4kb)

---
 libbb/Config.in | 10 ++++++++++
 libbb/copyfd.c  | 32 ++++++++++++++++++++++++--------
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/libbb/Config.in b/libbb/Config.in
index 5055015cf..6bbeffb43 100644
--- a/libbb/Config.in
+++ b/libbb/Config.in
@@ -110,6 +110,16 @@ config FEATURE_EDITING_FANCY_PROMPT
 	  Setting this option allows for prompts to use things like \w and
 	  \$ and escape codes.
 
+config FEATURE_COPYBUF_KB
+	int "Copy buffer size, in kilobytes"
+	range 1 1024
+	default 4
+	help
+	  Size of buffer used by cp, mv, install etc.
+	  Buffers which are 4 kb or less will be allocated on stack.
+	  Bigger buffers will be allocated with mmap, with fallback to 4 kb
+	  stack buffer if mmap fails.
+
 config MONOTONIC_SYSCALL
 	bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
 	default y
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
index 3255e424a..ed383ae28 100644
--- a/libbb/copyfd.c
+++ b/libbb/copyfd.c
@@ -9,31 +9,42 @@
 
 #include "libbb.h"
 
-#if BUFSIZ < 4096
-#undef BUFSIZ
-#define BUFSIZ 4096
-#endif
-
 /* Used by NOFORK applets (e.g. cat) - must not use xmalloc */
 
 static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
 {
 	int status = -1;
 	off_t total = 0;
-	char buffer[BUFSIZ];
+#if CONFIG_FEATURE_COPYBUF_KB <= 4
+	char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
+	enum { buffer_size = sizeof(buffer) };
+#else
+	char *buffer;
+	int buffer_size;
+
+	buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
+			PROT_READ | PROT_WRITE,
+			MAP_PRIVATE | MAP_ANON,
+			/* ignored: */ -1, 0);
+	buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
+	if (buffer == MAP_FAILED) {
+		buffer = alloca(4 * 1024);
+		buffer_size = 4 * 1024;
+	}
+#endif
 
 	if (src_fd < 0)
 		goto out;
 
 	if (!size) {
-		size = BUFSIZ;
+		size = buffer_size;
 		status = 1; /* copy until eof */
 	}
 
 	while (1) {
 		ssize_t rd;
 
-		rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ : size);
+		rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size);
 
 		if (!rd) { /* eof - all done */
 			status = 0;
@@ -62,6 +73,11 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
 		}
 	}
  out:
+
+#if CONFIG_FEATURE_COPYBUF_KB > 4
+	if (buffer_size != 4 * 1024)
+		munmap(buffer, buffer_size);
+#endif
 	return status ? -1 : total;
 }
 
-- 
cgit v1.2.3-55-g6feb