void bug(const char* p_text) { /* Rats. Try and write the reason to the network for diagnostics */ vsf_sysutil_activate_noblock(VSFTP_COMMAND_FD); (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, FTP_500_STRING, FTP_500_SIZE); (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, p_text, vsf_sysutil_strlen(p_text)); (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, "\r\n", 2); vsf_sysutil_exit(2); }
void vsf_exit(const char* p_text) { (void) vsf_sysutil_write_loop(VSFTP_COMMAND_FD, p_text, vsf_sysutil_strlen(p_text)); vsf_sysutil_exit(0); }
static struct vsf_transfer_ret do_file_recv(struct vsf_session* p_sess, int file_fd, int is_ascii) { static char* p_recvbuf; unsigned int num_to_write; struct vsf_transfer_ret ret_struct = { 0, 0 }; unsigned int chunk_size = get_chunk_size(); int prev_cr = 0; if (p_recvbuf == 0) { /* Now that we do ASCII conversion properly, the plus one is to cater for * the fact we may need to stick a '\r' at the front of the buffer if the * last buffer fragment eneded in a '\r' and the current buffer fragment * does not start with a '\n'. */ vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE + 1); } while (1) { const char* p_writebuf = p_recvbuf + 1; int retval = ftp_read_data(p_sess, p_recvbuf + 1, chunk_size); if (vsf_sysutil_retval_is_error(retval)) { ret_struct.retval = -2; return ret_struct; } else if (retval == 0 && !prev_cr) { /* Transfer done, nifty */ return ret_struct; } num_to_write = (unsigned int) retval; ret_struct.transferred += num_to_write; if (is_ascii) { /* Handle ASCII conversion if we have to. Note that using the same * buffer for source and destination is safe, because the ASCII -> * binary transform only ever results in a smaller file. */ struct ascii_to_bin_ret ret = vsf_ascii_ascii_to_bin(p_recvbuf, num_to_write, prev_cr); num_to_write = ret.stored; prev_cr = ret.last_was_cr; p_writebuf = ret.p_buf; } retval = vsf_sysutil_write_loop(file_fd, p_writebuf, num_to_write); if (vsf_sysutil_retval_is_error(retval) || (unsigned int) retval != num_to_write) { ret_struct.retval = -1; return ret_struct; } } }
int ftp_write_data(const struct vsf_session* p_sess, const char* p_buf, unsigned int len) { if (p_sess->data_use_ssl) { return ssl_write(p_sess->p_data_ssl, p_buf, len); } else { return vsf_sysutil_write_loop(p_sess->data_fd, p_buf, len); } }
static struct vsf_transfer_ret do_file_recv(struct vsf_session* p_sess, int file_fd, int is_ascii) { static char* p_recvbuf; unsigned int num_to_write; struct vsf_transfer_ret ret_struct = { 0, 0 }; unsigned int chunk_size = get_chunk_size(); if (p_recvbuf == 0) { vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE); } while (1) { int retval = ftp_read_data(p_sess, p_recvbuf, chunk_size); if (vsf_sysutil_retval_is_error(retval)) { vsf_cmdio_write(p_sess, FTP_BADSENDNET, "Failure reading network stream."); ret_struct.retval = -1; return ret_struct; } else if (retval == 0) { /* Transfer done, nifty */ vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File receive OK."); return ret_struct; } num_to_write = (unsigned int) retval; ret_struct.transferred += num_to_write; if (is_ascii) { /* Handle ASCII conversion if we have to. Note that using the same * buffer for source and destination is safe, because the ASCII -> * binary transform only ever results in a smaller file. */ num_to_write = vsf_ascii_ascii_to_bin(p_recvbuf, p_recvbuf, num_to_write); } retval = vsf_sysutil_write_loop(file_fd, p_recvbuf, num_to_write); if (vsf_sysutil_retval_is_error(retval) || (unsigned int) retval != num_to_write) { vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file."); ret_struct.retval = -1; return ret_struct; } } }
int ftp_write_data(const struct vsf_session* p_sess, const char* p_buf, unsigned int len) { if (p_sess->data_use_ssl && p_sess->ssl_slave_active) { int ret; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_WRITE); priv_sock_send_buf(p_sess->ssl_consumer_fd, p_buf, len); ret = priv_sock_get_int(p_sess->ssl_consumer_fd); /* Need to do this here too because it is useless in the slave process. */ vsf_sysutil_check_pending_actions(kVSFSysUtilIO, ret, p_sess->data_fd); return ret; } else if (p_sess->data_use_ssl) { return ssl_write(p_sess->p_data_ssl, p_buf, len); } else { return vsf_sysutil_write_loop(p_sess->data_fd, p_buf, len); } }
int str_write_loop(const struct mystr* p_str, const int fd) { return vsf_sysutil_write_loop(fd, str_getbuf(p_str), str_getlen(p_str)); }
static int do_sendfile(const int out_fd, const int in_fd, unsigned int num_send, filesize_t start_pos) { /* Probably should one day be shared with instance in ftpdataio.c */ static char* p_recvbuf; unsigned int total_written = 0; int retval; enum EVSFSysUtilError error; (void) start_pos; (void) error; #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE) if (tunable_use_sendfile) { static int s_sendfile_checked; static int s_runtime_sendfile_works; if (!s_sendfile_checked || s_runtime_sendfile_works) { do { #ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE retval = sendfile(out_fd, in_fd, NULL, num_send); #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) { /* XXX - start_pos will truncate on 32-bit machines - can we * say "start from current pos"? */ off_t written = 0; retval = sendfile(in_fd, out_fd, start_pos, num_send, NULL, &written, 0); /* Translate to Linux-like retval */ if (written > 0) { retval = (int) written; } } #elif defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE) { size_t written = 0; struct sendfilevec the_vec; vsf_sysutil_memclr(&the_vec, sizeof(the_vec)); the_vec.sfv_fd = in_fd; the_vec.sfv_off = start_pos; the_vec.sfv_len = num_send; retval = sendfilev(out_fd, &the_vec, 1, &written); /* Translate to Linux-like retval */ if (written > 0) { retval = (int) written; } } #elif defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) { struct sf_parms sf_iobuf; vsf_sysutil_memclr(&sf_iobuf, sizeof(sf_iobuf)); sf_iobuf.header_data = NULL; sf_iobuf.header_length = 0; sf_iobuf.trailer_data = NULL; sf_iobuf.trailer_length = 0; sf_iobuf.file_descriptor = in_fd; sf_iobuf.file_offset = start_pos; sf_iobuf.file_bytes = num_send; retval = send_file((int*)&out_fd, &sf_iobuf, 0); if (retval >= 0) { retval = sf_iobuf.bytes_sent; } } #else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */ { retval = sendfile(out_fd, in_fd, start_pos, num_send, NULL, 0); } #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */ error = vsf_sysutil_get_error(); vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, out_fd); } while (vsf_sysutil_retval_is_error(retval) && error == kVSFSysUtilErrINTR); if (!s_sendfile_checked) { s_sendfile_checked = 1; if (!vsf_sysutil_retval_is_error(retval) || error != kVSFSysUtilErrNOSYS) { s_runtime_sendfile_works = 1; } } if (!vsf_sysutil_retval_is_error(retval)) { return retval; } if (s_runtime_sendfile_works && error != kVSFSysUtilErrINVAL && error != kVSFSysUtilErrOPNOTSUPP) { return retval; } /* Fall thru to normal implementation. We won't check again. NOTE - * also falls through if sendfile() is OK but it returns EINVAL. For * Linux this means the file was not page cache backed. Original * complaint was trying to serve files from an NTFS filesystem! */ } } #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */ if (p_recvbuf == 0) { vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE); } while (1) { unsigned int num_read; unsigned int num_written; unsigned int num_read_this_time = VSFTP_DATA_BUFSIZE; if (num_read_this_time > num_send) { num_read_this_time = num_send; } retval = vsf_sysutil_read(in_fd, p_recvbuf, num_read_this_time); if (retval < 0) { return retval; } else if (retval == 0) { return -1; } num_read = (unsigned int) retval; retval = vsf_sysutil_write_loop(out_fd, p_recvbuf, num_read); if (retval < 0) { return retval; } num_written = (unsigned int) retval; total_written += num_written; if (num_written != num_read) { return num_written; } if (num_written > num_send) { bug("num_written bigger than num_send in do_sendfile"); } num_send -= num_written; if (num_send == 0) { /* Bingo! */ return total_written; } } }