237 lines
5.7 KiB
C
237 lines
5.7 KiB
C
/* This file shows how one could build a remote file server for MINIX.
|
|
* In this file there are several library routines for the basic system
|
|
* calls. Unlike the "real" ones, these call a remote file server instead
|
|
* of the local kernel. On client machines, one would replace the library
|
|
* routines with these routines, and then recompile programs. In this way,
|
|
* clients will then call the remote file server. It should be obvious that
|
|
* this file is just an example, and that a productio version would have to
|
|
* be much more complete.
|
|
*
|
|
* The file server3.c contains the start of a stateless file server. Because
|
|
* MINIX is not stateless, the conversion must be done in this library. For
|
|
* example, when an open() is done, the library records the name, but no
|
|
* operation is performed on the file server.
|
|
*
|
|
* An alternative approach to making a remote file systems is to replace FS,
|
|
* the local file server, with one that makes the calls to the remote file
|
|
* server itself. This approach is less efficient, because a call then
|
|
* consists of a local FS call plus a remote one, but it is more transparent
|
|
* because no programs need to recompiled.
|
|
*/
|
|
|
|
#include <amoeba.h>
|
|
#include <errno.h>
|
|
#include <minix/callnr.h>
|
|
#include "header.h"
|
|
|
|
#define MAX_FD 20
|
|
#define LOCAL 100
|
|
#define HEAPSIZE 512 /* space for file names */
|
|
#define WRITING 2
|
|
#define ER -1
|
|
#define FS 1
|
|
#define NIL_PTR (char*) 0
|
|
|
|
/* The local array is indexed by file descriptor. Those entries containing
|
|
* LOCAL are local (e.g., stdin), those containing REMOTE are remote, and
|
|
* those containing 0 are unassigned.
|
|
*/
|
|
|
|
char where[MAX_FD] = {LOCAL, LOCAL, LOCAL};
|
|
long pos[MAX_FD]; /* current offset */
|
|
char *server_name = "filsrv";
|
|
char *file_name[MAX_FD];
|
|
|
|
char heap[HEAPSIZE];
|
|
char *heap_ptr = heap;
|
|
header hdr1, hdr2;
|
|
char buffer[BUF_SIZE+NAME_SIZE];
|
|
|
|
extern int errno;
|
|
|
|
|
|
/*============================= Remote Library ==============================*/
|
|
int open(name, how)
|
|
char *name;
|
|
int how;
|
|
{
|
|
/* Open is entirely local. */
|
|
|
|
int i, len;
|
|
|
|
if (how < 0 || how > 2) { errno = EINVAL; return(ER);}
|
|
|
|
/* Find a free file descriptor. */
|
|
for (i = 0; i < MAX_FD; i++) {
|
|
if (where[i] == 0) {
|
|
len = strlen(name);
|
|
file_name[i] = heap_ptr;
|
|
bcopy(name, heap_ptr, len);
|
|
heap_ptr += len;
|
|
*heap_ptr++ = 0;
|
|
where[i] = how+1;
|
|
return(i);
|
|
}
|
|
}
|
|
errno = EMFILE;
|
|
return(ER);
|
|
}
|
|
|
|
int creat(name, mode)
|
|
char *name;
|
|
int mode;
|
|
{
|
|
/* Create a file. */
|
|
|
|
int i, len, n;
|
|
|
|
/* Find a free file descriptor. */
|
|
for (i = 0; i < MAX_FD; i++) {
|
|
if (where[i] == 0) {
|
|
len = strlen(name);
|
|
file_name[i] = heap_ptr;
|
|
bcopy(name, heap_ptr, len);
|
|
heap_ptr += len;
|
|
*heap_ptr++ = 0;
|
|
where[i] = WRITING;
|
|
|
|
strncpy(&hdr1.h_port, server_name, PORTSIZE);
|
|
hdr1.h_command = CREAT;
|
|
hdr1.h_size = mode;
|
|
n = trans(&hdr1, file_name[i], len+1, &hdr2, buffer, 0);
|
|
if (n < 0) {errno = EIO; return(ER);}
|
|
return(hdr2.h_status);
|
|
}
|
|
}
|
|
errno = EMFILE;
|
|
return(ER);
|
|
}
|
|
|
|
|
|
/* int close(fd)
|
|
int fd;
|
|
{
|
|
|
|
if (where[fd] == LOCAL) return(Xclose(fd));
|
|
if (where[fd] == 0) {errno = EBADF; return(ER);}
|
|
where[fd] = 0;
|
|
return(OK);
|
|
}
|
|
*/
|
|
|
|
int read(fd, buf, bytes)
|
|
int fd, bytes;
|
|
char buf[];
|
|
{
|
|
/* Primitive read() routine for reads up to 1K. */
|
|
|
|
int n;
|
|
|
|
if (where[fd] == LOCAL) return (Xread(fd, buf, bytes));
|
|
if ((where[fd]&1) == 0) {errno = EBADF; return(ER);}
|
|
if (bytes > BUF_SIZE) return(EINVAL); /* in a real version, fix this */
|
|
strncpy(&hdr1.h_port, server_name, PORTSIZE);
|
|
|
|
hdr1.h_command = READ;
|
|
hdr1.h_size = bytes;
|
|
hdr1.h_offset = pos[fd];
|
|
n = trans(&hdr1, file_name[fd], strlen(file_name[fd])+1, &hdr2, buf, bytes);
|
|
if (n < 0) {errno = EIO; return(ER);}
|
|
if (hdr2.h_extra != 0) errno = hdr2.h_extra;
|
|
pos[fd] += hdr2.h_status; /* advance file position */
|
|
return(hdr2.h_status);
|
|
}
|
|
|
|
|
|
int write(fd, buf, bytes)
|
|
int fd, bytes;
|
|
char buf[];
|
|
{
|
|
/* Primitive write() routine for writes up to 1K. This is a very simple
|
|
* routine. Because the server is stateless, for a write we must send both
|
|
* the data and the file name. In this example, the first 1K of the buffer
|
|
* is reserved for the data, with the file name starting at position 1024.
|
|
*/
|
|
|
|
int n, len;
|
|
|
|
if (where[fd] == LOCAL) return (Xwrite(fd, buf, bytes));
|
|
if ((where[fd]&02) == 0) {errno = EBADF; return(ER);}
|
|
if (bytes > BUF_SIZE) return(EINVAL); /* in a real version, fix this */
|
|
strncpy(&hdr1.h_port, server_name, PORTSIZE);
|
|
|
|
len = strlen(file_name[fd]);
|
|
hdr1.h_command = WRITE;
|
|
hdr1.h_size = bytes;
|
|
hdr1.h_offset = pos[fd];
|
|
bcopy(buf, buffer, bytes); /* copy data to message */
|
|
bcopy(file_name[fd], &buffer[BUF_SIZE], len+1);
|
|
n = trans(&hdr1, buffer, BUF_SIZE+len+1, &hdr2, buf, 0);
|
|
if(n < 0) {errno = EIO; return(ER);}
|
|
if (hdr2.h_extra != 0) errno = hdr2.h_extra;
|
|
pos[fd] += hdr2.h_status;
|
|
return(hdr2.h_status);
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Below are the real calls, which are sometimes needed. */
|
|
|
|
int Xread(fd, buffer, nbytes)
|
|
int fd;
|
|
char *buffer;
|
|
int nbytes;
|
|
{
|
|
int n;
|
|
n = callm1(FS, READ, fd, nbytes, 0, buffer, NIL_PTR, NIL_PTR);
|
|
return(n);
|
|
}
|
|
|
|
int Xwrite(fd, buffer, nbytes)
|
|
char *buffer;
|
|
int nbytes;
|
|
{
|
|
return callm1(FS, WRITE, fd, nbytes, 0, buffer, NIL_PTR, NIL_PTR);
|
|
}
|
|
|
|
|
|
int Xclose(fd)
|
|
int fd;
|
|
{
|
|
return callm1(FS, CLOSE, fd, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
|
|
|
|
}
|
|
|
|
|
|
/* ========================= test program =============================*/
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int fd1, n;
|
|
char b[1024];
|
|
|
|
if (argc != 2) {
|
|
printf("Usage: client3 file\n");
|
|
exit(1);
|
|
}
|
|
|
|
fd1 = open(argv[1], 0);
|
|
if (fd1 < 0) {
|
|
printf("Open of %s failed\n", argv[1]);
|
|
exit(1);
|
|
}
|
|
|
|
do {
|
|
if ((n=read(fd1, b, 1024) < 0)) {
|
|
printf("Cannot read %s\n", argv[1]);
|
|
exit(1);
|
|
}
|
|
if (write(1, b, n) < 0) {
|
|
printf("Cannot write stdout\n");
|
|
exit(1);
|
|
}
|
|
} while (n > 0);
|
|
}
|