diff -ur globus_ftp_client-3.6.orig/globus_ftp_client_attr.c globus_ftp_client-3.6/globus_ftp_client_attr.c --- globus_ftp_client-3.6.orig/globus_ftp_client_attr.c 2006-10-14 09:24:10.000000000 +0200 +++ globus_ftp_client-3.6/globus_ftp_client_attr.c 2007-06-28 22:24:37.000000000 +0200 @@ -64,6 +64,7 @@ i_attr->nl_ftp = GLOBUS_FALSE; i_attr->nl_io = GLOBUS_FALSE; i_attr->rfc1738_url = GLOBUS_FALSE; + i_attr->gridftp2 = GLOBUS_FALSE; *attr = i_attr; return GLOBUS_SUCCESS; @@ -337,6 +338,79 @@ /* globus_ftp_client_handleattr_get_rfc1738_url() */ /*@}*/ + +/** + * @name GridFTP2 support + */ +/*@{*/ +/** + * Enable/Disable GridFTP2 [GFD.41] support for servers supporting + * it. @ingroup globus_ftp_client_handleattr + * + * + * @param attr + * Attribute to modify + * @param gridftp + * Set to GLOBUS_TRUE to enable GridFTP2 support. + * Default of GLOBUS_FALSE specifies that GridFTP is disabled. + */ +globus_result_t +globus_ftp_client_handleattr_set_gridftp2( + globus_ftp_client_handleattr_t * attr, + globus_bool_t gridftp2) +{ + globus_object_t * err = GLOBUS_SUCCESS; + globus_i_ftp_client_handleattr_t * i_attr; + GlobusFuncName(globus_ftp_client_handleattr_set_gridftp2); + + if(attr == GLOBUS_NULL) + { + err = GLOBUS_I_FTP_CLIENT_ERROR_NULL_PARAMETER("attr"); + + goto error_exit; + } + i_attr = *(globus_i_ftp_client_handleattr_t **) attr; + + i_attr->gridftp2 = gridftp2; + + return GLOBUS_SUCCESS; + + error_exit: + return globus_error_put(err); +} +/* globus_ftp_client_handleattr_set_gridftp2() */ + +globus_result_t +globus_ftp_client_handleattr_get_gridftp2( + const globus_ftp_client_handleattr_t * attr, + globus_bool_t * gridftp2) +{ + const globus_i_ftp_client_handleattr_t * i_attr; + globus_object_t * err = GLOBUS_SUCCESS; + GlobusFuncName(globus_ftp_client_handleattr_get_gridftp2); + + if(attr == GLOBUS_NULL) + { + err = GLOBUS_I_FTP_CLIENT_ERROR_NULL_PARAMETER("attr"); + + goto error_exit; + } + if(gridftp2 == GLOBUS_NULL) + { + err = GLOBUS_I_FTP_CLIENT_ERROR_NULL_PARAMETER("gridftp2"); + + goto error_exit; + } + i_attr = *(const globus_i_ftp_client_handleattr_t **) attr; + (*gridftp2) = i_attr->gridftp2; + + return GLOBUS_SUCCESS; + error_exit: + return globus_error_put(err); +} +/* globus_ftp_client_handleattr_get_griftp2() */ +/*@}*/ + /** * @name URL Caching */ @@ -2669,6 +2743,7 @@ dest->nl_io = src->nl_io; dest->url_cache = GLOBUS_NULL; dest->plugins = GLOBUS_NULL; + dest->gridftp2 = src->gridftp2; tmp = src->url_cache; diff -ur globus_ftp_client-3.6.orig/globus_ftp_client.c globus_ftp_client-3.6/globus_ftp_client.c --- globus_ftp_client-3.6.orig/globus_ftp_client.c 2006-10-14 09:24:10.000000000 +0200 +++ globus_ftp_client-3.6/globus_ftp_client.c 2007-06-28 22:24:37.000000000 +0200 @@ -457,10 +457,15 @@ static const char * setup_mlst = "SETUP_MLST"; static const char * mlst = "MLST"; static const char * setup_stat = "SETUP_STAT"; + static const char * setup_getput_get = "SETUP_GETPUT_GET"; + static const char * setup_getput_put = "SETUP_GETPUT_PUT"; static const char * stat = "STAT"; static const char * retr = "RETR"; static const char * stor = "STOR"; static const char * mdtm = "MDTM"; + static const char * getput_pasv_get = "GETPUT_PASV_GET"; + static const char * getput_pasv_put = "GETPUT_PASV_PUT"; + static const char * getput_pasv_transfer = "GETPUT_PASV_TRANSFER"; static const char * ready_for_data = "READY_FOR_DATA"; static const char * need_last_block = "NEED_LAST_BLOCK"; static const char * need_empty_queue = "NEED_EMPTY_QUEUE"; @@ -594,6 +599,12 @@ case GLOBUS_FTP_CLIENT_TARGET_SETUP_STAT: return setup_stat; break; + case GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_GET: + return setup_getput_get; + break; + case GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_PUT: + return setup_getput_put; + break; case GLOBUS_FTP_CLIENT_TARGET_STAT: return stat; break; @@ -645,6 +656,15 @@ case GLOBUS_FTP_CLIENT_TARGET_MDTM: return mdtm; break; + case GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_GET: + return getput_pasv_get; + break; + case GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_PUT: + return getput_pasv_put; + break; + case GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_TRANSFER: + return getput_pasv_transfer; + break; case GLOBUS_FTP_CLIENT_TARGET_READY_FOR_DATA: return ready_for_data; break; diff -ur globus_ftp_client-3.6.orig/globus_ftp_client_data.c globus_ftp_client-3.6/globus_ftp_client_data.c --- globus_ftp_client-3.6.orig/globus_ftp_client_data.c 2005-04-19 01:01:36.000000000 +0200 +++ globus_ftp_client-3.6/globus_ftp_client_data.c 2007-06-28 22:24:37.000000000 +0200 @@ -178,7 +178,8 @@ !(i_handle->source->state == GLOBUS_FTP_CLIENT_TARGET_READY_FOR_DATA || i_handle->source->state == GLOBUS_FTP_CLIENT_TARGET_NEED_LAST_BLOCK) && !(i_handle->source->state == GLOBUS_FTP_CLIENT_TARGET_RETR || - i_handle->source->state == GLOBUS_FTP_CLIENT_TARGET_LIST)) || + i_handle->source->state == GLOBUS_FTP_CLIENT_TARGET_LIST || + i_handle->source->state == GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_GET)) || i_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FINALIZE) { /* We've already hit EOF on the data channel. We'll just @@ -387,7 +388,8 @@ if((i_handle->state == GLOBUS_FTP_CLIENT_HANDLE_DEST_STOR_OR_ESTO && !(i_handle->dest->state == GLOBUS_FTP_CLIENT_TARGET_READY_FOR_DATA || i_handle->dest->state == GLOBUS_FTP_CLIENT_TARGET_NEED_LAST_BLOCK) && - i_handle->dest->state != GLOBUS_FTP_CLIENT_TARGET_STOR) || + i_handle->dest->state != GLOBUS_FTP_CLIENT_TARGET_STOR && + i_handle->dest->state != GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_PUT) || i_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FINALIZE) { /* We've already sent EOF. We'll just return that information diff -ur globus_ftp_client-3.6.orig/globus_ftp_client.h globus_ftp_client-3.6/globus_ftp_client.h --- globus_ftp_client-3.6.orig/globus_ftp_client.h 2006-10-14 09:24:10.000000000 +0200 +++ globus_ftp_client-3.6/globus_ftp_client.h 2007-06-28 22:24:37.000000000 +0200 @@ -510,6 +510,16 @@ globus_bool_t * rfc1738_url); globus_result_t +globus_ftp_client_handleattr_set_gridftp2( + globus_ftp_client_handleattr_t * attr, + globus_bool_t gridftp2); + +globus_result_t +globus_ftp_client_handleattr_get_gridftp2( + const globus_ftp_client_handleattr_t * attr, + globus_bool_t * gridftp2); + +globus_result_t globus_ftp_client_handleattr_set_netlogger( globus_ftp_client_handleattr_t * attr, globus_netlogger_handle_t * nl_handle); @@ -1052,6 +1062,7 @@ GLOBUS_FTP_CLIENT_FEATURE_ERET, GLOBUS_FTP_CLIENT_FEATURE_SIZE, GLOBUS_FTP_CLIENT_FEATURE_CKSM, + GLOBUS_FTP_CLIENT_FEATURE_GETPUT, GLOBUS_FTP_CLIENT_FEATURE_MLST, GLOBUS_FTP_CLIENT_FEATURE_CHMOD, GLOBUS_FTP_CLIENT_FEATURE_MAX, diff -ur globus_ftp_client-3.6.orig/globus_ftp_client_plugin.h globus_ftp_client-3.6/globus_ftp_client_plugin.h --- globus_ftp_client-3.6.orig/globus_ftp_client_plugin.h 2006-10-14 09:24:10.000000000 +0200 +++ globus_ftp_client-3.6/globus_ftp_client_plugin.h 2007-06-28 22:24:37.000000000 +0200 @@ -74,7 +74,7 @@ /** ALLO, REST */ GLOBUS_FTP_CLIENT_CMD_MASK_TRANSFER_MODIFIERS = 1<<3, - /** STOR, RETR, ESTO, ERET, APPE, LIST, NLST, MLSD */ + /** STOR, RETR, ESTO, ERET, APPE, LIST, NLST, MLSD, GET, PUT */ GLOBUS_FTP_CLIENT_CMD_MASK_FILE_ACTIONS = 1<<4, /** HELP, SITE HELP, FEAT, STAT, SYST, SIZE */ diff -ur globus_ftp_client-3.6.orig/globus_ftp_client_state.c globus_ftp_client-3.6/globus_ftp_client_state.c --- globus_ftp_client-3.6.orig/globus_ftp_client_state.c 2007-02-06 03:38:22.000000000 +0100 +++ globus_ftp_client-3.6/globus_ftp_client_state.c 2007-06-28 22:24:37.000000000 +0200 @@ -124,6 +124,26 @@ globus_i_ftp_client_handle_t * client_handle, globus_ftp_control_response_t * response); +static +globus_result_t +globus_l_ftp_client_use_gridftp2_getput( + globus_i_ftp_client_target_t * target, + globus_bool_t * getput); + +static +globus_result_t +globus_l_ftp_client_send_get( + globus_i_ftp_client_target_t * target, + char * pathname, + globus_bool_t pasv); + +static +globus_result_t +globus_l_ftp_client_send_put( + globus_i_ftp_client_target_t * target, + char * pathname, + globus_bool_t pasv); + /** * Buffer size command applicability information. * @internal @@ -218,6 +238,7 @@ unsigned long pbsz = 0; int rc, oldrc, i; char * pathname; + globus_bool_t gridftp2_getput; GlobusFuncName(globus_i_ftp_client_response_callback); target = (globus_i_ftp_client_target_t *) user_arg; @@ -254,7 +275,17 @@ client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART) { goto finish; + } + + /* The behaviour of several states depends on whether to use the + * GFD.47 (a.k.a GridFTP 2) GETPUT extension. + */ + result = globus_l_ftp_client_use_gridftp2_getput(target, &gridftp2_getput); + if (result != GLOBUS_SUCCESS) + { + goto result_fault; } + /* This redo is used to make a second run through the state * machine, which a few states will require. */ @@ -1622,6 +1653,11 @@ goto redo; case GLOBUS_FTP_CLIENT_TARGET_SETUP_PASV: + if(gridftp2_getput == GLOBUS_TRUE) + { + goto skip_pasv; + } + if(globus_i_ftp_client_can_reuse_data_conn(client_handle)) { goto skip_pasv; @@ -1742,6 +1778,11 @@ } } + if(gridftp2_getput == GLOBUS_TRUE) + { + goto skip_port; + } + tmpstr = globus_libc_malloc(56 * client_handle->num_pasv_addresses + 7 /*SPOR|PORT|EPRT\r\n\0*/); /* ' |2|<45>|<5>|' == 56 */ @@ -2286,16 +2327,30 @@ } goto redo; case GLOBUS_FTP_CLIENT_GET: - target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_GET; - goto redo; + if (gridftp2_getput == GLOBUS_TRUE) + { + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_GET; + } + else + { + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_GET; + } + goto redo; case GLOBUS_FTP_CLIENT_PUT: - target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_PUT; + if (gridftp2_getput == GLOBUS_TRUE) + { + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_PUT; + } + else + { + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_PUT; + } goto redo; case GLOBUS_FTP_CLIENT_TRANSFER: if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_DEST_SETUP_CONNECTION) { - target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_TRANSFER_DEST; + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_TRANSFER_DEST; } else { @@ -2971,76 +3026,110 @@ { goto result_fault; } - break; + break; case GLOBUS_FTP_CLIENT_TARGET_SETUP_TRANSFER_DEST: globus_assert( client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_DEST_SETUP_CONNECTION); - /* The destination is prepared first. We send all - * of the commands we need to, including the STOR - * or ESTO, and then turn our attention to the - * source. - */ - target->mask = GLOBUS_FTP_CLIENT_CMD_MASK_FILE_ACTIONS; + /* The destination is prepared first. We send all of the + * commands we need to, including the PUT, STOR or ESTO, and + * then turn our attention to the source. + */ + target->mask = GLOBUS_FTP_CLIENT_CMD_MASK_FILE_ACTIONS; - if(client_handle->esto_alg_str != GLOBUS_NULL) - { - globus_i_ftp_client_plugin_notify_command( - client_handle, - target->url_string, - target->mask, - "ESTO %s %s" CRLF, - client_handle->esto_alg_str, - pathname); - } - else - { - globus_i_ftp_client_plugin_notify_command( - client_handle, - target->url_string, - target->mask, - "STOR %s" CRLF, - pathname); - } + if (gridftp2_getput == GLOBUS_TRUE) + { + result = + globus_l_ftp_client_send_put(target, pathname, GLOBUS_TRUE); + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } - if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || - client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || - client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) - { - break; - } + if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) + { + break; + } - globus_assert(client_handle->state == - GLOBUS_FTP_CLIENT_HANDLE_DEST_SETUP_CONNECTION); + if(globus_i_ftp_client_can_reuse_data_conn(client_handle)) + { + /* In this case we do not expect a 127 reply. + */ + target->state = GLOBUS_FTP_CLIENT_TARGET_STOR; + } + else + { + target->state = GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_TRANSFER; - target->state = GLOBUS_FTP_CLIENT_TARGET_STOR; + /* In this case we have to wait for the 127 reply + * before we can setup the transfer at the source. + */ + break; + } + } + else + { + if(client_handle->esto_alg_str != GLOBUS_NULL) + { + globus_i_ftp_client_plugin_notify_command( + client_handle, + target->url_string, + target->mask, + "ESTO %s %s" CRLF, + client_handle->esto_alg_str, + pathname); + } + else + { + globus_i_ftp_client_plugin_notify_command( + client_handle, + target->url_string, + target->mask, + "STOR %s" CRLF, + pathname); + } + + if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) + { + break; + } - if(client_handle->esto_alg_str != GLOBUS_NULL) - { - result = globus_ftp_control_send_command( - handle, - "ESTO %s %s" CRLF, - globus_i_ftp_client_response_callback, - user_arg, - client_handle->esto_alg_str, - pathname); - } - else - { - result = globus_ftp_control_send_command( - handle, - "STOR %s" CRLF, - globus_i_ftp_client_response_callback, - user_arg, + globus_assert(client_handle->state == + GLOBUS_FTP_CLIENT_HANDLE_DEST_SETUP_CONNECTION); + + target->state = GLOBUS_FTP_CLIENT_TARGET_STOR; + + if(client_handle->esto_alg_str != GLOBUS_NULL) + { + result = globus_ftp_control_send_command( + handle, + "ESTO %s %s" CRLF, + globus_i_ftp_client_response_callback, + user_arg, + client_handle->esto_alg_str, + pathname); + } + else + { + result = globus_ftp_control_send_command( + handle, + "STOR %s" CRLF, + globus_i_ftp_client_response_callback, + user_arg, pathname); - } + } - if(result != GLOBUS_SUCCESS) - { - goto result_fault; - } + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + } target = client_handle->source; @@ -3072,61 +3161,328 @@ target->mask = GLOBUS_FTP_CLIENT_CMD_MASK_FILE_ACTIONS; - if(client_handle->eret_alg_str) - { - globus_i_ftp_client_plugin_notify_command( - client_handle, - target->url_string, - target->mask, - "ERET %s %s" CRLF, - client_handle->eret_alg_str, - pathname); - } - else - { - globus_i_ftp_client_plugin_notify_command( - client_handle, - target->url_string, - target->mask, - "RETR %s" CRLF, - pathname); - } + if (gridftp2_getput == GLOBUS_TRUE) + { + result = + globus_l_ftp_client_send_get(target, pathname, GLOBUS_FALSE); + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } - if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || - client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || - client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) - { - break; - } - globus_assert(client_handle->state == - GLOBUS_FTP_CLIENT_HANDLE_THIRD_PARTY_TRANSFER); + if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) + { + break; + } + + target->state = GLOBUS_FTP_CLIENT_TARGET_RETR; + } + else + { + if(client_handle->eret_alg_str) + { + globus_i_ftp_client_plugin_notify_command( + client_handle, + target->url_string, + target->mask, + "ERET %s %s" CRLF, + client_handle->eret_alg_str, + pathname); + } + else + { + globus_i_ftp_client_plugin_notify_command( + client_handle, + target->url_string, + target->mask, + "RETR %s" CRLF, + pathname); + } + + if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) + { + break; + } + globus_assert(client_handle->state == + GLOBUS_FTP_CLIENT_HANDLE_THIRD_PARTY_TRANSFER); + + target->state = GLOBUS_FTP_CLIENT_TARGET_RETR; + + if(client_handle->eret_alg_str) + { + result = globus_ftp_control_send_command( + handle, + "ERET %s %s\r\n", + globus_i_ftp_client_response_callback, + user_arg, + client_handle->eret_alg_str, + pathname); + } + else + { + result = globus_ftp_control_send_command( + handle, + "RETR %s" CRLF, + globus_i_ftp_client_response_callback, + user_arg, + pathname); + } + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + } + break; - target->state = GLOBUS_FTP_CLIENT_TARGET_RETR; + case GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_GET: + globus_assert( + client_handle->state == + GLOBUS_FTP_CLIENT_HANDLE_SOURCE_SETUP_CONNECTION); - if(client_handle->eret_alg_str) - { - result = globus_ftp_control_send_command( - handle, - "ERET %s %s\r\n", - globus_i_ftp_client_response_callback, - user_arg, - client_handle->eret_alg_str, - pathname); - } - else - { - result = globus_ftp_control_send_command( - handle, - "RETR %s" CRLF, - globus_i_ftp_client_response_callback, - user_arg, - pathname); - } - if(result != GLOBUS_SUCCESS) - { - goto result_fault; - } - break; + client_handle->state = + GLOBUS_FTP_CLIENT_HANDLE_SOURCE_RETR_OR_ERET; + + if(target->mode == GLOBUS_FTP_CONTROL_MODE_EXTENDED_BLOCK || + globus_i_ftp_client_can_reuse_data_conn(client_handle)) + { + /* In extended block mode, we will be the passive party + * and do not expect a 127 reply. + * + * If a connection was cached, we do not expect a 127 reply + * either. + */ + target->state = GLOBUS_FTP_CLIENT_TARGET_RETR; + + /* Setup data connection. Since we do not expect a 127 + * reply, we need to do this before sending GET. + */ + result = + globus_ftp_control_data_connect_read(target->control_handle, + GLOBUS_NULL, + GLOBUS_NULL); + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + } + else + { + /* We require a 127 reply and will setup the connection once + * it has been received. + */ + target->state = GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_GET; + } + + target->mask = GLOBUS_FTP_CLIENT_CMD_MASK_FILE_ACTIONS; + if(target->mode == GLOBUS_FTP_CONTROL_MODE_EXTENDED_BLOCK) + { + /* In extended block mode, we will be the passive + * party. GLOBUS_FTP_CLIENT_TARGET_SETUP_PORT has already + * filled in client_handle->pasv_address. + */ + result = + globus_l_ftp_client_send_get(target, pathname, GLOBUS_FALSE); + } + else + { + /* In all other cases we prefer to be active. + */ + result = + globus_l_ftp_client_send_get(target, pathname, GLOBUS_TRUE); + } + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + break; + + case GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_PUT: + globus_assert( + client_handle->state == + GLOBUS_FTP_CLIENT_HANDLE_DEST_SETUP_CONNECTION); + + client_handle->state = GLOBUS_FTP_CLIENT_HANDLE_DEST_STOR_OR_ESTO; + + if(globus_i_ftp_client_can_reuse_data_conn(client_handle)) + { + /* In this case we do not expect a 127 reply. + */ + target->state = GLOBUS_FTP_CLIENT_TARGET_STOR; + + /* Create the data connection. + */ + result = + globus_ftp_control_data_connect_write(target->control_handle, + GLOBUS_NULL, + GLOBUS_NULL); + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + } + else + { + target->state = GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_PUT; + } + + target->mask = GLOBUS_FTP_CLIENT_CMD_MASK_FILE_ACTIONS; + result = globus_l_ftp_client_send_put(target, pathname, GLOBUS_TRUE); + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + break; + + case GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_GET: + if((!error) && + response->code == 127) + { + /* Setup our side of PASV. + */ + globus_l_ftp_client_parse_pasv( + handle, + response, + &client_handle->pasv_address, + &client_handle->num_pasv_addresses); + + if(client_handle->num_pasv_addresses == 1) + { + result = + globus_ftp_control_local_port( + handle, + client_handle->pasv_address); + } + else + { + result = + globus_ftp_control_local_spor( + handle, + client_handle->pasv_address, + client_handle->num_pasv_addresses); + } + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + + /* Create the data connection. + */ + result = + globus_ftp_control_data_connect_read(target->control_handle, + GLOBUS_NULL, + GLOBUS_NULL); + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + + target->state = GLOBUS_FTP_CLIENT_TARGET_RETR; + } + else + { + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_CONNECTION; + goto notify_fault; + } + break; + + case GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_PUT: + if((!error) && + response->code == 127) + { + /* Setup our side of PASV. + */ + globus_l_ftp_client_parse_pasv( + handle, + response, + &client_handle->pasv_address, + &client_handle->num_pasv_addresses); + + if(client_handle->num_pasv_addresses == 1) + { + result = + globus_ftp_control_local_port( + handle, + client_handle->pasv_address); + } + else + { + result = + globus_ftp_control_local_spor( + handle, + client_handle->pasv_address, + client_handle->num_pasv_addresses); + } + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + + /* Create the data connection. + */ + result = + globus_ftp_control_data_connect_write(target->control_handle, + GLOBUS_NULL, + GLOBUS_NULL); + if(result != GLOBUS_SUCCESS) + { + goto result_fault; + } + + target->state = GLOBUS_FTP_CLIENT_TARGET_STOR; + } + else + { + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_CONNECTION; + goto notify_fault; + } + break; + + case GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_TRANSFER: + if((!error) && + response->code == 127) + { + globus_l_ftp_client_parse_pasv( + handle, + response, + &client_handle->pasv_address, + &client_handle->num_pasv_addresses); + + /* The passive end of a 3rd party transfer is always the + * destination. + */ + target->state = GLOBUS_FTP_CLIENT_TARGET_STOR; + + /* Now continue setting up the source of the transfer. + */ + target = client_handle->source; + + error = + globus_i_ftp_client_target_activate(client_handle, + target, + ®istered); + if(registered == GLOBUS_FALSE) + { + if(client_handle->state==GLOBUS_FTP_CLIENT_HANDLE_ABORT || + client_handle->state==GLOBUS_FTP_CLIENT_HANDLE_RESTART) + { + break; + } + else + { + goto connection_error; + } + } + } + else + { + target->state = GLOBUS_FTP_CLIENT_TARGET_SETUP_CONNECTION; + goto notify_fault; + } + break; case GLOBUS_FTP_CLIENT_TARGET_LIST: case GLOBUS_FTP_CLIENT_TARGET_RETR: @@ -3858,6 +4214,13 @@ GLOBUS_FTP_CLIENT_FEATURE_SIZE, GLOBUS_FTP_CLIENT_TRUE); } + else if(strncmp(feature_label, "GETPUT", 6) == 0) + { + globus_i_ftp_client_feature_set( + target->features, + GLOBUS_FTP_CLIENT_FEATURE_GETPUT, + GLOBUS_FTP_CLIENT_TRUE); + } else if(strncmp(feature_label, "MLST", 4) == 0) { globus_i_ftp_client_feature_set( @@ -5003,5 +5366,247 @@ { } +static +globus_result_t +globus_l_ftp_client_use_gridftp2_getput( + globus_i_ftp_client_target_t * target, + globus_bool_t * getput) +{ + globus_i_ftp_client_handle_t * client_handle; + globus_ftp_client_handleattr_t handle_attr; + globus_result_t result; + + client_handle = target->owner; + handle_attr = &client_handle->attr; + + /* Does target support GFD.47? + */ + result = + globus_ftp_client_handleattr_get_gridftp2(&handle_attr, getput); + if(result != GLOBUS_SUCCESS || *getput == GLOBUS_FALSE) + { + return result; + } + + /* Does requested operation allow the use of GETPUT? + */ + if (client_handle->op != GLOBUS_FTP_CLIENT_TRANSFER + && client_handle->op != GLOBUS_FTP_CLIENT_GET + && client_handle->op != GLOBUS_FTP_CLIENT_PUT) + { + *getput = GLOBUS_FALSE; + return GLOBUS_SUCCESS; + } + + /* Are GFD.47 extensions enabled? + */ + if (globus_i_ftp_client_feature_get( + target->features, + GLOBUS_FTP_CLIENT_FEATURE_GETPUT) == GLOBUS_FTP_CLIENT_FALSE) + { + *getput = GLOBUS_FALSE; + return GLOBUS_SUCCESS; + } + + /* GFD.47 style GETPUT does not support extended server side + * processing. + */ + if (client_handle->eret_alg_str != GLOBUS_NULL) + { + *getput = GLOBUS_FALSE; + return GLOBUS_SUCCESS; + } + + /* In principal, GFD.47 supports striping, however the exact + * details for configuring striping using GETPUT are currently + * unknown. + */ + if (target->attr->layout.mode != GLOBUS_FTP_CONTROL_STRIPING_NONE) + { + *getput = GLOBUS_FALSE; + return GLOBUS_SUCCESS; + } + + /* GFD.47 doesn't tell us how to do IPv6. + */ + if(target->attr->allow_ipv6) + { + *getput = GLOBUS_FALSE; + return GLOBUS_SUCCESS; + } + + return GLOBUS_SUCCESS; +} + +/** + * Sends a GFD.47 compliant GET command. + */ +static +globus_result_t +globus_l_ftp_client_send_get( + globus_i_ftp_client_target_t * target, + char * pathname, + globus_bool_t pasv) +{ + char * tmpstr = GLOBUS_NULL; + globus_i_ftp_client_handle_t * client_handle; + int rc, oldrc; + globus_result_t result; + + client_handle = target->owner; + + tmpstr = globus_libc_malloc(56 * client_handle->num_pasv_addresses + 6); + + if(tmpstr == GLOBUS_NULL) + { + return globus_error_put(GLOBUS_ERROR_NO_INFO); + } + + if(globus_i_ftp_client_can_reuse_data_conn(client_handle)) + { + tmpstr[0] = 0; + } + else if(pasv == GLOBUS_TRUE) + { + sprintf(tmpstr, "pasv;"); + } + else + { + rc = oldrc = 0; + globus_assert(!target->attr->allow_ipv6); + globus_assert(client_handle->num_pasv_addresses == 1); + globus_assert(client_handle->pasv_address[0].hostlen != 16); + + rc += sprintf(&tmpstr[oldrc], + "port=%d,%d,%d,%d,%d,%d;", + client_handle->pasv_address[0].host[0], + client_handle->pasv_address[0].host[1], + client_handle->pasv_address[0].host[2], + client_handle->pasv_address[0].host[3], + (client_handle->pasv_address[0].port >> 8) + & 0xff, + client_handle->pasv_address[0].port & 0xff); + if(rc == oldrc) + { + globus_libc_free(tmpstr); + return globus_error_put(GLOBUS_ERROR_NO_INFO); + } + } + + globus_i_ftp_client_plugin_notify_command( + client_handle, + target->url_string, + target->mask, + "GET path=%s;%s" CRLF, + pathname, + tmpstr); + + if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) + { + globus_libc_free(tmpstr); + return GLOBUS_SUCCESS; + } + + result = + globus_ftp_control_send_command( + target->control_handle, + "GET path=%s;%s" CRLF, + globus_i_ftp_client_response_callback, + target, + pathname, + tmpstr); + + globus_libc_free(tmpstr); + + return result; +} + +/** + * Sends a GFD.47 compliant PUT command. + */ +static +globus_result_t +globus_l_ftp_client_send_put( + globus_i_ftp_client_target_t * target, + char * pathname, + globus_bool_t pasv) +{ + char * tmpstr = GLOBUS_NULL; + globus_i_ftp_client_handle_t * client_handle; + int rc, oldrc; + globus_result_t result; + + client_handle = target->owner; + + tmpstr = globus_libc_malloc(56 * client_handle->num_pasv_addresses + 6); + + if(tmpstr == GLOBUS_NULL) + { + return globus_error_put(GLOBUS_ERROR_NO_INFO); + } + + if(globus_i_ftp_client_can_reuse_data_conn(client_handle)) + { + tmpstr[0] = 0; + } + else if(pasv == GLOBUS_TRUE) + { + sprintf(tmpstr, "pasv;"); + } + else + { + rc = oldrc = 0; + globus_assert(!target->attr->allow_ipv6); + globus_assert(client_handle->num_pasv_addresses == 1); + globus_assert(client_handle->pasv_address[0].hostlen != 16); + + rc += sprintf(&tmpstr[oldrc], + "port=%d,%d,%d,%d,%d,%d;", + client_handle->pasv_address[0].host[0], + client_handle->pasv_address[0].host[1], + client_handle->pasv_address[0].host[2], + client_handle->pasv_address[0].host[3], + (client_handle->pasv_address[0].port >> 8) + & 0xff, + client_handle->pasv_address[0].port & 0xff); + if(rc == oldrc) + { + globus_libc_free(tmpstr); + return globus_error_put(GLOBUS_ERROR_NO_INFO); + } + } + + globus_i_ftp_client_plugin_notify_command( + client_handle, + target->url_string, + target->mask, + "PUT path=%s;%s" CRLF, + pathname, + tmpstr); + + if(client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_ABORT || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_RESTART || + client_handle->state == GLOBUS_FTP_CLIENT_HANDLE_FAILURE) + { + globus_libc_free(tmpstr); + return GLOBUS_SUCCESS; + } + + result = + globus_ftp_control_send_command( + target->control_handle, + "PUT path=%s;%s" CRLF, + globus_i_ftp_client_response_callback, + target, + pathname, + tmpstr); + + globus_libc_free(tmpstr); + + return result; +} + #endif diff -ur globus_ftp_client-3.6.orig/globus_i_ftp_client.h globus_ftp_client-3.6/globus_i_ftp_client.h --- globus_ftp_client-3.6.orig/globus_i_ftp_client.h 2006-10-14 09:24:10.000000000 +0200 +++ globus_ftp_client-3.6/globus_i_ftp_client.h 2007-06-28 22:24:37.000000000 +0200 @@ -189,6 +189,12 @@ globus_bool_t rfc1738_url; + /** + * Use GRIDFTP2 if supported by the server + */ + + globus_bool_t gridftp2; + /** * List of cached URLs. * @@ -324,12 +330,17 @@ GLOBUS_FTP_CLIENT_TARGET_SETUP_MDTM, GLOBUS_FTP_CLIENT_TARGET_SETUP_MLST, GLOBUS_FTP_CLIENT_TARGET_SETUP_STAT, + GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_GET, + GLOBUS_FTP_CLIENT_TARGET_SETUP_GETPUT_PUT, GLOBUS_FTP_CLIENT_TARGET_MLST, GLOBUS_FTP_CLIENT_TARGET_STAT, GLOBUS_FTP_CLIENT_TARGET_LIST, GLOBUS_FTP_CLIENT_TARGET_RETR, GLOBUS_FTP_CLIENT_TARGET_STOR, GLOBUS_FTP_CLIENT_TARGET_MDTM, + GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_GET, + GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_PUT, + GLOBUS_FTP_CLIENT_TARGET_GETPUT_PASV_TRANSFER, GLOBUS_FTP_CLIENT_TARGET_READY_FOR_DATA, GLOBUS_FTP_CLIENT_TARGET_NEED_LAST_BLOCK, GLOBUS_FTP_CLIENT_TARGET_NEED_EMPTY_QUEUE,