From df0870fc8ceb5a8fea66a4d0fe00e7db12317e33 Mon Sep 17 00:00:00 2001 From: simon Date: Sun, 28 Sep 2003 14:24:01 +0000 Subject: [PATCH] Uploads turn out to be much easier than downloads, so here's faster upload support in PSFTP as well. git-svn-id: svn://svn.tartarus.org/sgt/putty@3470 cda61777-01e9-0310-a592-d414129be87e --- psftp.c | 38 ++++++++++++----------- sftp.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- sftp.h | 7 ++++- 3 files changed, 127 insertions(+), 25 deletions(-) diff --git a/psftp.c b/psftp.c index 9e697d50..c1d4950b 100644 --- a/psftp.c +++ b/psftp.c @@ -441,7 +441,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart) */ ret = 1; xfer = xfer_download_init(fh, offset); - while (!xfer_download_done(xfer)) { + while (!xfer_done(xfer)) { void *vbuf; int ret, len; int wpos, wlen; @@ -506,12 +506,13 @@ int sftp_cmd_reget(struct sftp_command *cmd) int sftp_general_put(struct sftp_command *cmd, int restart) { struct fxp_handle *fh; + struct fxp_xfer *xfer; char *fname, *origoutfname, *outfname; struct sftp_packet *pktin; struct sftp_request *req, *rreq; uint64 offset; FILE *fp; - int ret; + int ret, err, eof; if (back == NULL) { printf("psftp: not connected to a host; use \"open host.name\"\n"); @@ -595,32 +596,35 @@ int sftp_general_put(struct sftp_command *cmd, int restart) * thus put up a progress bar. */ ret = 1; - while (1) { + xfer = xfer_upload_init(fh, offset); + err = eof = 0; + while ((!err && !eof) || !xfer_done(xfer)) { char buffer[4096]; int len, ret; - len = fread(buffer, 1, sizeof(buffer), fp); - if (len == -1) { - printf("error while reading local file\n"); - ret = 0; - break; - } else if (len == 0) { - break; + while (xfer_upload_ready(xfer) && !err && !eof) { + len = fread(buffer, 1, sizeof(buffer), fp); + if (len == -1) { + printf("error while reading local file\n"); + err = 1; + } else if (len == 0) { + eof = 1; + } else { + xfer_upload_data(xfer, buffer, len); + } } - sftp_register(req = fxp_write_send(fh, buffer, offset, len)); - rreq = sftp_find_request(pktin = sftp_recv()); - assert(rreq == req); - ret = fxp_write_recv(pktin, rreq); + pktin = sftp_recv(); + ret = xfer_upload_gotpkt(xfer, pktin); if (!ret) { printf("error while writing: %s\n", fxp_error()); - ret = 0; - break; + err = 1; } - offset = uint64_add32(offset, len); } + xfer_cleanup(xfer); + sftp_register(req = fxp_close_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); diff --git a/sftp.c b/sftp.c index fef207ff..4d5172b5 100644 --- a/sftp.c +++ b/sftp.c @@ -1049,7 +1049,7 @@ struct req { struct fxp_xfer { uint64 offset, furthestdata, filesize; - int nreqs, req_max, eof, err; + int req_totalsize, req_maxsize, eof, err; struct fxp_handle *fh; struct req *head, *tail; }; @@ -1061,8 +1061,8 @@ static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64 offset) xfer->fh = fh; xfer->offset = offset; xfer->head = xfer->tail = NULL; - xfer->nreqs = 0; - xfer->req_max = 4; /* FIXME: set properly! */ + xfer->req_totalsize = 0; + xfer->req_maxsize = 16384; xfer->err = 0; xfer->filesize = uint64_make(ULONG_MAX, ULONG_MAX); xfer->furthestdata = uint64_make(0, 0); @@ -1070,7 +1070,7 @@ static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64 offset) return xfer; } -int xfer_download_done(struct fxp_xfer *xfer) +int xfer_done(struct fxp_xfer *xfer) { /* * We're finished if we've seen EOF _and_ there are no @@ -1081,7 +1081,7 @@ int xfer_download_done(struct fxp_xfer *xfer) void xfer_download_queue(struct fxp_xfer *xfer) { - while (xfer->nreqs < xfer->req_max && !xfer->eof) { + while (xfer->req_totalsize < xfer->req_maxsize && !xfer->eof) { /* * Queue a new read request. */ @@ -1107,7 +1107,7 @@ void xfer_download_queue(struct fxp_xfer *xfer) fxp_set_userdata(req, rr); xfer->offset = uint64_add32(xfer->offset, rr->len); - xfer->nreqs++; + xfer->req_totalsize += rr->len; #ifdef DEBUG_DOWNLOAD { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing read request %p at %s\n", rr, buf); } @@ -1234,8 +1234,8 @@ int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len) xfer->head->prev = NULL; else xfer->tail = NULL; + xfer->req_totalsize -= rr->len; sfree(rr); - xfer->nreqs--; } if (retbuf) { @@ -1246,6 +1246,99 @@ int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len) return 0; } +struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64 offset) +{ + struct fxp_xfer *xfer = xfer_init(fh, offset); + + /* + * We set `eof' to 1 because this will cause xfer_done() to + * return true iff there are no outstanding requests. During an + * upload, our caller will be responsible for working out + * whether all the data has been sent, so all it needs to know + * from us is whether the outstanding requests have been + * handled once that's done. + */ + xfer->eof = 1; + + return xfer; +} + +int xfer_upload_ready(struct fxp_xfer *xfer) +{ + if (xfer->req_totalsize < xfer->req_maxsize) + return 1; + else + return 0; +} + +void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len) +{ + struct req *rr; + struct sftp_request *req; + + rr = snew(struct req); + rr->offset = xfer->offset; + rr->complete = 0; + if (xfer->tail) { + xfer->tail->next = rr; + rr->prev = xfer->tail; + } else { + xfer->head = rr; + rr->prev = NULL; + } + xfer->tail = rr; + rr->next = NULL; + + rr->len = len; + rr->buffer = NULL; + sftp_register(req = fxp_write_send(xfer->fh, buffer, rr->offset, len)); + fxp_set_userdata(req, rr); + + xfer->offset = uint64_add32(xfer->offset, rr->len); + xfer->req_totalsize += rr->len; + +#ifdef DEBUG_UPLOAD + { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing write request %p at %s [len %d]\n", rr, buf, len); } +#endif +} + +int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) +{ + struct sftp_request *rreq; + struct req *rr, *prev, *next; + int ret; + + rreq = sftp_find_request(pktin); + rr = (struct req *)fxp_get_userdata(rreq); + if (!rr) + return 0; /* this packet isn't ours */ + ret = fxp_write_recv(pktin, rreq); +#ifdef DEBUG_UPLOAD + printf("write request %p has returned [%d]\n", rr, ret); +#endif + + /* + * Remove this one from the queue. + */ + prev = rr->prev; + next = rr->next; + if (prev) + prev->next = next; + else + xfer->head = next; + if (next) + next->prev = prev; + else + xfer->tail = prev; + xfer->req_totalsize -= rr->len; + sfree(rr); + + if (!ret) + return -1; + + return 1; +} + void xfer_cleanup(struct fxp_xfer *xfer) { struct req *rr; diff --git a/sftp.h b/sftp.h index 5f8b38b5..54d91af2 100644 --- a/sftp.h +++ b/sftp.h @@ -229,10 +229,15 @@ struct sftp_packet *sftp_recv(void); struct fxp_xfer; struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64 offset); -int xfer_download_done(struct fxp_xfer *xfer); void xfer_download_queue(struct fxp_xfer *xfer); int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin); int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len); +struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64 offset); +int xfer_upload_ready(struct fxp_xfer *xfer); +void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len); +int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin); + +int xfer_done(struct fxp_xfer *xfer); void xfer_set_error(struct fxp_xfer *xfer); void xfer_cleanup(struct fxp_xfer *xfer); -- 2.11.0