|
|
@@ -2336,6 +2336,111 @@ libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int sftp_punchhole(LIBSSH2_SFTP_HANDLE *handle, off_t off, off_t len) |
|
|
|
{ |
|
|
|
LIBSSH2_SFTP *sftp = handle->sftp; |
|
|
|
LIBSSH2_CHANNEL *channel = sftp->channel; |
|
|
|
LIBSSH2_SESSION *session = channel->session; |
|
|
|
/* 55 = packet_len(4) + packet_type(1) + request_id(4) + |
|
|
|
string_len(4) + strlen("punchhole@funkthat.com")(22) + handle_len(4) + |
|
|
|
off_len(8) + len_len(8) */ |
|
|
|
uint32_t packet_len = handle->handle_len + 55; |
|
|
|
size_t data_len; |
|
|
|
unsigned char *packet, *s, *data; |
|
|
|
ssize_t rc; |
|
|
|
uint32_t retcode; |
|
|
|
|
|
|
|
if(sftp->punchhole_state == libssh2_NB_state_idle) { |
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, |
|
|
|
"Issuing punchhole command"); |
|
|
|
s = packet = LIBSSH2_ALLOC(session, packet_len); |
|
|
|
if(!packet) { |
|
|
|
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, |
|
|
|
"Unable to allocate memory for FXP_EXTENDED " |
|
|
|
"packet"); |
|
|
|
} |
|
|
|
|
|
|
|
_libssh2_store_u32(&s, packet_len - 4); |
|
|
|
*(s++) = SSH_FXP_EXTENDED; |
|
|
|
sftp->punchhole_request_id = sftp->request_id++; |
|
|
|
_libssh2_store_u32(&s, sftp->punchhole_request_id); |
|
|
|
_libssh2_store_str(&s, "punchhole@funkthat.com", 22); |
|
|
|
_libssh2_store_str(&s, handle->handle, handle->handle_len); |
|
|
|
_libssh2_store_u64(&s, off); |
|
|
|
_libssh2_store_u64(&s, len); |
|
|
|
|
|
|
|
sftp->punchhole_state = libssh2_NB_state_created; |
|
|
|
} |
|
|
|
else { |
|
|
|
packet = sftp->punchhole_packet; |
|
|
|
} |
|
|
|
|
|
|
|
if(sftp->punchhole_state == libssh2_NB_state_created) { |
|
|
|
rc = _libssh2_channel_write(channel, 0, packet, packet_len); |
|
|
|
if(rc == LIBSSH2_ERROR_EAGAIN || |
|
|
|
(0 <= rc && rc < (ssize_t)packet_len)) { |
|
|
|
sftp->punchhole_packet = packet; |
|
|
|
return LIBSSH2_ERROR_EAGAIN; |
|
|
|
} |
|
|
|
|
|
|
|
LIBSSH2_FREE(session, packet); |
|
|
|
sftp->punchhole_packet = NULL; |
|
|
|
|
|
|
|
if(rc < 0) { |
|
|
|
sftp->punchhole_state = libssh2_NB_state_idle; |
|
|
|
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, |
|
|
|
"_libssh2_channel_write() failed"); |
|
|
|
} |
|
|
|
sftp->punchhole_state = libssh2_NB_state_sent; |
|
|
|
} |
|
|
|
|
|
|
|
rc = sftp_packet_require(sftp, SSH_FXP_STATUS, |
|
|
|
sftp->punchhole_request_id, &data, &data_len, 9); |
|
|
|
if(rc == LIBSSH2_ERROR_EAGAIN) { |
|
|
|
return rc; |
|
|
|
} |
|
|
|
else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { |
|
|
|
if(data_len > 0) { |
|
|
|
LIBSSH2_FREE(session, data); |
|
|
|
} |
|
|
|
return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, |
|
|
|
"SFTP punchhole packet too short"); |
|
|
|
} |
|
|
|
else if(rc) { |
|
|
|
sftp->punchhole_state = libssh2_NB_state_idle; |
|
|
|
return _libssh2_error(session, rc, |
|
|
|
"Error waiting for FXP EXTENDED REPLY"); |
|
|
|
} |
|
|
|
|
|
|
|
sftp->punchhole_state = libssh2_NB_state_idle; |
|
|
|
|
|
|
|
retcode = _libssh2_ntohu32(data + 5); |
|
|
|
LIBSSH2_FREE(session, data); |
|
|
|
|
|
|
|
if(retcode != LIBSSH2_FX_OK) { |
|
|
|
sftp->last_errno = retcode; |
|
|
|
return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, |
|
|
|
"punchhole failed"); |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* libssh2_sftp_punchhole |
|
|
|
* Punch hole in remote file. |
|
|
|
*/ |
|
|
|
LIBSSH2_API int |
|
|
|
libssh2_sftp_punchhole(LIBSSH2_SFTP_HANDLE *hnd, off_t off, off_t len) |
|
|
|
{ |
|
|
|
int rc; |
|
|
|
if(!hnd) |
|
|
|
return LIBSSH2_ERROR_BAD_USE; |
|
|
|
BLOCK_ADJUST(rc, hnd->sftp->channel->session, |
|
|
|
sftp_punchhole(hnd, off, len)); |
|
|
|
return rc; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
* sftp_fstat |
|
|
|
* |
|
|
|