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

📄 ftpcmd.c

📁 linux下的FTP服务器。支持现在主流的FTP客户端软件。增加了一些额外的功能。
💻 C
📖 第 1 页 / 共 2 页
字号:
	getsockname(datalistenfd,(struct sockaddr *)&pasv_addr,&len);
	
	char temp[80]={0};
	int port=ntohs(pasv_addr.sin_port);
	int arr_port[2]={0};
	arr_port[0] = port/256;
	arr_port[1] = port%256;

	sprintf(temp,"Entering Passive Mode (%s.%d.%d)",localip,arr_port[0],arr_port[1]);
	
	int i=0;
	for(;i<strlen(temp);i++)
	{
		if (temp[i]=='.')
		{
			temp[i]=',';
		}
	}
	
	// 227 后面的参数要时合理的 给出服务器IP地址 和端口号 供客户端连接	
	ftp_global_var.IsPasv =1; // 保存被动模式
	ftp_global_var.pasv_mode_sockfd=datalistenfd;
	Tcp_listen(datalistenfd,5); // 开监听
	ServiceEcho(227,temp);
	return 0;
}
int do_rnfr(char * param)
{	
	// 先做绝对路径 ,相对路径先放着
	// ????????????????

	//strcpy(ftp_global_var.oldpathname,ftp_global_var.currpath);
	//strcat(ftp_global_var.oldpathname,"/");

	strcpy(ftp_global_var.oldpathname,param);
	
	ServiceEcho(350,"Ready for RNTO");
	//ServiceEcho(350,ftp_global_var.oldpathname);
	/*
	if (rename())
	{
	}
	*/
	return 0;
}

int do_rnto(char * param)
{
	//chdir(ftp_global_var.currpath);
	
	
	if (rename(ftp_global_var.oldpathname,param)==-1)
	{
		perror("rename error.");
	}

	ServiceEcho(250,"Rename successful");
	return 0;
}
int do_size(char * param)
{
	// 文件状态结构
	struct stat filestat;
	if (stat(param,&filestat)!=-1 && filestat.st_size != 4096)
	{
		char temp[80]={0};
		sprintf(temp,"%s size = %d",param,filestat.st_size);
		ServiceEcho(213,temp);
	}
	else
	{
		ServiceEcho(550,"Could not get file size.");
	}

	return 0;
}

int do_noop(char * param)
{
	ServiceEcho(200,"NOOP ok.");
	return 0;
}


