summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko2009-03-09 04:38:37 +0000
committerDenis Vlasenko2009-03-09 04:38:37 +0000
commit57a3b174989c7778fb255f716e090d5be807b9b7 (patch)
tree5f2aeaede8073e72176a4d63f533a2c203570d8f
parentd42eb81206dba25b01f68f98272daa34f61531d0 (diff)
downloadbusybox-57a3b174989c7778fb255f716e090d5be807b9b7.zip
busybox-57a3b174989c7778fb255f716e090d5be807b9b7.tar.gz
ftp: reduce amount of realloc's done in cmdio_write
text data bss dec hex filename 808562 476 7864 816902 c7706 busybox_old 808568 476 7864 816908 c770c busybox_unstripped
-rw-r--r--networking/ftpd.c46
1 files changed, 20 insertions, 26 deletions
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 4988ce0..b2d6ef2 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -102,7 +102,7 @@ struct globals {
int pasv_listen_fd;
int data_fd;
off_t restart_pos;
- char *ftp_cmp;
+ char *ftp_cmd;
char *ftp_arg;
#if ENABLE_FEATURE_FTP_WRITE
char *rnfr_filename;
@@ -112,8 +112,9 @@ struct globals {
#define G (*(struct globals*)&bb_common_bufsiz1)
#define INIT_G() do { } while (0)
+
static char *
-replace_text(const char *str, const char from, const char *to)
+escape_text(const char *prepend, const char *str, char from, const char *to, char append)
{
size_t retlen, remainlen, chunklen, tolen;
const char *remain;
@@ -124,29 +125,27 @@ replace_text(const char *str, const char from, const char *to)
tolen = strlen(to);
/* Simply alloc strlen(str)*strlen(to). "to" is max 2 so it's ok */
- ret = xmalloc(remainlen * tolen + 1);
- retlen = 0;
+ retlen = strlen(prepend);
+ ret = xmalloc(retlen + remainlen * tolen + 1 + 1);
+ strcpy(ret, prepend);
for (;;) {
- found = strchr(remain, from);
- if (found != NULL) {
- chunklen = found - remain;
+ found = strchrnul(remain, from);
+ chunklen = found - remain;
- /* Copy chunk which doesn't contain 'from' to ret */
- memcpy(&ret[retlen], remain, chunklen);
- retlen += chunklen;
+ /* Copy chunk which doesn't contain 'from' to ret */
+ memcpy(&ret[retlen], remain, chunklen);
+ retlen += chunklen;
+ if (*found != '\0') {
/* Now copy 'to' instead of 'from' */
memcpy(&ret[retlen], to, tolen);
retlen += tolen;
remain = found + 1;
} else {
- /*
- * The last chunk. We are already sure that we have enough space
- * so we can use strcpy.
- */
- strcpy(&ret[retlen], remain);
+ ret[retlen] = append;
+ ret[retlen+1] = '\0';
break;
}
}
@@ -163,15 +162,12 @@ replace_char(char *str, char from, char to)
static void
cmdio_write(unsigned status, const char *str)
{
- char *escaped_str, *response;
+ char *response;
int len;
/* FTP allegedly uses telnet protocol for command link.
* In telnet, 0xff is an escape char, and needs to be escaped: */
- escaped_str = replace_text(str, '\xff', "\xff\xff");
-
- response = xasprintf("%u%s\r", status, escaped_str);
- free(escaped_str);
+ response = escape_text(utoa(status), str, '\xff', "\xff\xff", '\r');
/* ?! does FTP send embedded LFs as NULs? wow */
len = strlen(response);
@@ -206,17 +202,15 @@ cmdio_write_raw(const char *p_text)
static void
handle_pwd(void)
{
- char *cwd, *promoted_cwd, *response;
+ char *cwd, *response;
cwd = xrealloc_getcwd_or_warn(NULL);
if (cwd == NULL)
cwd = xstrdup("");
/* We have to promote each " to "" */
- promoted_cwd = replace_text(cwd, '\"', "\"\"");
+ response = escape_text(" \"", cwd, '\"', "\"\"", '\"');
free(cwd);
- response = xasprintf(" \"%s\"", promoted_cwd);
- free(promoted_cwd);
cmdio_write(FTP_PWDOK, response);
free(response);
}
@@ -872,9 +866,9 @@ cmdio_get_cmd_and_arg(void)
uint32_t cmdval;
char *cmd;
- free(G.ftp_cmp);
+ free(G.ftp_cmd);
len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */
- G.ftp_cmp = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len);
+ G.ftp_cmd = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len);
if (!cmd)
exit(0);