1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Uploads turn out to be much easier than downloads, so here's faster

upload support in PSFTP as well.

[originally from svn r3470]
This commit is contained in:
Simon Tatham 2003-09-28 14:24:01 +00:00
parent bc83c59aa7
commit 77cc301862
3 changed files with 127 additions and 25 deletions

38
psftp.c
View File

@ -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);

107
sftp.c
View File

@ -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;

7
sftp.h
View File

@ -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);