void userhandler(int sig)
{
	ftp_global_var.endseek=0;
}
// 上传文件
int do_stor(char * param)
{
	int fd=0;
	if (ftp_global_var.isappe== 1)
	{
		
		 fd=open(param,O_CREAT | O_WRONLY |O_APPEND,0644); // 文件权限
	}
	else
	{
		fd=open(param,O_CREAT | O_WRONLY,0644); // 文件权限
	}

	if (fd<0)
	{
		if (ftp_global_var.isappe== 1)
		{
			ServiceEcho(553,"Appe fail.");
		}
		else
		{
			ServiceEcho(553,"Create file fail.");
		}
		
		return -1;
	}

	if(ftp_global_var.endseek>0)
	{
		lseek(fd,ftp_global_var.endseek,SEEK_SET);
		//lseek(fd,100000,SEEK_SET);
	}

	int sendsockfd;

	// 父亲进程

	if (ftp_global_var.IsPasv)
	{
		signal(SIGUSR1,userhandler);
		if (fork()==0)
		{
			// 子进程
			int sendsockfd = Tcp_accept(ftp_global_var.pasv_mode_sockfd,NULL,NULL);
			upload_file(fd,sendsockfd);
			shutdown(sendsockfd,0);
			Tcp_close(sendsockfd);
			close(fd);
			kill(getppid(),SIGUSR1);
			ServiceEcho(226,"File receive Ok");
			exit(0);
		}
		// 被动连接
		
		//ServiceEcho(150,"Here comes the directory listing"); // 说明已经连接上了。
		//ftp_global_var.endseek=0;
		
		ServiceEcho(150,"Ok to send data");
		//Tcp_close(ftp_global_var.pasv_mode_sockfd); // 关闭监听
		/*
		int clisockfd = Tcp_accept(ftp_global_var.pasv_mode_sockfd,NULL,NULL);
		Tcp_close(ftp_global_var.pasv_mode_sockfd); // 关闭监听
		download_file(fd,clisockfd);
		Tcp_close(clisockfd);
		*/
	}else
	{
		// 主动连接
		struct sockaddr_in servaddr,cliaddr;
		int servfd;
		int clifd;
		memset(&servaddr,0,sizeof(servaddr));
		memset(&cliaddr,0,sizeof(cliaddr));
		
		servaddr.sin_family = AF_INET;
		servaddr.sin_port = htons(20);
		//servaddr.sin_addr.s_addr = inet_addr();
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

		cliaddr.sin_family =AF_INET;
		cliaddr.sin_port = htons(ftp_global_var.port_port);
		cliaddr.sin_addr.s_addr = inet_addr(ftp_global_var.port_ip);
		
		int len=sizeof(cliaddr);
		ftp_global_var.uid = geteuid();
		ftp_global_var.gid = getegid();

		seteuid(0);
		setegid(0);
		// 只有ROOT 用户才有权限绑定20端口
		// ????????????? 调用语义是有问题的 借用一个函数
		sendsockfd = Tcp_service(ftp_global_var.port_ip,20);
		//servfd = socket(AF_INET,SOCK_DGRAM,0);
		seteuid(ftp_global_var.uid);
		setegid(ftp_global_var.gid);
		

		
		
		if (fork()==0)
		{
			connect(sendsockfd,(struct sockaddr *)&cliaddr,len);
						upload_file(fd,sendsockfd);
			shutdown(sendsockfd,0);
			Tcp_close(sendsockfd);
			close(fd);
			ServiceEcho(226,"File receive Ok");
			exit(0);
		}
		

		//download_file(fd,servfd);

		//shutdown(servfd,0);

		//Tcp_close(servfd);
		// 主动模式 服务器20 端口去。链接客户端
		ServiceEcho(150,"Ok to send data");
	}
	// 发送文件
	return 0;
}


/************************
	获得文件
*************************/
int do_retr(char * param)
{

	// 检查文件的存在性

	if (access(param,0)!=0)
	{
	//文件不存在
		ServiceEcho(550,"fail dot exist.");
		return 0;
	}else
	{
		//int 
	}

	// 应该对param 做个判断
	char temp[512]={0};

	// 文件状态结构
	struct stat filestat;
	
	if (stat(param,&filestat)!=-1)
	{
		// 正确调用

	}else
	{
		// 错误调用

	}

	if ('A'==ftp_global_var.transmode)
	{
		sprintf(temp,"Opening ASCII mode data connection for %s (%d bytes).",param,filestat.st_size);
		ServiceEcho(150,temp);
	}else if('I'==ftp_global_var.transmode)
	{
		sprintf(temp,"Opening BINARY  mode data connection for %s (%d bytes).",param,filestat.st_size );
		ServiceEcho(150,temp);
	}
		
	int fd=open(param,O_RDONLY);
	if (fd<0)
	{
		ServiceEcho(553,"download file fail.");
		return -1;
	}
	
	if (ftp_global_var.IsPasv)
	{
		// 被动链接
		int clisockfd = Tcp_accept(ftp_global_var.pasv_mode_sockfd,NULL,NULL);
		Tcp_close(ftp_global_var.pasv_mode_sockfd); // 关闭监听
		download_file(fd,clisockfd);
		Tcp_close(clisockfd);
	}
	else
	{
		// 主动连接
		struct sockaddr_in servaddr,cliaddr;
		int servfd;
		int clifd;
		memset(&servaddr,0,sizeof(servaddr));
		memset(&cliaddr,0,sizeof(cliaddr));
		
		servaddr.sin_family = AF_INET;
		servaddr.sin_port = htons(20);
		//servaddr.sin_addr.s_addr = inet_addr();
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

		cliaddr.sin_family =AF_INET;
		cliaddr.sin_port = htons(ftp_global_var.port_port);
		cliaddr.sin_addr.s_addr = inet_addr(ftp_global_var.port_ip);
		
		int len=sizeof(cliaddr);
		ftp_global_var.uid = geteuid();
		ftp_global_var.gid = getegid();

		seteuid(0);
		setegid(0);
		// 只有ROOT 用户才有权限绑定20端口
		// ????????????? 调用语义是有问题的 借用一个函数
		servfd = Tcp_service(ftp_global_var.port_ip,20);
		//servfd = socket(AF_INET,SOCK_DGRAM,0);
		seteuid(ftp_global_var.uid);
		setegid(ftp_global_var.gid);
	
		connect(servfd,(struct sockaddr *)&cliaddr,len);

	//	ServiceEcho(150,"Here comes the directory listing");

		download_file(fd,servfd);

		shutdown(servfd,0);

		Tcp_close(servfd);
		//Tcp_close(clifd);

		//ServiceEcho(226,"Directory send Ok");

		// 主动模式 服务器20 端口去。链接客户端
	}
	



	ServiceEcho(226,"File send Ok");


	//2. sendfile
	//3. 关闭连接
	//4. 信息提示

	// sendfile 
	return 0;
}

int do_appe(char * param)
{
	ftp_global_var.isappe=1;
	do_stor(param);
	return 0;
}

int do_abor(char * param)
{
	ServiceEcho(226,"Directory send Ok");
	return 0;
}

int do_mode(char * param)
{
	
    ServiceEcho(500,"Unknown command");
	return 0;
}
// stat 监控状态
int do_stat(char * param)
{
	
	//int up_count=0;
	//int down_count=0;
	//int up_bytes=0;
	//int down_bytes=0;
	
	//struct shared_count readshm;
	// 没有上传,下载就 的状态
	//Create_shm((key_t)1234,sizeof(struct shared_count),0666 | IPC_CREAT);
	//Read_download_shm(&readshm);
	
	char temp[1024]={0};

	//printf("%ld  %ld  %ld %ld ",pshm->upload_count,pshm->download_count,pshm->upload_bytes,pshm->download_bytes);
	sprintf(temp,"upload_file=%ld,download_file=%ld,upload_bytes=%ld,download_bytes=%ld",
		pshm->upload_count,pshm->download_count,pshm->upload_bytes,pshm->download_bytes);
	ServiceEcho(211,temp);
}

/*
	发送列表函数
*/
int send_list(int sockfd)
{
	struct stat sbuf;
	mode_t mode;
	char buf[1024];
	DIR *dp;
	struct dirent *link;
	dp=opendir(".");

	if (dp==NULL)
	{
		return -1;
	}

	while ((link=readdir(dp))!=0)
	{
		if (lstat(link->d_name, &sbuf)==-1)
		{
			perror("lstat");
			continue;
		}

		if (strcmp(link->d_name, ".") == 0 || strcmp(link->d_name, "..") == 0)
		{
			continue;
		}

		mode=sbuf.st_mode;
		char perms[] = "----------";
		perms[0]='?';
		switch (mode & S_IFMT)
		{
		case S_IFREG:
			perms[0] = '-';
			break;
		case S_IFDIR:
			perms[0] = 'd';
			break;
		case S_IFLNK:
			perms[0] = 'l';
			break;
		case S_IFIFO:
			perms[0] = 'p';
			break;
		case S_IFSOCK:
			perms[0] = 's';
			break;
		case S_IFCHR:
			perms[0] = 'c';
			break;
		case S_IFBLK:
			perms[0] = 'b';
			break;
		}
		if (mode & S_IRUSR)
			perms[1] = 'r';
		if (mode & S_IWUSR)
			perms[2] = 'w';
		if (mode & S_IXUSR)
			perms[3] = 'x';
		if (mode & S_IRGRP)
			perms[4] = 'r';
		if (mode & S_IWGRP)
			perms[5] = 'w';
		if (mode & S_IXGRP)
			perms[6] = 'x';
		if (mode & S_IROTH)
			perms[7] = 'r';
		if (mode & S_IWOTH)
			perms[8] = 'w';
		if (mode & S_IXOTH)
			perms[9] = 'x';
		perms[10] = '\0';

		int off=0;
		memset(buf,0,sizeof(buf));
		off += sprintf(buf+off, "%s ",perms);
		off += sprintf (buf + off, " %3d %-8d %-8d ",sbuf.st_nlink, sbuf.st_uid, sbuf.st_gid);
		off+=sprintf(buf + off, "%8lu ", (unsigned long)sbuf.st_size);

		char* p_date_format = "%b %e %H:%M";
		char datebuf[13]={0};
		struct tm* p_tm;
		struct timeval tv;
		long local_time;
		gettimeofday(&tv,NULL);
		local_time = tv.tv_sec;
		
		p_tm = localtime(&sbuf.st_mtime);

		if (sbuf.st_mtime > local_time ||
			(local_time - sbuf.st_mtime) > 60*60*24*182)
		{
			p_date_format = "%b %e  %Y";
		}
		strftime(datebuf, sizeof(datebuf), p_date_format, p_tm);

		off += sprintf (buf + off, "%s ", datebuf);

		if (S_ISLNK(sbuf.st_mode))
		{
			char tmp[1024]={0};
			readlink(link->d_name,tmp,sizeof(tmp));
			off += sprintf (buf + off, "%s -> %s", link->d_name,tmp);
		}
		else
		{
			off += sprintf (buf + off, "%s", link->d_name);
		}
		off += sprintf (buf + off, "%s", "\r\n");		
		write_loop(sockfd,buf,strlen(buf));
	}
	closedir(dp);
}
FTPCMD cmd_list[] = {
	{"USER",	do_user,	CHECK_NOLOGIN | NEED_PARAM	},
	{"PASS",	do_pass,	CHECK_NOLOGIN				},
	{"CWD",		do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"XCWD",	do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"CDUP",	do_cdup,	CHECK_LOGIN | NO_PARAM		},
	{"XCUP",	do_cdup,	CHECK_LOGIN | NO_PARAM		},
	{"SYST",    do_syst,	CHECK_LOGIN					},
	{"PWD",     do_pwd,		CHECK_LOGIN | NO_PARAM		},
	{"XPWD",    do_pwd,		CHECK_LOGIN | NO_PARAM		},
	{"TYPE",    do_type,	CHECK_LOGIN | NEED_PARAM	},
	{"PORT",    do_port,	CHECK_LOGIN | NEED_PARAM	},
	{"LIST",    do_list,	CHECK_LOGIN					},
	{"NLST",    do_nlst,	CHECK_LOGIN					},
	{"CWD",     do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"XCWD",	do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"CDUP",    do_cdup,	CHECK_LOGIN | NO_PARAM		},
	{"RMD",     do_rmd,		CHECK_LOGIN | NEED_PARAM	},
	{"XRMD",    do_rmd,		CHECK_LOGIN | NEED_PARAM	},
	{"MKD",     do_mkd,		CHECK_LOGIN | NEED_PARAM	},
	{"XMKD",    do_mkd,		CHECK_LOGIN | NEED_PARAM	},
	{"DELE",    do_dele,	CHECK_LOGIN | NEED_PARAM	},

	{"REIN",    do_rein,	CHECK_LOGIN					},
	{"HELP",    do_help,	CHECK_LOGIN					},
	{"QUIT",    do_quit,	NO_CHECK					},
	{"REST",    do_rest,	CHECK_LOGIN | NEED_PARAM	},
	{"PASV",    do_pasv,	CHECK_LOGIN | NO_PARAM		},
	{"RNFR",    do_rnfr,	CHECK_LOGIN | NEED_PARAM	},
	{"RNTO",    do_rnto,	CHECK_LOGIN | NEED_PARAM	},
	{"SIZE",    do_size,	CHECK_LOGIN | NEED_PARAM	},
	{"NOOP",    do_noop,	NO_CHECK					},
	{"STOR",    do_stor,	CHECK_LOGIN | NEED_PARAM	},
	{"RETR",    do_retr,	CHECK_LOGIN | NEED_PARAM	},
	{"APPE",    do_appe,	CHECK_LOGIN | NEED_PARAM	},
	{"ABOR",    do_abor,	CHECK_LOGIN | NO_PARAM		},


	{"ACCT",	NULL,0									},
    {"SMNT",	NULL,0									},
    {"STRU",	NULL,0									},
    {"MODE",	NULL,0									},
    {"STOU",	NULL,0									},
    {"ALLO",	NULL,0									},
    {"MDTM",    NULL,   CHECK_LOGIN | NEED_PARAM		},
    {"SITE",    NULL,   CHECK_LOGIN | NEED_PARAM		},
    {"STAT",    do_stat,   CHECK_LOGIN | NEED_PARAM		},
	{"MODE",    do_mode,CHECK_LOGIN},
	{NULL,      NULL, 0}

};



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -