add libssh2_scp_recv2 to support large (> 2GB) files on windows

This commit is contained in:
David Byron 2015-06-29 17:16:43 -07:00 committed by Alexander Lamaison
parent 4961014033
commit 6c84a426be
14 changed files with 167 additions and 18 deletions

View File

@ -119,6 +119,7 @@ set(MAN_PAGES
libssh2_publickey_remove_ex.3 libssh2_publickey_remove_ex.3
libssh2_publickey_shutdown.3 libssh2_publickey_shutdown.3
libssh2_scp_recv.3 libssh2_scp_recv.3
libssh2_scp_recv2.3
libssh2_scp_send.3 libssh2_scp_send.3
libssh2_scp_send64.3 libssh2_scp_send64.3
libssh2_scp_send_ex.3 libssh2_scp_send_ex.3

View File

@ -89,6 +89,7 @@ dist_man_MANS = \
libssh2_publickey_remove_ex.3 \ libssh2_publickey_remove_ex.3 \
libssh2_publickey_shutdown.3 \ libssh2_publickey_shutdown.3 \
libssh2_scp_recv.3 \ libssh2_scp_recv.3 \
libssh2_scp_recv2.3 \
libssh2_scp_send.3 \ libssh2_scp_send.3 \
libssh2_scp_send64.3 \ libssh2_scp_send64.3 \
libssh2_scp_send_ex.3 \ libssh2_scp_send_ex.3 \

View File

@ -8,6 +8,9 @@ LIBSSH2_CHANNEL *
libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb); libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
.SH DESCRIPTION .SH DESCRIPTION
This function is \fBDEPRECATED\fP. Use \fIlibssh2_scp_recv2(3)\fP
instead!
\fIsession\fP - Session instance as returned by \fIsession\fP - Session instance as returned by
.BR libssh2_session_init_ex(3) .BR libssh2_session_init_ex(3)

32
docs/libssh2_scp_recv2.3 Normal file
View File

@ -0,0 +1,32 @@
.TH libssh2_scp_recv2 3 "29 Jun 2015" "libssh2 1.6.1" "libssh2 manual"
.SH NAME
libssh2_scp_recv2 - request a remote file via SCP
.SH SYNOPSIS
#include <libssh2.h>
LIBSSH2_CHANNEL *
libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, struct_stat *sb);
.SH DESCRIPTION
\fIsession\fP - Session instance as returned by
.BR libssh2_session_init_ex(3)
\fIpath\fP - Full path and filename of file to transfer. That is the remote
file name.
\fIsb\fP - Populated with remote file's size, mode, mtime, and atime
Request a file from the remote host via SCP.
.SH RETURN VALUE
Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors.
.SH ERRORS
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
\fILIBSSH2_ERROR_SCP_PROTOCOL\fP -
\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would
block.
.SH SEE ALSO
.BR libssh2_session_init_ex(3)
.BR libssh2_channel_open_ex(3)

View File

@ -41,7 +41,7 @@ int main(int argc, char *argv[])
const char *username="username"; const char *username="username";
const char *password="password"; const char *password="password";
const char *scppath="/tmp/TEST"; const char *scppath="/tmp/TEST";
struct stat fileinfo; libssh2_struct_stat fileinfo;
int rc; int rc;
off_t got=0; off_t got=0;
@ -137,7 +137,7 @@ int main(int argc, char *argv[])
} }
/* Request a file via SCP */ /* Request a file via SCP */
channel = libssh2_scp_recv(session, scppath, &fileinfo); channel = libssh2_scp_recv2(session, scppath, &fileinfo);
if (!channel) { if (!channel) {
fprintf(stderr, "Unable to open a session: %d\n", fprintf(stderr, "Unable to open a session: %d\n",
@ -151,7 +151,7 @@ int main(int argc, char *argv[])
int amount=sizeof(mem); int amount=sizeof(mem);
if((fileinfo.st_size -got) < amount) { if((fileinfo.st_size -got) < amount) {
amount = fileinfo.st_size -got; amount = (int)(fileinfo.st_size -got);
} }
rc = libssh2_channel_read(channel, mem, amount); rc = libssh2_channel_read(channel, mem, amount);

View File

@ -88,16 +88,16 @@ int main(int argc, char *argv[])
const char *username="username"; const char *username="username";
const char *password="password"; const char *password="password";
const char *scppath="/tmp/TEST"; const char *scppath="/tmp/TEST";
struct stat fileinfo; libssh2_struct_stat fileinfo;
#ifdef HAVE_GETTIMEOFDAY #ifdef HAVE_GETTIMEOFDAY
struct timeval start; struct timeval start;
struct timeval end; struct timeval end;
long time_ms; long time_ms;
#endif #endif
int rc; int rc;
int total = 0;
int spin = 0; int spin = 0;
off_t got=0; libssh2_struct_stat_size got = 0;
libssh2_struct_stat_size total = 0;
#ifdef WIN32 #ifdef WIN32
WSADATA wsadata; WSADATA wsadata;
@ -207,9 +207,9 @@ int main(int argc, char *argv[])
#endif #endif
/* Request a file via SCP */ /* Request a file via SCP */
fprintf(stderr, "libssh2_scp_recv()!\n"); fprintf(stderr, "libssh2_scp_recv2()!\n");
do { do {
channel = libssh2_scp_recv(session, scppath, &fileinfo); channel = libssh2_scp_recv2(session, scppath, &fileinfo);
if (!channel) { if (!channel) {
if(libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { if(libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
@ -235,7 +235,7 @@ int main(int argc, char *argv[])
int amount=sizeof(mem); int amount=sizeof(mem);
if ((fileinfo.st_size -got) < amount) { if ((fileinfo.st_size -got) < amount) {
amount = fileinfo.st_size - got; amount = (int)(fileinfo.st_size - got);
} }
/* loop until we block */ /* loop until we block */
@ -262,10 +262,10 @@ int main(int argc, char *argv[])
gettimeofday(&end, NULL); gettimeofday(&end, NULL);
time_ms = tvdiff(end, start); time_ms = tvdiff(end, start);
fprintf(stderr, "Got %d bytes in %ld ms = %.1f bytes/sec spin: %d\n", total, fprintf(stderr, "Got " LIBSSH2_STRUCT_STAT_SIZE_FORMAT " bytes in %ld ms = %.1f bytes/sec spin: %d\n", total,
time_ms, total/(time_ms/1000.0), spin ); time_ms, total/(time_ms/1000.0), spin);
#else #else
fprintf(stderr, "Got %d bytes spin: %d\n", total, spin); fprintf(stderr, "Got " LIBSSH2_STRUCT_STAT_SIZE_FORMAT " bytes spin: %d\n", total, spin);
#endif #endif
libssh2_channel_free(channel); libssh2_channel_free(channel);

View File

@ -243,7 +243,7 @@ int main(int argc, char *argv[])
/* Other channel types are supported via: /* Other channel types are supported via:
* libssh2_scp_send() * libssh2_scp_send()
* libssh2_scp_recv() * libssh2_scp_recv2()
* libssh2_channel_direct_tcpip() * libssh2_channel_direct_tcpip()
*/ */

View File

@ -217,7 +217,7 @@ int main(int argc, char *argv[])
/* Other channel types are supported via: /* Other channel types are supported via:
* libssh2_scp_send() * libssh2_scp_send()
* libssh2_scp_recv() * libssh2_scp_recv2()
* libssh2_channel_direct_tcpip() * libssh2_channel_direct_tcpip()
*/ */

View File

@ -145,6 +145,67 @@ typedef int libssh2_socket_t;
#define LIBSSH2_INVALID_SOCKET -1 #define LIBSSH2_INVALID_SOCKET -1
#endif /* WIN32 */ #endif /* WIN32 */
/*
* Determine whether there is small or large file support on windows.
*/
#if defined(_MSC_VER) && !defined(_WIN32_WCE)
# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
# define USE_WIN32_LARGE_FILES
# else
# define USE_WIN32_SMALL_FILES
# endif
#endif
#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES)
# define USE_WIN32_LARGE_FILES
#endif
#if defined(__WATCOMC__) && !defined(USE_WIN32_LARGE_FILES)
# define USE_WIN32_LARGE_FILES
#endif
#if defined(__POCC__)
# undef USE_WIN32_LARGE_FILES
#endif
#if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
# define USE_WIN32_SMALL_FILES
#endif
/*
* Large file (>2Gb) support using WIN32 functions.
*/
#ifdef USE_WIN32_LARGE_FILES
# include <io.h>
# include <sys/types.h>
# include <sys/stat.h>
# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%I64d"
typedef struct _stati64 libssh2_struct_stat;
typedef __int64 libssh2_struct_stat_size;
#endif
/*
* Small file (<2Gb) support using WIN32 functions.
*/
#ifdef USE_WIN32_SMALL_FILES
# include <sys/types.h>
# include <sys/stat.h>
# ifndef _WIN32_WCE
# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%d"
typedef struct _stat libssh2_struct_stat;
typedef off_t libssh2_struct_stat_size;
# endif
#endif
#ifndef LIBSSH2_STRUCT_STAT_SIZE_FORMAT
# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%zd"
typedef struct stat libssh2_struct_stat;
typedef off_t libssh2_struct_stat_size;
#endif
/* Part of every banner, user specified or not */ /* Part of every banner, user specified or not */
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION #define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
@ -805,9 +866,14 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
/* libssh2_scp_recv is DEPRECATED, do not use! */
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session,
const char *path, const char *path,
struct stat *sb); struct stat *sb);
/* Use libssh2_scp_recv2 for large (> 2GB) file support on windows */
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv2(LIBSSH2_SESSION *session,
const char *path,
libssh2_struct_stat *sb);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session,
const char *path, int mode, const char *path, int mode,
size_t size, long mtime, size_t size, long mtime,

View File

@ -545,6 +545,7 @@ endif
@echo $(DL) libssh2_knownhost_readfile,$(DL) >> $@ @echo $(DL) libssh2_knownhost_readfile,$(DL) >> $@
@echo $(DL) libssh2_knownhost_writefile,$(DL) >> $@ @echo $(DL) libssh2_knownhost_writefile,$(DL) >> $@
@echo $(DL) libssh2_scp_recv,$(DL) >> $@ @echo $(DL) libssh2_scp_recv,$(DL) >> $@
@echo $(DL) libssh2_scp_recv2,$(DL) >> $@
@echo $(DL) libssh2_scp_send64,$(DL) >> $@ @echo $(DL) libssh2_scp_send64,$(DL) >> $@
@echo $(DL) libssh2_scp_send_ex,$(DL) >> $@ @echo $(DL) libssh2_scp_send_ex,$(DL) >> $@
@echo $(DL) libssh2_session_abstract,$(DL) >> $@ @echo $(DL) libssh2_session_abstract,$(DL) >> $@

View File

@ -38,6 +38,7 @@ include(CheckSymbolExists)
include(CheckFunctionExistsMayNeedLibrary) include(CheckFunctionExistsMayNeedLibrary)
include(CheckIncludeFiles) include(CheckIncludeFiles)
include(CheckTypeSize) include(CheckTypeSize)
include(CheckSymbolExists)
include(CheckNonblockingSocketSupport) include(CheckNonblockingSocketSupport)
include(SocketLibraries) include(SocketLibraries)
@ -281,6 +282,10 @@ if(HAVE_STDLIB_H)
else() else()
check_function_exists(strtoll HAVE_STRTOLL) check_function_exists(strtoll HAVE_STRTOLL)
endif() endif()
if (NOT HAVE_STRTOLL)
# Try _strtoi64 if strtoll isn't available
check_symbol_exists(_strtoi64 stdlib.h HAVE_STRTOI64)
endif()
check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF) check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR

View File

@ -64,6 +64,7 @@
#cmakedefine HAVE_SELECT #cmakedefine HAVE_SELECT
#cmakedefine HAVE_SOCKET #cmakedefine HAVE_SOCKET
#cmakedefine HAVE_STRTOLL #cmakedefine HAVE_STRTOLL
#cmakedefine HAVE_STRTOI64
#cmakedefine HAVE_SNPRINTF #cmakedefine HAVE_SNPRINTF
/* OpenSSL functions */ /* OpenSSL functions */

View File

@ -779,7 +779,7 @@ struct _LIBSSH2_SESSION
int sftpInit_sent; /* number of bytes from the buffer that have been int sftpInit_sent; /* number of bytes from the buffer that have been
sent */ sent */
/* State variables used in libssh2_scp_recv() */ /* State variables used in libssh2_scp_recv() / libssh_scp_recv2() */
libssh2_nonblocking_states scpRecv_state; libssh2_nonblocking_states scpRecv_state;
unsigned char *scpRecv_command; unsigned char *scpRecv_command;
size_t scpRecv_command_len; size_t scpRecv_command_len;
@ -790,6 +790,9 @@ struct _LIBSSH2_SESSION
/* we have the type and we can parse such numbers */ /* we have the type and we can parse such numbers */
long long scpRecv_size; long long scpRecv_size;
#define scpsize_strtol strtoll #define scpsize_strtol strtoll
#elif defined(HAVE_STRTOI64)
__int64 scpRecv_size;
#define scpsize_strtol _strtoi64
#else #else
long scpRecv_size; long scpRecv_size;
#define scpsize_strtol strtol #define scpsize_strtol strtol

View File

@ -268,7 +268,7 @@ shell_quotearg(const char *path, unsigned char *buf,
* *
*/ */
static LIBSSH2_CHANNEL * static LIBSSH2_CHANNEL *
scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb) scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb)
{ {
int cmd_len; int cmd_len;
int rc; int rc;
@ -724,7 +724,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
} }
if (sb) { if (sb) {
memset(sb, 0, sizeof(struct stat)); memset(sb, 0, sizeof(libssh2_struct_stat));
sb->st_mtime = session->scpRecv_mtime; sb->st_mtime = session->scpRecv_mtime;
sb->st_atime = session->scpRecv_atime; sb->st_atime = session->scpRecv_atime;
@ -759,11 +759,47 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
/* /*
* libssh2_scp_recv * libssh2_scp_recv
* *
* Open a channel and request a remote file via SCP * DEPRECATED
*
* Open a channel and request a remote file via SCP. This receives files larger
* than 2 GB, but is unable to report the proper size on platforms where the
* st_size member of struct stat is limited to 2 GB (e.g. windows).
* *
*/ */
LIBSSH2_API LIBSSH2_CHANNEL * LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb)
{
LIBSSH2_CHANNEL *ptr;
/* scp_recv uses libssh2_struct_stat, so pass one if the caller gave us a struct to populate... */
libssh2_struct_stat sb_intl;
libssh2_struct_stat *sb_ptr;
sb_ptr = sb ? &sb_intl : NULL;
BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb_ptr));
/* ...and populate the caller's with as much info as fits. */
if (sb) {
memset(sb, 0, sizeof(struct stat));
sb->st_mtime = sb_intl.st_mtime;
sb->st_atime = sb_intl.st_atime;
sb->st_size = (off_t)sb_intl.st_size;
sb->st_mode = sb_intl.st_mode;
}
return ptr;
}
/*
* libssh2_scp_recv2
*
* Open a channel and request a remote file via SCP. This supports files > 2GB
* on platforms that support it.
*
*/
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, libssh2_struct_stat * sb)
{ {
LIBSSH2_CHANNEL *ptr; LIBSSH2_CHANNEL *ptr;
BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb)); BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb));