Subject: v25i026: A real-time, multithreaded Internet archive server, Part03/03
Newsgroups: comp.sources.unix
Approved: vixie@pa.dec.com

Submitted-By: wen-king@vlsi.cs.caltech.edu
Posting-Number: Volume 25, Issue 26
Archive-Name: fsp/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 3)."
# Contents:  bsd_src/ls.c bsd_src/random.c server_file.c
# Wrapped by vixie@cognition.pa.dec.com on Fri Dec 13 17:53:12 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'bsd_src/ls.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bsd_src/ls.c'\"
else
echo shar: Extracting \"'bsd_src/ls.c'\" \(10950 characters\)
sed "s/^X//" >'bsd_src/ls.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1989 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Michael Fischbein.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that: (1) source distributions retain this entire copyright
X * notice and comment, and (2) distributions including binaries display
X * the following acknowledgement:  ``This product includes software
X * developed by the University of California, Berkeley and its contributors''
X * in the documentation or other materials provided with the distribution
X * and in all advertising materials mentioning features or use of this
X * software. Neither the name of the University nor the names of its
X * contributors may be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
char copyright[] =
X"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
static char sccsid[] = "@(#)ls.c	5.42 (Berkeley) 5/17/90";
X#endif /* not lint */
X
X#include "../client_def.h"
X#include <sys/ioctl.h>
X#include <string.h>
X#include "ls.h"
X#include "tweak.h"
X
int (*sortfcn)(), (*printfcn)();
char *emalloc();
X
int termwidth = 80;		/* default terminal width */
X
X/* flags */
int f_accesstime;		/* use time of last access */
int f_column;			/* columnated format */
int f_group;			/* show group ownership of a file */
int f_ignorelink;		/* indirect through symbolic link operands */
int f_inode;			/* print inode */
int f_kblocks;			/* print size in kilobytes */
int f_listalldot;		/* list . and .. as well */
int f_listdir;			/* list actual directory, not contents */
int f_listdot;			/* list files beginning with . */
int f_longform;			/* long listing format */
int f_needstat;			/* if need to stat files */
int f_newline;			/* if precede with newline */
int f_nonprint;			/* show unprintables as ? */
int f_nosort;			/* don't sort output */
int f_recursive;		/* ls subdirectories also */
int f_reversesort;		/* reverse whatever sort is used */
int f_singlecol;		/* use single column output */
int f_size;			/* list size in short listing */
int f_statustime;		/* use time of last mode change */
int f_dirname;			/* if precede with directory name */
int f_timesort;			/* sort by time vice name */
int f_total;			/* if precede with "total" line */
int f_type;			/* add type character for non-regular files */
X
fls_main(argc, argv)
X	int argc;
X	char **argv;
X{
X	extern int optind;
X	int ch;
X	char *p, *getenv();
X	int acccmp(), modcmp(), namecmp(), prcopy(), printcol();
X	int printlong(), printscol(), revacccmp(), revmodcmp(), revnamecmp();
X	int revstatcmp(), statcmp();
X
X	/* terminal defaults to -Cq, non-terminal defaults to -1 */
X	if (isatty(1)) {
X		f_nonprint = 1;
X		termwidth  = 80;
X#ifdef TIOCGWINSZ
X		{   struct winsize win;
X		    if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
X			    if (p = getenv("COLUMNS"))
X				    termwidth = atoi(p);
X		    }
X		    else
X			    termwidth = win.ws_col;
X		}
X#endif
X		f_column = 1;
X	} else
X		f_singlecol = 1;
X
X	/* root is -A automatically */
X	if (!getuid())
X		f_listdot = 1;
X
X	while ((ch = getopt(argc, argv, "1ACFLRacdfgiklqrstu")) != EOF) {
X		switch (ch) {
X		/*
X		 * -1, -C and -l all override each other
X		 * so shell aliasing works right
X		 */
X		case '1':
X			f_singlecol = 1;
X			f_column = f_longform = 0;
X			break;
X		case 'C':
X			f_column = 1;
X			f_longform = f_singlecol = 0;
X			break;
X		case 'l':
X			f_longform = 1;
X			f_column = f_singlecol = 0;
X			break;
X		/* -c and -u override each other */
X		case 'c':
X			f_statustime = 1;
X			f_accesstime = 0;
X			break;
X		case 'u':
X			f_accesstime = 1;
X			f_statustime = 0;
X			break;
X		case 'F':
X			f_type = 1;
X			break;
X		case 'L':
X			f_ignorelink = 1;
X			break;
X		case 'R':
X			f_recursive = 1;
X			break;
X		case 'a':
X			f_listalldot = 1;
X			/* FALLTHROUGH */
X		case 'A':
X			f_listdot = 1;
X			break;
X		case 'd':
X			f_listdir = 1;
X			break;
X		case 'f':
X			f_nosort = 1;
X			break;
X		case 'g':
X			f_group = 1;
X			break;
X		case 'i':
X			f_inode = 1;
X			break;
X		case 'k':
X			f_kblocks = 1;
X			break;
X		case 'q':
X			f_nonprint = 1;
X			break;
X		case 'r':
X			f_reversesort = 1;
X			break;
X		case 's':
X			f_size = 1;
X			break;
X		case 't':
X			f_timesort = 1;
X			break;
X		default:
X		case '?':
X			usage();
X		}
X	}
X	argc -= optind;
X	argv += optind;
X
X	/* -d turns off -R */
X	if (f_listdir)
X		f_recursive = 0;
X
X	/* if need to stat files */
X	f_needstat = f_longform || f_recursive || f_timesort ||
X	    f_size || f_type;
X
X	/* select a sort function */
X	if (f_reversesort) {
X		if (!f_timesort)
X			sortfcn = revnamecmp;
X		else if (f_accesstime)
X			sortfcn = revacccmp;
X		else if (f_statustime)
X			sortfcn = revstatcmp;
X		else /* use modification time */
X			sortfcn = revmodcmp;
X	} else {
X		if (!f_timesort)
X			sortfcn = namecmp;
X		else if (f_accesstime)
X			sortfcn = acccmp;
X		else if (f_statustime)
X			sortfcn = statcmp;
X		else /* use modification time */
X			sortfcn = modcmp;
X	}
X
X	/* select a print function */
X	if (f_singlecol)
X		printfcn = printscol;
X	else if (f_longform)
X		printfcn = printlong;
X	else
X		printfcn = printcol;
X
X	if (!argc) {
X		argc = 1;
X		argv[0] = ".";
X		argv[1] = NULL;
X	}
X	doargs(argc, argv);
X}
X
static char path[2*1024 + 1];
static char *endofpath = path;
X
doargs(argc, argv)
X	int argc;
X	char **argv;
X{
X	register LS *dstatp, *rstatp;
X	register int cnt, dircnt, dirmax, maxlen, regcnt, regmax;
X	LS *dstats, *rstats;
X	struct stat sb;
X	char top[2*1024 + 1], **av, *av2[2];
X	unsigned long blocks;
X	extern char **glob();
X
X	/*
X	 * walk through the operands, building separate arrays of LS
X	 * structures for directory and non-directory files.
X	 */
X	dstats = rstats = NULL;
X	dirmax = regmax = 0;
X
X	for (dircnt = regcnt = 0; *argv; ++argv)
X	{
X	    if(!(av = glob(*argv))) { av = av2; av2[0] = *argv; av2[1] = 0; }
X
X	    for( ; *av; av++)
X	    {
X		if (util_stat(*av, &sb)) {
X			perror(*av);
X			if (errno == ENOENT)
X				continue;
X			ls_bad(1);
X		}
X		if ((S_IFDIR & sb.st_mode) && !f_listdir) {
X			if(dirmax == dircnt)
X			{
X			    dirmax += 10;
X			    if (!dstats)
X			    {
X				dstatp = dstats = (LS *)emalloc(dirmax *
X								(sizeof(LS)));
X			    } else 
X			    {
X				dstats = (LS *)realloc(dstats,
X							dirmax * (sizeof(LS)));
X				dstatp = dstats + dircnt;
X			    }
X			}
X			dstatp->name = *av;
X			dstatp->lstat = sb;
X			++dstatp;
X			++dircnt;
X		}
X		else {
X			if(regmax == regcnt)
X			{
X			    regmax += 10;
X
X			    if (!rstats)
X			    {
X				blocks = 0;
X				maxlen = -1;
X				rstatp = rstats = (LS *)emalloc(regmax *
X						    (sizeof(LS)));
X			    } else
X			    {
X				rstats = (LS *)realloc(rstats,
X							regmax * (sizeof(LS)));
X				rstatp = rstats + regcnt;
X			    }
X			}
X			rstatp->name = *av;
X			rstatp->lstat = sb;
X
X			/* save name length for -C format */
X			rstatp->len = strlen(*av);
X
X			if (f_nonprint)
X				prcopy(*av, *av, rstatp->len);
X
X			/* calculate number of blocks if -l/-s formats */
X			if (f_longform || f_size)
X				blocks += (sb.st_size + 1023)/1024;
X
X			/* save max length if -C format */
X			if (f_column && maxlen < rstatp->len)
X				maxlen = rstatp->len;
X
X			++rstatp;
X			++regcnt;
X		}
X	    }
X	}
X	/* display regular files */
X	if (regcnt) {
X		rstats[0].lstat.st_btotal = blocks;
X		rstats[0].lstat.st_maxlen = maxlen;
X		displaydir(rstats, regcnt);
X		f_newline = f_dirname = 1;
X	}
X	/* display directories */
X	if (dircnt) {
X		register char *p;
X
X		f_total = 1;
X		if (dircnt > 1) {
X			(void)util_getwd(top);
X			qsort((char *)dstats, dircnt, sizeof(LS), sortfcn);
X			f_dirname = 1;
X		}
X		for (cnt = 0; cnt < dircnt; ++dstats) {
X			for (endofpath = path, p = dstats->name;
X			    *endofpath = *p++; ++endofpath);
X			subdir(dstats);
X			f_newline = 1;
X			if (++cnt < dircnt && util_cd(top)) {
X				perror(top);
X				ls_bad(1);
X			}
X		}
X	}
X}
X
displaydir(stats, num)
X	LS *stats;
X	register int num;
X{
X	register char *p, *savedpath;
X	LS *lp;
X
X	if (num > 1 && !f_nosort) {
X		unsigned long save1, save2;
X
X		save1 = stats[0].lstat.st_btotal;
X		save2 = stats[0].lstat.st_maxlen;
X		qsort((char *)stats, num, sizeof(LS), sortfcn);
X		stats[0].lstat.st_btotal = save1;
X		stats[0].lstat.st_maxlen = save2;
X	}
X
X	printfcn(stats, num);
X
X	if (f_recursive) {
X		savedpath = endofpath;
X		for (lp = stats; num--; ++lp) {
X			if (!(S_IFDIR & lp->lstat.st_mode))
X				continue;
X			p = lp->name;
X			if (p[0] == '.' && (!p[1] || p[1] == '.' && !p[2]))
X				continue;
X			if (endofpath != path && endofpath[-1] != '/')
X				*endofpath++ = '/';
X			for (; *endofpath = *p++; ++endofpath);
X			f_newline = f_dirname = f_total = 1;
X			subdir(lp);
X			*(endofpath = savedpath) = '\0';
X		}
X	}
X}
X
subdir(lp)
X	LS *lp;
X{
X	LS *stats;
X	int num;
X
X	if (f_newline)
X		(void)putchar('\n');
X	if (f_dirname)
X		(void)printf("%s:\n", path);
X
X	if (util_cd(lp->name)) {
X		perror(lp->name);
X		return;
X	}
X	if (num = tabdir(lp, &stats)) {
X		displaydir(stats, num);
X		(void)free((char *)stats);
X	}
X	if (util_cd("..")) {
X		perror("..");
X		ls_bad(1);
X	}
X}
X
tabdir(lp, s_stats)
X	LS *lp, **s_stats;
X{
X	register RDIR *dirp;
X	register int cnt, maxentry, maxlen;
X	register char *p;
X	struct rdirent *dp;
X	unsigned long blocks;
X	LS *stats;
X
X	if (!(dirp = util_opendir("."))) {
X		perror(lp->name);
X		return(0);
X	}
X	blocks = maxentry = maxlen = 0;
X	stats = NULL;
X	for (cnt = 0; dp = util_readdir(dirp);) {
X		/* this does -A and -a */
X		p = dp->d_name;
X		if (p[0] == '.') {
X			if (!f_listdot)
X				continue;
X			if (!f_listalldot && (!p[1] || p[1] == '.' && !p[2]))
X				continue;
X		}
X		if (cnt == maxentry) {
X#define	DEFNUM	256
X			maxentry += DEFNUM;
X			if(stats)
X			{
X			  if (!(*s_stats = stats = (LS *)realloc((char *)stats,
X			    (unsigned int)maxentry * sizeof(LS))))
X				nomem();
X			} else
X			{
X			  if (!(*s_stats = stats = (LS *)malloc(
X			    (unsigned int)maxentry * sizeof(LS))))
X				nomem();
X			}
X		}
X		if (f_needstat && util_stat(dp->d_name, &stats[cnt].lstat)) {
X			/*
X			 * don't exit -- this could be an NFS mount that has
X			 * gone away.  Flush stdout so the messages line up.
X			 */
X			(void)fflush(stdout);
X			perror(dp->d_name);
X			continue;
X		}
X		stats[cnt].name = dp->d_name;
X
X		/*
X		 * get the inode from the directory, so the -f flag
X		 * works right.
X		 */
X		stats[cnt].lstat.st_ino = dp->d_ino;
X
X		/* save name length for -C format */
X		stats[cnt].len = dp->d_namlen;
X
X		/* calculate number of blocks if -l/-s formats */
X		if (f_longform || f_size)
X			blocks += (stats[cnt].lstat.st_size + 1023)/1024;
X
X		/* save max length if -C format */
X		if (f_column && maxlen < (int)dp->d_namlen)
X			maxlen = dp->d_namlen;
X		++cnt;
X	}
X	(void)util_closedir(dirp);
X
X	if (cnt) {
X		stats[0].lstat.st_btotal = blocks;
X		stats[0].lstat.st_maxlen = maxlen;
X	} else if (stats) {
X		(void)free((char *)stats);
X	}
X	return(cnt);
X}
END_OF_FILE
if test 10950 -ne `wc -c <'bsd_src/ls.c'`; then
    echo shar: \"'bsd_src/ls.c'\" unpacked with wrong size!
fi
# end of 'bsd_src/ls.c'
fi
if test -f 'bsd_src/random.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bsd_src/random.c'\"
else
echo shar: Extracting \"'bsd_src/random.c'\" \(12955 characters\)
sed "s/^X//" >'bsd_src/random.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1983 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that: (1) source distributions retain this entire copyright
X * notice and comment, and (2) distributions including binaries display
X * the following acknowledgement:  ``This product includes software
X * developed by the University of California, Berkeley and its contributors''
X * in the documentation or other materials provided with the distribution
X * and in all advertising materials mentioning features or use of this
X * software. Neither the name of the University nor the names of its
X * contributors may be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)random.c	5.7 (Berkeley) 6/1/90";
X#endif /* LIBC_SCCS and not lint */
X
X#include <stdio.h>
X
X/*
X * random.c:
X * An improved random number generation package.  In addition to the standard
X * rand()/srand() like interface, this package also has a special state info
X * interface.  The initstate() routine is called with a seed, an array of
X * bytes, and a count of how many bytes are being passed in; this array is then
X * initialized to contain information for random number generation with that
X * much state information.  Good sizes for the amount of state information are
X * 32, 64, 128, and 256 bytes.  The state can be switched by calling the
X * setstate() routine with the same array as was initiallized with initstate().
X * By default, the package runs with 128 bytes of state information and
X * generates far better random numbers than a linear congruential generator.
X * If the amount of state information is less than 32 bytes, a simple linear
X * congruential R.N.G. is used.
X * Internally, the state information is treated as an array of longs; the
X * zeroeth element of the array is the type of R.N.G. being used (small
X * integer); the remainder of the array is the state information for the
X * R.N.G.  Thus, 32 bytes of state information will give 7 longs worth of
X * state information, which will allow a degree seven polynomial.  (Note: the 
X * zeroeth word of state information also has some other information stored
X * in it -- see setstate() for details).
X * The random number generation technique is a linear feedback shift register
X * approach, employing trinomials (since there are fewer terms to sum up that
X * way).  In this approach, the least significant bit of all the numbers in
X * the state table will act as a linear feedback shift register, and will have
X * period 2^deg - 1 (where deg is the degree of the polynomial being used,
X * assuming that the polynomial is irreducible and primitive).  The higher
X * order bits will have longer periods, since their values are also influenced
X * by pseudo-random carries out of the lower bits.  The total period of the
X * generator is approximately deg*(2**deg - 1); thus doubling the amount of
X * state information has a vast influence on the period of the generator.
X * Note: the deg*(2**deg - 1) is an approximation only good for large deg,
X * when the period of the shift register is the dominant factor.  With deg
X * equal to seven, the period is actually much longer than the 7*(2**7 - 1)
X * predicted by this formula.
X */
X
X
X
X/*
X * For each of the currently supported random number generators, we have a
X * break value on the amount of state information (you need at least this
X * many bytes of state info to support this random number generator), a degree
X * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
X * the separation between the two lower order coefficients of the trinomial.
X */
X
X#define		TYPE_0		0		/* linear congruential */
X#define		BREAK_0		8
X#define		DEG_0		0
X#define		SEP_0		0
X
X#define		TYPE_1		1		/* x**7 + x**3 + 1 */
X#define		BREAK_1		32
X#define		DEG_1		7
X#define		SEP_1		3
X
X#define		TYPE_2		2		/* x**15 + x + 1 */
X#define		BREAK_2		64
X#define		DEG_2		15
X#define		SEP_2		1
X
X#define		TYPE_3		3		/* x**31 + x**3 + 1 */
X#define		BREAK_3		128
X#define		DEG_3		31
X#define		SEP_3		3
X
X#define		TYPE_4		4		/* x**63 + x + 1 */
X#define		BREAK_4		256
X#define		DEG_4		63
X#define		SEP_4		1
X
X
X/*
X * Array versions of the above information to make code run faster -- relies
X * on fact that TYPE_i == i.
X */
X
X#define		MAX_TYPES	5		/* max number of types above */
X
static  int		degrees[ MAX_TYPES ]	= { DEG_0, DEG_1, DEG_2,
X								DEG_3, DEG_4 };
X
static  int		seps[ MAX_TYPES ]	= { SEP_0, SEP_1, SEP_2,
X								SEP_3, SEP_4 };
X
X
X
X/*
X * Initially, everything is set up as if from :
X *		initstate( 1, &randtbl, 128 );
X * Note that this initialization takes advantage of the fact that srandom()
X * advances the front and rear pointers 10*rand_deg times, and hence the
X * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
X * element of the state information, which contains info about the current
X * position of the rear pointer is just
X *	MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3.
X */
X
static  long		randtbl[ DEG_3 + 1 ]	= { TYPE_3,
X			    0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 
X			    0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 
X			    0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 
X			    0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 
X			    0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 
X			    0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 
X			    0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 
X					0xf5ad9d0e, 0x8999220b, 0x27fb47b9 };
X
X/*
X * fptr and rptr are two pointers into the state info, a front and a rear
X * pointer.  These two pointers are always rand_sep places aparts, as they cycle
X * cyclically through the state information.  (Yes, this does mean we could get
X * away with just one pointer, but the code for random() is more efficient this
X * way).  The pointers are left positioned as they would be from the call
X *			initstate( 1, randtbl, 128 )
X * (The position of the rear pointer, rptr, is really 0 (as explained above
X * in the initialization of randtbl) because the state table pointer is set
X * to point to randtbl[1] (as explained below).
X */
X
static  long		*fptr			= &randtbl[ SEP_3 + 1 ];
static  long		*rptr			= &randtbl[ 1 ];
X
X
X
X/*
X * The following things are the pointer to the state information table,
X * the type of the current generator, the degree of the current polynomial
X * being used, and the separation between the two pointers.
X * Note that for efficiency of random(), we remember the first location of
X * the state information, not the zeroeth.  Hence it is valid to access
X * state[-1], which is used to store the type of the R.N.G.
X * Also, we remember the last location, since this is more efficient than
X * indexing every time to find the address of the last element to see if
X * the front and rear pointers have wrapped.
X */
X
static  long		*state			= &randtbl[ 1 ];
X
static  int		rand_type		= TYPE_3;
static  int		rand_deg		= DEG_3;
static  int		rand_sep		= SEP_3;
X
static  long		*end_ptr		= &randtbl[ DEG_3 + 1 ];
X
X
X
X/*
X * srandom:
X * Initialize the random number generator based on the given seed.  If the
X * type is the trivial no-state-information type, just remember the seed.
X * Otherwise, initializes state[] based on the given "seed" via a linear
X * congruential generator.  Then, the pointers are set to known locations
X * that are exactly rand_sep places apart.  Lastly, it cycles the state
X * information a given number of times to get rid of any initial dependencies
X * introduced by the L.C.R.N.G.
X * Note that the initialization of randtbl[] for default usage relies on
X * values produced by this routine.
X */
X
srandom( x )
X
X    unsigned		x;
X{
X    	register  int		i, j;
X	long random();
X
X	if(  rand_type  ==  TYPE_0  )  {
X	    state[ 0 ] = x;
X	}
X	else  {
X	    j = 1;
X	    state[ 0 ] = x;
X	    for( i = 1; i < rand_deg; i++ )  {
X		state[i] = 1103515245*state[i - 1] + 12345;
X	    }
X	    fptr = &state[ rand_sep ];
X	    rptr = &state[ 0 ];
X	    for( i = 0; i < 10*rand_deg; i++ )  random();
X	}
X}
X
X
X
X/*
X * initstate:
X * Initialize the state information in the given array of n bytes for
X * future random number generation.  Based on the number of bytes we
X * are given, and the break values for the different R.N.G.'s, we choose
X * the best (largest) one we can and set things up for it.  srandom() is
X * then called to initialize the state information.
X * Note that on return from srandom(), we set state[-1] to be the type
X * multiplexed with the current value of the rear pointer; this is so
X * successive calls to initstate() won't lose this information and will
X * be able to restart with setstate().
X * Note: the first thing we do is save the current state, if any, just like
X * setstate() so that it doesn't matter when initstate is called.
X * Returns a pointer to the old state.
X */
X
char  *
initstate( seed, arg_state, n )
X
X    unsigned		seed;			/* seed for R. N. G. */
X    char		*arg_state;		/* pointer to state array */
X    int			n;			/* # bytes of state info */
X{
X	register  char		*ostate		= (char *)( &state[ -1 ] );
X
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	if(  n  <  BREAK_1  )  {
X	    if(  n  <  BREAK_0  )  {
X		fprintf( stderr, "initstate: not enough state (%d bytes); ignored.\n", n );
X		return 0;
X	    }
X	    rand_type = TYPE_0;
X	    rand_deg = DEG_0;
X	    rand_sep = SEP_0;
X	}
X	else  {
X	    if(  n  <  BREAK_2  )  {
X		rand_type = TYPE_1;
X		rand_deg = DEG_1;
X		rand_sep = SEP_1;
X	    }
X	    else  {
X		if(  n  <  BREAK_3  )  {
X		    rand_type = TYPE_2;
X		    rand_deg = DEG_2;
X		    rand_sep = SEP_2;
X		}
X		else  {
X		    if(  n  <  BREAK_4  )  {
X			rand_type = TYPE_3;
X			rand_deg = DEG_3;
X			rand_sep = SEP_3;
X		    }
X		    else  {
X			rand_type = TYPE_4;
X			rand_deg = DEG_4;
X			rand_sep = SEP_4;
X		    }
X		}
X	    }
X	}
X	state = &(  ( (long *)arg_state )[1]  );	/* first location */
X	end_ptr = &state[ rand_deg ];	/* must set end_ptr before srandom */
X	srandom( seed );
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	return( ostate );
X}
X
X
X
X/*
X * setstate:
X * Restore the state from the given state array.
X * Note: it is important that we also remember the locations of the pointers
X * in the current state information, and restore the locations of the pointers
X * from the old state information.  This is done by multiplexing the pointer
X * location into the zeroeth word of the state information.
X * Note that due to the order in which things are done, it is OK to call
X * setstate() with the same state as the current state.
X * Returns a pointer to the old state information.
X */
X
char  *
setstate( arg_state )
X
X    char		*arg_state;
X{
X	register  long		*new_state	= (long *)arg_state;
X	register  int		type		= new_state[0]%MAX_TYPES;
X	register  int		rear		= new_state[0]/MAX_TYPES;
X	char			*ostate		= (char *)( &state[ -1 ] );
X
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	switch(  type  )  {
X	    case  TYPE_0:
X	    case  TYPE_1:
X	    case  TYPE_2:
X	    case  TYPE_3:
X	    case  TYPE_4:
X		rand_type = type;
X		rand_deg = degrees[ type ];
X		rand_sep = seps[ type ];
X		break;
X
X	    default:
X		fprintf( stderr, "setstate: state info has been munged; not changed.\n" );
X	}
X	state = &new_state[ 1 ];
X	if(  rand_type  !=  TYPE_0  )  {
X	    rptr = &state[ rear ];
X	    fptr = &state[ (rear + rand_sep)%rand_deg ];
X	}
X	end_ptr = &state[ rand_deg ];		/* set end_ptr too */
X	return( ostate );
X}
X
X
X
X/*
X * random:
X * If we are using the trivial TYPE_0 R.N.G., just do the old linear
X * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
X * same in all ther other cases due to all the global variables that have been
X * set up.  The basic operation is to add the number at the rear pointer into
X * the one at the front pointer.  Then both pointers are advanced to the next
X * location cyclically in the table.  The value returned is the sum generated,
X * reduced to 31 bits by throwing away the "least random" low bit.
X * Note: the code takes advantage of the fact that both the front and
X * rear pointers can't wrap on the same call by not testing the rear
X * pointer if the front one has wrapped.
X * Returns a 31-bit random number.
X */
X
long
random()
X{
X	long		i;
X	
X	if(  rand_type  ==  TYPE_0  )  {
X	    i = state[0] = ( state[0]*1103515245 + 12345 )&0x7fffffff;
X	}
X	else  {
X	    *fptr += *rptr;
X	    i = (*fptr >> 1)&0x7fffffff;	/* chucking least random bit */
X	    if(  ++fptr  >=  end_ptr  )  {
X		fptr = state;
X		++rptr;
X	    }
X	    else  {
X		if(  ++rptr  >=  end_ptr  )  rptr = state;
X	    }
X	}
X	return( i );
X}
X
END_OF_FILE
if test 12955 -ne `wc -c <'bsd_src/random.c'`; then
    echo shar: \"'bsd_src/random.c'\" unpacked with wrong size!
fi
# end of 'bsd_src/random.c'
fi
if test -f 'server_file.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'server_file.c'\"
else
echo shar: Extracting \"'server_file.c'\" \(11591 characters\)
sed "s/^X//" >'server_file.c' <<'END_OF_FILE'
X    /*********************************************************************\
X    *  Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu)   *
X    *                                                                     *
X    *  You may copy or modify this file in any manner you wish, provided  *
X    *  that this notice is always included, and that you hold the author  *
X    *  harmless for any loss or damage resulting from the installation or *
X    *  use of this software.                                              *
X    \*********************************************************************/
X
X#include "server_def.h"
X
X/*****************************************************************************
X* This file handles all file io in request to client requests.
X*****************************************************************************/
X
X#define NBSIZE (2*sizeof(UBUF))
X
extern *malloc();
X
X#define fexist(A) (!access(A,0))
X#define touch(A) close(open(A,O_CREAT,0777))
X
X/*****************************************************************************
X* Routine to check a path string given by the client.
X* Will replace null string by ".".
X* In case of error, returns the error string.
X*****************************************************************************/
X
char *check_path(path,len)
X    char *path;
X    int len;
X{
X    char *s;
X    int state;
X
X    if(len < 1) return("Path must have non-zero lenght");
X    if(len == 1 && path[0] == 0) { *path++ = '.'; *path = 0; return(NULLP); }
X    if(path[len-1]) return("Path not null terminated");
X
X    for(s = path, state = 0; *s; s++)
X    {
X	if(*s <= ' ' || *s >= '~') return("Path contains illegal chars");
X
X	switch(*s)
X	{
X	    case '.': if(!state) return("Path can't begin with '.'");
X		      break;
X
X	    case '/': if(!state) return("Path can't contain '//'");
X		      state = 0;
X		      break;
X
X	    default : state = 1;
X		      break;
X	}
X    }
X
X    return(NULLP);
X}
X
X/*****************************************************************************
X* Put the directory name of path into dbuf.
X*****************************************************************************/
X
char *get_dir_name(path,dbuf)
X    char *path, *dbuf;
X{
X    char *p1,*p2,*p3;
X
X    for(p1 = path, p2 = p3 = dbuf; *p1; p1++, p3++)
X    {
X	if((*p3 = *p1) == '/') p2 = p3;
X    }
X
X    if(dbuf == p2) { dbuf[0] = '.'; dbuf[1] = 0; }
X	      else { *p2 = 0;			 }
X
X    return(dbuf);
X}
X
X/*****************************************************************************
X* Reads directory and write directory listing file.
X*****************************************************************************/
X
static build_dir_file(fp)
X    FILE *fp;
X{
X    int nlen, skip, rem;
X    DIR *dir_f;
X    struct dirent *dp;
X    struct stat    sb;
X    register char  *s;
X    RDIRENT rdb;
X    static char marker[] = "******************";
X
X    if(!(dir_f = opendir(".")))	/* assume I have cd to path already */
X	{ fprintf(stderr,"Can't open dir during initialization\n"); exit(1); }
X
X    for(rem = UBUF_SPACE; dp = readdir(dir_f); )
X    {
X	if (dp->d_ino == 0) continue;
X	s = dp->d_name;
X						/* hide dot files */
X	if((s[0] == '.') && ((s[1] !=  0 ) &&
X			     (s[1] != '.' || s[2] != 0))) continue;
X
X	if(stat(dp->d_name,&sb)) continue;
X
X	nlen = strlen(s)+1;
X
X	if(rem < RDHSIZE + nlen)
X	{
X	    rdb.type = RDTYPE_SKIP;
X	    if(rem <= RDHSIZE) { fwrite(marker,1,rem    ,fp); }
X			  else { fwrite(marker,1,RDHSIZE,fp);
X				 fwrite(s, 1,rem-RDHSIZE,fp); }
X	    rem = UBUF_SPACE;
X	}
X
X	rdb.type = ((S_IFDIR & sb.st_mode)) ? RDTYPE_DIR : RDTYPE_FILE;
X	rdb.size = htonl(sb.st_size);
X	rdb.time = htonl(sb.st_mtime);
X
X	fwrite(&rdb,1,RDHSIZE,fp);
X	fwrite(s,1,nlen,fp);
X	rem -= (nlen + RDHSIZE);
X
X	if((skip = (nlen + RDHSIZE) & 0x3))
X		{ fwrite(&rdb,1,4-skip,fp); rem -= (4-skip); }
X
X	if(!rem) rem = UBUF_SPACE;
X    }
X
X    rdb.type = RDTYPE_END;
X    fwrite(&rdb,1,RDHSIZE,fp);
X
X    fflush(fp);
X    closedir(dir_f);
X}
X
X/***************************************************************************/
X
char *server_get_dir(path,fp)	/* assume path is validated */
X    char *path;			/* returned file may not point at BOF */
X    FILE **fp;
X{
X    struct stat sd, sf;
X    char   list_p[NBSIZE];
X
X    if(!*path) path = ".";
X    if(stat(path,&sd)) return("Can't find directory");
X    if(!(S_IFDIR & sd.st_mode)) return("Not a directory");
X
X    sprintf(list_p,"%s/.FSP_CONTENT",path);
X
X    if(!stat(list_p,&sf) && (sf.st_mtime >= sd.st_mtime))
X    {
X	*fp = fopen(list_p,"r");
X	if(!*fp) return("Can't read directory listing");
X	return((char *)0);
X    }
X
X    if(!(*fp = fopen(list_p,"w+"))) return("Can't create directory listing");
X    if(chdir(path)) return("Can't cd to directory");
X    build_dir_file(*fp);
X    if(chdir(home_dir) == -1) { perror("chdir2"); exit(1); }
X    return(NULLP);
X}
X
X/**********************************************************************/
X
char *server_del_file(path,inet_num)		/* assume path is validated */
X    char *path;
X    unsigned long inet_num;
X{
X    struct stat sb;
X    char   dir_p[NBSIZE], no_del_p[NBSIZE], owner_p[NBSIZE];
X
X    if(stat(path,&sb)) return("unlink: file not accessible");
X    if(!(S_IFREG & sb.st_mode)) return("unlink: not an ordinary file");
X
X    get_dir_name(path,dir_p);
X    sprintf(owner_p ,"%s/.OWN.%08X"  ,dir_p,inet_num);
X    sprintf(no_del_p,"%s/.FSP_NO_DEL",dir_p	     );
X
X    if(!fexist(owner_p) && fexist(no_del_p))
X			return("no permission for removing this file");
X
X    if(unlink(path) == -1) return("unlink: cannot unlink");
X
X    return(NULLP);
X}
X
X/**********************************************************************/
X
char *server_del_dir(path,inet_num)		/* assume path is validated */
X    char *path;
X    unsigned long inet_num;
X{
X    struct stat sb;
X    char   dir_p[NBSIZE], no_del_p[NBSIZE], no_add_p[NBSIZE], owner_p[NBSIZE];
X    int    has_no_del_p, has_no_add_p;
X
X    if(stat(path,&sb)) return("rmdir: directory not accessible");
X    if(!(S_IFDIR & sb.st_mode)) return("rmdir: not an ordinary directory");
X
X    get_dir_name(path,dir_p);
X    sprintf( owner_p,"%s/.OWN.%08X"  ,dir_p,inet_num);
X    sprintf(no_del_p,"%s/.FSP_NO_DEL",dir_p         );
X
X    if(!fexist(owner_p) && fexist(no_del_p))
X			return("no permission for removing this directory");
X
X    sprintf( owner_p,"%s/.OWN.%08X"   ,path,inet_num);
X    sprintf(   dir_p,"%s/.FSP_CONTENT",path         );
X    sprintf(no_del_p,"%s/.FSP_NO_DEL" ,path                );
X    sprintf(no_add_p,"%s/.FSP_NO_ADD" ,path                );
X
X    if(!fexist(owner_p)) return("no permission for removing this directory");
X
X    unlink(owner_p); unlink(  dir_p);
X    has_no_del_p = !unlink(no_del_p);
X    has_no_add_p = !unlink(no_add_p);
X
X    if(rmdir(path) != 0)
X    {
X	if(has_no_del_p) touch(no_del_p);
X	if(has_no_add_p) touch(no_add_p);
X	if(     owner_p) touch( owner_p);
X	return("rmdir: cannot unlink");
X    }
X
X    return(NULLP);
X}
X
X/**********************************************************************/
X
char *server_make_dir(path,inet_num)		/* assume path is validated */
X    char *path;
X    unsigned long inet_num;
X{
X    char   dir_p[NBSIZE], no_del_p[NBSIZE], no_add_p[NBSIZE], owner_p[NBSIZE];
X
X    get_dir_name(path,dir_p);
X    sprintf( owner_p,"%s/.OWN.%08X"  ,dir_p,inet_num);
X    sprintf(no_add_p,"%s/.FSP_NO_ADD",dir_p         );
X
X    if(!fexist(owner_p) && fexist(no_add_p))
X			return("no permission for directory creation");
X
X    sprintf( owner_p,"%s/.OWN.%08X"   ,path,inet_num);
X    sprintf(   dir_p,"%s/.FSP_CONTENT",path         );
X    sprintf(no_del_p,"%s/.FSP_NO_DEL" ,path         );
X    sprintf(no_add_p,"%s/.FSP_NO_ADD" ,path         );
X
X    if(mkdir(path,0777) != 0) return("Can't create directory");
X
X    touch(no_del_p);
X    touch(no_add_p);
X    touch( owner_p);
X    return(NULLP);
X}
X
X/**********************************************************************/
X
char *server_get_file(path,fp)		/* assume path is validated */
X    char *path;
X    FILE **fp;
X{
X    struct stat sb;
X
X    if(stat(path,&sb)) return("Can't find file");
X    if(!(S_IFREG & sb.st_mode)) return("Not a file");
X    if(!(*fp = fopen(path,"r"))) return("Can't open file");
X    return(NULLP);
X}
X
X/**********************************************************************/
X
char *server_get_pro(s,inet_num)	/* s is both I and O */
X    char *s;
X    unsigned long inet_num;
X{
X    struct stat sb;
X    char   buf[NBSIZE];
X    char  *owner_s, *del_s, *add_s;
X
X    if(stat(s,&sb)) return("getpro: directory not accessible");
X    if(!(S_IFDIR & sb.st_mode)) return("getpro: not an ordinary directory");
X
X    sprintf(buf,"%s/.OWN.%08X",s,inet_num);
X    owner_s = (fexist(buf)) ? "your" : "some other";
X    sprintf(buf,"%s/.FSP_NO_DEL" ,s); del_s = (fexist(buf)) ? "NO" : "YES";
X    sprintf(buf,"%s/.FSP_NO_ADD" ,s); add_s = (fexist(buf)) ? "NO" : "YES";
X
X    sprintf(s,"(owner: %s machine)(delete: %s)(create: %s)",
X						owner_s, del_s, add_s);
X    return(NULLP);
X}
X
X/**********************************************************************/
X
char *server_set_pro(path,key,inet_num)
X    char *path, *key;
X    unsigned long inet_num;
X{
X    struct stat sb;
X    char   buf[NBSIZE];
X
X    if(stat(path,&sb)) return("getpro: directory not accessible");
X    if(!(S_IFDIR & sb.st_mode)) return("getpro: not an ordinary directory");
X
X    sprintf(buf,"%s/.OWN.%08X",path,inet_num);
X    if(!fexist(buf)) return("no permission for changing the protection-mode");
X
X    switch(key[1])
X    {
X	case 'c': sprintf(buf,"%s/.FSP_NO_ADD",path); break;
X	case 'd': sprintf(buf,"%s/.FSP_NO_DEL",path); break;
X	default : return("bad flag");
X    }
X
X    switch(key[0])
X    {
X	case '-': touch(buf);  break;
X	case '+': unlink(buf); break;
X	default : return("bad flag");
X    }
X
X    return(NULLP);
X}
X
X/**********************************************************************
X*  These two are used for file uploading.
X**********************************************************************/
X
char *server_up_load(data,len,pos,inet_num)
X    char *data;
X    unsigned len;
X    unsigned long pos, inet_num;
X{
X    FILE *fp;
X    char  tname[NBSIZE];
X
X    sprintf(tname,".TMP.%08X",inet_num);
X
X    if(pos) {		     fp = fopen(tname,"a"); }
X       else { unlink(tname); fp = fopen(tname,"w"); }
X
X    if(!fp) return("Cannot open temporary file");
X
X    fwrite(data, 1, len, fp);
X    fclose(fp);
X
X    return(NULLP);
X}
X
char *server_install(path,inet_num)
X    char *path;
X    unsigned long inet_num;
X{
X    FILE *ft, *fp;
X    char   tname[NBSIZE], no_add_p[NBSIZE], owner_p[NBSIZE], buf[512];
X    int bytes;
X
X    get_dir_name(path,tname);
X    sprintf( owner_p,"%s/.OWN.%08X"  ,tname,inet_num);
X    sprintf(no_add_p,"%s/.FSP_NO_ADD",tname         );
X    sprintf(tname,".TMP.%08X"        ,      inet_num);
X
X    if(!fexist(owner_p) && fexist(no_add_p))
X    {
X	unlink(tname);
X	return("no permission for writting to that file");
X    }
X
X    unlink(path);
X    if(link(tname,path) == 0) { unlink(tname); return(NULLP); }
X
X    if(!(ft = fopen(tname,"r"))) { unlink(tname);
X				   return("Can't open temporary file"); }
X
X    if(!(fp = fopen(path ,"w"))) { unlink(tname); fclose(ft);
X				   return("Can't open file for output"); }
X
X    while(bytes = fread(buf,1,sizeof(buf),ft)) fwrite(buf,1,bytes,fp);
X
X    fclose(ft); fclose(fp); unlink(tname); return(NULLP);
X}
X
X/**********************************************************************/
X
init_home_dir()
X{
X    if(*home_dir != '/') { fprintf(stderr,"[%s] does not start with a /\n");
X			   exit(1); }
X
X    if(chdir(home_dir) == -1) { perror("chdir"); exit(1); }
X
X    if(dbug) { fprintf(stderr,"home on %s\n",home_dir); fflush(stderr); }
X}
X
X/***************************************************************************/
END_OF_FILE
if test 11591 -ne `wc -c <'server_file.c'`; then
    echo shar: \"'server_file.c'\" unpacked with wrong size!
fi
# end of 'server_file.c'
fi
echo shar: End of archive 3 \(of 3\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
