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

📄 ftp_srv2.c

📁 用Dynamic C写的ftp程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	n = fd & FILE_MASK;
	if (cwd == 1) {
		// var
		if (n != README_FILENO)
			return logmodtime;
	}
	return starttime;
}

// This must be a 64-byte string, exactly repeated once, to 128 bytes.
const char random_data[129] =
"The quick brown fox jumps over the lazy dog. !@#$%^&*()-=+[]{}\r\nThe quick brown fox jumps over the lazy dog. !@#$%^&*()-=+[]{}\r\n";

int my_read(int fd, char *buf, long offset, int len)
{
	auto LogEntry le;
	auto File f;
	auto int cwd, n;
	auto unsigned i, j;

	cwd = DIR2NUMBER(fd);
	n = fd & FILE_MASK;

	if (n == README_FILENO) {
		memcpy(buf, readmes[cwd] + (int)offset, len);
		return len;
	}
	switch (cwd) {
		case 0:
			return sspec_readfile(n, buf, offset, len);
		case 1: /* var */
			switch (n) {
				case FN_LOG:
					if (len < 192)
						return 192;		// Tell server we need this much buffer
					if (!offset)
						// 1st request
						log_seek(MY_LOG, 0);
					if (log_next(MY_LOG, &le) < 0)
						return 0;
					log_format(&le, buf, len, 1);
					n = strlen(buf);
					strcpy(buf+n, "\r\n");
					return n+2;
				case FN_LOG_REV:
					if (len < 192)
						return 192;		// Tell server we need this much buffer
					if (!offset)
						// 1st request
						log_seek(MY_LOG, 1);
					if (log_prev(MY_LOG, &le) < 0)
						return 0;
					log_format(&le, buf, len, 1);
					n = strlen(buf);
					strcpy(buf+n, "\r\n");
					return n+2;
					
				case FN_LOG_APPEND:
					break;
			}
			return 0;
		case 2: /* dev */
			switch (n) {
				case FN_KMEM:
					// Read the entire address space
					xmem2root(buf, offset, len);
					return len;
				case FN_RANDOM:
					// Random data returned.  We don't really generate random data.
					// Instead, we return a repeated string.  Since this goes forever,
					// the client will need to abort the download when they have seen
					// enough (e.g. press the STOP botton on a browser, or Ctl-C on a
					// command-line client).
					j = (unsigned)offset & 63;
					for (n = 0; n < len; n += 64) {
						i = (unsigned)len - n;
						if (i > 64)
							i = 64;
						memcpy(buf + n, random_data + j, i);
					}
					return len;
				case FN_FS2_IMAGE:
					// Entire FS2 file system.
					return 0;
				default:
					// FS2 logical extent, as a raw dump
					return 0;
			}
		case 3: /* fs2 */
			// Read a FS2 file in normal mode.
			if (fopen_rd(&f, n))
				return 0;	// should not happen
			fseek(&f, offset, SEEK_SET);
			fread(&f, buf, len);
			fclose(&f);
			return len;
	}
	return 0;
}

int my_write(int fd, char *buf, long offset, int len)
{
	static char log[LOG_MAX_MESSAGE+10];
	static int loglen;
	static int logpri;
	static int discard;
	auto File f;
	auto int bl, c;
	auto int n;

	if (!offset) {
		loglen = -1;
		discard = 0;
	}
	bl = len;
	
	// If this is called, we know file is OK for write.
	if (fd > FILENUMBER(3, 0) && fd <= FILENUMBER(3, 255)) {
		// Normal FS2 file write
		n = fd & FILE_MASK;
		if (fopen_wr(&f, n))
			return -1;
		fseek(&f, offset, SEEK_SET);
		bl = fwrite(&f, buf, len);
		fclose(&f);
		return bl;
	}
	else if (fd == FILENUMBER(1, FN_LOG_APPEND)) {
		// Append messages to the log.  Each message is of the form
		//  [optional digit] [string] [optional CR] LF
		// If the first char is a digit 0-7, this is assumed to be the priority of
		// the message.  The rest of the characters up to the end of line are put into
		// the log.  If a CR preceeds the LF, it is discarded.  The total length of the
		// line is limited to 115 (LOG_MAX_MESSAGE) characters; any others are discarded.
		// This process is complicated by the fact that the FTP server insists that we
		// process all data.  We must therefore maintain some state information about where
		// we were up to, since we can't log partial messages.  The information is kept in
		// static variables.  This makes the code non-reentrant, but that doesn't matter
		// because we only support one write operation at a time.
		while (bl) {
			if (discard) {
				while (bl) {
					buf++;
					bl--;
					if (buf[-1] == '\n') {
						discard = 0;
						loglen = -1;
						break;
					}
				}
			}
			c = 0;
			while (loglen < LOG_MAX_MESSAGE+2 && bl) {
				if (loglen < 0) {
					if (isdigit(*buf)) {
						logpri = *buf - '0';
						if (logpri > 7) logpri = 7;
						buf++;
						bl--;
					}
					else
						logpri = LOG_INFO;
					loglen = 0;
					continue;
				}
				c = log[loglen++] = *buf;
				buf++;
				bl--;
				if (c == '\n')
					break;
			}
			if (c == '\n') {
				// Got legitimate EOL
				loglen--;
				if (loglen && log[loglen-1] == '\r')
					loglen--;
				log_put(LOG_MAKEPRI(MY_FAC, logpri), 0, log, loglen);
				logmodtime = SEC_TIMER;
				loglen = -1;
			}
			else if (bl) {
				discard = 1;
				log_put(LOG_MAKEPRI(MY_FAC, logpri), 0, log, LOG_MAX_MESSAGE);
				logmodtime = SEC_TIMER;
			}
		}
		return len;
	}
	return -1;
}

int my_close(int fd)
{
	printf("Closed %s transfer\n", writing ? "write" : "read");
	if (writing)
		writing = 0;
	else
		reading--;
	return 0;
}

int my_cd(int cwd, char * dir, int uid)
{
	int rc;
	rc = filename2number(dir, cwd, 1, O_RDONLY);
	printf("dir: %s, cwd: %d, new cwd: %d\n", dir, cwd, rc);
	return rc;
}

int my_pwd(int cwd, char * buf)
{
	strcpy(buf, "/");
	strcat(buf, dirnames[cwd]);
	return 0;
}

int my_dirlist(int item, char *line, int listing, int uid, int cwd)
{
	// This is not quite as easy as it might be: we want to return the ".." and
	// README entries first in the list, so a bit of reordering must be done.
	// The ".." entry is probably superfluous, but we want to make the illusion
	// complete that we are a Unix machine :-)  Maybe we should do "." as well?
	int attribs, fd, spec;
	long length;
	char name[80];
	char attrstr[11];
	char buf[16];
	long modtm;
	int lxn;

	attribs = 0444;
	length = 0;
	
	switch (cwd) {
		case 0:	/* root */
			switch (item) {
				case 0:
					fd = README_FILENO;
					strcpy(name, README_NAME);
					break;
				case 1:
				case 2:
				case 3:
					/* Directories */
					fd = item + DIR_FILENO;
					attribs = 01555;
					strcpy(name, dirnames[item]);
					length = 10;
					break;
				default:
					// sspec names
					spec = sspec_findnextfile(item-NUM_DIRS, SERVER_FTP);
					if (spec < 0)
						return -1;
					fd = spec;
					item = spec+NUM_DIRS;
					strcpy(name, sspec_getname(spec));
					break;
			}
			break;
		default:
			fd = NUMBER2DIR(cwd);
			if (item == 0) {
				strcpy(name, "..");
				attribs = 01555;
				length = 10;
				break;
			}
			if (item == 1) {
				strcpy(name, README_NAME);
				fd |= README_FILENO;
				break;
			}
			switch (cwd) {
				case 1: /* var */
					if (item-2 < NUM_VARS) {
						strcpy(name, varnames[item-2]);
						fd |= item-2 + FN_VAR;
						if (item-2 == FN_LOG_APPEND)
							attribs = 0222;
					}
					else
						return -1;
					break;
				case 2: /* dev */
					if (item-2 < NUM_DEVS) {
						strcpy(name, devnames[item-2]);
						fd |= item-2 + FN_DEV;
					}
					else {
						lxn = item-1-NUM_DEVS;
						if (lxn > _fs.num_lx)
							return -1;
						sprintf(name, "fs2_ext_%d", lxn);
						fd |= lxn;
					}
					break;
				case 3: /* fs2 */
					while (item <= 256 && !FS_EXISTS(item-1))
						item++;
					if (item > 256)
							return -1;
					sprintf(name, "file%d", item-1);
					fd |= item-1;
					attribs = 0666;
					break;
			}
	}

	if (!length && fd >= 0)
		length = my_getfilesize(fd);
	if (fd >= 0)
		modtm = my_mdtm(fd);
	else
		modtm = 0;
		
	if (listing)
		sprintf(line, "%s\r\n", name);
	else {
		strcpy(attrstr, "---");
		if (attribs & 0400)
			attrstr[0] = 'r';
		if (attribs & 0200)
			attrstr[1] = 'w';
		if (attribs & 0100)
			attrstr[2] = 'x';
		sprintf(line, "%c%s%s%s   1 anonymous\tanonymous\t%10lu %s %s\r\n",
			attribs & 01000 ? 'd' : '-',
			attrstr, attrstr, attrstr, length, ftp_ls_date(modtm, buf), name);
	}
	return item;
}

int my_delete(char * name, int uid, int cwd)
{
	auto int fd, n;
	
	if (writing || reading)
		return FTP_ERR_UNAVAIL;
	fd = filename2number(name, cwd, 0, O_RDONLY);
	if (fd < 0)
		return FTP_ERR_NOTFOUND;
	if (fd > FILENUMBER(3, 0) && fd <= FILENUMBER(3, 255)) {
		n = fd & FILE_MASK;
		if (fdelete(n))
			return FTP_ERR_UNAVAIL;
		return 0;
	}
	return FTP_ERR_BADMODE;
}

FTPhandlers hnd;

/********************************
 * Main program                 *
 ********************************/


main()
{
	int file;
	int user;
	int rc;

	printf("Initializing file system.  Please wait...\n");
	rc = fs_init(0,0);
	if (rc) {
		printf("Could not initialize filesystem, error number %d\n", errno);
		exit(2);
	}
	fs_print_lxs(0);
	
	log_open(MY_LOG, 1);
	log_put(MY_FACPRI, 0, "----log start-----", 18);
	log_put(MY_FACPRI, 0, "FTP Server started", 18);
	log_put(MY_FACPRI, 0, "------------------", 18);

	starttime = logmodtime = SEC_TIMER;
	writing = 0;
	reading = 0;

	hnd.open = my_open;
	hnd.read = my_read;
	hnd.write = my_write;
	hnd.close = my_close;
	hnd.getfilesize = my_getfilesize;
	hnd.dirlist = my_dirlist;
	hnd.cd = my_cd;
	hnd.pwd = my_pwd;
	hnd.mdtm = my_mdtm;
	hnd.delete = my_delete;

	// Set up the first file and user
	file = sspec_addxmemfile("rabbitA.gif", rabbit1_gif, SERVER_FTP);
	user = sauth_adduser("anonymous", "", SERVER_FTP);
	ftp_set_anonymous(user);
	sspec_setuser(file, user);
	sspec_setuser(sspec_addxmemfile("test1", rabbit1_gif, SERVER_FTP), user);
	sspec_setuser(sspec_addxmemfile("test2", rabbit1_gif, SERVER_FTP), user);

	// Set up the second file and user
	file = sspec_addxmemfile("rabbitF.gif", rabbit1_gif, SERVER_FTP);
	user = sauth_adduser("foo", "bar", SERVER_FTP);
	sspec_setuser(file, user);
	sspec_setuser(sspec_addxmemfile("test3", rabbit1_gif, SERVER_FTP), user);
	sspec_setuser(sspec_addxmemfile("test4", rabbit1_gif, SERVER_FTP), user);
	
	sock_init();
	ip_print_ifs();

	ftp_init(&hnd); /* use custom handlers */

	tcp_reserveport(FTP_CMDPORT);	// Port 21

	// Now we sit back and relax...
	while(1) {
		ftp_tick();
	}
}

⌨️ 快捷键说明

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