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:
parent
80a3418b8c
commit
dc9495df03
102
miscutils/rx.c
102
miscutils/rx.c
@ -1,15 +1,12 @@
|
|||||||
/* vi: set sw=4 ts=4: */
|
/* vi: set sw=4 ts=4: */
|
||||||
/*-------------------------------------------------------------------------
|
/*
|
||||||
* Filename: xmodem.c
|
|
||||||
* Copyright: Copyright (C) 2001, Hewlett-Packard Company
|
* Copyright: Copyright (C) 2001, Hewlett-Packard Company
|
||||||
* Author: Christopher Hoover <ch@hpl.hp.com>
|
* Author: Christopher Hoover <ch@hpl.hp.com>
|
||||||
* Description: xmodem functionality for uploading of kernels
|
* Description: xmodem functionality for uploading of kernels
|
||||||
* and the like
|
* and the like
|
||||||
* Created at: Thu Dec 20 01:58:08 PST 2001
|
* Created at: Thu Dec 20 01:58:08 PST 2001
|
||||||
*-----------------------------------------------------------------------*/
|
*
|
||||||
/*
|
* xmodem functionality for uploading of kernels and the like
|
||||||
* xmodem.c: xmodem functionality for uploading of kernels and
|
|
||||||
* the like
|
|
||||||
*
|
*
|
||||||
* Copyright (C) 2001 Hewlett-Packard Laboratories
|
* Copyright (C) 2001 Hewlett-Packard Laboratories
|
||||||
*
|
*
|
||||||
@ -26,6 +23,7 @@
|
|||||||
#define ACK 0x06
|
#define ACK 0x06
|
||||||
#define NAK 0x15
|
#define NAK 0x15
|
||||||
#define BS 0x08
|
#define BS 0x08
|
||||||
|
#define PAD 0x1A
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cf:
|
Cf:
|
||||||
@ -44,69 +42,93 @@ Cf:
|
|||||||
|
|
||||||
static int read_byte(unsigned timeout)
|
static int read_byte(unsigned timeout)
|
||||||
{
|
{
|
||||||
char buf[1];
|
unsigned char buf;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
alarm(timeout);
|
alarm(timeout);
|
||||||
/* NOT safe_read! We want ALRM to interrupt us */
|
/* NOT safe_read! We want ALRM to interrupt us */
|
||||||
n = read(read_fd, buf, 1);
|
n = read(read_fd, &buf, 1);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
if (n == 1)
|
if (n == 1)
|
||||||
return (unsigned char)buf[0];
|
return buf;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int receive(/*int read_fd, */int file_fd)
|
static int receive(/*int read_fd, */int file_fd)
|
||||||
{
|
{
|
||||||
unsigned char blockBuf[1024];
|
unsigned char blockBuf[1024];
|
||||||
|
unsigned blockLength = 0;
|
||||||
unsigned errors = 0;
|
unsigned errors = 0;
|
||||||
unsigned wantBlockNo = 1;
|
unsigned wantBlockNo = 1;
|
||||||
unsigned length = 0;
|
unsigned length = 0;
|
||||||
int do_crc = 1;
|
int do_crc = 1;
|
||||||
char nak = 'C';
|
char reply_char;
|
||||||
unsigned timeout = TIMEOUT_LONG;
|
unsigned timeout = TIMEOUT_LONG;
|
||||||
|
|
||||||
/* Flush pending input */
|
/* Flush pending input */
|
||||||
tcflush(read_fd, TCIFLUSH);
|
tcflush(read_fd, TCIFLUSH);
|
||||||
|
|
||||||
/* Ask for CRC; if we get errors, we will go with checksum */
|
/* 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 (;;) {
|
for (;;) {
|
||||||
int blockBegin;
|
int blockBegin;
|
||||||
int blockNo, blockNoOnesCompl;
|
int blockNo, blockNoOnesCompl;
|
||||||
int blockLength;
|
int cksum_or_crc;
|
||||||
int cksum_crc; /* cksum OR crc */
|
|
||||||
int expected;
|
int expected;
|
||||||
int i,j;
|
int i, j;
|
||||||
|
|
||||||
blockBegin = read_byte(timeout);
|
blockBegin = read_byte(timeout);
|
||||||
if (blockBegin < 0)
|
if (blockBegin < 0)
|
||||||
goto timeout;
|
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;
|
timeout = TIMEOUT;
|
||||||
nak = NAK;
|
reply_char = NAK;
|
||||||
|
|
||||||
switch (blockBegin) {
|
switch (blockBegin) {
|
||||||
case SOH:
|
case SOH:
|
||||||
case STX:
|
case STX:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EOT:
|
case EOT:
|
||||||
nak = ACK;
|
reply_char = ACK;
|
||||||
full_write(write_fd, &nak, 1);
|
full_write(write_fd, &reply_char, 1);
|
||||||
return length;
|
return length;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* block no */
|
/* Block no */
|
||||||
blockNo = read_byte(TIMEOUT);
|
blockNo = read_byte(TIMEOUT);
|
||||||
if (blockNo < 0)
|
if (blockNo < 0)
|
||||||
goto timeout;
|
goto timeout;
|
||||||
|
|
||||||
/* block no one's compliment */
|
/* Block no, in one's complement form */
|
||||||
blockNoOnesCompl = read_byte(TIMEOUT);
|
blockNoOnesCompl = read_byte(TIMEOUT);
|
||||||
if (blockNoOnesCompl < 0)
|
if (blockNoOnesCompl < 0)
|
||||||
goto timeout;
|
goto timeout;
|
||||||
@ -126,15 +148,15 @@ static int receive(/*int read_fd, */int file_fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (do_crc) {
|
if (do_crc) {
|
||||||
cksum_crc = read_byte(TIMEOUT);
|
cksum_or_crc = read_byte(TIMEOUT);
|
||||||
if (cksum_crc < 0)
|
if (cksum_or_crc < 0)
|
||||||
goto timeout;
|
goto timeout;
|
||||||
cksum_crc = (cksum_crc << 8) | read_byte(TIMEOUT);
|
cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT);
|
||||||
if (cksum_crc < 0)
|
if (cksum_or_crc < 0)
|
||||||
goto timeout;
|
goto timeout;
|
||||||
} else {
|
} else {
|
||||||
cksum_crc = read_byte(TIMEOUT);
|
cksum_or_crc = read_byte(TIMEOUT);
|
||||||
if (cksum_crc < 0)
|
if (cksum_or_crc < 0)
|
||||||
goto timeout;
|
goto timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,9 +177,9 @@ static int receive(/*int read_fd, */int file_fd)
|
|||||||
expected = expected ^ blockBuf[i] << 8;
|
expected = expected ^ blockBuf[i] << 8;
|
||||||
for (j = 0; j < 8; j++) {
|
for (j = 0; j < 8; j++) {
|
||||||
if (expected & 0x8000)
|
if (expected & 0x8000)
|
||||||
expected = expected << 1 ^ 0x1021;
|
expected = (expected << 1) ^ 0x1021;
|
||||||
else
|
else
|
||||||
expected = expected << 1;
|
expected = (expected << 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expected &= 0xffff;
|
expected &= 0xffff;
|
||||||
@ -166,25 +188,19 @@ static int receive(/*int read_fd, */int file_fd)
|
|||||||
expected += blockBuf[i];
|
expected += blockBuf[i];
|
||||||
expected &= 0xff;
|
expected &= 0xff;
|
||||||
}
|
}
|
||||||
if (cksum_crc != expected) {
|
if (cksum_or_crc != expected) {
|
||||||
bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
|
bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
|
||||||
: "checksum error, expected 0x%02x, got 0x%02x",
|
: "checksum error, expected 0x%02x, got 0x%02x",
|
||||||
expected, cksum_crc);
|
expected, cksum_or_crc);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
wantBlockNo++;
|
wantBlockNo++;
|
||||||
length += blockLength;
|
length += blockLength;
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
|
|
||||||
bb_perror_msg("can't write to file");
|
|
||||||
goto fatal;
|
|
||||||
}
|
|
||||||
next:
|
next:
|
||||||
errors = 0;
|
errors = 0;
|
||||||
nak = ACK;
|
reply_char = ACK;
|
||||||
full_write(write_fd, &nak, 1);
|
full_write(write_fd, &reply_char, 1);
|
||||||
continue;
|
continue;
|
||||||
error:
|
error:
|
||||||
timeout:
|
timeout:
|
||||||
@ -192,9 +208,9 @@ static int receive(/*int read_fd, */int file_fd)
|
|||||||
if (errors == MAXERRORS) {
|
if (errors == MAXERRORS) {
|
||||||
/* Abort */
|
/* Abort */
|
||||||
|
|
||||||
/* if were asking for crc, try again w/o crc */
|
/* If were asking for crc, try again w/o crc */
|
||||||
if (nak == 'C') {
|
if (reply_char == 'C') {
|
||||||
nak = NAK;
|
reply_char = NAK;
|
||||||
errors = 0;
|
errors = 0;
|
||||||
do_crc = 0;
|
do_crc = 0;
|
||||||
goto timeout;
|
goto timeout;
|
||||||
@ -209,7 +225,7 @@ static int receive(/*int read_fd, */int file_fd)
|
|||||||
/* Flush pending input */
|
/* Flush pending input */
|
||||||
tcflush(read_fd, TCIFLUSH);
|
tcflush(read_fd, TCIFLUSH);
|
||||||
|
|
||||||
full_write(write_fd, &nak, 1);
|
full_write(write_fd, &reply_char, 1);
|
||||||
} /* for (;;) */
|
} /* for (;;) */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
testsuite/rx.tests
Normal file
27
testsuite/rx.tests
Normal 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
|
Loading…
x
Reference in New Issue
Block a user