X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/c606c42da46efa232c1f29791877f07d98da262e..479fe1ba750b1cda0ad3a159f2727619555436b0:/sftp.c diff --git a/sftp.c b/sftp.c index fef207ff..a55262a7 100644 --- a/sftp.c +++ b/sftp.c @@ -334,6 +334,14 @@ static struct sftp_request *sftp_alloc_request(void) return r; } +void sftp_cleanup_request(void) +{ + if (sftp_requests == NULL) { + freetree234(sftp_requests); + sftp_requests = NULL; + } +} + void sftp_register(struct sftp_request *req) { req->registered = 1; @@ -1049,7 +1057,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 +1069,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 +1078,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 +1089,8 @@ 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 && !xfer->err) { /* * Queue a new read request. */ @@ -1107,7 +1116,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); } @@ -1147,6 +1156,8 @@ int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) #endif } else if (rr->retlen < 0) { /* some error other than EOF; signal it back to caller */ + xfer_set_error(xfer); + rr->complete = -1; return -1; } @@ -1234,8 +1245,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 +1257,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;