diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2015-09-06 16:05:24 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2015-09-06 16:05:24 +0200 |
commit | 471a181c3ad4a3fa6267ce13791116121b43725d (patch) | |
tree | f4f608496364920b06b9f8c1d5e9e59fe9865df1 /src | |
parent | 42dece6021fa1ab8fdc4e8d8a729e5f7aa17fd27 (diff) | |
download | cssh-471a181c3ad4a3fa6267ce13791116121b43725d.tar.gz cssh-471a181c3ad4a3fa6267ce13791116121b43725d.tar.bz2 |
made writing fair to all session (splitting downloads in pieces)
Diffstat (limited to 'src')
-rw-r--r-- | src/cssh.c | 91 |
1 files changed, 51 insertions, 40 deletions
@@ -1,3 +1,5 @@ +#define _FILE_OFFSET_BITS 64 + #include <libssh/libssh.h> #include <libssh/callbacks.h> @@ -66,6 +68,8 @@ typedef struct scp_data_t { ssh_scp scp; scp_read_state_e read_state; scp_dir_stack_t dir_stack; + int fd; + char *filename; char *buf; uint64_t size; uint64_t bytesReceived; @@ -436,6 +440,11 @@ static void cleanup_sessions( ssh_session **session, ssh_channel **channel, scp_ ssh_scp_free( *scp ); scp = NULL; } + char *filename = (*scp_data)[i].filename; + if( filename != NULL ) { + free( filename ); + filename = NULL; + } char *buf = (*scp_data)[i].buf; if( buf != NULL ) { free( buf ); @@ -1112,6 +1121,7 @@ int main( int argc, char *argv[] ) } snprintf( full_path, len, "%s/%s", pwd, host[i] ); rc = push_dir_stack( &scp_data[i].dir_stack, full_path ); + scp_data[i].filename = full_path; if( rc < 0 ) { fprintf( stderr, "ERROR: failed remember initial base directory '%s' in directory stack\n", @@ -1129,6 +1139,8 @@ int main( int argc, char *argv[] ) cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } + } else { + scp_data[i].filename = pwd; } } @@ -1158,7 +1170,7 @@ int main( int argc, char *argv[] ) exit( EXIT_FAILURE ); } - const char *filename = ssh_scp_request_get_filename( scp_data[i].scp ); + const char *filename = ssh_scp_request_get_filename( scp_data[i].scp ); int mode = ssh_scp_request_get_permissions( scp_data[i].scp ); fprintf( stderr, "Receiving directory '%s' with permissions '0%o'\n", filename, mode ); @@ -1203,8 +1215,8 @@ int main( int argc, char *argv[] ) free( full_path ); cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); - } - free( full_path ); + } + free( full_path ); } break; case SSH_SCP_REQUEST_ENDDIR: @@ -1244,51 +1256,19 @@ int main( int argc, char *argv[] ) exit( EXIT_FAILURE ); } snprintf( full_path, len, "%s/%s", dir, filename ); + int fd = open( full_path, O_WRONLY | O_CREAT | O_TRUNC, mode ); if( fd < 0 ) { fprintf( stderr, "ERROR: Unable to open file '%s': %s\n", full_path, strerror( errno ) ); - free( full_path ); cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } - free( full_path ); - - // TODO: we receive a buffer of data < 65k, so we must introduce a - // state machine here so we know we still have to read or initiate the accept, - // this is also quite handy as we can show some progress bar here or some ETA - // TODO: write buffer to received file in workdir of host[i] - // TODO: slurping it all for one connection is not fair to other connections, - // we should read a buffer and then check the states of the other and hit the - // loop again, this needs a state machine.. + + scp_data[i].fd = fd; + scp_data[i].filename = full_path; scp_data[i].bytesReceived = 0; - while( scp_data[i].bytesReceived < scp_data[i].size ) { - rc = ssh_scp_read( scp_data[i].scp, scp_data[i].buf, BUFSIZE ); - if( rc == SSH_ERROR ) { - fprintf( stderr, "ERROR: reading data for file '%s' failed: %s\n", - filename, ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - scp_data[i].bytesReceived += rc; - if( rc > 0 ) { - ssize_t r = write( fd, scp_data[i].buf, rc ); - if( r < 0 ) { - fprintf( stderr, "ERROR: writing data to file '%s' failed: %s\n", - filename, strerror( errno ) ); - cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - } - } - - rc = close( fd ); - if( rc < 0 ) { - fprintf( stderr, "ERROR: Unable to close file '%s': %s\n", - filename, strerror( errno ) ); - cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } + scp_data[i].read_state = CSSH_SCP_READ_STATE_READING; } break; case SSH_SCP_REQUEST_EOF: @@ -1319,6 +1299,37 @@ int main( int argc, char *argv[] ) break; case CSSH_SCP_READ_STATE_READING: + if( scp_data[i].bytesReceived < scp_data[i].size ) { + rc = ssh_scp_read( scp_data[i].scp, scp_data[i].buf, BUFSIZE ); + if( rc == SSH_ERROR ) { + fprintf( stderr, "ERROR: reading data for file '%s' failed: %s\n", + scp_data[i].filename, ssh_get_error( session[i] ) ); + cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + scp_data[i].bytesReceived += rc; + if( rc > 0 ) { + ssize_t r = write( scp_data[i].fd, scp_data[i].buf, rc ); + if( r < 0 ) { + fprintf( stderr, "ERROR: writing data to file '%s' failed: %s\n", + scp_data[i].filename, strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + } + } else { + rc = close( scp_data[i].fd ); + if( rc < 0 ) { + fprintf( stderr, "ERROR: Unable to close file '%s': %s\n", + scp_data[i].filename, strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp_data, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + scp_data[i].read_state = CSSH_SCP_READ_STATE_IDLE; + scp_data[i].fd = 0; + free( scp_data[i].filename ); + scp_data[i].filename = NULL; + } break; case CSSH_SCP_READ_STATE_EOF: |