📄 ftpsend.c
字号:
/* $Id: ftpsend.c,v 1.18 2005/10/05 19:32:47 splicednetworks Exp $ * * ftpsend.c -- send/receive files and file listings * * Yet Another FTP Client * Copyright (C) 1998-2001, Martin Hedenfalk <mhe@stacken.kth.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. See COPYING for more details. */#include "syshdr.h"#include "ftp.h"#include "socket.h"#include "xmalloc.h"#include "ftpsigs.h"#include "gvars.h"#include "ssh_cmd.h"#include "ssh_ftp.h"static int ftp_pasv(unsigned char result[6]){ int pa[6]; char *e; int i; if(!ftp->has_pasv_command) { ftp_err(_("Host doesn't support passive mode\n")); return -1; } ftp_set_tmp_verbosity(vbNone); /* request passive mode */ ftp_cmd("PASV"); if(!ftp_connected()) return -1; if(ftp->code != ctComplete) { ftp_err(_("Unable to enter passive mode\n")); if(ftp->code == ctError) /* no use try it again */ ftp->has_pasv_command = false; return -1; } e = ftp->reply + 4; while(!isdigit((int)*e)) e++; if(sscanf(e, "%d,%d,%d,%d,%d,%d", &pa[0], &pa[1], &pa[2], &pa[3], &pa[4], &pa[5]) != 6) { ftp_err(_("Error parsing PASV reply: '%s'\n"), ftp_getreply(false)); return -1; } for(i=0; i<6; i++) result[i] = (unsigned char)(pa[i] & 0xFF); return 0;}static bool ftp_is_passive(void){ if(!ftp || !ftp->url || ftp->url->pasvmode == -1) return gvPasvmode; return ftp->url->pasvmode;}static int ftp_init_transfer(void){ struct sockaddr_in sa; unsigned char *a, *p; unsigned char pac[6]; if(!ftp_connected()) goto err0; if (!(ftp->data = sock_create())) { goto err0; } sock_copy(ftp->data, ftp->ctrl); if(ftp_is_passive()) { if(ftp_pasv(pac) != 0) { goto err1; } sock_getsockname(ftp->ctrl, &sa); memcpy(&sa.sin_addr, pac, (size_t)4); memcpy(&sa.sin_port, pac+4, (size_t)2); if(sock_connect_addr(ftp->data, &sa) == -1) goto err1; } else { sock_listen(ftp->data); a = (unsigned char *)&ftp->data->local_addr.sin_addr; p = (unsigned char *)&ftp->data->local_addr.sin_port; ftp_set_tmp_verbosity(vbError); ftp_cmd("PORT %d,%d,%d,%d,%d,%d", a[0], a[1], a[2], a[3], p[0], p[1]); if(ftp->code != ctComplete) goto err1; } sock_throughput(ftp->data); return 0; err1: sock_destroy(ftp->data); err0: return -1;}int ftp_type(transfer_mode_t type){ if(ftp->ssh_pid) /* FIXME: is this relevant for ssh ? */ return 0; if(type == tmCurrent) return 0; if(ftp->prev_type != type) { ftp_cmd("TYPE %c", type == tmAscii ? 'A' : 'I'); if(ftp->code != ctComplete) return -1; ftp->prev_type = type; } return 0;}static ftp_transfer_func foo_hookf = 0;/* abort routine originally from Cftp by Dieter Baron */int ftp_abort(FILE *fp){ char buf[4096]; fd_set ready; struct timeval poll; if(ftp->ssh_pid) /* FIXME: what? */ return 0; if(!ftp_connected()) return -1; ftp_set_close_handler(); poll.tv_sec = poll.tv_usec = 0; FD_ZERO(&ready); FD_SET(ftp->ctrl->handle, &ready); if(select(ftp->ctrl->handle+1, &ready, 0, 0, &poll) == 1) { ftp_trace("There is data on the control channel, won't send ABOR\n"); /* read remaining bytes from connection */ while(fp && fread(buf, 1, 4096, fp) > 0) /* LOOP */ ; return 0; } ftp->ti.interrupted = true; ftp_err(_("Waiting for remote to finish abort...\n")); ftp_trace("--> telnet interrupt\n"); if(sock_telnet_interrupt(ftp->ctrl) != 0) ftp_err("telnet interrupt: %s\n", strerror(errno)); /* ftp_cmd("ABOR") won't work here, * we must flush data between the ABOR command and ftp_read_reply() */ sock_krb_printf(ftp->ctrl, "ABOR"); sock_printf(ftp->ctrl, "\r\n"); sock_flush(ftp->ctrl); if(ftp_get_verbosity() == vbDebug) ftp_err("--> [%s] ABOR\n", ftp->url->hostname); else ftp_trace("--> [%s] ABOR\n", ftp->url->hostname); /* read remaining bytes from connection */ while(fp && fread(buf, 1, 4096, fp) > 0) /* LOOP */ ; /* we expect a 426 or 226 reply here... */ ftp_read_reply(); if(ftp->fullcode != 426 && ftp->fullcode != 226) ftp_trace("Huh!? Expected a 426 or 226 reply\n"); /* ... and a 226 or 225 reply here, respectively */ /* FIXME: should skip this reply if prev. reply wasn't 426 or 226 ? */ ftp_read_reply(); if(ftp->fullcode != 226 && ftp->fullcode != 225) ftp_trace("Huh!? Expected a 226 or 225 reply\n"); return -1;}static int wait_for_data(FILE *fd, bool wait_for_read){ fd_set fds; struct timeval tv; int r; /* watch fd to see if it has input */ FD_ZERO(&fds); FD_SET(fileno(fd), &fds); /* wait max 1 second */ tv.tv_sec = 10; tv.tv_usec = 0; if(wait_for_read) r = select(fileno(fd)+1, &fds, 0, 0, &tv); else /* wait for write */ r = select(fileno(fd)+1, 0, &fds, 0, &tv);#if 0 if(r < 0 && errno == EINTR && gvSigStopReceived && ftp_sigints() == 0) { gvSigStopReceived = false; r = 0; }#endif if(r < 0) {/* perror("\nselect");*/ if(errno == EINTR) { if(gvSighupReceived) return 1; if(gvInterrupted) return -1; if(ftp_sigints() == 0) /* assume it is a SIGSTOP/SIGCONT signal */ return 0; } return -1; } if(r) ftp->ti.stalled = 0; else ftp->ti.stalled++; return r;}static int wait_for_input(void){ int r; do { r = wait_for_data(ftp->data->sin, true); if(r == -1) { if(errno == EINTR) ftp->ti.interrupted = true; return -1; } if(r == 0 && foo_hookf) foo_hookf(&ftp->ti); } while(r == 0); return 0;}static int wait_for_output(void){ int r; do { r = wait_for_data(ftp->data->sout, false); if(r == -1) return -1; if(r == 0 && foo_hookf) foo_hookf(&ftp->ti); } while(r == 0); return 0;}static int maybe_abort(FILE *in, FILE *out){ unsigned i; i = ftp_sigints(); ftp_set_close_handler(); ftp->ti.finished = true; if(ftp->ti.interrupted) i++; if(i > 0 || ferror(in) || ferror(out)) { if(ferror(in)) { ftp_err(_("read error: %s\n"), strerror(errno)); ftp->ti.ioerror = true; } else if(ferror(out)) { ftp_err(_("write error: %s\n"), strerror(errno)); ftp->ti.ioerror = true; } return ftp_abort(ftp->ti.transfer_is_put ? out : in); } return 0;}static int FILE_recv_binary(FILE *in, FILE *out){ size_t n; char *buf; time_t then = time(0) - 1; time_t now; ftp_set_close_handler(); if(foo_hookf) foo_hookf(&ftp->ti); ftp->ti.begin = false; clearerr(in); clearerr(out); buf = (char *)xmalloc(FTP_BUFSIZ); while(!feof(in)) { if(wait_for_input() != 0) { ftp_trace("wait_for_input() returned non-zero\n"); break; }#ifdef SECFTP n = sec_read(fileno(in), buf, FTP_BUFSIZ);#else n = fread(buf, sizeof(char), FTP_BUFSIZ, in);#endif if(n <= 0) break; if(ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } if(fwrite(buf, sizeof(char), n, out) != n) break; ftp->ti.size += n; if(foo_hookf) { now = time(0); if(now > then) { foo_hookf(&ftp->ti); then = now; } } } free(buf); ftp_set_close_handler(); return maybe_abort(in, out);}static int FILE_send_binary(FILE *in, FILE *out){ size_t n; char *buf; time_t then = time(0) - 1; time_t now; ftp_set_close_handler(); if(foo_hookf) foo_hookf(&ftp->ti); ftp->ti.begin = false; clearerr(in); clearerr(out); buf = (char *)xmalloc(FTP_BUFSIZ); while(!feof(in)) { n = fread(buf, sizeof(char), FTP_BUFSIZ, in); if(n <= 0) break; if(ftp_sigints() > 0) break; if(wait_for_output() != 0) break;#ifdef SECFTP if(sec_write(fileno(out), buf, n) != n) break;#else if(fwrite(buf, sizeof(char), n, out) != n) break;#endif ftp->ti.size += n; if(foo_hookf) { now = time(0); if(now > then) { foo_hookf(&ftp->ti); then = now; } } }#ifdef SECFTP sec_fflush(out);#endif free(buf); return maybe_abort(in, out);}static int krb_getc(FILE *fp){#ifdef SECFTP return sec_getc(fp);#else return fgetc(fp);#endif}static int FILE_recv_ascii(FILE *in, FILE *out){ char *buf = (char *)xmalloc(FTP_BUFSIZ); int c; time_t then = time(0) - 1; time_t now; ftp_set_close_handler(); if(foo_hookf) foo_hookf(&ftp->ti); ftp->ti.begin = false; clearerr(in); clearerr(out); while((c = krb_getc(in)) != EOF) { if(ftp_sigints() > 0) break; if(wait_for_input() != 0) break; if(c == '\n') ftp->ti.barelfs++; else if(c == '\r') { c = krb_getc(in); if(c == EOF) break; if(c != '\n') { ungetc(c, in); c = '\r'; } } if(fputc(c, out) == EOF) break; ftp->ti.size++; if(foo_hookf) { now = time(0); if(now > then) { foo_hookf(&ftp->ti); then = now; } } } free(buf); return maybe_abort(in, out);}static int FILE_send_ascii(FILE *in, FILE *out){ char *buf = (char *)xmalloc(FTP_BUFSIZ); int c; time_t then = time(0) - 1; time_t now; ftp_set_close_handler(); if(foo_hookf) foo_hookf(&ftp->ti); ftp->ti.begin = false; clearerr(in); clearerr(out); while((c = fgetc(in)) != EOF) { if(ftp_sigints() > 0) break; if(wait_for_output() != 0) break; if(c == '\n') { if(fputc('\r', out) == EOF) break; ftp->ti.size++; } if(fputc(c, out) == EOF) break; ftp->ti.size++; if(foo_hookf) { now = time(0); if(now > then) { foo_hookf(&ftp->ti); then = now; } } } free(buf); return maybe_abort(in, out);}void reset_transfer_info(void){ ftp->ti.barelfs = 0; ftp->ti.size = 0L; ftp->ti.ioerror = false; ftp->ti.interrupted = false; ftp->ti.transfer_is_put = false; ftp->ti.restart_size = 0L; ftp->ti.finished = false; ftp->ti.stalled = 0; ftp->ti.begin = true; gettimeofday(&ftp->ti.start_time, 0); if(!ftp->ti.local_name) ftp->ti.local_name = xstrdup("local");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -