Skip to content
ftp.c 120 KiB
Newer Older
    ftp->file = cur_pos;  /* the rest is the file name */
  }
    ftp->file = curl_easy_unescape(conn->data, ftp->file, 0, NULL);
      failf(data, "no memory");
      return CURLE_OUT_OF_MEMORY;
    }
  }
  else
    ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
                       pointer */

  if(data->set.upload && !ftp->file &&
     (!ftp->no_transfer || conn->bits.no_body)) {
    /* We need a file name when uploading. Return error! */
    failf(data, "Uploading to a URL without a file name!");
    return CURLE_URL_MALFORMAT;
  }

  ftpc->cwddone = FALSE; /* default to not done */
    /* prevpath is "raw" so we convert the input path before we compare the
       strings */
    char *path = curl_easy_unescape(conn->data, data->reqdata.path, 0, NULL);
    if(!path)
      return CURLE_OUT_OF_MEMORY;

    dlen = strlen(path) - (ftp->file?strlen(ftp->file):0);
    if((dlen == strlen(ftpc->prevpath)) &&
       curl_strnequal(path, ftpc->prevpath, dlen)) {
      infof(data, "Request has same path as previous transfer\n");
Daniel Stenberg's avatar
Daniel Stenberg committed
    }
  return retcode;
}



/***********************************************************************
 *
 * ftp_cwd_and_create_path()
 *
 * Creates full path on remote target host.
 *
 */
static
CURLcode ftp_cwd_and_create_path(struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  struct ftp_conn *ftpc = &conn->proto.ftpc;
Daniel Stenberg's avatar
Daniel Stenberg committed
    /* already done and fine */
    return CURLE_OK;

  /* This is a re-used connection. Since we change directory to where the
     transfer is taking place, we must now get back to the original dir
     where we ended up after login: */
  if (conn->bits.reuse && ftpc->entrypath) {
    if ((result = ftp_cwd_and_mkd(conn, ftpc->entrypath)) != CURLE_OK)
    /* RFC 1738 says empty components should be respected too, but
       that is plain stupid since CWD can't be used with an empty argument */
    if ((result = ftp_cwd_and_mkd(conn, ftpc->dirs[i])) != CURLE_OK)
/* call this when the DO phase has completed */
static CURLcode ftp_dophase_done(struct connectdata *conn,
                                 bool connected)
{
  CURLcode result = CURLE_OK;
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  if(connected)
    result = Curl_ftp_nextconnect(conn);

  if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
    /* Failure detected, close the second socket if it was created already */
    sclose(conn->sock[SECONDARYSOCKET]);
    conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
    result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
  else if(!connected)
    /* since we didn't connect now, we want do_more to get called */
    conn->bits.do_more = TRUE;

  ftpc->ctl_valid = TRUE; /* seems good */

  return result;
}

/* called from multi.c while DOing */
CURLcode Curl_ftp_doing(struct connectdata *conn,
                        bool *dophase_done)
{
  CURLcode result;
  result = Curl_ftp_multi_statemach(conn, dophase_done);

  if(*dophase_done) {
    result = ftp_dophase_done(conn, FALSE /* not connected */);

    DEBUGF(infof(conn->data, "DO phase is complete\n"));

/***********************************************************************
 *
 * ftp_regular_transfer()
 *
 * The input argument is already checked for validity.
 *
 * Performs all commands done before a regular transfer between a local and a
 * remote host.
 *
 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
 * Curl_ftp_done() function without finding any major problem.
 */
static
CURLcode ftp_regular_transfer(struct connectdata *conn,
                              bool *dophase_done)
  bool connected=0;
  struct SessionHandle *data = conn->data;
  struct ftp_conn *ftpc = &conn->proto.ftpc;
  data->reqdata.size = -1; /* make sure this is unknown at this point */

  Curl_pgrsSetUploadCounter(data, 0);
  Curl_pgrsSetDownloadCounter(data, 0);
  Curl_pgrsSetUploadSize(data, 0);
  Curl_pgrsSetDownloadSize(data, 0);

  ftpc->ctl_valid = TRUE; /* starts good */
  result = ftp_perform(conn,
                       &connected, /* have we connected after PASV/PORT */
                       dophase_done); /* all commands in the DO-phase done? */
    if(!*dophase_done)
      /* the DO phase has not completed yet */
      return CURLE_OK;

    result = ftp_dophase_done(conn, connected);
    if(result)
      return result;
}



/***********************************************************************
 *
 * ftp_3rdparty()
 *
 * The input argument is already checked for validity.
 * Performs a 3rd party transfer between two remote hosts.
 */
static CURLcode ftp_3rdparty(struct connectdata *conn)
{
  struct Curl_transfer_keeper *k = &conn->data->reqdata.keep;
  /* both control connections start out fine */
  conn->proto.ftpc.ctl_valid = TRUE;
  conn->sec_conn->proto.ftpc.ctl_valid = TRUE;
  k->size = -1;
  result = ftp_3rdparty_pretransfer(conn);
  if (!result)
    result = ftp_3rdparty_transfer(conn);