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>
This commit is contained in:
Denys Vlasenko 2009-08-02 19:45:31 +02:00
parent 80a3418b8c
commit dc9495df03
2 changed files with 86 additions and 43 deletions

View File

@ -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 (;;) */
}

27
testsuite/rx.tests Normal file
View File

@ -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