version 1.170, 2023/03/28 07:44:32 |
version 1.171, 2023/04/30 22:54:22 |
|
|
u_char *handle; |
u_char *handle; |
int local_fd = -1, write_error; |
int local_fd = -1, write_error; |
int read_error, write_errno, lmodified = 0, reordered = 0, r; |
int read_error, write_errno, lmodified = 0, reordered = 0, r; |
u_int64_t offset = 0, size, highwater; |
u_int64_t offset = 0, size, highwater = 0, maxack = 0; |
u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK; |
u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK; |
off_t progress_counter; |
off_t progress_counter; |
size_t handle_len; |
size_t handle_len; |
|
|
error("open local \"%s\": %s", local_path, strerror(errno)); |
error("open local \"%s\": %s", local_path, strerror(errno)); |
goto fail; |
goto fail; |
} |
} |
offset = highwater = 0; |
|
if (resume_flag) { |
if (resume_flag) { |
if (fstat(local_fd, &st) == -1) { |
if (fstat(local_fd, &st) == -1) { |
error("stat local \"%s\": %s", |
error("stat local \"%s\": %s", |
|
|
close(local_fd); |
close(local_fd); |
return -1; |
return -1; |
} |
} |
offset = highwater = st.st_size; |
offset = highwater = maxack = st.st_size; |
} |
} |
|
|
/* Read from remote and write to local */ |
/* Read from remote and write to local */ |
|
|
write_errno = errno; |
write_errno = errno; |
write_error = 1; |
write_error = 1; |
max_req = 0; |
max_req = 0; |
|
} else { |
|
/* |
|
* Track both the highest offset acknowledged |
|
* and the highest *contiguous* offset |
|
* acknowledged. |
|
* We'll need the latter for ftruncate()ing |
|
* interrupted transfers. |
|
*/ |
|
if (maxack < req->offset + len) |
|
maxack = req->offset + len; |
|
if (!reordered && req->offset <= highwater) |
|
highwater = maxack; |
|
else if (!reordered && req->offset > highwater) |
|
reordered = 1; |
} |
} |
else if (!reordered && req->offset <= highwater) |
|
highwater = req->offset + len; |
|
else if (!reordered && req->offset > highwater) |
|
reordered = 1; |
|
progress_counter += len; |
progress_counter += len; |
free(data); |
free(data); |
|
|
|
|
/* Sanity check */ |
/* Sanity check */ |
if (TAILQ_FIRST(&requests) != NULL) |
if (TAILQ_FIRST(&requests) != NULL) |
fatal("Transfer complete, but requests still in queue"); |
fatal("Transfer complete, but requests still in queue"); |
|
|
|
if (!read_error && !write_error && !interrupted) { |
|
/* we got everything */ |
|
highwater = maxack; |
|
} |
|
|
/* |
/* |
* Truncate at highest contiguous point to avoid holes on interrupt, |
* Truncate at highest contiguous point to avoid holes on interrupt, |
* or unconditionally if writing in place. |
* or unconditionally if writing in place. |
*/ |
*/ |
if (inplace_flag || read_error || write_error || interrupted) { |
if (inplace_flag || read_error || write_error || interrupted) { |
if (reordered && resume_flag) { |
if (reordered && resume_flag && |
|
(read_error || write_error || interrupted)) { |
error("Unable to resume download of \"%s\": " |
error("Unable to resume download of \"%s\": " |
"server reordered requests", local_path); |
"server reordered requests", local_path); |
} |
} |
|
|
struct stat sb; |
struct stat sb; |
Attrib a, t, *c = NULL; |
Attrib a, t, *c = NULL; |
u_int32_t startid, ackid; |
u_int32_t startid, ackid; |
u_int64_t highwater = 0; |
u_int64_t highwater = 0, maxack = 0; |
struct request *ack = NULL; |
struct request *ack = NULL; |
struct requests acks; |
struct requests acks; |
size_t handle_len; |
size_t handle_len; |
|
|
ack->id, ack->len, (unsigned long long)ack->offset); |
ack->id, ack->len, (unsigned long long)ack->offset); |
++ackid; |
++ackid; |
progress_counter += ack->len; |
progress_counter += ack->len; |
|
/* |
|
* Track both the highest offset acknowledged and the |
|
* highest *contiguous* offset acknowledged. |
|
* We'll need the latter for ftruncate()ing |
|
* interrupted transfers. |
|
*/ |
|
if (maxack < ack->offset + ack->len) |
|
maxack = ack->offset + ack->len; |
if (!reordered && ack->offset <= highwater) |
if (!reordered && ack->offset <= highwater) |
highwater = ack->offset + ack->len; |
highwater = maxack; |
else if (!reordered && ack->offset > highwater) { |
else if (!reordered && ack->offset > highwater) { |
debug3_f("server reordered ACKs"); |
debug3_f("server reordered ACKs"); |
reordered = 1; |
reordered = 1; |
|
|
stop_progress_meter(); |
stop_progress_meter(); |
free(data); |
free(data); |
|
|
|
if (status == SSH2_FX_OK && !interrupted) { |
|
/* we got everything */ |
|
highwater = maxack; |
|
} |
if (status != SSH2_FX_OK) { |
if (status != SSH2_FX_OK) { |
error("write remote \"%s\": %s", remote_path, fx2txt(status)); |
error("write remote \"%s\": %s", remote_path, fx2txt(status)); |
status = SSH2_FX_FAILURE; |
status = SSH2_FX_FAILURE; |