Commit b0b2824b authored by Patrick Monnerat's avatar Patrick Monnerat
Browse files

- Introduced a SYST-based test to properly set-up name format when dealing ...

- Introduced a SYST-based test to properly set-up name format when dealing  with the OS/400 FTP server.
- Fixed an ftp_readresp() bug preventing detection of failing control socket  and causing FTP client to loop forever.
parent 0cb6f305
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -6,6 +6,13 @@

                                  Changelog

Patrick Monnerat (24 Aug 2009)
- Introduced a SYST-based test to properly set-up name format when dealing
  with the OS/400 FTP server.

- Fixed an ftp_readresp() bug preventing detection of failing control socket
  and causing FTP client to loop forever.

Daniel Stenberg (24 Aug 2009)
- Marc de Bruin pointed out that configure --with-gnutls=PATH didn't work
  properly and provided a fix. http://curl.haxx.se/bug/view.cgi?id=2843008
+85 −5
Original line number Diff line number Diff line
@@ -439,14 +439,16 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
#ifdef CURL_DOES_CONVERSIONS
      if((res == CURLE_OK) && (gotbytes > 0)) {
        /* convert from the network encoding */
        result = res = Curl_convert_from_network(data, ptr, gotbytes);
        res = Curl_convert_from_network(data, ptr, gotbytes);
        /* Curl_convert_from_network calls failf if unsuccessful */
      }
#endif /* CURL_DOES_CONVERSIONS */

      if(CURLE_OK != res)
      if(CURLE_OK != res) {
        result = res;	/* Set the outer result variable to this error. */
        keepon = FALSE;
      }
    }

    if(!keepon)
      ;
@@ -742,6 +744,8 @@ static void state(struct connectdata *conn,
    "PROT",
    "CCC",
    "PWD",
    "SYST",
    "NAMEFMT",
    "QUOTE",
    "RETR_PREQUOTE",
    "STOR_PREQUOTE",
@@ -2733,10 +2737,11 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)

    case FTP_PWD:
      if(ftpcode == 257) {
        char *dir = malloc(nread+1);
        char *store=dir;
        char *ptr=&data->state.buffer[4];  /* start on the first letter */
        char *dir;
        char *store;

        dir = malloc(nread + 1);
        if(!dir)
          return CURLE_OUT_OF_MEMORY;

@@ -2751,7 +2756,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
        if('\"' == *ptr) {
          /* it started good */
          ptr++;
          while(ptr && *ptr) {
          for (store = dir; *ptr;) {
            if('\"' == *ptr) {
              if('\"' == ptr[1]) {
                /* "quote-doubling" */
@@ -2769,10 +2774,30 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
            store++;
            ptr++;
          }
          if(ftpc->entrypath)
            free(ftpc->entrypath);
          ftpc->entrypath =dir; /* remember this */
          infof(data, "Entry path is '%s'\n", ftpc->entrypath);
          /* also save it where getinfo can access it: */
          data->state.most_recent_ftp_entrypath = ftpc->entrypath;

          /* If the path name does not look like an absolute path (i.e.: it
             does not start with a '/'), we probably need some server-dependent
             adjustments. For example, this is the case when connecting to
             an OS400 FTP server: this server supports two name syntaxes,
             the default one being incompatible with standard pathes. In
             addition, this server switches automatically to the regular path
             syntax when one is encountered in a command: this results in
             having an entrypath in the wrong syntax when later used in CWD.
               The method used here is to check the server OS: we do it only
             if the path name looks strange to minimize overhead on other
             systems. */

          if(!ftpc->server_os && ftpc->entrypath[0] != '/') {
            NBFTPSENDF(conn, "SYST", NULL);
            state(conn, FTP_SYST);
            break;
          }
        }
        else {
          /* couldn't get the path */
@@ -2784,6 +2809,57 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
      DEBUGF(infof(data, "protocol connect phase DONE\n"));
      break;

    case FTP_SYST:
      if(ftpcode == 215) {
        char *ptr=&data->state.buffer[4];  /* start on the first letter */
        char *os;
        char *store;

        os = malloc(nread + 1);
        if(!os)
          return CURLE_OUT_OF_MEMORY;

        /* Reply format is like
           215<space><OS-name><space><commentary>
        */
        while (*ptr == ' ')
          ptr++;
        for (store = os; *ptr && *ptr != ' ';)
          *store++ = *ptr++;
        *store = '\0'; /* zero terminate */
        ftpc->server_os = os;

        /* Check for special servers here. */

        if(strequal(ftpc->server_os, "OS/400")) {
          /* Force OS400 name format 1. */
          NBFTPSENDF(conn, "SITE NAMEFMT 1", NULL);
          state(conn, FTP_NAMEFMT);
          break;
        }
      else {
        /* Nothing special for the target server. */
       }
      }
      else {
        /* Cannot identify server OS. Continue anyway and cross fingers. */
      }

      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
      DEBUGF(infof(data, "protocol connect phase DONE\n"));
      break;

    case FTP_NAMEFMT:
      if(ftpcode == 250) {
        /* Name format change successful: reload initial path. */
        ftp_state_pwd(conn);
        break;
      }

      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
      DEBUGF(infof(data, "protocol connect phase DONE\n"));
      break;

    case FTP_QUOTE:
    case FTP_POSTQUOTE:
    case FTP_RETR_PREQUOTE:
@@ -3843,6 +3919,10 @@ static CURLcode ftp_disconnect(struct connectdata *conn)
    free(ftpc->prevpath);
    ftpc->prevpath = NULL;
  }
  if(ftpc->server_os) {
    free(ftpc->server_os);
    ftpc->server_os = NULL;
  }

  return CURLE_OK;
}
+3 −0
Original line number Diff line number Diff line
@@ -362,6 +362,8 @@ typedef enum {
  FTP_PROT,
  FTP_CCC,
  FTP_PWD,
  FTP_SYST,
  FTP_NAMEFMT,
  FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
  FTP_RETR_PREQUOTE,
  FTP_STOR_PREQUOTE,
@@ -458,6 +460,7 @@ struct ftp_conn {
  struct timeval response; /* set to Curl_tvnow() when a command has been sent
                              off, used to time-out response reading */
  ftpstate state; /* always use ftp.c:state() to change state! */
  char * server_os;     /* The target server operating system. */
};

/****************************************************************************
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
 test635 test636 test637 test558 test559 test1086 test1087 test1088        \
 test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096   \
 test1097 test560 test561 test1098 test1099 test562 test563 test1100       \
 test564 test1101
 test564 test1101 test1102 test1103

filecheck:
	@mkdir test-place; \

tests/data/test1102

0 → 100644
+51 −0
Original line number Diff line number Diff line
<testcase>
<info>
<keywords>
FTP
SYST
SITE
OS400
</keywords>
</info>
# Server-side
<reply>
<data nocheck="yes">
blabla
</data>
<servercmd>
REPLY PWD 257 "QGPL" is the current library
REPLY SYST 215  OS/400 runs this server
REPLY SITE 250 Name format set to 1
</servercmd>
</reply>

# Client-side
<client>
<server>
ftp
</server>
 <name>
FTP OS/400 server name format check
 </name>
 <command>
ftp://%HOSTIP:%FTPPORT/1102
</command>
</client>

# Verify data after the test has been "shot"
<verify>
<protocol>
USER anonymous
PASS ftp@example.com
PWD
SYST
SITE NAMEFMT 1
PWD
EPSV
TYPE I
SIZE 1102
RETR 1102
QUIT
</protocol>
</verify>
</testcase>
Loading