version 1.18.2.1, 2002/03/07 17:37:47 |
version 1.18.2.2, 2002/05/17 00:03:24 |
|
|
|
|
/* Some filexfer v.0 servers don't support large packets */ |
/* Some filexfer v.0 servers don't support large packets */ |
if (version == 0) |
if (version == 0) |
ret->transfer_buflen = MAX(ret->transfer_buflen, 20480); |
ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); |
|
|
return(ret); |
return(ret); |
} |
} |
|
|
debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); |
debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); |
|
|
id = conn->msg_id++; |
id = conn->msg_id++; |
send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, |
send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, |
strlen(path)); |
strlen(path)); |
status = get_status(conn->fd_in, id); |
status = get_status(conn->fd_in, id); |
if (status != SSH2_FX_OK) |
if (status != SSH2_FX_OK) |
|
|
|
|
id = conn->msg_id++; |
id = conn->msg_id++; |
|
|
send_string_request(conn->fd_out, id, |
send_string_request(conn->fd_out, id, |
conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, |
conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, |
path, strlen(path)); |
path, strlen(path)); |
|
|
return(get_decode_stat(conn->fd_in, id, quiet)); |
return(get_decode_stat(conn->fd_in, id, quiet)); |
|
|
if (quiet) |
if (quiet) |
debug("Server version does not support lstat operation"); |
debug("Server version does not support lstat operation"); |
else |
else |
error("Server version does not support lstat operation"); |
log("Server version does not support lstat operation"); |
return(NULL); |
return(do_stat(conn, path, quiet)); |
} |
} |
|
|
id = conn->msg_id++; |
id = conn->msg_id++; |
|
|
char *handle, u_int handle_len) |
char *handle, u_int handle_len) |
{ |
{ |
Buffer msg; |
Buffer msg; |
|
|
buffer_init(&msg); |
buffer_init(&msg); |
buffer_clear(&msg); |
buffer_clear(&msg); |
buffer_put_char(&msg, SSH2_FXP_READ); |
buffer_put_char(&msg, SSH2_FXP_READ); |
|
|
buffer_put_int(&msg, len); |
buffer_put_int(&msg, len); |
send_msg(fd_out, &msg); |
send_msg(fd_out, &msg); |
buffer_free(&msg); |
buffer_free(&msg); |
} |
} |
|
|
int |
int |
do_download(struct sftp_conn *conn, char *remote_path, char *local_path, |
do_download(struct sftp_conn *conn, char *remote_path, char *local_path, |
|
|
u_int id; |
u_int id; |
u_int len; |
u_int len; |
u_int64_t offset; |
u_int64_t offset; |
TAILQ_ENTRY(request) tq; |
TAILQ_ENTRY(request) tq; |
}; |
}; |
TAILQ_HEAD(reqhead, request) requests; |
TAILQ_HEAD(reqhead, request) requests; |
struct request *req; |
struct request *req; |
|
|
|
|
/* Send some more requests */ |
/* Send some more requests */ |
while (num_req < max_req) { |
while (num_req < max_req) { |
debug3("Request range %llu -> %llu (%d/%d)", |
debug3("Request range %llu -> %llu (%d/%d)", |
offset, offset + buflen - 1, num_req, max_req); |
(unsigned long long)offset, |
|
(unsigned long long)offset + buflen - 1, |
|
num_req, max_req); |
req = xmalloc(sizeof(*req)); |
req = xmalloc(sizeof(*req)); |
req->id = conn->msg_id++; |
req->id = conn->msg_id++; |
req->len = buflen; |
req->len = buflen; |
|
|
offset += buflen; |
offset += buflen; |
num_req++; |
num_req++; |
TAILQ_INSERT_TAIL(&requests, req, tq); |
TAILQ_INSERT_TAIL(&requests, req, tq); |
send_read_request(conn->fd_out, req->id, req->offset, |
send_read_request(conn->fd_out, req->id, req->offset, |
req->len, handle, handle_len); |
req->len, handle, handle_len); |
} |
} |
|
|
|
|
break; |
break; |
case SSH2_FXP_DATA: |
case SSH2_FXP_DATA: |
data = buffer_get_string(&msg, &len); |
data = buffer_get_string(&msg, &len); |
debug3("Received data %llu -> %llu", req->offset, |
debug3("Received data %llu -> %llu", |
req->offset + len - 1); |
(unsigned long long)req->offset, |
|
(unsigned long long)req->offset + len - 1); |
if (len > req->len) |
if (len > req->len) |
fatal("Received more data than asked for " |
fatal("Received more data than asked for " |
"%d > %d", len, req->len); |
"%d > %d", len, req->len); |
|
|
} else { |
} else { |
/* Resend the request for the missing data */ |
/* Resend the request for the missing data */ |
debug3("Short data block, re-requesting " |
debug3("Short data block, re-requesting " |
"%llu -> %llu (%2d)", req->offset + len, |
"%llu -> %llu (%2d)", |
req->offset + req->len - 1, num_req); |
(unsigned long long)req->offset + len, |
|
(unsigned long long)req->offset + |
|
req->len - 1, num_req); |
req->id = conn->msg_id++; |
req->id = conn->msg_id++; |
req->len -= len; |
req->len -= len; |
req->offset += len; |
req->offset += len; |
send_read_request(conn->fd_out, req->id, |
send_read_request(conn->fd_out, req->id, |
req->offset, req->len, handle, handle_len); |
req->offset, req->len, handle, handle_len); |
/* Reduce the request size */ |
/* Reduce the request size */ |
if (len < buflen) |
if (len < buflen) |
|
|
/* Only one request at a time |
/* Only one request at a time |
* after the expected EOF */ |
* after the expected EOF */ |
debug3("Finish at %llu (%2d)", |
debug3("Finish at %llu (%2d)", |
offset, num_req); |
(unsigned long long)offset, |
|
num_req); |
max_req = 1; |
max_req = 1; |
} |
} |
else if (max_req < conn->num_requests + 1) { |
else if (max_req < conn->num_requests + 1) { |
|
|
fatal("Transfer complete, but requests still in queue"); |
fatal("Transfer complete, but requests still in queue"); |
|
|
if (read_error) { |
if (read_error) { |
error("Couldn't read from remote file \"%s\" : %s", |
error("Couldn't read from remote file \"%s\" : %s", |
remote_path, fx2txt(status)); |
remote_path, fx2txt(status)); |
do_close(conn, handle, handle_len); |
do_close(conn, handle, handle_len); |
} else if (write_error) { |
} else if (write_error) { |
|
|
u_int id; |
u_int id; |
u_int len; |
u_int len; |
u_int64_t offset; |
u_int64_t offset; |
TAILQ_ENTRY(outstanding_ack) tq; |
TAILQ_ENTRY(outstanding_ack) tq; |
}; |
}; |
TAILQ_HEAD(ackhead, outstanding_ack) acks; |
TAILQ_HEAD(ackhead, outstanding_ack) acks; |
struct outstanding_ack *ack; |
struct outstanding_ack *ack; |
|
|
buffer_put_string(&msg, data, len); |
buffer_put_string(&msg, data, len); |
send_msg(conn->fd_out, &msg); |
send_msg(conn->fd_out, &msg); |
debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", |
debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", |
id, (u_int64_t)offset, len); |
id, (unsigned long long)offset, len); |
} else if (TAILQ_FIRST(&acks) == NULL) |
} else if (TAILQ_FIRST(&acks) == NULL) |
break; |
break; |
|
|
if (ack == NULL) |
if (ack == NULL) |
fatal("Unexpected ACK %u", id); |
fatal("Unexpected ACK %u", id); |
|
|
if (id == startid || len == 0 || |
if (id == startid || len == 0 || |
id - ackid >= conn->num_requests) { |
id - ackid >= conn->num_requests) { |
|
u_int r_id; |
|
|
buffer_clear(&msg); |
buffer_clear(&msg); |
get_msg(conn->fd_in, &msg); |
get_msg(conn->fd_in, &msg); |
type = buffer_get_char(&msg); |
type = buffer_get_char(&msg); |
id = buffer_get_int(&msg); |
r_id = buffer_get_int(&msg); |
|
|
if (type != SSH2_FXP_STATUS) |
if (type != SSH2_FXP_STATUS) |
fatal("Expected SSH2_FXP_STATUS(%d) packet, " |
fatal("Expected SSH2_FXP_STATUS(%d) packet, " |
|
|
|
|
/* Find the request in our queue */ |
/* Find the request in our queue */ |
for(ack = TAILQ_FIRST(&acks); |
for(ack = TAILQ_FIRST(&acks); |
ack != NULL && ack->id != id; |
ack != NULL && ack->id != r_id; |
ack = TAILQ_NEXT(ack, tq)) |
ack = TAILQ_NEXT(ack, tq)) |
; |
; |
if (ack == NULL) |
if (ack == NULL) |
fatal("Can't find request for ID %d", id); |
fatal("Can't find request for ID %d", r_id); |
TAILQ_REMOVE(&acks, ack, tq); |
TAILQ_REMOVE(&acks, ack, tq); |
|
|
if (status != SSH2_FX_OK) { |
if (status != SSH2_FX_OK) { |
|
|
close(local_fd); |
close(local_fd); |
goto done; |
goto done; |
} |
} |
debug3("In write loop, ack for %u %d bytes at %llu", |
debug3("In write loop, ack for %u %d bytes at %llu", |
ack->id, ack->len, ack->offset); |
ack->id, ack->len, (unsigned long long)ack->offset); |
++ackid; |
++ackid; |
free(ack); |
free(ack); |
} |
} |