Пример #1
0
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;
    }
  }
}
Пример #2
0
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;
}
Пример #3
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);
    }
  }
}
Пример #4
0
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;
    }
  }
}
Пример #5
0
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;
    }
  }
}
Пример #6
0
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;
    }
}