mirror of https://github.com/ipxe/ipxe.git
[ftp] Cope with RETR completion prior to all data received
Based on a patch contributed by Sergey Vlasov <vsu@altlinux.ru> : In my testing with "qemu -net user" the 226 response to RETR was often received earlier than final packets of the data connection; this caused the received file to become truncated without any error indication. Fix this by adding an intermediate state FTP_TRANSFER between FTP_RETR and FTP_QUIT, so that the transfer is considered to be complete only when both the end of data connection is encountered and the final reply to the RETR command is received.pull/1/head
parent
fe1f017bde
commit
8f4c2b4a4c
|
@ -35,6 +35,7 @@ enum ftp_state {
|
|||
FTP_TYPE,
|
||||
FTP_PASV,
|
||||
FTP_RETR,
|
||||
FTP_WAIT,
|
||||
FTP_QUIT,
|
||||
FTP_DONE,
|
||||
};
|
||||
|
@ -116,14 +117,15 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) {
|
|||
* snprintf() call.
|
||||
*/
|
||||
static const char * ftp_strings[] = {
|
||||
[FTP_CONNECT] = "",
|
||||
[FTP_CONNECT] = NULL,
|
||||
[FTP_USER] = "USER anonymous\r\n",
|
||||
[FTP_PASS] = "PASS etherboot@etherboot.org\r\n",
|
||||
[FTP_TYPE] = "TYPE I\r\n",
|
||||
[FTP_PASV] = "PASV\r\n",
|
||||
[FTP_RETR] = "RETR %s\r\n",
|
||||
[FTP_RETR] = "RETR %s\r\n",
|
||||
[FTP_WAIT] = NULL,
|
||||
[FTP_QUIT] = "QUIT\r\n",
|
||||
[FTP_DONE] = "",
|
||||
[FTP_DONE] = NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -169,6 +171,27 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
|
|||
} while ( --len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to next state and send the appropriate FTP control string
|
||||
*
|
||||
* @v ftp FTP request
|
||||
*
|
||||
*/
|
||||
static void ftp_next_state ( struct ftp_request *ftp ) {
|
||||
|
||||
/* Move to next state */
|
||||
if ( ftp->state < FTP_DONE )
|
||||
ftp->state++;
|
||||
|
||||
/* Send control string if needed */
|
||||
if ( ftp_strings[ftp->state] != NULL ) {
|
||||
DBGC ( ftp, "FTP %p sending ", ftp );
|
||||
DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
|
||||
xfer_printf ( &ftp->control, ftp_strings[ftp->state],
|
||||
ftp->uri->path );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an FTP control channel response
|
||||
*
|
||||
|
@ -223,17 +246,9 @@ static void ftp_reply ( struct ftp_request *ftp ) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Move to next state */
|
||||
if ( ftp->state < FTP_DONE )
|
||||
ftp->state++;
|
||||
|
||||
/* Send control string */
|
||||
if ( ftp->state < FTP_DONE ) {
|
||||
DBGC ( ftp, "FTP %p sending ", ftp );
|
||||
DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
|
||||
xfer_printf ( &ftp->control, ftp_strings[ftp->state],
|
||||
ftp->uri->path );
|
||||
}
|
||||
/* Move to next state and send control string */
|
||||
ftp_next_state ( ftp );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,8 +346,11 @@ static void ftp_data_closed ( struct xfer_interface *data, int rc ) {
|
|||
ftp, strerror ( rc ) );
|
||||
|
||||
/* If there was an error, close control channel and record status */
|
||||
if ( rc )
|
||||
if ( rc ) {
|
||||
ftp_done ( ftp, rc );
|
||||
} else {
|
||||
ftp_next_state ( ftp );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue