home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff294.lzh
/
DNet
/
unix
/
server
/
snfs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-12-11
|
13KB
|
615 lines
/*
* SNFS.C V1.1
*
* DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
*
* NETWORK FILE SYSTEM SERVER
*
* Accepts connections to files or directories & read-write or dir-scan calls.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <sys/resource.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include "servers.h"
#include "snfs.h"
/* #define DEBUG */
#define MAXHANDLES 256
char *FDName();
extern void AmigaToUnixPath();
extern void ConcatPath();
extern char *malloc();
extern char *TailPart();
extern char *strcpy();
int Chan;
typedef struct {
short isopen;
short fd;
int modes;
int remodes;
long pos;
char *name;
} HANDLE;
HANDLE Handle[MAXHANDLES];
chandler()
{
union wait stat;
struct rusage rus;
while (wait3(&stat, WNOHANG, &rus) > 0);
}
void NFs();
main(ac,av)
char *av[];
{
long chann = DListen(PORT_NFS);
int fd;
int n;
char buf[1024];
extern int errno;
if (av[1])
chdir(av[1]);
#ifdef DEBUG
freopen("NFS", "w", stderr);
fprintf(stderr, "RUNNING\n");
fflush(stderr);
#endif
signal(SIGCHLD, chandler);
signal(SIGPIPE, SIG_IGN);
for (;;) {
fd = DAccept(chann);
if (fd < 0) {
if (errno == EINTR)
continue;
break;
}
if (fork() == NULL) {
NFs(fd);
#ifdef DEBUG
fprintf(stderr, "CLOSING\n");
fflush(stderr);
#endif
_exit(1);
}
close(fd);
}
perror("NFS");
}
void
NFs(chan)
int chan;
{
OpenHandle("/", "", O_RDONLY); /* root */
for (;;) {
struct {
char cmd;
unsigned char blen;
unsigned long dlen;
} Base;
long bytes;
union {
OpOpen Open;
OpRead Read;
OpWrite Write;
OpClose Close;
OpSeek Seek;
OpParent Parent;
OpDelete Delete;
OpCreateDir CreateDir;
OpDup Dup;
OpNextDir NextDir;
OpRename Rename;
} R;
union {
RtOpen Open;
RtRead Read;
RtWrite Write;
RtSeek Seek;
RtParent Parent;
RtDelete Delete;
RtCreateDir CreateDir;
RtDup Dup;
RtNextDir NextDir;
RtRename Rename;
} W;
long h;
char buf[256];
if (ggread(chan, &Base, sizeof(Base)) != sizeof(Base))
break;
#ifdef DEBUG
fprintf(stderr, "command %02x %ld %ld\n",
Base.cmd, Base.blen, Base.dlen
);
fflush(stderr);
#endif
if (ggread(chan, &R, Base.blen) != Base.blen)
break;
switch(Base.cmd) {
case 'M': /* create directory */
{
ggread(chan, buf, Base.dlen);
AmigaToUnixPath(buf);
mkdir(buf, 0777);
#ifdef DEBUG
fprintf(stderr, "MakeDir %s\n", buf);
fflush(stderr);
#endif
}
R.Open.DirHandle = R.CreateDir.DirHandle;
/* FALL THROUGH */
case 'P':
if (Base.cmd == 'P') {
char *name = FDName(R.Parent.Handle);
short i = strlen(name)-1;
#ifdef DEBUG
fprintf(stderr, "Parent Dir of: %s\n", name);
fflush(stderr);
#endif
if (i >= 0 && name[i] == '/') /* remove tailing /'s */
--i;
if (i < 0) {
W.Open.Handle = -1;
gwrite(chan, &W.Open, sizeof(W.Open));
#ifdef DEBUG
fprintf(stderr, "NO PARENT\n");
fflush(stderr);
#endif
break;
}
while (i >= 0 && name[i] != '/') /* remove name */
--i;
while (i >= 0 && name[i] == '/') /* remove tailing /'s */
--i;
++i;
if (i == 0) { /* at root */
buf[i++] = '/';
}
strncpy(buf, name, i);
buf[i] = 0;
#ifdef DEBUG
fprintf(stderr, "Parent Exists: %s\n", buf);
fflush(stderr);
#endif
R.Open.DirHandle = 0;
}
R.Open.Modes = 1005;
/* FALL THROUGH */
case 'O': /* open */
if (Base.cmd == 'O') {
ggread(chan, buf, Base.dlen);
AmigaToUnixPath(buf);
#ifdef DEBUG
fprintf(stderr, "OPEN: %s %d\n", buf, Base.dlen);
fflush(stderr);
#endif
}
if (R.Open.Modes == 1006)
h = OpenHandle(FDName(R.Open.DirHandle),buf,
O_CREAT|O_TRUNC|O_RDWR
);
else
h = OpenHandle(FDName(R.Open.DirHandle),buf, O_RDWR);
#ifdef DEBUG
fprintf(stderr, "Open h = %d name = %s modes=%d\n",
h, buf, R.Open.Modes
);
fflush(stderr);
#endif
if (h >= 0) {
struct stat stat;
if (fstat(FDHandle(h), &stat) < 0)
perror("fstat");
W.Open.Handle = h;
W.Open.Prot = 0;
W.Open.Type = (stat.st_mode & S_IFDIR) ? 1 : -1;
#ifdef DEBUG
fprintf(stderr, "fstat type %d\n", W.Open.Type);
fflush(stderr);
#endif
W.Open.Size = stat.st_size;
SetDate(&W.Open.Date, stat.st_mtime);
gwrite(chan, &W.Open, sizeof(W.Open));
if (Base.cmd == 'P') { /* tag name */
char *tail = TailPart(buf);
unsigned char c = strlen(tail) + 1;
gwrite(chan, &c, 1);
gwrite(chan, tail, c);
}
} else {
W.Open.Handle = -1;
gwrite(chan, &W.Open, sizeof(W.Open));
}
break;
case 'N': /* next directory. Scan beg. at index */
{
DIR *dir = opendir(FDName(R.NextDir.Handle));
struct stat sbuf;
struct direct *dp;
long index = 0;
char buf[1024];
while (dir && index <= R.NextDir.Index + 2) {
if ((dp = readdir(dir)) == NULL)
break;
++index;
}
if (dir)
closedir(dir);
if (index <= R.NextDir.Index + 2) {
W.Open.Handle = -1;
} else {
W.Open.Handle = index;
strcpy(buf, FDName(R.NextDir.Handle));
strcat(buf, "/");
strcat(buf, dp->d_name);
stat(buf, &sbuf);
W.Open.Prot = 0;
W.Open.Type = (sbuf.st_mode & S_IFDIR) ? 1 : -1;
#ifdef DEBUG
fprintf(stderr, "fstat type %d\n", W.Open.Type);
fflush(stderr);
#endif
W.Open.Size = sbuf.st_size;
SetDate(&W.Open.Date, sbuf.st_mtime);
}
gwrite(chan, &W.Open, sizeof(W.Open));
if (W.Open.Handle >= 0) {
unsigned char len = strlen(dp->d_name) + 1;
gwrite(chan, &len, 1);
gwrite(chan, dp->d_name, len);
}
}
break;
case 'r': /* RENAME */
{
char tmp1[512];
char tmp2[512];
char buf1[1024];
char buf2[1024];
ggread(chan, buf, Base.dlen);
strcpy(tmp1, buf);
strcpy(tmp2, buf + strlen(buf) + 1);
AmigaToUnixPath(tmp1);
AmigaToUnixPath(tmp2);
ConcatPath(FDName(R.Rename.DirHandle1), tmp1, buf1);
ConcatPath(FDName(R.Rename.DirHandle2), tmp2, buf2);
#ifdef DEBUG
fprintf(stderr, "Rename %s to %s\n", buf1, buf2);
fflush(stderr);
#endif
if (rename(buf1, buf2) < 0)
W.Rename.Error = 1;
else
W.Rename.Error = 0;
gwrite(chan, &W.Rename.Error, sizeof(W.Rename.Error));
}
break;
case 'd': /* DUP */
h = DupHandle(R.Dup.Handle);
if (h >= 0) {
struct stat stat;
if (fstat(FDHandle(h), &stat) < 0)
perror("fstat");
W.Open.Handle = h;
W.Open.Prot = 0;
W.Open.Type = (stat.st_mode & S_IFDIR) ? 1 : -1;
#ifdef DEBUG
fprintf(stderr, "fstat type %d\n", W.Open.Type);
fflush(stderr);
#endif
W.Open.Size = stat.st_size;
SetDate(&W.Open.Date, stat.st_mtime);
} else {
W.Open.Handle = -1;
}
gwrite(chan, &W.Dup, sizeof(W.Dup));
break;
case 'R': /* READ */
{
int fd = FDHandle(R.Read.Handle);
char *buf = malloc(R.Read.Bytes);
W.Read.Bytes = read(fd, buf, R.Read.Bytes);
#ifdef DEBUG
fprintf(stderr, "h=%d fd %d Read %d Result=%d\n",
R.Read.Handle, fd, R.Read.Bytes, W.Read.Bytes
);
fflush(stderr);
#endif
gwrite(chan, &W.Read, sizeof(W.Read));
if (W.Read.Bytes > 0)
gwrite(chan, buf, W.Read.Bytes);
free(buf);
}
break;
case 'W':
{
int fd = FDHandle(R.Write.Handle);
char *buf = malloc(R.Write.Bytes);
if (ggread(chan, buf, R.Write.Bytes) != R.Write.Bytes)
break;
W.Write.Bytes = write(fd, buf, R.Write.Bytes);
#ifdef DEBUG
fprintf(stderr, "h=%d fd %d Write %d Result=%d\n",
R.Write.Handle, fd, R.Write.Bytes, W.Write.Bytes
);
fflush(stderr);
#endif
gwrite(chan, &W.Write, sizeof(W.Write));
free(buf);
}
break;
case 'C':
{
CloseHandle(R.Close.Handle);
}
break;
case 'S':
{
int fd = FDHandle(R.Seek.Handle);
W.Seek.OldOffset = lseek(fd, 0, 1);
W.Seek.NewOffset = lseek(fd, R.Seek.Offset, R.Seek.How);
#ifdef DEBUG
fprintf(stderr, "h %d SEEK %d %d %d result = %d\n",
R.Seek.Handle, fd, R.Seek.Offset, R.Seek.How,
W.Seek.NewOffset
);
fflush(stderr);
#endif
gwrite(chan, &W.Seek, sizeof(W.Seek));
}
break;
case 'D':
{
char buf2[1024];
ggread(chan, buf, Base.dlen); /* get name to delete */
AmigaToUnixPath(buf);
ConcatPath(FDName(R.Delete.DirHandle), buf, buf2);
unlink(buf2);
rmdir(buf2);
#ifdef DEBUG
fprintf(stderr, "Delete %s\n", buf2);
fflush(stderr);
#endif
W.Delete.Error = 0;
gwrite(chan, &W.Delete, sizeof(W.Delete));
}
break;
default:
exit(1);
break;
}
}
}
OpenHandle(base, tail, modes)
char *base;
char *tail;
int modes;
{
short i;
int fd;
char name[1024];
ConcatPath(base, tail, name);
for (i = 0; i < MAXHANDLES; ++i) {
if (Handle[i].isopen == 0)
break;
}
if (i == MAXHANDLES)
return(-1);
fd = open(name, modes, 0666);
if (fd < 0 && (modes & O_RDWR) && !(modes & O_CREAT)) {
modes &= ~O_RDWR;
fd = open(name, modes);
}
Handle[i].name = strcpy(malloc(strlen(name)+1), name);
Handle[i].fd = fd;
#ifdef DEBUG
fprintf(stderr, "OpenHandle: %d = open %s %d\n", Handle[i].fd, name,modes);
fflush(stderr);
#endif
if (Handle[i].fd < 0)
return(-1);
Handle[i].modes = modes;
Handle[i].remodes= modes & ~(O_TRUNC|O_CREAT);
Handle[i].isopen = 1;
return(i);
}
CloseHandle(h)
{
#ifdef DEBUG
fprintf(stderr, " Close Handle %d\n", h);
fflush(stderr);
#endif
if (h >= 0 && h < MAXHANDLES && Handle[h].isopen) {
if (Handle[h].fd >= 0)
close(Handle[h].fd);
Handle[h].fd = -1;
Handle[h].isopen = 0;
free(Handle[h].name);
}
}
/*
* Insert ../ for / at beginning.
*/
void
AmigaToUnixPath(buf)
char *buf;
{
char *base = buf;
#ifdef DEBUG
fprintf(stderr, "AmigaToUnixPath %s", buf);
#endif
if (*buf == ':')
*buf++ = '/';
while (*buf == '/') {
bcopy(buf, buf + 2, strlen(buf)+1);
buf[0] = buf[1] = '.';
buf += 3;
}
#ifdef DEBUG
fprintf(stderr, " TO %s\n", base);
fflush(stderr);
#endif
}
void
ConcatPath(s1, s2, buf)
char *s1, *s2;
char *buf;
{
#ifdef DEBUG
fprintf(stderr, "ConCatPaths From '%s' '%s'\n", s1, s2);
#endif
while (strncmp(s2, "../", 3) == 0) { /* parent */
;
break;
}
while (strncmp(s2, "./", 2) == 0) { /* current */
s2 += 2;
}
if (s2[0] == '/') {
strcpy(buf, s2);
return;
}
if (s1[0] == 0 && s2[0] == 0) {
strcpy(buf, ".");
return;
}
if (s1[0] == 0)
s1 = ".";
strcpy(buf, s1);
if (s1[strlen(s1)-1] != '/')
strcat(buf, "/");
strcat(buf, s2);
#ifdef DEBUG
fprintf(stderr, "ConCatPaths to %s\n", buf);
fflush(stderr);
#endif
}
char *
FDName(h)
{
#ifdef DEBUG
fprintf(stderr, "FDName(%d) =", h);
#endif
if (h >= 0 && h < MAXHANDLES && Handle[h].isopen) {
#ifdef DEBUG
fprintf(stderr, "%s\n", Handle[h].name);
fflush(stderr);
#endif
return(Handle[h].name);
}
#ifdef DEBUG
fprintf(stderr, "??\n");
fflush(stderr);
#endif
return(".");
}
DupHandle(h)
{
short n = -1;
if (h >= 0 && h < MAXHANDLES && Handle[h].isopen)
n = OpenHandle(".",Handle[h].name, Handle[h].remodes & ~O_RDWR);
return(n);
}
FDHandle(h)
{
int fd = -1;
if (h >= 0 && h < MAXHANDLES && Handle[h].isopen) {
fd = Handle[h].fd;
if (fd < 0) {
Handle[h].fd = fd = open(Handle[h].name, Handle[h].remodes, 0666);
if (fd >= 0 && !(Handle[h].modes & O_APPEND))
lseek(fd, Handle[h].pos, 0);
}
}
return(fd);
}
char *
TailPart(path)
char *path;
{
register char *ptr = path + strlen(path) - 1;
while (ptr >= path && *ptr != '/')
--ptr;
++ptr;
#ifdef DEBUG
fprintf(stderr, "TAILPART '%s' -> %s\n", path, ptr);
fflush(stderr);
#endif
return(ptr);
}
SetDate(date, mtime)
STAMP *date;
time_t mtime;
{
struct tm *tm = localtime(&mtime);
long years = tm->tm_year; /* since 1900 */
long days;
years += 300; /* since 1600 */
days = (years / 400) * 146097; /* # days every four cents */
years = years % 400;
/*
* First assume a leap year every 4 years, then correct for centuries.
* never include the 'current' year in the calculations. Thus, year 0
* (a leap year) is included only if years > 0.
*/
days += years * 365 + ((years+3) / 4);
if (years <= 100)
;
else if (years <= 200) /* no leap 3 of 4 cent. marks */
days -= 1;
else if (years <= 300)
days -= 2;
else
days -= 3;
days -= 138062; /* 1600 -> 1978 */
date->ds_Days = days + tm->tm_yday;
date->ds_Minute= tm->tm_min + tm->tm_hour * 60;
date->ds_Tick = tm->tm_sec * 50;
}