static void control_getline(struct mystr* p_str, struct vsf_session* p_sess) { if (p_sess->p_control_line_buf == 0) { vsf_secbuf_alloc(&p_sess->p_control_line_buf, VSFTP_MAX_COMMAND_LINE); } ftp_getline(p_sess, p_str, p_sess->p_control_line_buf); /* As mandated by the FTP specifications.. */ str_replace_char(p_str, '\0', '\n'); /* If the last character is a \r, strip it */ { unsigned int len = str_getlen(p_str); while (len > 0 && str_get_char_at(p_str, len - 1) == '\r') { str_trunc(p_str, len - 1); --len; } } }
int str_readlink(struct mystr* p_str, const struct mystr* p_filename_str) { static char* p_readlink_buf; int retval; if (p_readlink_buf == 0) { vsf_secbuf_alloc(&p_readlink_buf, VSFTP_PATH_MAX); } /* In case readlink() fails */ str_empty(p_str); /* Note: readlink(2) does not NULL terminate, but our wrapper does */ retval = vsf_sysutil_readlink(str_getbuf(p_filename_str), p_readlink_buf, VSFTP_PATH_MAX); if (vsf_sysutil_retval_is_error(retval)) { return retval; } str_alloc_text(p_str, p_readlink_buf); return 0; }
static void ftp_getline(struct mystr* p_str) { static char* s_p_readline_buf; if (s_p_readline_buf == 0) { vsf_secbuf_alloc(&s_p_readline_buf, VSFTP_MAX_COMMAND_LINE); } str_netfd_alloc(p_str, VSFTP_COMMAND_FD, '\n', s_p_readline_buf, VSFTP_MAX_COMMAND_LINE); /* As mandated by the FTP specifications.. */ str_replace_char(p_str, '\0', '\n'); /* If the last character is a \r, strip it */ { unsigned int len = str_getlen(p_str); if (len > 0 && str_get_char_at(p_str, len - 1) == '\r') { str_trunc(p_str, len - 1); } } }
static struct vsf_transfer_ret do_file_send_rwloop(struct vsf_session* p_sess, int file_fd, int is_ascii) { static char* p_readbuf; static char* p_asciibuf; struct vsf_transfer_ret ret_struct = { 0, 0 }; unsigned int chunk_size = get_chunk_size(); char* p_writefrom_buf; int prev_cr = 0; if (p_readbuf == 0) { vsf_secbuf_alloc(&p_readbuf, VSFTP_DATA_BUFSIZE); } if (is_ascii) { if (p_asciibuf == 0) { /* NOTE!! * 2 factor because we can double the data by doing our ASCII * linefeed mangling */ vsf_secbuf_alloc(&p_asciibuf, VSFTP_DATA_BUFSIZE * 2); } p_writefrom_buf = p_asciibuf; } else { p_writefrom_buf = p_readbuf; } while (1) { unsigned int num_to_write; int retval = vsf_sysutil_read(file_fd, p_readbuf, chunk_size); if (vsf_sysutil_retval_is_error(retval)) { ret_struct.retval = -1; return ret_struct; } else if (retval == 0) { /* Success - cool */ return ret_struct; } if (is_ascii) { struct bin_to_ascii_ret ret = vsf_ascii_bin_to_ascii(p_readbuf, p_asciibuf, (unsigned int) retval, prev_cr); num_to_write = ret.stored; prev_cr = ret.last_was_cr; } else { num_to_write = (unsigned int) retval; } retval = ftp_write_data(p_sess, p_writefrom_buf, num_to_write); if (!vsf_sysutil_retval_is_error(retval)) { ret_struct.transferred += (unsigned int) retval; } if (vsf_sysutil_retval_is_error(retval) || (unsigned int) retval != num_to_write) { ret_struct.retval = -2; return ret_struct; } } }
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; } } }
static struct vsf_transfer_ret do_file_send_rwloop(struct vsf_session* p_sess, int file_fd, int is_ascii) { static char* p_readbuf; static char* p_asciibuf; struct vsf_transfer_ret ret_struct = { 0, 0 }; unsigned int chunk_size = get_chunk_size(); char* p_writefrom_buf; if (p_readbuf == 0) { /* NOTE!! * 2 factor because we can double the data by doing our ASCII * linefeed mangling */ vsf_secbuf_alloc(&p_asciibuf, VSFTP_DATA_BUFSIZE * 2); vsf_secbuf_alloc(&p_readbuf, VSFTP_DATA_BUFSIZE); } if (is_ascii) { p_writefrom_buf = p_asciibuf; } else { p_writefrom_buf = p_readbuf; } while (1) { unsigned int num_to_write; int retval = vsf_sysutil_read(file_fd, p_readbuf, chunk_size); if (vsf_sysutil_retval_is_error(retval)) { vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure reading local file."); ret_struct.retval = -1; return ret_struct; } else if (retval == 0) { /* Success - cool */ vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File send OK."); return ret_struct; } if (is_ascii) { num_to_write = vsf_ascii_bin_to_ascii(p_readbuf, p_asciibuf, (unsigned int) retval); } else { num_to_write = (unsigned int) retval; } retval = ftp_write_data(p_sess, p_writefrom_buf, num_to_write); if (vsf_sysutil_retval_is_error(retval) || (unsigned int) retval != num_to_write) { vsf_cmdio_write(p_sess, FTP_BADSENDNET, "Failure writing network stream."); ret_struct.retval = -1; return ret_struct; } ret_struct.transferred += (unsigned int) retval; } }