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

📄 cmd.c

📁 福建博洋教育C/C++软件项目实战Linux网络编程阶段:FTP服务器开发
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "CMD.h"
#include "Public.h"
#include "NetWork.h"

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/ipc.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>

FTPCMD cmdList[] =
{
	{"USER",	do_user,	NO_LOGIN | NEED_PARAM	},
	{"PASS",	do_pass,							},
	{"XCUP",	do_cdup,	NEED_LOGIN				},
	{"SYST",    do_syst,	NEED_LOGIN				},
	{"PWD",     do_pwd,		NEED_LOGIN				},
	{"XPWD",    do_pwd,		NEED_LOGIN				},
	{"PASV",    do_pasv,	NEED_LOGIN				},
	{"TYPE",    do_type,	NEED_LOGIN | NEED_PARAM	},
	{"PORT",    do_port,	NEED_LOGIN | NEED_PARAM	},
	{"LIST",    do_list,	NEED_LOGIN				},
	{"FEAT",	NULL,								},
	{"NLST",    do_nlst,	NEED_LOGIN				},
	{"CWD",		do_cwd,		NEED_LOGIN | NEED_PARAM	},
	{"XCWD",	do_cwd,		NEED_LOGIN | NEED_PARAM	},
	{"CDUP",    do_cdup,	NEED_LOGIN				},
	{"RMD",     do_rmd,		NEED_LOGIN | NEED_PARAM	},
	{"XRMD",    do_rmd,		NEED_LOGIN | NEED_PARAM	},
	{"MKD",     do_mkd,		NEED_LOGIN | NEED_PARAM	},
	{"XMKD",    do_mkd,		NEED_LOGIN | NEED_PARAM	},
	{"DELE",    do_dele,	NEED_LOGIN | NEED_PARAM	},

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

	{"ACCT",	NULL,								},
    {"SMNT",	NULL,								},
    {"STRU",	NULL,								},
    {"MODE",	NULL,								},
    {"STOU",	NULL,								},
    {"ALLO",	NULL,								},
    {"MDTM",    NULL,	    NEED_LOGIN | NEED_PARAM	},
    {"SITE",    NULL,       NEED_LOGIN | NEED_PARAM	},
    {"STAT",    do_stat,    NEED_LOGIN | NEED_PARAM	},
	{NULL}
};

/* 用户 */
int do_user(char *userName)
{
	RTrim(userName);
	if (strcmp(userName, "anonymous") == 0 || strlen(userName) == 0)
		strcpy(State.uname, "ftp");
	else
		strcpy(State.uname, userName);

	if (strlen(State.uname) == 0)
	{
		Write(State.s, FTP_BADCMD, strlen(FTP_BADCMD));
		return -1;
	}

	Write(State.s, FTP_GIVEPWORD, strlen(FTP_GIVEPWORD));

	return 0;
}

/* 密码 */
int do_pass(char *userPass)
{
	if (strlen(State.uname) == 0)
	{
		Write(State.s, FTP_NEEDUSER, strlen(FTP_NEEDUSER));
		return -1;
	}
	memset(State.homeDir, 0, sizeof(State.homeDir));
	strcpy(State.upass, userPass);

	struct passwd *userInfo;
	memset(&userInfo, 0, sizeof(userInfo));

	GetUser(State.uname, &userInfo);
	if (strcmp(State.uname, "ftp") != 0)
	{
		int rt = CheckPass(State.uname, State.upass);
		if (rt != PASS_OK)
		{
			Write(State.s, FTP_LOGINERR, strlen(FTP_LOGINERR));
			return -1;
		}
	}
	else
	{
		if (State.anologin == 0)
		{
			Write(State.s, "530 Anonymous can not login\r\n", strlen("530 Anonymous can not login\r\n"));
			return 0;
		}
	}

	State.isLogin = 1;
	setegid(userInfo->pw_gid);
	seteuid(userInfo->pw_uid);

	GetHomeDir(State.uname, State.homeDir);

	if (chdir(State.homeDir) == -1)
	{
		Write(State.s, FTP_FILEFAIL, strlen(FTP_FILEFAIL));
		return -1;
	}
	Write(State.s, FTP_LOGINOK, strlen(FTP_LOGINOK));
	return 0;
}

/* 打印服务器信息 */
int do_syst(char *param)
{
	Write(State.s, FTP_SYSTOK, strlen(FTP_SYSTOK));
	return 0;
}

/* 打印当前目录 */
int do_pwd(char *param)
{
	char path[MAX_BUF_SIZE];
	char *cpath = path;
	memset(path, 0, sizeof(path));

	getcwd(cpath, MAX_BUF_SIZE-1);
	if (strcmp(State.uname, "ftp") == 0)
	{
		char hhPath[MAX_BUF_SIZE];
		char *hPath = hhPath;
		GetHomeDir("ftp", hPath);
		while (*cpath == *hPath)
		{
			cpath++;
			hPath++;
		}
		*cpath = '/';
	}

	char fs257[MAX_BUF_SIZE];
	memset(fs257, 0, sizeof(fs257));
	sprintf(fs257, "257 \"%s\"\r\n", cpath);
	Write(State.s, fs257, strlen(fs257));

	return 0;
}

/* 列出文件详情 */
int do_list(char *mode)
{
	if (Connect() == -1)
	{
		//....................
		return -1;
	}

	Write(State.s, FTP_DATACONN, strlen(FTP_DATACONN));
	signal(SIGUSR1, TransOK);
	signal(SIGCHLD, SIG_IGN);
	if (fork() == 0)
	{
		if (lsdir(2) == -1)
		{
			//.................
			close(State.Socket);	
			return -1;
		}
		close(State.Socket);
		exit(0);
	}
	close(State.Socket);

	return 0;
}

/* 列出文件夹与文件 */
int do_nlst(char *param)
{
	if (Connect() == -1)
	{
		//....................
		return -1;
	}

	Write(State.s, FTP_DATACONN, strlen(FTP_DATACONN));
	signal(SIGUSR1, TransOK);
	signal(SIGCHLD, SIG_IGN);

	if (fork() == 0)
	{
		if (lsdir(1) == -1)
		{
			//.................
			close(State.Socket);	
			return -1;
		}
		close(State.Socket);
		exit(0);
	}
	close(State.Socket);

	return 0;
}

/* 列出目录 */
int lsdir(int flag)
{
	struct stat sbuf;
	mode_t mode;
	char buf[MAX_BUF_SIZE];
	DIR *dp;
	struct dirent *link;

	dp = opendir(".");
	if (dp == NULL)
		return -1;

	while ((link = readdir(dp)) != 0)
	{
		memset(buf, 0, MAX_BUF_SIZE);
		if (lstat(link->d_name, &sbuf) == -1)
			continue;

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

		if (flag == 1)
		{
			sprintf(buf, "%s\r\n", link->d_name);
			Write(State.Socket, buf, strlen(buf));
		}
		else
		{
			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(State.Socket, buf, strlen(buf));
		}
	}

	close(State.Socket);
	closedir(dp);
	Write(State.s, FTP_TRANSFEROK, strlen(FTP_TRANSFEROK));
	kill(getppid(), SIGUSR1);

	return 0;
}

/* 返回文件大小 */
int do_size(char *file)
{
	struct stat filestat;
	char m213[MIN_BUF_SIZE];

	memset(&filestat, 0, sizeof(filestat));
	lstat(file, &filestat);

	memset(m213, 0, sizeof(m213));
	sprintf(m213, "213 %d\r\n", filestat.st_size);
	Write(State.s, m213, strlen(m213));
	return 0;
}

/* 回到上一层目录 */
int do_cdup(char *param)
{
	if (strcmp(State.uname, "ftp") == 0)
	{
		char buf[MIN_BUF_SIZE];
		char buf2[MIN_BUF_SIZE];

		memset(buf, 0, sizeof(buf));
		memset(buf2, 0, sizeof(buf2));

		getcwd(buf, MIN_BUF_SIZE);
		GetHomeDir(State.uname, buf2);

		if (strcmp(buf, buf2) == 0)
		{
			Write(State.s, FTP_CWDOK, strlen(FTP_CWDOK));
			return 1;
		}
	}

	chdir("..");
	Write(State.s, FTP_CWDOK, strlen(FTP_CWDOK));

	return 0;
}

/* 修改传输模式 */
int do_type(char *tType)
{
	if (strcmp(tType, "A") == 0)
	{
		strcpy(State.type, "ASCII");
		Write(State.s, "200 Switching to ASCII Mode\r\n", strlen("200 Switching to ASCII Mode\r\n"));
		return 0;
	}
	else
	{
		strcpy(State.type, "IMAGE");
		Write(State.s, "200 Switching to IMAGE Mode\r\n", strlen("200 Switching to IMAGE Mode\r\n"));
		return 0;
	}
}

/* 主动模式 */
int do_port(char *ipPort)
{
	char ip[MIN_BUF_SIZE];
	int  port;

	GetIpPort(ipPort, ip, &port);

	strcpy(State.ip, ip);
	State.port = port;
	State.mode = 1;

	Write(State.s, FTP_PORTOK, strlen(FTP_PORTOK));
	return 0;
}

/* 被动模式 */
int do_pasv(char *param)
{
	int cSize, port;
	char ip[MIN_BUF_SIZE];
	char sIp[MIN_BUF_SIZE];
	socklen_t namelen;
	struct sockaddr_in name;
	struct sockaddr_in addr;

	memset(ip, 0, sizeof(ip));

	if ((State.sSocket = NetContral(NULL, 0, -1, 2)) == SERVER_LISTEN_EXCEPTION)
		return -1;
	namelen = sizeof(name);
	getsockname(State.sSocket, (struct sockaddr*)&name, &namelen);
	port = ntohs(name.sin_port);

	GetLocalIp(ip);

	PutIpPort(sIp, ip, port);
	strcpy(State.ip, ip);
	State.port = port;
	State.mode = 2;

	char m227[MAX_BUF_SIZE];
	memset(m227, 0, sizeof(m227));
	sprintf(m227, "227 Entering Passive Mode(%s)\r\n", sIp);
	Write(State.s, m227, strlen(m227));

	return 0;
}

/* 连接 */
int Connect()
{
	if (State.mode == 1)
	{
		int oldid = getuid();
		seteuid(0);
		if ((State.Socket = NetContral(State.ip, State.port, 20, 1)) == CLIENT_CONNECT_FAIL)
		{
			seteuid(oldid);
			return -1;
		}
		else
		{
			seteuid(oldid);
			return 0;
		}
	}
	else
	{
		State.Socket = accept(State.sSocket, NULL, NULL);
		close(State.sSocket);
		State.sSocket = -1;
		return 0;
	}
}

/* 下载OK */
void DownloadOK(int i)
{
	Write(State.s, FTP_TRANSFEROK, strlen(FTP_TRANSFEROK));
	close(State.Socket);
	State.Socket  = -1;
}

/* 下载 */
int do_retr(char *fileName)

⌨️ 快捷键说明

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