diff options
author | Marin Hannache <git@mareo.fr> | 2012-08-15 17:04:41 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2012-08-15 17:04:41 +0100 |
commit | 1170a36e6bb8091a638c815a17c2ec43715ad0a3 (patch) | |
tree | bc67db841caae43a6ba886eaa02b7efb828c1d0b | |
parent | 501527daab88a2911f5309d5215decf7011a7fde (diff) | |
download | ipxe-1170a36e6bb8091a638c815a17c2ec43715ad0a3.zip ipxe-1170a36e6bb8091a638c815a17c2ec43715ad0a3.tar.gz ipxe-1170a36e6bb8091a638c815a17c2ec43715ad0a3.tar.bz2 |
[ftp] Add support for the FTP SIZE command
The FTP SIZE command allows us to get the size of a particular file,
as a consequence, we can now show proper transfer progression while
fetching a file using the FTP protocol.
Signed-off-by: Marin Hannache <git@mareo.fr>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/net/tcp/ftp.c | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c index e5bc8e9..9f93fb6 100644 --- a/src/net/tcp/ftp.c +++ b/src/net/tcp/ftp.c @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + #include <stdint.h> #include <stdlib.h> #include <stdio.h> @@ -34,6 +53,7 @@ enum ftp_state { FTP_USER, FTP_PASS, FTP_TYPE, + FTP_SIZE, FTP_PASV, FTP_RETR, FTP_WAIT, @@ -68,6 +88,8 @@ struct ftp_request { char status_text[5]; /** Passive-mode parameters, as text */ char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */ + /** File size, as text */ + char filesize[20]; }; /** @@ -157,6 +179,7 @@ static struct ftp_control_string ftp_strings[] = { [FTP_USER] = { "USER ", ftp_user }, [FTP_PASS] = { "PASS ", ftp_password }, [FTP_TYPE] = { "TYPE I", NULL }, + [FTP_SIZE] = { "SIZE ", ftp_uri_path }, [FTP_PASV] = { "PASV", NULL }, [FTP_RETR] = { "RETR ", ftp_uri_path }, [FTP_WAIT] = { NULL, NULL }, @@ -234,6 +257,14 @@ static void ftp_reply ( struct ftp_request *ftp ) { if ( status_major == '1' ) return; + /* If the SIZE command is not supported by the server, we go to + * the next step. + */ + if ( ( status_major == '5' ) && ( ftp->state == FTP_SIZE ) ) { + ftp_next_state ( ftp ); + return; + } + /* Anything other than success (2xx) or, in the case of a * repsonse to a "USER" command, a password prompt (3xx), is a * fatal error. @@ -245,6 +276,26 @@ static void ftp_reply ( struct ftp_request *ftp ) { return; } + /* Parse file size */ + if ( ftp->state == FTP_SIZE ) { + size_t filesize; + char *endptr; + + /* Parse size */ + filesize = strtoul ( ftp->filesize, &endptr, 10 ); + if ( *endptr != '\0' ) { + DBGC ( ftp, "FTP %p invalid SIZE \"%s\"\n", + ftp, ftp->filesize ); + ftp_done ( ftp, -EPROTO ); + return; + } + + /* Use seek() to notify recipient of filesize */ + DBGC ( ftp, "FTP %p file size is %zd bytes\n", ftp, filesize ); + xfer_seek ( &ftp->xfer, filesize ); + xfer_seek ( &ftp->xfer, 0 ); + } + /* Open passive connection when we get "PASV" response */ if ( ftp->state == FTP_PASV ) { char *ptr = ftp->passive_text; @@ -295,35 +346,33 @@ static int ftp_control_deliver ( struct ftp_request *ftp, while ( len-- ) { c = *(data++); - switch ( c ) { - case '\r' : - case '\n' : + if ( ( c == '\r' ) || ( c == '\n' ) ) { /* End of line: call ftp_reply() to handle * completed reply. Avoid calling ftp_reply() * twice if we receive both \r and \n. */ - if ( recvsize == 0 ) + if ( recvbuf != ftp->status_text ) ftp_reply ( ftp ); /* Start filling up the status code buffer */ recvbuf = ftp->status_text; recvsize = sizeof ( ftp->status_text ) - 1; - break; - case '(' : + } else if ( ( ftp->state == FTP_PASV ) && ( c == '(' ) ) { /* Start filling up the passive parameter buffer */ recvbuf = ftp->passive_text; recvsize = sizeof ( ftp->passive_text ) - 1; - break; - case ')' : + } else if ( ( ftp->state == FTP_PASV ) && ( c == ')' ) ) { /* Stop filling the passive parameter buffer */ recvsize = 0; - break; - default : + } else if ( ( ftp->state == FTP_SIZE ) && ( c == ' ' ) ) { + /* Start filling up the file size buffer */ + recvbuf = ftp->filesize; + recvsize = sizeof ( ftp->filesize ) - 1; + } else { /* Fill up buffer if applicable */ if ( recvsize > 0 ) { *(recvbuf++) = c; recvsize--; } - break; } } |