int ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type) { databuf_t *data = NULL; char *ptr; int lastch; int rcvd; if (ftp == NULL) return 0; if (!ftp_type(ftp, type)) goto bail; if ((data = ftp_getdata(ftp)) == NULL) goto bail; if (!ftp_putcmd(ftp, "RETR", path)) goto bail; if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) goto bail; if ((data = data_accept(data)) == NULL) goto bail; lastch = 0; while ((rcvd = my_recv(data->fd, data->buf, FTP_BUFSIZE))) { if (rcvd == -1) goto bail; if (type == FTPTYPE_ASCII) { for (ptr = data->buf; rcvd; rcvd--, ptr++) { if (lastch == '\r' && *ptr != '\n') putc('\r', outfp); if (*ptr != '\r') putc(*ptr, outfp); lastch = *ptr; } } else { fwrite(data->buf, rcvd, 1, outfp); } } if (type == FTPTYPE_ASCII && lastch == '\r') putc('\r', outfp); data = data_close(data); if (ferror(outfp)) goto bail; if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) goto bail; return 1; bail: data_close(data); return 0; }
unsigned long long ftp_filesize(const char *path) { unsigned long long ret; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_filesize(path); #endif if(!ftp->has_size_command) return -1; if(ftp_type(tmBinary) != 0) return -1; ftp_set_tmp_verbosity(vbError); ftp_cmd("SIZE %s", path); if(ftp->fullcode == 502) { ftp->has_size_command = false; return -1; } if(ftp->code == ctComplete) { sscanf(ftp->reply, "%*s %llu", &ret); return ret; } return -1; }
static int ftp_init_receive(const char *path, transfer_mode_t mode, ftp_transfer_func hookf) { long rp = ftp->restart_offset; char *e; ftp->restart_offset = 0L; foo_hookf = hookf; reset_transfer_info(); if(ftp_init_transfer() != 0) return -1; ftp_type(mode); if(rp > 0) { /* fp is assumed to be fseek'd already */ ftp_cmd("REST %ld", rp); if(ftp->code != ctContinue) return -1; ftp->ti.size = rp; ftp->ti.restart_size = rp; } ftp_cmd("RETR %s", path); if(ftp->code != ctPrelim) return -1; if(!sock_accept(ftp->data, "r", ftp_is_passive())) { ftp_err(_("data connection not accepted\n")); return -1; } /* try to get the total file size */ { /* see if we have cached this directory/file */ rfile *f = ftp_cache_get_file(path); if(f) ftp->ti.total_size = f->size; else { /* try to figure out file size from RETR reply * Opening BINARY mode data connection for foo.mp3 (14429793 bytes) * ^^^^^^^^ aha! * * note: this might not be the _total_ filesize if we are RESTarting */ e = strstr(ftp->reply, " bytes"); if(e != 0) { while((e > ftp->reply) && isdigit((int)e[-1])) e--; ftp->ti.total_size = strtoul(e,NULL,10); } /* else we don't bother */ } } return 0; }
/* {{{ ftp_nb_get */ int ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos) { databuf_t *data = NULL; char arg[11]; if (ftp == NULL) { return PHP_FTP_FAILED; } if (!ftp_type(ftp, type)) { goto bail; } if ((data = ftp_getdata(ftp)) == NULL) { goto bail; } if (resumepos>0) { int arg_len = snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos); if (arg_len < 0) { goto bail; } if (!ftp_putcmd(ftp, "REST", sizeof("REST")-1, arg, arg_len)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 350)) { goto bail; } } if (!ftp_putcmd(ftp, "RETR", sizeof("RETR")-1, path, path_len)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) { goto bail; } if ((data = data_accept(data, ftp)) == NULL) { goto bail; } ftp->data = data; ftp->stream = outstream; ftp->lastch = 0; ftp->nb = 1; return (ftp_nb_continue_read(ftp)); bail: ftp->data = data_close(ftp, data); return PHP_FTP_FAILED; }
/* {{{ ftp_size */ zend_long ftp_size(ftpbuf_t *ftp, const char *path) { if (ftp == NULL) { return -1; } if (!ftp_type(ftp, FTPTYPE_IMAGE)) { return -1; } if (!ftp_putcmd(ftp, "SIZE", path)) { return -1; } if (!ftp_getresp(ftp) || ftp->resp != 213) { return -1; } return atol(ftp->inbuf); }
/* {{{ ftp_nb_put */ int ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, zend_long startpos) { databuf_t *data = NULL; char arg[11]; if (ftp == NULL) { return 0; } if (!ftp_type(ftp, type)) { goto bail; } if ((data = ftp_getdata(ftp)) == NULL) { goto bail; } if (startpos > 0) { snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 350)) { goto bail; } } if (!ftp_putcmd(ftp, "STOR", path)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) { goto bail; } if ((data = data_accept(data, ftp)) == NULL) { goto bail; } ftp->data = data; ftp->stream = instream; ftp->lastch = 0; ftp->nb = 1; return (ftp_nb_continue_write(ftp)); bail: ftp->data = data_close(ftp, data); return PHP_FTP_FAILED; }
int ftp_list(const char *cmd, const char *param, FILE *fp) { if (!cmd || !fp || !ftp_connected()) return -1; #ifdef HAVE_LIBSSH if (ftp->session) return ssh_list(cmd, param, fp); #endif reset_transfer_info(); foo_hookf = NULL; #if 0 /* don't care about transfer type, binary should work well... */ ftp_type(tmAscii); #endif if (ftp_init_transfer() != 0) { ftp_err(_("transfer initialization failed")); return -1; } ftp_set_tmp_verbosity(vbNone); if (param) ftp_cmd("%s %s", cmd, param); else ftp_cmd("%s", cmd); if (ftp->code != ctPrelim) return -1; if (!sock_accept(ftp->data, "r", ftp_is_passive())) { perror("accept()"); return -1; } if (FILE_recv_ascii(ftp->data, fp) != 0) return -1; sock_destroy(ftp->data); ftp->data = NULL; ftp_read_reply(); return ftp->code == ctComplete ? 0 : -1; }
/** * Generates response message for client * @param cmd Current command * @param state Current connection state */ void response(Command *cmd, State *state) { switch(lookup_cmd(cmd->command)){ case USER: ftp_user(cmd,state); break; case PASS: ftp_pass(cmd,state); break; case PASV: ftp_pasv(cmd,state); break; case LIST: ftp_list(cmd,state); break; case CWD: ftp_cwd(cmd,state); break; case PWD: ftp_pwd(cmd,state); break; case MKD: ftp_mkd(cmd,state); break; case RMD: ftp_rmd(cmd,state); break; case RETR: ftp_retr(cmd,state); break; case STOR: ftp_stor(cmd,state); break; case DELE: ftp_dele(cmd,state); break; case SIZE: ftp_size(cmd,state); break; case ABOR: ftp_abor(state); break; case QUIT: ftp_quit(state); break; case TYPE: ftp_type(cmd,state); break; case CDUP: ftp_cdup(state); break; case HELP: ftp_help(cmd, state); break; case NLST: ftp_nlst(cmd, state); break; case RNFR: ftp_rnfr(cmd, state); break; case RNTO: ftp_rnto(cmd, state); break; case APPE: ftp_appe(cmd, state); break; case NOOP: if(state->logged_in){ state->message = "200 Zzz...\n"; }else{ state->message = "530 Please login with USER and PASS\n"; } write_state(state); break; default: state->message = "500 Unknown command\n"; write_state(state); break; } }
/* {{{ ftp_put */ int ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, zend_long startpos) { databuf_t *data = NULL; zend_long size; char *ptr; int ch; char arg[11]; if (ftp == NULL) { return 0; } if (!ftp_type(ftp, type)) { goto bail; } if ((data = ftp_getdata(ftp)) == NULL) { goto bail; } ftp->data = data; if (startpos > 0) { snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 350)) { goto bail; } } if (!ftp_putcmd(ftp, "STOR", path)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) { goto bail; } if ((data = data_accept(data, ftp)) == NULL) { goto bail; } size = 0; ptr = data->buf; while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) { /* flush if necessary */ if (FTP_BUFSIZE - size < 2) { if (my_send(ftp, data->fd, data->buf, size) != size) { goto bail; } ptr = data->buf; size = 0; } if (ch == '\n' && type == FTPTYPE_ASCII) { *ptr++ = '\r'; size++; } *ptr++ = ch; size++; } if (size && my_send(ftp, data->fd, data->buf, size) != size) { goto bail; } ftp->data = data = data_close(ftp, data); if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) { goto bail; } return 1; bail: ftp->data = data_close(ftp, data); return 0; }
/* {{{ ftp_get */ int ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, zend_long resumepos) { databuf_t *data = NULL; size_t rcvd; char arg[11]; if (ftp == NULL) { return 0; } if (!ftp_type(ftp, type)) { goto bail; } if ((data = ftp_getdata(ftp)) == NULL) { goto bail; } ftp->data = data; if (resumepos > 0) { snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 350)) { goto bail; } } if (!ftp_putcmd(ftp, "RETR", path)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) { goto bail; } if ((data = data_accept(data, ftp)) == NULL) { goto bail; } while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) { if (rcvd == -1) { goto bail; } if (type == FTPTYPE_ASCII) { #ifndef PHP_WIN32 char *s; #endif char *ptr = data->buf; char *e = ptr + rcvd; /* logic depends on the OS EOL * Win32 -> \r\n * Everything Else \n */ #ifdef PHP_WIN32 php_stream_write(outstream, ptr, (e - ptr)); ptr = e; #else while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) { php_stream_write(outstream, ptr, (s - ptr)); if (*(s + 1) == '\n') { s++; php_stream_putc(outstream, '\n'); } ptr = s + 1; } #endif if (ptr < e) { php_stream_write(outstream, ptr, (e - ptr)); } } else if (rcvd != php_stream_write(outstream, data->buf, rcvd)) { goto bail; } } ftp->data = data = data_close(ftp, data); if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) { goto bail; } return 1; bail: ftp->data = data_close(ftp, data); return 0; }
/* transfers SRCFILE on SRCFTP to DESTFILE on DESTFTP * using pasv mode on SRCFTP and port mode on DESTFTP * */ int ftp_fxpfile(Ftp *srcftp, const char *srcfile, Ftp *destftp, const char *destfile, fxpmode_t how, transfer_mode_t mode) { int r; unsigned int old_reply_timeout; Ftp *thisftp; unsigned char addr[6]; /* printf("FxP: %s -> %s\n", srcftp->url->hostname, destftp->url->hostname);*/ if(srcftp == destftp) { ftp_err(_("FxP between same hosts\n")); return -1; } #ifdef HAVE_LIBSSH if(ftp->session) { ftp_err("FxP with SSH not implemented\n"); return -1; } #endif thisftp = ftp; /* save currently active connection */ /* setup source side */ ftp_use(srcftp); ftp_type(mode); // TODO: IPv6 support if(!ftp_pasv(false, addr, NULL)) { ftp_use(thisftp); return -1; } ftp->ti.total_size = -1; /* setup destination side */ ftp_use(destftp); ftp_type(mode); ftp_cmd("PORT %d,%d,%d,%d,%d,%d", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); if(ftp->code != ctComplete) { ftp_use(thisftp); return -1; } ftp->ti.total_size = -1; ftp_use(destftp); if(how == fxpResume) { rfile *f; f = ftp_get_file(destfile); if(f && f->size != (unsigned long long)-1) ftp->restart_offset = f->size; else { ftp->restart_offset = ftp_filesize(destfile); if(ftp->restart_offset == (unsigned long long)-1) { ftp_err(_("unable to get remote filesize of '%s'," " unable to resume\n"), destfile); ftp->restart_offset = 0L; } } } else ftp->restart_offset = 0L; if(ftp->restart_offset) { /* RESTart on destftp */ ftp_cmd("REST %ld", ftp->restart_offset); if(ftp->code != ctContinue) return -1; ftp_use(srcftp); ftp_cmd("REST %ld", ftp->restart_offset); if(ftp->code != ctContinue) return -1; } /* issue a STOR command on DESTFTP */ ftp_use(destftp); switch(how) { case fxpUnique: if(ftp->has_stou_command) { ftp_cmd("STOU %s", destfile); if(ftp->fullcode == 502) ftp->has_stou_command = false; } else { ftp->code = ctError; ftp->fullcode = 502; } break; case fxpAppend: ftp_cmd("APPE %s", destfile); break; case fxpNormal: default: ftp_cmd("STOR %s", destfile); break; } ftp_cache_flush_mark_for(destfile); if(ftp->code != ctPrelim) { ftp_use(thisftp); return -1; } /* issue a RETR command on SRCFTP */ ftp_use(srcftp); ftp_cmd("RETR %s", srcfile); if(ftp->code != ctPrelim) { ftp_use(destftp); ftp_abort(NULL); ftp_use(thisftp); return -1; } ftp_use(destftp); old_reply_timeout = ftp->reply_timeout; ftp_reply_timeout(0); ftp_read_reply(); ftp_reply_timeout(old_reply_timeout); r = (ftp->code == ctComplete ? 0 : -1); ftp_use(srcftp); old_reply_timeout = ftp->reply_timeout; ftp_reply_timeout(0); ftp_read_reply(); ftp_reply_timeout(old_reply_timeout); ftp_use(thisftp); return r; }
static int ftp_send(const char *path, FILE *fp, putmode_t how, transfer_mode_t mode, ftp_transfer_func hookf) { int r; long rp = ftp->restart_offset; ftp->restart_offset = 0L; if(how == putUnique && !ftp->has_stou_command) return -1; if (how == putTryUnique && !ftp->has_stou_command) how = putNormal; reset_transfer_info(); ftp->ti.transfer_is_put = true; if(ftp_init_transfer() != 0) return -1; ftp_type(mode); if(rp > 0) { /* fp is assumed to be fseek'd already */ ftp_cmd("REST %ld", rp); if(ftp->code != ctContinue) return -1; ftp->ti.size = rp; ftp->ti.restart_size = rp; } ftp_set_tmp_verbosity(vbError); switch (how) { case putAppend: ftp_cmd("APPE %s", path); break; case putTryUnique: case putUnique: ftp_cmd("STOU %s", path); if (ftp->fullcode == 502 || ftp->fullcode == 504) { ftp->has_stou_command = false; if (how == putTryUnique) how = putNormal; else break; } else break; default: ftp_cmd("STOR %s", path); break; } if(ftp->code != ctPrelim) return -1; if(how == putUnique) { /* try to figure out remote filename */ char *e = strstr(ftp->reply, " for "); if(e) { int l; e += 5; l = strlen(e); if(l) { free(ftp->ti.local_name); if(*e == '\'') ftp->ti.local_name = xstrndup(e+1, l-3); else ftp->ti.local_name = xstrndup(e, l-1); ftp_trace("parsed unique filename as '%s'\n", ftp->ti.local_name); } } } if(!sock_accept(ftp->data, "w", ftp_is_passive())) { ftp_err(_("data connection not accepted\n")); return -1; } ftp_cache_flush_mark_for(path); if(mode == tmBinary) r = FILE_send_binary(fp, ftp->data); else r = FILE_send_ascii(fp, ftp->data); sock_flush(ftp->data); sock_destroy(ftp->data); ftp->data = 0; if(r == 0) { transfer_finished(); ftp_read_reply(); ftp->ti.ioerror = (ftp->code != ctComplete); if(ftp->code != ctComplete) { ftp_trace("transfer failed\n"); return -1; } } else transfer_finished(); return 0; }
/** * 作用: 从本地复制文件到服务器 STOR * 参数: SOCKET,源地址,目的地址,文件大小 * 返回值: 0 表示列表成功 result>0 表示其他错误响应码 * -1:文件创建失败 -2 pasv接口错误 * */ int ftp_local2server(SOCKET c_sock, char* s, char* d, int* size) { SOCKET d_sock; ssize_t len, send_len; char buf[BUFSIZ]; FILE *fp; int send_re; int result; // 打开本地文件 fp = fopen(s, "rb"); if (NULL == fp) { logger.error("从本地复制文件到服务器 can't open the file."); return -1; } // 设置传输模式 ftp_type(c_sock, 'I'); // 连接到PASV接口 d_sock = ftp_pasv_connect(c_sock); if (d_sock == -1) { fclose(fp); return -1; } // 发送STOR命令 memset(buf, sizeof(buf), 0); sprintf(buf, "STOR %s\r\n", d); send_re = ftp_sendcmd(c_sock, buf); if (send_re >= 300 || send_re == 0) { fclose(fp); return send_re; } // 开始向PASV通道写数据 memset(buf, sizeof(buf), 0); while ((len = fread(buf, 1, BUFSIZ, fp)) > 0) { send_len = send(d_sock, buf, len, 0); if (send_len != len) { closesocket(d_sock); fclose(fp); return -1; } if (NULL != size) { *size += send_len; } } // 完成上传 closesocket(d_sock); fclose(fp); // 向服务器接收响应码 memset(buf, sizeof(buf), 0); len = recv(c_sock, buf, BUFSIZ, 0); buf[len] = 0; sscanf(buf, "%d", &result); if (result >= 300) { return result; } return 0; }
/** * 作用: 从服务器复制文件到本地 RETR * 参数: SOCKET,源地址,目的地址,文件大小 * 返回值: 0 表示列表成功 result>0 表示其他错误响应码 * -1:文件创建失败 -2 pasv接口错误 * */ int ftp_server2local(SOCKET c_sock, char *s, char* d, int* size) { SOCKET d_sock; ssize_t len, write_len; char buf[BUFSIZ]; int result; *size = 0; // 打开本地文件 FILE* fp = fopen(d, "wb"); if (NULL == fp) { logger.error("从服务器复制文件到本地 can't open the file."); return -1; } // 设置传输模式 ftp_type(c_sock, 'I'); // 连接到PASV接口,用于传输文件 d_sock = ftp_pasv_connect(c_sock); if (d_sock == -1) { fclose(fp); // 关闭文件 return -2; } // 发送RETR命令 memset(buf, sizeof(buf), 0); sprintf(buf, "RETR %s\r\n", s); result = ftp_sendcmd(c_sock, buf); // 150 Opening data channel for file download from server of "xxxx" if (result >= 300 || result == 0) // 失败可能是没有权限什么的,具体看响应码 { fclose(fp); return result; } // 开始向PASV读取数据(下载) memset(buf, sizeof(buf), 0); while ((len = recv(d_sock, buf, BUFSIZ, 0)) > 0) { write_len = fwrite(&buf, len, 1, fp); if (write_len != 1) // 写入文件不完整 { closesocket(d_sock); // 关闭套接字 fclose(fp); // 关闭文件 return -1; } if (NULL != size) { *size += write_len; } } // 下载完成 closesocket(d_sock); fclose(fp); // 向服务器接收返回值 memset(buf, sizeof(buf), 0); len = recv(c_sock, buf, BUFSIZ, 0); buf[len] = 0; sscanf(buf, "%d", &result); if (result >= 300) { return result; } //226 Successfully transferred "xxxx" return 0; }
int ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, ftptype_t type) { databuf_t *data = NULL; int size; char *ptr; int ch; if (ftp == NULL) return 0; if (!ftp_type(ftp, type)) goto bail; if ((data = ftp_getdata(ftp)) == NULL) goto bail; if (!ftp_putcmd(ftp, "STOR", path)) goto bail; if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) goto bail; if ((data = data_accept(data)) == NULL) goto bail; size = 0; ptr = data->buf; while ((ch = getc(infp)) != EOF) { /* flush if necessary */ if (FTP_BUFSIZE - size < 2) { if (my_send(data->fd, data->buf, size) != size) goto bail; ptr = data->buf; size = 0; } if (ch == '\n' && type == FTPTYPE_ASCII) { *ptr++ = '\r'; size++; } *ptr++ = ch; size++; } if (size && my_send(data->fd, data->buf, size) != size) goto bail; if (ferror(infp)) goto bail; data = data_close(data); if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) goto bail; return 1; bail: data_close(data); return 0; }