aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ftp.c90
-rw-r--r--lib/urldata.h3
2 files changed, 88 insertions, 5 deletions
diff --git a/lib/ftp.c b/lib/ftp.c
index b68cc027c..26cf19795 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -439,13 +439,15 @@ 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;
}
diff --git a/lib/urldata.h b/lib/urldata.h
index 1ee6637d2..bc2eff960 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -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. */
};
/****************************************************************************