📄 ftp-basic.c
字号:
/* Parse the response. */ s = respline; for (s += 4; *s && !ISDIGIT (*s); s++) ; if (!*s) return FTPINVPASV; /* First, get the address family */ af = 0; for (; ISDIGIT (*s); s++) af = (*s - '0') + 10 * af; if (af != 4 && af != 6) { xfree (respline); return FTPINVPASV; } if (!*s || *s++ != ',') { xfree (respline); return FTPINVPASV; } /* Then, get the address length */ addrlen = 0; for (; ISDIGIT (*s); s++) addrlen = (*s - '0') + 10 * addrlen; if (!*s || *s++ != ',') { xfree (respline); return FTPINVPASV; } if (addrlen > 16) { xfree (respline); return FTPINVPASV; } if ((af == 4 && addrlen != 4) || (af == 6 && addrlen != 16)) { xfree (respline); return FTPINVPASV; } /* Now, we get the actual address */ for (i = 0; i < addrlen; i++) { tmp[i] = 0; for (; ISDIGIT (*s); s++) tmp[i] = (*s - '0') + 10 * tmp[i]; if (*s == ',') s++; else { xfree (respline); return FTPINVPASV; } } /* Now, get the port length */ portlen = 0; for (; ISDIGIT (*s); s++) portlen = (*s - '0') + 10 * portlen; if (!*s || *s++ != ',') { xfree (respline); return FTPINVPASV; } if (portlen > 2) { xfree (respline); return FTPINVPASV; } /* Finally, we get the port number */ tmpprt[0] = 0; for (; ISDIGIT (*s); s++) tmpprt[0] = (*s - '0') + 10 * tmpprt[0]; if (!*s || *s++ != ',') { xfree (respline); return FTPINVPASV; } tmpprt[1] = 0; for (; ISDIGIT (*s); s++) tmpprt[1] = (*s - '0') + 10 * tmpprt[1]; assert (s != NULL); if (af == 4) { addr->family = AF_INET; memcpy (IP_INADDR_DATA (addr), tmp, 4); *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1]; DEBUGP (("lpsv addr is: %s\n", print_address(addr))); DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0])); DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1])); DEBUGP (("*port is: %d\n", *port)); } else { assert (af == 6); addr->family = AF_INET6; memcpy (IP_INADDR_DATA (addr), tmp, 16); *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1]; DEBUGP (("lpsv addr is: %s\n", print_address(addr))); DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0])); DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1])); DEBUGP (("*port is: %d\n", *port)); } xfree (respline); return FTPOK;}/* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP transfer. Reads the response from server and parses it. Reads the host and port addresses and returns them. */uerr_tftp_epsv (int csock, ip_address *ip, int *port){ char *request, *respline, *start, delim, *s; int nwritten, i; uerr_t err; int tport; assert (ip != NULL); assert (port != NULL); /* IP already contains the IP address of the control connection's peer, so we don't need to call socket_ip_address here. */ /* Form the request. */ /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */ request = ftp_request ("EPSV", (ip->family == AF_INET ? "1" : "2")); /* And send it. */ nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get the server response. */ err = ftp_response (csock, &respline); if (err != FTPOK) return err; if (*respline != '2') { xfree (respline); return FTPNOPASV; } assert (respline != NULL); DEBUGP(("respline is %s\n", respline)); /* Parse the response. */ s = respline; /* Skip the useless stuff and get what's inside the parentheses */ start = strchr (respline, '('); if (start == NULL) { xfree (respline); return FTPINVPASV; } /* Skip the first two void fields */ s = start + 1; delim = *s++; if (delim < 33 || delim > 126) { xfree (respline); return FTPINVPASV; } for (i = 0; i < 2; i++) { if (*s++ != delim) { xfree (respline); return FTPINVPASV; } } /* Finally, get the port number */ tport = 0; for (i = 1; ISDIGIT (*s); s++) { if (i > 5) { xfree (respline); return FTPINVPASV; } tport = (*s - '0') + 10 * tport; } /* Make sure that the response terminates correcty */ if (*s++ != delim) { xfree (respline); return FTPINVPASV; } if (*s++ != ')') { xfree (respline); return FTPINVPASV; } *port = tport; xfree (respline); return FTPOK;}#endif/* Sends the TYPE request to the server. */uerr_tftp_type (int csock, int type){ char *request, *respline; int nwritten; uerr_t err; char stype[2]; /* Construct argument. */ stype[0] = type; stype[1] = 0; /* Send TYPE request. */ request = ftp_request ("TYPE", stype); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err != FTPOK) return err; if (*respline != '2') { xfree (respline); return FTPUNKNOWNTYPE; } xfree (respline); /* All OK. */ return FTPOK;}/* Changes the working directory by issuing a CWD command to the server. */uerr_tftp_cwd (int csock, const char *dir){ char *request, *respline; int nwritten; uerr_t err; /* Send CWD request. */ request = ftp_request ("CWD", dir); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err != FTPOK) return err; if (*respline == '5') { xfree (respline); return FTPNSFOD; } if (*respline != '2') { xfree (respline); return FTPRERR; } xfree (respline); /* All OK. */ return FTPOK;}/* Sends REST command to the FTP server. */uerr_tftp_rest (int csock, wgint offset){ char *request, *respline; int nwritten; uerr_t err; request = ftp_request ("REST", number_to_static_string (offset)); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err != FTPOK) return err; if (*respline != '3') { xfree (respline); return FTPRESTFAIL; } xfree (respline); /* All OK. */ return FTPOK;}/* Sends RETR command to the FTP server. */uerr_tftp_retr (int csock, const char *file){ char *request, *respline; int nwritten; uerr_t err; /* Send RETR request. */ request = ftp_request ("RETR", file); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err != FTPOK) return err; if (*respline == '5') { xfree (respline); return FTPNSFOD; } if (*respline != '1') { xfree (respline); return FTPRERR; } xfree (respline); /* All OK. */ return FTPOK;}/* Sends the LIST command to the server. If FILE is NULL, send just `LIST' (no space). */uerr_tftp_list (int csock, const char *file){ char *request, *respline; int nwritten; uerr_t err; bool ok = false; int i = 0; /* Try `LIST -a' first and revert to `LIST' in case of failure. */ const char *list_commands[] = { "LIST -a", "LIST" }; do { /* Send request. */ request = ftp_request (list_commands[i], file); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err == FTPOK) { if (*respline == '5') { err = FTPNSFOD; } else if (*respline == '1') { err = FTPOK; ok = true; } else { err = FTPRERR; } xfree (respline); } ++i; } while (i < countof (list_commands) && !ok); return err;}/* Sends the SYST command to the server. */uerr_tftp_syst (int csock, enum stype *server_type){ char *request, *respline; int nwritten; uerr_t err; /* Send SYST request. */ request = ftp_request ("SYST", NULL); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err != FTPOK) return err; if (*respline == '5') { xfree (respline); return FTPSRVERR; } /* Skip the number (215, but 200 (!!!) in case of VMS) */ strtok (respline, " "); /* Which system type has been reported (we are interested just in the first word of the server response)? */ request = strtok (NULL, " "); if (request == NULL) *server_type = ST_OTHER; else if (!strcasecmp (request, "VMS")) *server_type = ST_VMS; else if (!strcasecmp (request, "UNIX")) *server_type = ST_UNIX; else if (!strcasecmp (request, "WINDOWS_NT") || !strcasecmp (request, "WINDOWS2000")) *server_type = ST_WINNT; else if (!strcasecmp (request, "MACOS")) *server_type = ST_MACOS; else if (!strcasecmp (request, "OS/400")) *server_type = ST_OS400; else *server_type = ST_OTHER; xfree (respline); /* All OK. */ return FTPOK;}/* Sends the PWD command to the server. */uerr_tftp_pwd (int csock, char **pwd){ char *request, *respline; int nwritten; uerr_t err; /* Send PWD request. */ request = ftp_request ("PWD", NULL); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err != FTPOK) return err; if (*respline == '5') { err: xfree (respline); return FTPSRVERR; } /* Skip the number (257), leading citation mark, trailing citation mark and everything following it. */ strtok (respline, "\""); request = strtok (NULL, "\""); if (!request) /* Treat the malformed response as an error, which the caller has to handle gracefully anyway. */ goto err; /* Has the `pwd' been already allocated? Free! */ xfree_null (*pwd); *pwd = xstrdup (request); xfree (respline); /* All OK. */ return FTPOK;}/* Sends the SIZE command to the server, and returns the value in 'size'. * If an error occurs, size is set to zero. */uerr_tftp_size (int csock, const char *file, wgint *size){ char *request, *respline; int nwritten; uerr_t err; /* Send PWD request. */ request = ftp_request ("SIZE", file); nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); *size = 0; return WRITEFAILED; } xfree (request); /* Get appropriate response. */ err = ftp_response (csock, &respline); if (err != FTPOK) { *size = 0; return err; } if (*respline == '5') { /* * Probably means SIZE isn't supported on this server. * Error is nonfatal since SIZE isn't in RFC 959 */ xfree (respline); *size = 0; return FTPOK; } errno = 0; *size = str_to_wgint (respline + 4, NULL, 10); if (errno) { /* * Couldn't parse the response for some reason. On the (few) * tests I've done, the response is 213 <SIZE> with nothing else - * maybe something a bit more resilient is necessary. It's not a * fatal error, however. */ xfree (respline); *size = 0; return FTPOK; } xfree (respline); /* All OK. */ return FTPOK;}/* If URL's params are of the form "type=X", return character X. Otherwise, return 'I' (the default type). */charftp_process_type (const char *params){ if (params && 0 == strncasecmp (params, "type=", 5) && params[5] != '\0') return TOUPPER (params[5]); else return 'I';}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -