sftp: Add support for fsync (OpenSSH extension).
The new libssh2_sftp_fsync API causes data and metadata in the currently open file to be committed to disk at the server. This is an OpenSSH extension to the SFTP protocol. See: https://bugzilla.mindrot.org/show_bug.cgi?id=1798
Этот коммит содержится в:
родитель
a12f3ffab5
Коммит
6e0d757f24
@ -120,6 +120,7 @@ dist_man_MANS = \
|
||||
libssh2_sftp_fstat.3 \
|
||||
libssh2_sftp_fstat_ex.3 \
|
||||
libssh2_sftp_fstatvfs.3 \
|
||||
libssh2_sftp_fsync.3 \
|
||||
libssh2_sftp_get_channel.3 \
|
||||
libssh2_sftp_init.3 \
|
||||
libssh2_sftp_last_error.3 \
|
||||
|
39
docs/libssh2_sftp_fsync.3
Обычный файл
39
docs/libssh2_sftp_fsync.3
Обычный файл
@ -0,0 +1,39 @@
|
||||
.TH libssh2_sftp_fsync 3 "8 Apr 2013" "libssh2 1.4.4" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_sftp_fsync - synchronize file to disk
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
int
|
||||
libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
This function causes the remote server to synchronize the file
|
||||
data and metadata to disk (like fsync(2)).
|
||||
|
||||
For this to work requires fsync@openssh.com support on the server.
|
||||
|
||||
\fIhandle\fP - SFTP File Handle as returned by
|
||||
.BR libssh2_sftp_open_ex(3)
|
||||
|
||||
.SH RETURN VALUE
|
||||
Returns 0 on success or negative on failure. If used in non-blocking mode, it
|
||||
returns LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
||||
|
||||
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
|
||||
|
||||
\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response
|
||||
was received on the socket, or an SFTP operation caused an errorcode
|
||||
to be returned by the server. In particular, this can be returned if
|
||||
the SSH server does not support the fsync operation: the SFTP subcode
|
||||
\fILIBSSH2_FX_OP_UNSUPPORTED\fP will be returned in this case.
|
||||
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.4.4 and OpenSSH 6.3.
|
||||
.SH SEE ALSO
|
||||
.BR fsync(2)
|
@ -247,6 +247,7 @@ LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \
|
||||
|
||||
LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
|
||||
const char *buffer, size_t count);
|
||||
LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle);
|
||||
|
||||
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
|
||||
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
|
||||
|
97
src/sftp.c
97
src/sftp.c
@ -986,6 +986,10 @@ sftp_shutdown(LIBSSH2_SFTP *sftp)
|
||||
LIBSSH2_FREE(session, sftp->symlink_packet);
|
||||
sftp->symlink_packet = NULL;
|
||||
}
|
||||
if (sftp->fsync_packet) {
|
||||
LIBSSH2_FREE(session, sftp->fsync_packet);
|
||||
sftp->fsync_packet = NULL;
|
||||
}
|
||||
|
||||
sftp_packet_flush(sftp);
|
||||
|
||||
@ -2014,6 +2018,99 @@ libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer,
|
||||
|
||||
}
|
||||
|
||||
static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
|
||||
{
|
||||
LIBSSH2_SFTP *sftp = handle->sftp;
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
/* 34 = packet_len(4) + packet_type(1) + request_id(4) +
|
||||
string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */
|
||||
uint32_t packet_len = handle->handle_len + 34;
|
||||
size_t data_len;
|
||||
unsigned char *packet, *s, *data;
|
||||
ssize_t rc;
|
||||
uint32_t retcode;
|
||||
|
||||
if (sftp->fsync_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Issuing fsync 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->fsync_request_id = sftp->request_id++;
|
||||
_libssh2_store_u32(&s, sftp->fsync_request_id);
|
||||
_libssh2_store_str(&s, "fsync@openssh.com", 17);
|
||||
_libssh2_store_str(&s, handle->handle, handle->handle_len);
|
||||
|
||||
sftp->fsync_state = libssh2_NB_state_created;
|
||||
} else {
|
||||
packet = sftp->fsync_packet;
|
||||
}
|
||||
|
||||
if (sftp->fsync_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->fsync_packet = packet;
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, packet);
|
||||
sftp->fsync_packet = NULL;
|
||||
|
||||
if (rc < 0) {
|
||||
sftp->fsync_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"_libssh2_channel_write() failed");
|
||||
}
|
||||
sftp->fsync_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
sftp->fsync_request_id, &data, &data_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
sftp->fsync_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, rc,
|
||||
"Error waiting for FXP EXTENDED REPLY");
|
||||
}
|
||||
|
||||
sftp->fsync_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,
|
||||
"fsync failed");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* libssh2_sftp_fsync
|
||||
* Commit data on the handle to disk.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd)
|
||||
{
|
||||
int rc;
|
||||
if(!hnd)
|
||||
return LIBSSH2_ERROR_BAD_USE;
|
||||
BLOCK_ADJUST(rc, hnd->sftp->channel->session,
|
||||
sftp_fsync(hnd));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sftp_fstat
|
||||
*
|
||||
|
@ -175,6 +175,11 @@ struct _LIBSSH2_SFTP
|
||||
/* State variable used in sftp_write() */
|
||||
libssh2_nonblocking_states write_state;
|
||||
|
||||
/* State variables used in sftp_fsync() */
|
||||
libssh2_nonblocking_states fsync_state;
|
||||
unsigned char *fsync_packet;
|
||||
uint32_t fsync_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_readdir() */
|
||||
libssh2_nonblocking_states readdir_state;
|
||||
unsigned char *readdir_packet;
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user