From 635976a25836e7fd120249a29c7fc70a5e58dc99 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sun, 30 Aug 2015 15:26:21 +0200 Subject: indroduced dirstack, first recursive copy successful --- src/cssh.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 225 insertions(+), 40 deletions(-) diff --git a/src/cssh.c b/src/cssh.c index 09b1c3d..66272ef 100644 --- a/src/cssh.c +++ b/src/cssh.c @@ -8,8 +8,11 @@ #include #include #include +#include +#include #include #include +#include #include "msleep.h" @@ -48,6 +51,60 @@ typedef enum scp_read_state_e { CSSH_SCP_READ_STATE_EOF } scp_read_state_e; +typedef struct scp_dir_stack_entry_t { + char *dir; + struct scp_dir_stack_entry_t *next; +} scp_dir_stack_entry_t; + +typedef struct scp_dir_stack_t { + struct scp_dir_stack_entry_t *head; +} scp_dir_stack_t; + +static int push_dir_stack( scp_dir_stack_t *stack, const char *dir ) +{ + struct scp_dir_stack_entry_t *e = (struct scp_dir_stack_entry_t *)malloc( sizeof( scp_dir_stack_entry_t ) ); + if( e == NULL ) { + return -1; + } + + e->dir = strdup( dir ); + e->next = stack->head; + stack->head = e; + + return 0; +} + +static void pop_dir_stack( scp_dir_stack_t *stack ) +{ + if( stack->head != NULL ) { + struct scp_dir_stack_entry_t *e = stack->head; + stack->head = stack->head->next; + free( e->dir ); + free( e ); + } +} + +static char *top_dir_stack( scp_dir_stack_t *stack ) +{ + if( stack->head != NULL ) { + return stack->head->dir; + } else { + return NULL; + } +} + +static void free_dir_stack( scp_dir_stack_t *stack ) +{ + while( stack->head != NULL ) { + pop_dir_stack( stack ); + } +} + +static void create_dir_stack( scp_dir_stack_t *stack ) +{ + stack->head = NULL; +} + static execution_mode_e determine_execution_mode( const char *argv0 ) { char *b = ssh_basename( argv0 ); @@ -327,7 +384,7 @@ static int read_hosts_file( const char *hosts_file, unsigned short default_port, return 0; } -static void cleanup_sessions( ssh_session **session, ssh_channel **channel, ssh_scp **scp, scp_read_state_e **read_state, char ***buf, char **host, unsigned short *port, const int nof_sessions, bool verbose ) +static void cleanup_sessions( ssh_session **session, ssh_channel **channel, ssh_scp **scp, scp_read_state_e **read_state, char ***buf, scp_dir_stack_t **dir_stack, char **host, unsigned short *port, const int nof_sessions, bool verbose ) { for( unsigned int i = 0; i < nof_sessions; i++ ) { if( ssh_is_connected( (*session)[i] ) ) { @@ -348,6 +405,9 @@ static void cleanup_sessions( ssh_session **session, ssh_channel **channel, ssh_ if( buf != NULL ) { free( (*buf)[i] ); } + if( dir_stack != NULL ) { + free_dir_stack( &(*dir_stack)[i] ); + } ssh_disconnect( (*session)[i] ); if( verbose ) { fprintf( stderr, "Disconnected from '%s', port %d..\n", host[i], port[i] ); @@ -367,6 +427,9 @@ static void cleanup_sessions( ssh_session **session, ssh_channel **channel, ssh_ if( buf != NULL ) { free( *buf ); } + if( dir_stack != NULL ) { + free( *dir_stack ); + } free( *session ); free( *host ); free( port ); @@ -473,7 +536,7 @@ int main( int argc, char *argv[] ) bool *is_connected = (bool *)malloc( ( nof_sessions + 1 ) * sizeof( bool ) ); if( is_connected == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for 'is_connected'" ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_SUCCESS ); } memset( is_connected, false, ( nof_sessions + 1 ) * sizeof( bool ) ); @@ -492,7 +555,7 @@ int main( int argc, char *argv[] ) } else { fprintf( stderr, "ERROR: error connecting to '%s', port '%d': %s\n", host[i], port[i], ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -512,7 +575,7 @@ int main( int argc, char *argv[] ) auth_state_e *auth_state = (auth_state_e *)malloc( ( nof_sessions + 1 ) * sizeof( auth_state_e ) ); if( auth_state == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for 'auth_state'" ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } memset( auth_state, CSSH_AUTH_INIT, ( nof_sessions + 1 ) * sizeof( auth_state_e ) ); @@ -523,7 +586,7 @@ int main( int argc, char *argv[] ) if( verify_knownhost( session[i] ) < 0 ) { fprintf( stderr, "ERROR: closing connection to '%s', port '%d' due to security reasons\n", host[i], port[i] ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } auth_state[i] = CSSH_AUTH_VERIFY_HOST_DONE; @@ -544,7 +607,7 @@ int main( int argc, char *argv[] ) } else { fprintf( stderr, "ERROR: ssh_userauth_none to '%s', port '%d' failed: %s\n", host[i], port[i], ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } break; @@ -569,7 +632,7 @@ int main( int argc, char *argv[] ) } else if( rc == SSH_AUTH_DENIED ) { auth_state[i] = CSSH_AUTH_PUBKEY_DONE_FAILED; } else { - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } break; @@ -588,7 +651,7 @@ int main( int argc, char *argv[] ) } else if( rc == SSH_AUTH_DENIED ) { auth_state[i] = CSSH_AUTH_PASSWORD_DONE_FAILED; } else { - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } break; @@ -608,7 +671,7 @@ int main( int argc, char *argv[] ) case CSSH_AUTH_DONE_FAILED: // one authentication failed, bail out for now fprintf( stderr, "ERROR: authentication failed for one host ('%s'), aborting now", host[i] ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -631,7 +694,7 @@ int main( int argc, char *argv[] ) memset( channel, 0, nof_sessions + 1 ); if( channel == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for ssh_channels" ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } for( unsigned int i = 0; i < nof_sessions; i++ ) { @@ -639,7 +702,7 @@ int main( int argc, char *argv[] ) if( channel[i] == NULL ) { fprintf( stderr, "ERROR: Unable to open SSH channel: %s\n", ssh_get_error( session[i] ) ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -647,7 +710,7 @@ int main( int argc, char *argv[] ) for( unsigned int i = 0; i < nof_sessions; i++ ) { rc = ssh_channel_open_session( channel[i] ); if( rc != SSH_OK ) { - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -665,7 +728,7 @@ int main( int argc, char *argv[] ) } if( cmd[0] == '\0' ) { fprintf( stderr, "ERROR: Empty command, no interactive CLI supported currently\n" ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -675,7 +738,7 @@ int main( int argc, char *argv[] ) if( rc != SSH_OK ) { fprintf( stderr, "ERROR: Executing SSH command '%s' failed: %s\n", cmd, ssh_get_error( session[i] ) ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -684,7 +747,7 @@ int main( int argc, char *argv[] ) bool *eof_sent = (bool *)malloc( ( nof_sessions + 1 ) * sizeof( bool ) ); if( eof_sent == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for 'eof_sent'" ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } memset( eof_sent, false, ( nof_sessions + 1 ) * sizeof( bool ) ); @@ -692,7 +755,7 @@ int main( int argc, char *argv[] ) if( is_eof == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for 'is_eof'" ); free( eof_sent ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } memset( is_eof, false, ( nof_sessions + 1 ) * sizeof( bool ) ); @@ -723,7 +786,7 @@ int main( int argc, char *argv[] ) ssh_get_error( session[i] ) ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -734,7 +797,7 @@ int main( int argc, char *argv[] ) ssh_get_error( session[i] ) ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -749,7 +812,7 @@ int main( int argc, char *argv[] ) strerror( errno ) ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -758,7 +821,7 @@ int main( int argc, char *argv[] ) wrc, nread ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -770,7 +833,7 @@ int main( int argc, char *argv[] ) ssh_get_error( session[i] ) ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -781,7 +844,7 @@ int main( int argc, char *argv[] ) ssh_get_error( session[i] ) ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -792,7 +855,7 @@ int main( int argc, char *argv[] ) strerror( errno ) ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -801,7 +864,7 @@ int main( int argc, char *argv[] ) wrc, nread ); free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -817,7 +880,7 @@ int main( int argc, char *argv[] ) free( eof_sent ); free( is_eof ); - cleanup_sessions( &session, &channel, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, &channel, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); } break; @@ -834,7 +897,7 @@ int main( int argc, char *argv[] ) memset( scp, 0, nof_sessions + 1 ); if( scp == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for ssh_scp" ); - cleanup_sessions( &session, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } for( unsigned int i = 0; i < nof_sessions; i++ ) { @@ -845,7 +908,7 @@ int main( int argc, char *argv[] ) if( scp[i] == NULL ) { fprintf( stderr, "ERROR: Unable to open SCP channel: %s\n", ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, &scp, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -855,7 +918,7 @@ int main( int argc, char *argv[] ) if( rc != SSH_OK ) { fprintf( stderr, "ERROR: Unable to initialize SCP sessions: %s\n", ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, &scp, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -863,7 +926,7 @@ int main( int argc, char *argv[] ) char **buf = (char **)malloc( ( nof_sessions + 1 ) * sizeof( char * ) ); if( buf == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for receiving buffers of ssh_scp" ); - cleanup_sessions( &session, NULL, &scp, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, NULL, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } memset( buf, 0, ( nof_sessions + 1 ) * sizeof( char * ) ); @@ -871,7 +934,7 @@ int main( int argc, char *argv[] ) buf[i] = (char *)malloc( BUFSIZE ); if( buf[i] == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for receiving buffers of ssh_scp" ); - cleanup_sessions( &session, NULL, &scp, NULL, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, NULL, &buf, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -880,11 +943,42 @@ int main( int argc, char *argv[] ) scp_read_state_e *read_state = (scp_read_state_e *)malloc( ( nof_sessions + 1 ) * sizeof( scp_read_state_e ) ); if( read_state == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for 'is_eof'" ); - cleanup_sessions( &session, NULL, &scp, NULL, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, NULL, &buf, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } memset( read_state, CSSH_SCP_READ_STATE_IDLE, ( nof_sessions + 1 ) * sizeof( scp_read_state_e ) ); + scp_dir_stack_t *dir_stack = (scp_dir_stack_t *)malloc( ( nof_sessions + 1 ) * sizeof( scp_dir_stack_t ) ); + if( dir_stack == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for 'dir_stack'" ); + cleanup_sessions( &session, NULL, &scp, NULL, &buf, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + for( unsigned int i = 0; i < nof_sessions; i++ ) { + create_dir_stack( &dir_stack[i] ); + + char *pwd = getcwd( NULL, 0 ); + if( pwd == NULL ) { + fprintf( stderr, "ERROR: failed to determine working directory for SCP for host '%s': %s\n", + host[i], strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + + rc = push_dir_stack( &dir_stack[i], pwd ); + + // TODO: directory should be a base per hostname[i] + + if( rc < 0 ) { + fprintf( stderr, "ERROR: failed remember initial base directory '%s' in directory stack\n", + pwd ); + free( pwd ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + free( pwd ); + } + while( !all_eof ) { switch( copy_direction ) { @@ -902,6 +996,16 @@ int main( int argc, char *argv[] ) switch( rc ) { case SSH_SCP_REQUEST_NEWDIR: { // TODO: mkdir in host[i] workspace + + char *dir = top_dir_stack( &dir_stack[i] ); + rc = chdir( dir ); + if( rc < 0 ) { + fprintf( stderr, "ERROR: failed to change to directory '%s': %s\n", + dir, strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + const char *filename = ssh_scp_request_get_filename( scp[i] ); int mode = ssh_scp_request_get_permissions( scp[i] ); fprintf( stderr, "Receiving directory '%s' with permissions '0%o'\n", @@ -910,15 +1014,48 @@ int main( int argc, char *argv[] ) if( rc != SSH_OK ) { fprintf( stderr, "ERROR: accepting request for directory '%s' failed: %s\n", filename, ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, &scp, &read_state, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + // TODO: change dir to workspace of scp[i] + rc = mkdir( filename, mode ); + if( rc < 0 ) { + fprintf( stderr, "ERROR: failed to create directory '%s': %s\n", + filename, strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } + char *pwd = getcwd( NULL, 0 ); + if( pwd == NULL ) { + fprintf( stderr, "ERROR: failed to determine working directory for SCP for host '%s': %s\n", + host[i], strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + size_t len = strlen( pwd ) + 2 + strlen( filename ); + char *full_path = (char *)malloc( len ); + if( full_path == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for full path of directory '%s'\n", + filename ); + free( pwd ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + snprintf( full_path, len, "%s/%s", pwd, filename ); + rc = push_dir_stack( &dir_stack[i], full_path ); + free( pwd ); + if( rc < 0 ) { + fprintf( stderr, "ERROR: failed remember directory '%s' in directory stack\n", + full_path ); + free( full_path ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + free( full_path ); } break; case SSH_SCP_REQUEST_ENDDIR: - // TODO: leave current workspace - // TODO: we need a stack per client connection - // to remember the current directory we are in + pop_dir_stack( &dir_stack[i] ); break; case SSH_SCP_REQUEST_NEWFILE: { @@ -931,9 +1068,40 @@ int main( int argc, char *argv[] ) if( rc != SSH_OK ) { fprintf( stderr, "ERROR: accepting request for file '%s' failed: %s\n", filename, ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, &scp, &read_state, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } + + char *dir = top_dir_stack( &dir_stack[i] ); + rc = chdir( dir ); + if( rc < 0 ) { + fprintf( stderr, "ERROR: failed to change to directory '%s': %s\n", + dir, strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + + size_t len = strlen( dir ) + 2 + strlen( filename ); + char *full_path = (char *)malloc( len ); + if( full_path == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for full path of directory '%s'\n", + filename ); + free( dir ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + snprintf( full_path, len, "%s/%s", dir, filename ); + free( dir ); + 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, &read_state, &buf, &dir_stack, 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 @@ -947,10 +1115,27 @@ int main( int argc, char *argv[] ) 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, &read_state, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } bytesReceived += rc; + if( rc > 0 ) { + ssize_t r = write( fd, buf[i], rc ); + if( r < 0 ) { + fprintf( stderr, "ERROR: writing data to file '%s' failed: %s\n", + filename, strerror( errno ) ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, 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, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); } } break; @@ -968,14 +1153,14 @@ int main( int argc, char *argv[] ) case SSH_ERROR: fprintf( stderr, "ERROR: error from remote host '%s': %s\n", host[i], ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, &scp, &read_state, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); break; case SSH_SCP_REQUEST_WARNING: fprintf( stderr, "WARNING: remote host '%s': %s\n", host[i], ssh_scp_request_get_warning( scp[i] ) ); - cleanup_sessions( &session, NULL, &scp, &read_state, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); break; } @@ -984,7 +1169,7 @@ int main( int argc, char *argv[] ) } } - cleanup_sessions( &session, NULL, &scp, &read_state, &buf, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, &read_state, &buf, &dir_stack, host, port, nof_sessions, args_info.verbose_given > 0 ); } break; -- cgit v1.2.3-54-g00ecf