/* * 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 #include #include #include #include #include #include #include #include #include #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; }