📄 ftpcli.c
字号:
fprintf(control,"TYPE L %d\n",ftp->logbsize);
break;
}
ftp->typesent = ftp->type;
if(!ftp->batch){
resp = getresp(ftp,200);
if(resp == -1 || resp > 299)
goto failure;
} else
typewait = 1;
}
fprintf(control,"XMD5 %s\n",remotename);
if(typewait)
(void)getresp(ftp,200);
(void)getresp(ftp,200);
failure:;
return 0;
}
static int
docompare(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char *remotename,*localname;
register struct ftpcli *ftp;
ftp = (struct ftpcli *)p;
if(ftp == NULL){
printf(Notsess);
return 1;
}
remotename = argv[1];
if(argc > 2)
localname = argv[2];
else
localname = remotename;
if(compsub(ftp,localname,remotename) == 0)
printf("Same\n");
else
printf("Different\n");
return 0;
}
/* Compare a collection of files */
static int
domcompare(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct ftpcli *ftp;
FILE *files;
char *buf;
int i;
long r;
if((ftp = (struct ftpcli *)p) == NULL){
printf(Notsess);
return 1;
}
buf = mallocw(DIRBUF);
ftp->state = RECEIVING_STATE;
for(i=1;i<argc;i++){
files = tmpfile();
r = getsub(ftp,"NLST",argv[i],files);
if(ftp->abort)
break; /* Aborted */
if(r == -1){
printf("Can't NLST %s\n",argv[i]);
continue;
}
/* The tmp file now contains a list of the remote files, so
* go get 'em. Break out if the user signals an abort.
*/
rewind(files);
while(fgets(buf,DIRBUF,files) != NULL){
rip(buf);
if(compsub(ftp,buf,buf) == 0)
printf("%s - Same\n",buf);
else
printf("%s - Different\n",buf);
if(ftp->abort){
/* User abort */
ftp->abort = 0;
fclose(files);
free(buf);
ftp->state = COMMAND_STATE;
return 1;
}
}
fclose(files);
}
free(buf);
ftp->state = COMMAND_STATE;
ftp->abort = 0;
return 0;
}
/* Common subroutine to compare a local with a remote file
* Return 1 if files are different, 0 if they are the same
*/
static int
compsub(ftp,localname,remotename)
struct ftpcli *ftp;
char *localname;
char *remotename;
{
char *mode,*cp;
FILE *control,*fp;
int resp,i;
int typewait = 0;
uint8 remhash[16];
uint8 lochash[16];
control = ftp->control;
switch(ftp->type){
case IMAGE_TYPE:
case LOGICAL_TYPE:
mode = READ_BINARY;
break;
case ASCII_TYPE:
mode = READ_TEXT;
break;
}
if((fp = fopen(localname,mode)) == NULL){
printf("Can't read local file %s\n",localname);
return 1;
}
if(ftp->typesent != ftp->type){
switch(ftp->type){
case ASCII_TYPE:
fprintf(control,"TYPE A\n");
break;
case IMAGE_TYPE:
fprintf(control,"TYPE I\n");
break;
case LOGICAL_TYPE:
fprintf(control,"TYPE L %d\n",ftp->logbsize);
break;
}
ftp->typesent = ftp->type;
if(!ftp->batch){
resp = getresp(ftp,200);
if(resp == -1 || resp > 299)
goto failure;
} else
typewait = 1;
}
fprintf(control,"XMD5 %s\n",remotename);
/* Try to overlap the two MD5 operations */
md5hash(fp,lochash,ftp->type == ASCII_TYPE);
fclose(fp);
if(typewait && (resp = getresp(ftp,200)) > 299)
goto failure;
if((resp = getresp(ftp,200)) > 299){
if(resp == 500)
ftp->update = 0; /* XMD5 not supported */
goto failure;
}
if((cp = strchr(ftp->line,' ')) == NULL){
printf("Error in response\n");
goto failure;
}
/* Convert ascii/hex back to binary */
readhex(remhash,cp,sizeof(remhash));
if(ftp->verbose > 1){
printf("Loc ");
for(i=0;i<sizeof(lochash);i++)
printf("%02x",lochash[i]);
printf(" %s\n",localname);
}
if(memcmp(lochash,remhash,sizeof(remhash)) == 0)
return 0;
else
return 1;
failure:;
return 1;
}
/* Common code to LIST/NLST/RETR and mget
* Returns number of bytes received if successful
* Returns -1 on error
*/
static long
getsub(ftp,command,remotename,fp)
register struct ftpcli *ftp;
char *command,*remotename;
FILE *fp;
{
unsigned long total;
FILE *control;
int cnt,resp,i,savmode;
struct sockaddr_in lsocket;
struct sockaddr_in lcsocket;
int32 startclk,rate;
int vsave;
int typewait = 0;
int prevstate;
int d;
if(ftp == NULL)
return -1;
savmode = ftp->type;
control = ftp->control;
/* Open the data connection */
d = socket(AF_INET,SOCK_STREAM,0);
listen(d,0); /* Accept only one connection */
switch(ftp->type){
case IMAGE_TYPE:
case LOGICAL_TYPE:
ftp->data = fdopen(d,"r+b");
break;
case ASCII_TYPE:
ftp->data = fdopen(d,"r+t");
break;
}
prevstate = ftp->state;
ftp->state = RECEIVING_STATE;
/* Send TYPE message, if necessary */
if(strcmp(command,"LIST") == 0 || strcmp(command,"NLST") == 0){
/* Directory listings are always in ASCII */
ftp->type = ASCII_TYPE;
}
if(ftp->typesent != ftp->type){
switch(ftp->type){
case ASCII_TYPE:
fprintf(control,"TYPE A\n");
break;
case IMAGE_TYPE:
fprintf(control,"TYPE I\n");
break;
case LOGICAL_TYPE:
fprintf(control,"TYPE L %d\n",ftp->logbsize);
break;
}
ftp->typesent = ftp->type;
if(!ftp->batch){
resp = getresp(ftp,200);
if(resp == -1 || resp > 299)
goto failure;
} else
typewait = 1;
}
/* Send the PORT message. Use the IP address
* on the local end of our control connection.
*/
i = SOCKSIZE;
getsockname(d,(struct sockaddr *)&lsocket,&i); /* Get port number */
i = SOCKSIZE;
getsockname(fileno(ftp->control),(struct sockaddr *)&lcsocket,&i);
lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
sendport(control,&lsocket);
if(!ftp->batch){
/* Get response to PORT command */
resp = getresp(ftp,200);
if(resp == -1 || resp > 299)
goto failure;
}
/* Generate the command to start the transfer */
if(remotename != NULL)
fprintf(control,"%s %s\n",command,remotename);
else
fprintf(control,"%s\n",command);
if(ftp->batch){
/* Get response to TYPE command, if sent */
if(typewait){
resp = getresp(ftp,200);
if(resp == -1 || resp > 299)
goto failure;
}
/* Get response to PORT command */
resp = getresp(ftp,200);
if(resp == -1 || resp > 299)
goto failure;
}
/* Get the intermediate "150" response */
resp = getresp(ftp,100);
if(resp == -1 || resp >= 400)
goto failure;
/* Wait for the server to open the data connection */
cnt = 0;
d = accept(d,NULL,&cnt);
startclk = msclock();
/* If output is to the screen, temporarily disable hash marking */
vsave = ftp->verbose;
if(vsave >= V_HASH && fp == NULL)
ftp->verbose = V_NORMAL;
total = recvfile(fp,ftp->data,ftp->type,ftp->verbose);
/* Immediately close the data connection; some servers (e.g., TOPS-10)
* wait for the data connection to close completely before returning
* the completion message on the control channel
*/
fclose(ftp->data);
ftp->data = NULL;
#ifdef CPM
if(fp != NULL && ftp->type == ASCII_TYPE)
putc(CTLZ,fp);
#endif
if(remotename == NULL)
remotename = "";
if(total == -1){
printf("%s %s: Error/abort during data transfer\n",command,remotename);
} else if(ftp->verbose >= V_SHORT){
startclk = msclock() - startclk;
rate = 0;
if(startclk != 0){ /* Avoid divide-by-zero */
if(total < 4294967L) {
rate = (total*1000)/startclk;
} else { /* Avoid overflow */
rate = total/(startclk/1000);
}
}
printf("%s %s: %lu bytes in %lu sec (%lu/sec)\n",
command,remotename, total,startclk/1000,rate);
}
/* Get the "Sent" message */
getresp(ftp,200);
ftp->state = prevstate;
ftp->verbose = vsave;
ftp->type = savmode;
return total;
failure:
/* Error, quit */
if(fp != NULL && fp != stdout)
fclose(fp);
fclose(ftp->data);
ftp->data = NULL;
ftp->state = prevstate;
ftp->type = savmode;
return -1;
}
/* Send a file. Syntax: put <local name> [<remote name>] */
static int
doput(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct ftpcli *ftp;
char *remotename,*localname;
if((ftp = (struct ftpcli *)p) == NULL){
printf(Notsess);
return 1;
}
localname = argv[1];
if(argc < 3)
remotename = localname;
else
remotename = argv[2];
putsub(ftp,remotename,localname);
return 0;
}
/* Put a collection of files */
static int
domput(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct ftpcli *ftp;
FILE *files;
int i;
char *buf;
if((ftp = (struct ftpcli *)p) == NULL){
printf(Notsess);
return 1;
}
if((files = tmpfile()) == NULL){
printf("Can't list local files\n");
return 1;
}
for(i=1;i<argc;i++)
getdir(argv[i],0,files);
rewind(files);
buf = mallocw(DIRBUF);
ftp->state = SENDING_STATE;
while(fgets(buf,DIRBUF,files) != NULL){
rip(buf);
if(!ftp->update || compsub(ftp,buf,buf) != 0)
putsub(ftp,buf,buf);
if(ftp->abort)
break; /* User abort */
}
fclose(files);
free(buf);
ftp->state = COMMAND_STATE;
ftp->abort = 0;
return 0;
}
/* Common code to put, mput.
* Returns number of bytes sent if successful
* Returns -1 on error
*/
static long
putsub(ftp,remotename,localname)
register struct ftpcli *ftp;
char *remotename,*localname;
{
char *mode;
int i,resp,d;
unsigned long total;
FILE *fp,*control;
struct sockaddr_in lsocket,lcsocket;
int32 startclk,rate;
int typewait = 0;
int prevstate;
control = ftp->control;
if(ftp->type == IMAGE_TYPE)
mode = READ_BINARY;
else
mode = READ_TEXT;
/* Open the file */
if((fp = fopen(localname,mode)) == NULL){
printf("Can't read %s: %s\n",localname,sys_errlist[errno]);
return -1;
}
if(ftp->type == ASCII_TYPE && isbinary(fp)){
printf("Warning: type is ASCII and %s appears to be binary\n",localname);
}
/* Open the data connection */
d = socket(AF_INET,SOCK_STREAM,0);
ftp->data = fdopen(d,"w+");
listen(d,0);
prevstate = ftp->state;
ftp->state = SENDING_STATE;
/* Send TYPE message, if necessary */
if(ftp->typesent != ftp->type){
switch(ftp->type){
case ASCII_TYPE:
fprintf(control,"TYPE A\n");
break;
case IMAGE_TYPE:
fprintf(control,"TYPE I\n");
break;
case LOGICAL_TYPE:
fprintf(control,"TYPE L %d\n",ftp->logbsize);
break;
}
ftp->typesent = ftp->type;
/* Get response to TYPE command */
if(!ftp->batch){
resp = getresp(ftp,200);
if(resp == -1 || resp > 299){
goto failure;
}
} else
typewait = 1;
}
/* Send the PORT message. Use the IP address
* on the local end of our control connection.
*/
i = SOCKSIZE;
getsockname(d,(struct sockaddr *)&lsocket,&i);
i = SOCKSIZE;
getsockname(fileno(ftp->control),(struct sockaddr *)&lcsocket,&i);
lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
sendport(control,&lsocket);
if(!ftp->batch){
/* Get response to PORT command */
resp = getresp(ftp,200);
if(resp == -1 || resp > 299){
goto failure;
}
}
/* Generate the command to start the transfer */
fprintf(control,"STOR %s\n",remotename);
if(ftp->batch){
/* Get response to TYPE command, if sent */
if(typewait){
resp = getresp(ftp,200);
if(resp == -1 || resp > 299){
goto failure;
}
}
/* Get response to PORT command */
resp = getresp(ftp,200);
if(resp == -1 || resp > 299){
goto failure;
}
}
/* Get the intermediate "150" response */
resp = getresp(ftp,100);
if(resp == -1 || resp >= 400){
goto failure;
}
/* Wait for the data connection to open. Otherwise the first
* block of data would go out with the SYN, and this may confuse
* some other TCPs
*/
accept(d,NULL,(int *)NULL);
startclk = msclock();
total = sendfile(fp,ftp->data,ftp->type,ftp->verbose);
fflush(ftp->data);
shutdown(fileno(ftp->data),1); /* Send EOF (FIN) */
fclose(fp);
/* Wait for control channel ack before calculating transfer time;
* this accounts for transmitted data in the pipe
*/
getresp(ftp,200);
fclose(ftp->data);
ftp->data = NULL;
if(total == -1){
printf("STOR %s: Error/abort during data transfer\n",remotename);
} else if(ftp->verbose >= V_SHORT){
startclk = msclock() - startclk;
rate = 0;
if(startclk != 0){ /* Avoid divide-by-zero */
if(total < 4294967L) {
rate = (total*1000)/startclk;
} else { /* Avoid overflow */
rate = total/(startclk/1000);
}
}
printf("STOR %s: %lu bytes in %lu sec (%lu/sec)\n",
remotename,total,startclk/1000,rate);
}
ftp->state = prevstate;
return total;
failure:
/* Error, quit */
fclose(fp);
fclose(ftp->data);
ftp->data = NULL;
ftp->state = prevstate;
return -1;
}
/* send PORT message */
static void
sendport(fp,socket)
FILE *fp;
struct sockaddr_in *socket;
{
/* Send PORT a,a,a,a,p,p message */
fprintf(fp,"PORT %u,%u,%u,%u,%u,%u\n",
hibyte(hiword(socket->sin_addr.s_addr)),
lobyte(hiword(socket->sin_addr.s_addr)),
hibyte(loword(socket->sin_addr.s_addr)),
lobyte(loword(socket->sin_addr.s_addr)),
hibyte(socket->sin_port),
lobyte(socket->sin_port));
}
/* Wait for, read and display response from FTP server. Return the result code.
*/
static int
getresp(ftp,mincode)
struct ftpcli *ftp;
int mincode; /* Keep reading until at least this code comes back */
{
int rval;
fflush(ftp->control);
for(;;){
/* Get line */
if(fgets(ftp->line,LINELEN,ftp->control) == NULL){
rval = -1;
break;
}
rip(ftp->line); /* Remove cr/lf */
rval = atoi(ftp->line);
if(rval >= 400 || ftp->verbose >= V_NORMAL)
printf("%s\n",ftp->line); /* Display to user */
/* Messages with dashes are continued */
if(ftp->line[3] != '-' && rval >= mincode)
break;
}
return rval;
}
/* Issue a prompt and read a line from the user */
static int
getline(sp,prompt,buf,n)
struct session *sp;
char *prompt;
char *buf;
int n;
{
printf(prompt);
fflush(stdout);
fgets(buf,n,stdin);
return strlen(buf);
}
static int
keychar(c)
int c;
{
struct ftpcli *ftp;
if(c != CTLC)
return 1; /* Ignore all but ^C */
fprintf(Current->output,"^C\n");
ftp = Current->cb.ftp;
switch(ftp->state){
case COMMAND_STATE:
alert(Current->proc,EABORT);
break;
case SENDING_STATE:
/* Send a premature EOF.
* Unfortunately we can't just reset the connection
* since the remote side might end up waiting forever
* for us to send something.
*/
shutdown(fileno(ftp->data),1); /* Note fall-thru */
ftp->abort = 1;
break;
case RECEIVING_STATE:
/* Just blow away the receive socket */
shutdown(fileno(ftp->data),2); /* Note fall-thru */
ftp->abort = 1;
break;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -