add directory study
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
CFLAGS=-F
|
||||
all: client1 server1 client2 server2 client3 server3
|
||||
|
||||
client1: header.h client1.s
|
||||
cc -o client1 client1.s
|
||||
|
||||
client2: header.h client2.s
|
||||
cc -o client2 client2.s
|
||||
|
||||
client3: header.h client3.s
|
||||
cc -o client3 client3.s
|
||||
|
||||
server1: header.h server1.s
|
||||
cc -o server1 server1.s
|
||||
chmem =1000 server1
|
||||
|
||||
server2: header.h server2.s
|
||||
cc -o server2 server2.s
|
||||
chmem =1000 server2
|
||||
|
||||
server3: header.h server3.s
|
||||
cc -o server3 server3.s
|
||||
chmem =1000 server3
|
||||
@@ -0,0 +1,59 @@
|
||||
This directory contains several examples of networking code. These examples
|
||||
also serve as programs to test the correctness and performance of the
|
||||
networking and to provide some useful utility functions. In all the tests,
|
||||
the client and server may run on the same machine, or if an Ethernet is
|
||||
installed, on different machines. The ports 'xyz' used in tests 1 and 2
|
||||
are examples. It is possible to run multiple tests at the same time (e.g.,
|
||||
n1 sets of (client1, server1) and n2 sets of (client2, server2), provided
|
||||
that each pair of (clientX, serverX) uses a port not used by any other process.
|
||||
|
||||
1. Test 1 consists of two programs, server1.c and client1.c. This test
|
||||
transfers 1 megabyte from the client to the server in 1K chunks, has the
|
||||
server transform the data and send it back. The client then verifies if
|
||||
the returned data is correct. To run the test, type the following lines:
|
||||
|
||||
make client1 server1
|
||||
server1 xyz &
|
||||
client1 xyz
|
||||
|
||||
If an Ethernet is installed and the kernel has been compiled with
|
||||
-DAM_KERNEL, the server and client may either be on the same machine or
|
||||
one different ones. If there is no Ethernet and the kernel has been
|
||||
compiled with _DAM_KERNEL -DNONET, both processes must be on the same CPU.
|
||||
|
||||
At the end of the test, "ok" is printed if no errors occurred. Otherwise
|
||||
the number of bad transactions is printed. Both the client and server exit
|
||||
by themselves after the test has been completed.
|
||||
|
||||
2. Test 2 consists of two programs, server2.c and client2.c. This test
|
||||
measures the performance of the transactions. Like test 1, it can be run
|
||||
either locally or remotely. The test consists of having the client request
|
||||
n bytes of data from the server, where n grows from 1 to 30,000 bytes per
|
||||
transaction. For each value of n, the test is run 1000 times to increase
|
||||
the statistical accuracy. For each value of n, the value of n, the delay
|
||||
(transaction time in milliseconds), and the throughput (bytes/sec moved)
|
||||
is reported. To run the test, type:
|
||||
|
||||
make client2 server2
|
||||
server2 xyz &
|
||||
client2 xyz
|
||||
|
||||
|
||||
3. Test 3 is an example of how one might go about making a remote file server
|
||||
for MINIX to service diskless PCs. In this approach, one writes a server,
|
||||
server3.c in this example, and a set of library routines, contained in
|
||||
client3.c. These library routines should have the same names as the MINIX
|
||||
system calls, such as open(), read(), and write(). When programs are linked
|
||||
with these routines instead of the usual ones, the routines make calls to
|
||||
the remote file server instead of FS. The file client3.c contains not only
|
||||
a few of these library routines, but also a short main program to test them.
|
||||
The main program fetches a file from the remote file server and copies it to
|
||||
stdout. To test the program, type:
|
||||
|
||||
make client3 server3
|
||||
server3 &
|
||||
client3 <filename>
|
||||
|
||||
where <filename> is the name of a file on the same machine as server3. The
|
||||
result of this command will be that <filename> is written to client3's
|
||||
standard output.
|
||||
@@ -0,0 +1,56 @@
|
||||
/* This program tests the basic RPC to see if it works. */
|
||||
|
||||
#include <amoeba.h>
|
||||
#include "header.h"
|
||||
|
||||
#define MAX_TRIALS 1000
|
||||
|
||||
char buffer1[BUF_SIZE], buffer2[BUF_SIZE];
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
|
||||
header hdr1, hdr2;
|
||||
int cnt, i, base = 0, size, errors, blocks, iterations = 0;
|
||||
long bad_trans = 0;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: client1 portname\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Copy the filename into the start of the buffer. */
|
||||
strncpy(&hdr1.h_port, argv[1], PORTSIZE);
|
||||
hdr1.h_command = WORK;
|
||||
|
||||
printf("Number of tests performed = %5d ", 0);
|
||||
|
||||
while (iterations < MAX_TRIALS) {
|
||||
/* Initialize the buffer. */
|
||||
for (i = 0; i < BUF_SIZE; i++) buffer1[i] = base + i;
|
||||
|
||||
size = trans(&hdr1, buffer1, BUF_SIZE, &hdr2, buffer2, BUF_SIZE);
|
||||
if (size < 0) {
|
||||
printf("\nTransaction failed. Error = %d. ", size);
|
||||
printf("Hit F1 to see if AMTASK running.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Check reply. */
|
||||
errors = 0;
|
||||
for (i = 0; i < BUF_SIZE; i++)
|
||||
if ( (buffer2[i]&0377) != ( (buffer1[i]+1)&0377)) errors++;
|
||||
if (errors > 0) bad_trans++;
|
||||
blocks++;
|
||||
base++;
|
||||
iterations++;
|
||||
if (iterations % 10 == 0) printf("\b\b\b\b\b\b%5d ", iterations);
|
||||
}
|
||||
|
||||
/* Test done. Send null trans to tell server. Report on errors. */
|
||||
hdr1.h_command = QUIT;
|
||||
trans(&hdr1, buffer1, 0, &hdr2, buffer2, BUF_SIZE);
|
||||
printf("\b. Number of errors = %d.\n", bad_trans);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* This file is the client of a test program for measuring RPC speed. */
|
||||
|
||||
#include <amoeba.h>
|
||||
#include <minix/callnr.h>
|
||||
#include "header.h"
|
||||
|
||||
#define TRIALS 1000
|
||||
|
||||
char buffer[MAX_TRANS];
|
||||
int bytes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096,
|
||||
8192, 16384, 30000, 0};
|
||||
|
||||
header hdr1, hdr2;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i, cnt;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: client2 portname\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Copy the filename into the start of the buffer. */
|
||||
strncpy(&hdr1.h_port, argv[1], PORTSIZE);
|
||||
hdr1.h_command = READ;
|
||||
|
||||
printf("Buf size Delay Throughput (Each test repeated %d times)\n", TRIALS);
|
||||
printf(" (msec/trans) (bytes/sec)\n");
|
||||
printf("-------- ------------ -----------\n");
|
||||
|
||||
i = 0;
|
||||
while (bytes[i] != 0) {
|
||||
run_test(bytes[i], TRIALS);
|
||||
i++;
|
||||
}
|
||||
hdr1.h_command = QUIT;
|
||||
trans(&hdr1, buffer, 0, &hdr2, buffer, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
run_test(count, trials)
|
||||
int count, trials;
|
||||
{
|
||||
/* Run a performance test. */
|
||||
|
||||
int i, n;
|
||||
long start, finish, traffic, sec, msec, delay, throughput;
|
||||
|
||||
time(&start); /* record starting time */
|
||||
for (i = 0; i < trials; i++) {
|
||||
hdr1.h_command = READ;
|
||||
hdr1.h_size = (unshort) count;
|
||||
n = trans(&hdr1, buffer, 0, &hdr2, buffer, MAX_TRANS);
|
||||
if (n < 0) {
|
||||
printf("Transaction failed. Error = %d. ", n);
|
||||
printf("Hit F1 to see if AMTASK running.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
time(&finish);
|
||||
sec = finish - start; /* time for this trial in seconds */
|
||||
msec = 1000L * sec;
|
||||
traffic = (long) trials * (long) count;
|
||||
delay = msec/trials; /* msec per transaction */
|
||||
if (sec != 0L)
|
||||
throughput = traffic/sec;
|
||||
else
|
||||
throughput = 0L;
|
||||
printf(" %5d %4D %7D\n", count, delay, throughput);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
/* 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);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/* Some declarations need by the example clients and servers. */
|
||||
|
||||
char *file_server = "filsrv";
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
#define NAME_SIZE 512
|
||||
#define WORK 1
|
||||
#define QUIT 999
|
||||
#define MAX_TRANS 30000
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <amoeba.h>
|
||||
#include "header.h"
|
||||
|
||||
char buffer[BUF_SIZE];
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
unshort getreq(), putrep();
|
||||
|
||||
header hdr;
|
||||
int cnt, i, iterations = 0;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: server1 portname\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
strncpy( (char *) &hdr.h_port, argv[1], PORTSIZE); /* init port */
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Wait for a request to arrive. */
|
||||
if ((cnt = (short) getreq(&hdr, buffer, BUF_SIZE)) < 0) {
|
||||
printf("Server's getreq failed. Error = %d. ", cnt);
|
||||
printf("Hit F1 to see if AMTASK running.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Opcode QUIT indicates that we are done. */
|
||||
if (hdr.h_command == QUIT) {
|
||||
putrep(&hdr, buffer, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* We have a request. Increment each byte. */
|
||||
for (i = 0; i < cnt; i++) buffer[i]++;
|
||||
|
||||
/* Send back reply. */
|
||||
hdr.h_status = 0;
|
||||
putrep(&hdr, buffer, cnt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <amoeba.h>
|
||||
#include "header.h"
|
||||
|
||||
char buffer[MAX_TRANS];
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
|
||||
header hdr;
|
||||
int count;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: server2 portname\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
strncpy( (char *) &hdr.h_port, argv[1], PORTSIZE); /* init port */
|
||||
|
||||
while (1) {
|
||||
/* Wait for a request to arrive. */
|
||||
count = (short) getreq(&hdr, buffer, MAX_TRANS);
|
||||
if (count < 0) {
|
||||
printf("Server's getreq failed. Error = %d. ", count);
|
||||
printf("Hit F1 to see if AMTASK running.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Opcode QUIT indicates that we are done. */
|
||||
if (hdr.h_command == QUIT) {
|
||||
putrep(&hdr, buffer, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* We have a request. Reply. */
|
||||
count = hdr.h_size;
|
||||
putrep(&hdr, buffer, count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <amoeba.h>
|
||||
#include <minix/callnr.h>
|
||||
#include <errno.h>
|
||||
#include "header.h"
|
||||
|
||||
header hdr; /* header for incoming messages */
|
||||
char buffer[BUF_SIZE+NAME_SIZE]; /* buffer for incoming messages */
|
||||
char *server_name = "filsrv";
|
||||
int repsize;
|
||||
extern int errno;
|
||||
|
||||
main()
|
||||
{
|
||||
/* This is a primitive file server. The client runs with a special set of
|
||||
* routines for read(), write(), etc. that call this server. The server is
|
||||
* stateless.
|
||||
*/
|
||||
|
||||
int s;
|
||||
int count;
|
||||
unshort opcode, size;
|
||||
|
||||
strncpy( (char *) &hdr.h_port, server_name, PORTSIZE); /* init port */
|
||||
|
||||
while (1) {
|
||||
/* Wait for a request to arrive. */
|
||||
count = (short) getreq(&hdr, buffer, MAX_TRANS);
|
||||
if (count < 0) {
|
||||
printf("Server's getreq failed. Error = %d. ", count);
|
||||
printf("Hit F1 to see if AMTASK running.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Dispatch on opcode. */
|
||||
opcode = hdr.h_command;
|
||||
repsize = 0;
|
||||
errno = 0;
|
||||
switch(opcode) {
|
||||
case CREAT: s = do_creat(); break;
|
||||
case READ: s = do_read(); break;
|
||||
case WRITE: s = do_write(); break;
|
||||
default: s = EINVAL; break;
|
||||
}
|
||||
|
||||
/* Work done. Send a reply. */
|
||||
hdr.h_status = (unshort) s;
|
||||
hdr.h_extra = (unshort) errno;
|
||||
putrep(&hdr, buffer, repsize);
|
||||
}
|
||||
}
|
||||
|
||||
int do_read()
|
||||
{
|
||||
/* Stateless read. */
|
||||
|
||||
int fd, n;
|
||||
long offset;
|
||||
unshort count;
|
||||
|
||||
offset = hdr.h_offset;
|
||||
count = hdr.h_size;
|
||||
if (count > MAX_TRANS) count = MAX_TRANS;
|
||||
|
||||
fd = open(buffer, 0); /* open the file for reading */
|
||||
if (fd < 0) return(errno);
|
||||
lseek(fd, offset, 0);
|
||||
n = read(fd, buffer, count);
|
||||
close(fd);
|
||||
repsize = n;
|
||||
return(n);
|
||||
}
|
||||
|
||||
int do_write()
|
||||
{
|
||||
/* Stateless write. */
|
||||
|
||||
int fd, n;
|
||||
long offset;
|
||||
unshort count;
|
||||
|
||||
offset = hdr.h_offset;
|
||||
count = hdr.h_size;
|
||||
if (count > MAX_TRANS) count = MAX_TRANS;
|
||||
|
||||
fd = open(&buffer[BUF_SIZE], 2); /* open the file for writing */
|
||||
if (fd < 0) return(errno);
|
||||
lseek(fd, offset, 0);
|
||||
n = write(fd, buffer, count);
|
||||
close(fd);
|
||||
return(n);
|
||||
}
|
||||
|
||||
int do_creat()
|
||||
{
|
||||
/* Stateless creat. */
|
||||
|
||||
int fd, n, mode;
|
||||
|
||||
|
||||
mode = hdr.h_size;
|
||||
fd = creat(buffer, mode); /* creat the file */
|
||||
close(fd);
|
||||
return(fd);
|
||||
}
|
||||
Reference in New Issue
Block a user