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: */
|
||||
/*-------------------------------------------------------------------------
|
||||
* 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
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…
Reference in New Issue
Block a user