diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-08-02 21:45:31 +0400 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-08-02 21:45:31 +0400 |
commit | dc9495df03f411d67eb46002670ffea12bdd32ba (patch) | |
tree | c0d8f4c7a2482f6564252638d2d5f3b1f05aacb2 | |
parent | 80a3418b8c96300826842f109cd297280d3fbe05 (diff) |
rx: strip padding from last block. closes bug 501.
function old new delta
rx_main 876 974 +98
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/rx.c | 102 | ||||
-rw-r--r-- | testsuite/rx.tests | 27 |
2 files changed, 86 insertions, 43 deletions
diff --git a/miscutils/rx.c b/miscutils/rx.c index 94eb4522d..3a8b6a8fe 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@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 000000000..417f04b57 --- /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 |