⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpcli.c

📁 嵌入式TCP/IP协议栈。 C 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
			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 + -