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

📄 ftp_srv2.c

📁 用Dynamic C写的ftp程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*******************************************************************************
        ftp_srv2.c
        Z-World, 2000

        Demonstration of a simple FTP server, using the ftp library.
        This extends the ftp_server.c example to demonstrate more advanced
        use of the FTP server via use of customized handler functions.

        This is a complex and complete example.  It contains the seeds of some
        very useful functionality, such as the ability to read and write the
        Rabbit log (uses LOG.LIB), read and write FS2 files (uses FS2.LIB)
        and get a dump of the entire physical address space.  This sample
        also shows how to set up multi-interface servers.  For example, you
        can run the server on both ethernet and serial PPP.

        Since this example uses FS2, you will need to ensure that you configure
        the filesystem options correctly.  For example, you might need to
        edit RABBITBIOS.C to define some space for a RAM filesystem.  See the
        FS2 documentation.

        Note that the FTP server library itself knows nothing about the complex
        resource hierarchy that we set up.  This is an artifact of the way the
        custom handler functions present information to the FTP client.

   How it works...
   
   We try to look like a simple filesystem.  In the root directory, the normal
   sspec_* resources are available (as per FTP_SERVER.C).  There are some added
   directory entries:
     /var
           log
           log_rev
           log_append
           README
     /dev
           kmem
           fs2_ext_1
           fs2_ext_2   etc.
           random
           fs2_image
           README

     /fs2
           file1
           file2       etc.
           README

   /var contains resources to access the log file (as configured above).  The
   log can be retrieved in forward (oldest first) or reverse (newest first) order.
   README is a short description of the directory contents.  log_append is
   a writable file.  Anything uploaded here is appended to the log.  The format of
   each line in the uploaded log file is an optional digit (0-7) immediately
   followed by the log line (max 115 chars).  Longer lines are truncated.  If no
   initial digit, uses the default message priority (6 = INFO).  The downloaded
   log contains a standard system-V Unix look-alike prefix, so you could grep
   for various things of interest.

   /dev contains a kmem "file" which is actually the entire physical address space
   of the Rabbit (all 1Mbyte of it).  /dev also contains raw images of all of the
   FS2 "logical extents".  "random" is an infinite file which reads out as
   pseudo-random garbage.  "fs2_image" is an image of the entire FS2 filesystem,
   i.e. the concatenation of all LX's in numerical ascending order.
   [Note: reading the raw filesystem images is not yet implemented - will read
   back as a zero-length file].

   /fs2 is a "mount point" which contains all of the FS2 files, by number.
   These files can be read, written and deleted.

   Since the FTP server only deals with integer "file descriptors", we have to
   map the above resource presentation into a distinct integer for each
   resource.  We do this by dividing the integer into bitfields.  The high
   3 bits (not counting the sign bit) specifies the directory number:
     0 for the root, 1 for /var, 2 for /dev and 3 for /fs2.  Others (4-7) not used.
   The remaining 12 bits specify the file in the directory.

*******************************************************************************/
#class auto

//#define FTP_VERBOSE
//#define FTP_DEBUG

#define TCPCONFIG		1		// 1 = static ethernet, 4 = multiple interface

#define FTP_INTERFACE IF_ANY		// Allow FTP via any interface

/*
 * FTP configuration
 */

#define FTP_NODEFAULTHANDLER		// We are using our own handlers
#define FTP_EXTENSIONS				// Support the DELE, SIZE and MDTM commands (required for this demo)

/*
 * We are not defining any static resources.  Defining the following macro
 * tells ZSERVER.LIB (used by the FTP server) not to look for these static
 * resources.
 */
#define SSPEC_NO_STATIC

/*
 * Logging and FS2 config.  See LOG.LIB and LOG_DEFS.LIB (in "filesystem".)
 */
#define LOG_USE_XMEM						// Either LOG_USE_FS2 or LOG_USE_XMEM
#define LOG_XMEM_SIZE		16384L	// Memory quota for XMEM log
#define LOG_XMEM_CIRCULAR	1			// XMEM log wraps around

#define MY_LOG		LOG_DEST_XMEM	// Tell this demo what log dest to use
#define MY_FAC		0
#define MY_FACPRI	LOG_MAKEPRI(MY_FAC, LOG_INFO)	// Log facility/priority to use

#define FS_MAX_FILES		12	// Maximum expected existing files on all LXs

// Amount of program flash to use (becomes 2nd or 3rd basic LX, depending on whether
// you have a 2nd flash).  May need to change some BIOS settings e.g. XMEM_RESERVE_SIZE.
#define FS2_USE_PROGRAM_FLASH	256

/********************************
 * End of configuration section *
 ********************************/

#memmap xmem
#use "dcrtcp.lib"
#use "ftp_server.lib"
#use "fs2.lib"
#use "log.lib"

#ximport "samples/tcpip/http/pages/rabbit1.gif" rabbit1_gif

/********************************
 * Custom FTP handlers          *
 ********************************/


#define DIR_MASK	0x7000
#define FILE_MASK 0x0FFF
#define DIR2NUMBER(fd) (((fd) & DIR_MASK) >> 12)
#define FILENUMBER(cwd, n) ((cwd)<<12 | (n))
#define NUMBER2DIR(cwd) ((cwd) << 12 & DIR_MASK)
#define NUM_DIRS 4
#define README_FILENO  (FILE_MASK-8)		// consistent file number for the "README"
#define DIR_FILENO  (FILE_MASK - 7)
#define IS_A_DIR(fd) (((fd) & FILE_MASK) >= DIR_FILENO)
#define README_NAME "README"

const char * dirnames[NUM_DIRS] =
{
	""
  ,"var"
  ,"dev"
  ,"fs2"
};

const char * readmes[NUM_DIRS] =
{
	"This is the top level directory.  Please feel free to explore me.\r\n"
  ,"You can download or append to the log files herein.\r\n"
  ,"You can access raw memory and filesystems here.\r\nrandom sends back random data forever so you will have to terminate the download manually.\r\n"
  ,"This directory contains all of the FS2 files, by number.\r\nTo create new file, upload to file<n> where <n> is the file number in decimal (1-255).\r\n"
};

#define NUM_VARS	3
const char * varnames[NUM_VARS] =
{
	"log"
  ,"log_rev"
  ,"log_append"
};
#define FN_VAR	0
#define FN_LOG			(FN_VAR+0)
#define FN_LOG_REV	(FN_VAR+1)
#define FN_LOG_APPEND (FN_VAR+2)

#define NUM_DEVS	3
const char * devnames[NUM_DEVS] =
{
	"kmem"
  ,"random"
  ,"fs2_image"
};
// File numbers 0-255 are reserved for FS2 logical extent numbers
#define FN_DEV			256
#define FN_KMEM		(FN_DEV+0)
#define FN_RANDOM		(FN_DEV+1)
#define FN_FS2_IMAGE	(FN_DEV+2)


long starttime;
long logmodtime;
int writing;
int reading;

int filename2number(char * name, int cwd, int want_dir, unsigned options)
{
	// Return +ve for normal file, -1 for not found, -2 if root directory specified
	// If want_dir is true, then only returns +ve "cwd" number if directory specified.
	int fd;
	int d;
	int lxn;
	char * dir;		// Point to directory part of name (or NULL)
	char * fname;	// Point to actual name
	int spec;

	if (*name == '/') {
		cwd = 0;			// absolute path
		name++;
		if (!*name)
			return want_dir ? 0 : -2;	// Can't be called with just "/" (indicate this special case).
	}
repeat:
	fd = NUMBER2DIR(cwd);	// Init directory bits
	if (fname = strchr(name, '/')) {
		dir = name;
		*fname++ = 0;
	}
	else {
		dir = NULL;
		fname = name;
	}
	printf("looking for dir=%s, name=%s, cwd=%d\n",
	  dir ? dir : "<null>", fname, cwd);
	if (dir) {
		if (cwd) {
			if (!strcmp(dir, "..")) {
				cwd = 0;
				name = fname;
				goto repeat;
			}
			return -1;	// No directories under anything but root
		}
		for (d = 1; d < NUM_DIRS; d++)
			if (!strcmp(dir, dirnames[d])) {
				fd = NUMBER2DIR(d);
				cwd = d;
				break;
			}
		if (d == NUM_DIRS)
			return -1;	// No such directory (under root).
	}
	if (!strcmp(fname, ".."))
		return want_dir ? 0 : -2;	// Must be specifying root directory
	if (!strcmp(fname, README_NAME))
		fd |= README_FILENO;
	else switch (cwd) {
		case 0:
			// In the root dir we have the server spec files, plus the directory names.
			// dir names are given pseudo-file numbers starting at DIR_FILENO
			for (d = 1; d < NUM_DIRS; d++)
				if (!strcmp(fname, dirnames[d]))
					return want_dir ? d : (DIR_FILENO + d);
			// Otherwise, locate a server spec resource
			fd = sspec_findname(name, SERVER_FTP);
			break;
		case 1: /* var */
			for (d = 0; d < NUM_VARS; d++)
				if (!strcmp(fname, varnames[d])) {
					fd |= (FN_VAR + d);
					break;
				}
			if (d == NUM_VARS)
				fd = -1;
			break;
		case 2: /* dev */
			for (d = 0; d < NUM_DEVS; d++)
				if (!strcmp(fname, devnames[d])) {
					fd |= (FN_DEV + d);
					break;
				}
			if (d < NUM_DEVS)
				break;
			if (!memcmp(fname, "fs2_ext_", 8) && isdigit(fname[8]) && !fname[9]) {
				fd |= lxn = (fname[8] - '0');
				if (lxn < 0 || lxn > _fs.num_lx)
					fd = -1;
			}
			else
				fd = -1;
			break;
		case 3: /* fs2 */
			if (!memcmp(fname, "file", 4)) {
				d = 0;
				fname += 4;
				while (isdigit(*fname) && d < 256) {
					d = d * 10 + (*fname - '0');
					fname++;
				}
				if (*fname || !d || d > 255)
					return -1;
				if (!FS_EXISTS(d) &&
				    (options != O_WRONLY))
					return -1;
				fd |= d;
			}
			else
				fd = -1;
			break;
		default:
			fd = -1;
	}
	if (fd < 0)
		return fd;
	if (want_dir) {
		if (IS_A_DIR(fd))
			return (fd & FILE_MASK) - DIR_FILENO;
		else
			return -3;	// not a directory
	}
	return fd;
}


int my_open(char *name, int options, int uid, int cwd)
{
	auto int fd, n;
	auto File f;

	if (writing)
		return FTP_ERR_UNAVAIL;
	printf("my_open: name=%s...\n", name);
	fd = filename2number(name, cwd, 0, options);
	printf("...cwd=%d, fd=%d\n", cwd, fd);
	if (fd < 0)
		return FTP_ERR_NOTFOUND;
	if (IS_A_DIR(fd))
		return FTP_ERR_NOTFOUND;
	if (options == O_WRONLY) {
		if (reading)
			return FTP_ERR_UNAVAIL;
		// Write access requested.  OK for /var/log_append.
		if (fd == FILENUMBER(1, FN_LOG_APPEND)) {
			writing = 1;
			return fd;
		}
		if (fd > FILENUMBER(3, 0) && fd <= FILENUMBER(3, 255)) {
			// Writing to FS2 file
			n = fd & FILE_MASK;
			if (!FS_EXISTS(n)) {
				// Try to create.
				if (fcreate(&f, n))
					return -1;
				fclose(&f);
			}
			else {
				// Exists: truncate it to zero length
				if (fdelete(n) || fcreate(&f, n))
					return -1;
				fclose(&f);
			}
			writing = 1;
			return fd;
		}
	}
	if (options != O_RDONLY)
		return FTP_ERR_BADMODE;
	reading++;
	return fd;
}

long my_getfilesize(int fd)
{
	auto int cwd;
	auto int n;
	auto FS_lxd * lxd;
	auto FS_ef * ef;
	auto long sum;

	if (fd < 0)
		return 0;
	cwd = DIR2NUMBER(fd);
	n = fd & FILE_MASK;
	if (n == README_FILENO)
		return strlen(readmes[cwd]);
	if (IS_A_DIR(fd))
		return 10;	// Dummy amount for directories
	switch (cwd) {
		case 0:
			return sspec_getlength(n);
		case 1: /* var */
			if (n == FN_LOG_APPEND)
				return 0;				// This is a write-only file
			return LOG_XMEM_SIZE<<1;	// Others maximum log size (but expanded to account for
											// formatting characters).
		case 2: /* dev */
			switch (n) {
				case FN_KMEM:
					return 0x100000;	// 1M address space
				case FN_RANDOM:
					return -1;			// Indefinite
				case FN_FS2_IMAGE:
					sum = 0;
					for (n = 1; n <= _fs.num_lx; n++) {
						lxd = _fs.lx + n;
						sum += lxd->ps_size * lxd->num_ps;
					}
					return sum;
				default:
					if (n < 1 || n > _fs.num_lx)
						return 0;	// Should not happen
					lxd = _fs.lx + n;
					return lxd->ps_size * lxd->num_ps; 
			}
			break;
		case 3: /* fs2 */
			if (FS_EXISTS(n)) {
				ef = FS_EF_OF_FILE(n);
				return ef->eof;
			}
	}
	return 0;
}

long my_mdtm(int fd)
{
	// Return modification date/time.  Most files we just fake it as the start time
	// of the demo, except for the log we update the mod time.
	int cwd;
	int n;

	if (fd < 0)
		return 0;	// If not valid, return 1980 (should never happen)
	cwd = DIR2NUMBER(fd);

⌨️ 快捷键说明

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