[git commit] rx: strip padding from last block. closes bug 501.

Denys Vlasenko vda.linux at googlemail.com
Sun Aug 2 17:45:31 UTC 2009


commit: http://git.busybox.net/busybox/commit/?id=dc9495df03f411d67eb46002670ffea12bdd32ba
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
rx_main                                              876     974     +98

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 miscutils/rx.c     |  102 ++++++++++++++++++++++++++++++----------------------
 testsuite/rx.tests |   27 ++++++++++++++
 2 files changed, 86 insertions(+), 43 deletions(-)
 create mode 100644 testsuite/rx.tests

diff --git a/miscutils/rx.c b/miscutils/rx.c
index 94eb452..3a8b6a8 100644
--- a/miscutils/rx.c
+++ b/miscutils/rx.c
@@ -1,15 +1,12 @@
 /* vi: set sw=4 ts=4: */
-/*-------------------------------------------------------------------------
- * Filename:      xmodem.c
+/*
  * Copyright:     Copyright (C) 2001, Hewlett-Packard Company
  * Author:        Christopher Hoover <ch at hpl.hp.com>
  * Description:   xmodem functionality for uploading of kernels
  *                and the like
  * Created at:    Thu Dec 20 01:58:08 PST 2001
- *-----------------------------------------------------------------------*/
-/*
- * xmodem.c: xmodem functionality for uploading of kernels and
- *            the like
+ *
+ * xmodem functionality for uploading of kernels and the like
  *
  * Copyright (C) 2001 Hewlett-Packard Laboratories
  *
@@ -26,6 +23,7 @@
 #define ACK 0x06
 #define NAK 0x15
 #define BS  0x08
+#define PAD 0x1A
 
 /*
 Cf:
@@ -44,69 +42,93 @@ Cf:
 
 static int read_byte(unsigned timeout)
 {
-	char buf[1];
+	unsigned char buf;
 	int n;
 
 	alarm(timeout);
 	/* NOT safe_read! We want ALRM to interrupt us */
-	n = read(read_fd, buf, 1);
+	n = read(read_fd, &buf, 1);
 	alarm(0);
 	if (n == 1)
-		return (unsigned char)buf[0];
+		return buf;
 	return -1;
 }
 
 static int receive(/*int read_fd, */int file_fd)
 {
 	unsigned char blockBuf[1024];
+	unsigned blockLength = 0;
 	unsigned errors = 0;
 	unsigned wantBlockNo = 1;
 	unsigned length = 0;
 	int do_crc = 1;
-	char nak = 'C';
+	char reply_char;
 	unsigned timeout = TIMEOUT_LONG;
 
 	/* Flush pending input */
 	tcflush(read_fd, TCIFLUSH);
 
 	/* Ask for CRC; if we get errors, we will go with checksum */
-	full_write(write_fd, &nak, 1);
+	reply_char = 'C';
+	full_write(write_fd, &reply_char, 1);
 
 	for (;;) {
 		int blockBegin;
 		int blockNo, blockNoOnesCompl;
-		int blockLength;
-		int cksum_crc;	/* cksum OR crc */
+		int cksum_or_crc;
 		int expected;
-		int i,j;
+		int i, j;
 
 		blockBegin = read_byte(timeout);
 		if (blockBegin < 0)
 			goto timeout;
 
+		/* If last block, remove padding */
+		if (blockBegin == EOT) {
+			/* Data blocks can be padded with ^Z characters */
+			/* This code tries to detect and remove them */
+			if (blockLength >= 3
+			 && blockBuf[blockLength - 1] == PAD
+			 && blockBuf[blockLength - 2] == PAD
+			 && blockBuf[blockLength - 3] == PAD
+			) {
+				while (blockLength
+			           && blockBuf[blockLength - 1] == PAD
+				) {
+					blockLength--;
+				}
+			}
+		}
+		/* Write previously received block */
+		if (blockLength) {
+			errno = 0;
+			if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
+				bb_perror_msg("can't write to file");
+				goto fatal;
+			}
+		}
+
 		timeout = TIMEOUT;
-		nak = NAK;
+		reply_char = NAK;
 
 		switch (blockBegin) {
 		case SOH:
 		case STX:
 			break;
-
 		case EOT:
-			nak = ACK;
-			full_write(write_fd, &nak, 1);
+			reply_char = ACK;
+			full_write(write_fd, &reply_char, 1);
 			return length;
-
 		default:
 			goto error;
 		}
 
-		/* block no */
+		/* Block no */
 		blockNo = read_byte(TIMEOUT);
 		if (blockNo < 0)
 			goto timeout;
 
-		/* block no one's compliment */
+		/* Block no, in one's complement form */
 		blockNoOnesCompl = read_byte(TIMEOUT);
 		if (blockNoOnesCompl < 0)
 			goto timeout;
@@ -126,15 +148,15 @@ static int receive(/*int read_fd, */int file_fd)
 		}
 
 		if (do_crc) {
-			cksum_crc = read_byte(TIMEOUT);
-			if (cksum_crc < 0)
+			cksum_or_crc = read_byte(TIMEOUT);
+			if (cksum_or_crc < 0)
 				goto timeout;
-			cksum_crc = (cksum_crc << 8) | read_byte(TIMEOUT);
-			if (cksum_crc < 0)
+			cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT);
+			if (cksum_or_crc < 0)
 				goto timeout;
 		} else {
-			cksum_crc = read_byte(TIMEOUT);
-			if (cksum_crc < 0)
+			cksum_or_crc = read_byte(TIMEOUT);
+			if (cksum_or_crc < 0)
 				goto timeout;
 		}
 
@@ -155,9 +177,9 @@ static int receive(/*int read_fd, */int file_fd)
 				expected = expected ^ blockBuf[i] << 8;
 				for (j = 0; j < 8; j++) {
 					if (expected & 0x8000)
-						expected = expected << 1 ^ 0x1021;
+						expected = (expected << 1) ^ 0x1021;
 					else
-						expected = expected << 1;
+						expected = (expected << 1);
 				}
 			}
 			expected &= 0xffff;
@@ -166,25 +188,19 @@ static int receive(/*int read_fd, */int file_fd)
 				expected += blockBuf[i];
 			expected &= 0xff;
 		}
-		if (cksum_crc != expected) {
+		if (cksum_or_crc != expected) {
 			bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
 			                   : "checksum error, expected 0x%02x, got 0x%02x",
-					    expected, cksum_crc);
+					expected, cksum_or_crc);
 			goto error;
 		}
 
 		wantBlockNo++;
 		length += blockLength;
-
-		errno = 0;
-		if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
-			bb_perror_msg("can't write to file");
-			goto fatal;
-		}
  next:
 		errors = 0;
-		nak = ACK;
-		full_write(write_fd, &nak, 1);
+		reply_char = ACK;
+		full_write(write_fd, &reply_char, 1);
 		continue;
  error:
  timeout:
@@ -192,9 +208,9 @@ static int receive(/*int read_fd, */int file_fd)
 		if (errors == MAXERRORS) {
 			/* Abort */
 
-			/* if were asking for crc, try again w/o crc */
-			if (nak == 'C') {
-				nak = NAK;
+			/* If were asking for crc, try again w/o crc */
+			if (reply_char == 'C') {
+				reply_char = NAK;
 				errors = 0;
 				do_crc = 0;
 				goto timeout;
@@ -209,7 +225,7 @@ static int receive(/*int read_fd, */int file_fd)
 		/* Flush pending input */
 		tcflush(read_fd, TCIFLUSH);
 
-		full_write(write_fd, &nak, 1);
+		full_write(write_fd, &reply_char, 1);
 	} /* for (;;) */
 }
 
diff --git a/testsuite/rx.tests b/testsuite/rx.tests
new file mode 100644
index 0000000..417f04b
--- /dev/null
+++ b/testsuite/rx.tests
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright 2009 by Denys Vlasenko
+# Licensed under GPL v2, see file LICENSE for details.
+
+. testing.sh
+
+# testing "test name" "options" "expected result" "file input" "stdin"
+
+# Simple one-block file transfer
+# rx => 'C'
+# rx <= SOH <blockno> <255-blockno> <128 byte padded with x1A> <crc> <crc>
+# rx => ACK
+# rx <= EOT
+# rx => ACK
+testing "rx" \
+	"rx rx.OUTFILE | hexdump -vC && cat rx.OUTFILE" \
+"\
+00000000  43 06 06                                          |C..|\n\
+00000003\n\
+???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????" \
+	"" "\1\1\376\
+???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????\
+\x1A\x1A\x1A\x1A\x1A\x4B\xB0\4"
+
+rm -f rx.OUTFILE 2>/dev/null
+
+exit $FAILCOUNT
-- 
1.6.3.3



More information about the busybox-cvs mailing list