home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
lan
/
soss.arj
/
SRC
/
NFS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-11
|
31KB
|
1,056 lines
/*
* nfs.c --
* NFS server implementation for PC. Runs on top of the
* net daemon (netd.c).
*
* Author:
* See-Mong Tan, 6/12/88.
* Modified by:
* Rich Braun @ Kronos, 2/15/91
*
* Revision history:
*
* $Log: nfs.c_v $
* Revision 1.5 1991/04/11 20:41:26 richb
* Validate pathnames before invoking pntoin, to prevent crashes.
*
* Revision 1.4 1991/03/15 22:41:19 richb
* Numerous patches.
*
* Revision 1.3 1991/02/20 19:15:39 richb
* Minor changes for file_create; add RCS headers.
*
*/
#ifdef RCSID
static char _rcsid_ = "$Id: nfs.c_v 1.5 1991/04/11 20:41:26 richb Exp $";
#endif
#include "common.h"
#include "msc-dos.h" /* dos and ... */
#include <direct.h> /* directory ops */
#include "..\rpc\a_unix.h"
static char *reply_err = "RPC error: cannot transmit\n";
static char *mem_err = "malloc: no more memory\n";
/*
* bool_t nfs_init() --
* Initializes NFS server. Creates and registers transport
* handle for NFS server. Returns TRUE if successful, or FALSE
* if an error occurred.
*/
bool_t nfs_init()
{
SVCXPRT *transp;
int nfs_sock;
struct sockaddr_in addr;
static void nfs_dispatch(struct svc_req *, SVCXPRT *);
addr.sin_family = AF_INET;
addr.sin_port = htons(NFS_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if ((nfs_sock = sock_create(SOCK_DGRAM, IPPROTO_UDP, &addr)) < 0) {
(void) fprintf(stderr, "cannot create nfs socket\n");
return FALSE;
}
if ((transp = svcudp_create(nfs_sock, 1)) == (SVCXPRT *) NULL) {
(void) fprintf(stderr, "cannot create udp handle\n");
sock_close(nfs_sock);
return FALSE;
}
if (! svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_dispatch,
IPPROTO_UDP)) {
(void) fprintf(stderr, "cannot register handle\n");
sock_close(nfs_sock);
return FALSE;
}
return TRUE;
}
/*
* void nfs_dispatch(struct svc_req *req, SVCXPRT *transp) --
* NFS server dispatch routine.
*/
static void nfs_dispatch(req, transp)
struct svc_req *req;
SVCXPRT *transp;
{
#if DEBUG
static char *names[] = {"NULL", "GETATTR", "SETATTR", "ROOT", "LOOKUP",
"READLINK", "READ", "WRITECACHE", "WRITE", "CREATE",
"REMOVE", "RENAME", "LINK", "SYMLINK", "MKDIR",
"RMDIR", "READDIR", "STATFS", "<invalid>"};
DBGPRT1 (nfsdisp, ">>> NFS_%s", names[(req->rq_proc > NFS_STATFS) ?
NFS_STATFS+1 : req->rq_proc]);
#endif
/* find which procedure to call */
switch((int) req->rq_proc) {
case NFS_GETATTR: nfs_getattr(transp, req); break;
case NFS_NULL: nfs_null(transp, req); break;
case NFS_READ: nfs_read(transp, req); break;
case NFS_WRITE: nfs_write(transp, req); break;
case NFS_STATFS: nfs_statfs(transp, req); break;
case NFS_LOOKUP: nfs_lookup(transp, req); break;
case NFS_READDIR: nfs_readdir(transp, req); break;
case NFS_CREATE: nfs_create(transp, req); break;
case NFS_MKDIR: nfs_mkdir(transp, req); break;
case NFS_REMOVE: nfs_remove(transp, req); break;
case NFS_RMDIR: nfs_rmdir(transp, req); break;
case NFS_RENAME: nfs_rename(transp, req); break;
case NFS_SETATTR: nfs_setattr(transp, req); break;
case NFS_LINK: nfs_link(transp, req); break;
case NFS_SYMLINK: nfs_symlink(transp, req); break;
default:
DBGPRT1 (nfsdisp, "unsupp procedure %d",
req->rq_proc);
nfs_error(transp, req);
break;
}
}
/*
* void nfs_null(SVCXPRT *xprt, struct svc_req *req) --
* Sends an empty reply. Used for "ping-ing" the nfs server.
*/
void nfs_null(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
if (! svc_sendreply(xprt, xdr_void, (char *) NULL))
(void) fprintf(stderr, reply_err);
}
/*
* void nfs_read(SVCXPRT *xprt, struct svc_req *req) --
* Reads requested file and sends it over the wire.
*/
void nfs_read(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsreadargs *r_args; /* the argument */
struct nfsrdresult r_rslt; /* the read result */
char databuf [RD_SIZ];
u_long count; /* request size */
int bytes; /* bytes read */
r_args = (struct nfsreadargs *) malloc(sizeof(struct nfsreadargs));
if (r_args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(r_args, sizeof(struct nfsreadargs));
if (! svc_getargs(xprt, xdr_readargs, r_args)) {
svcerr_decode(xprt);
(void) free(r_args);
return;
}
(void) bzero(&r_rslt, sizeof(struct nfsrdresult));
/* set pointer to data in results struct */
r_rslt.rr_data = databuf;
count = r_args->ra_count;
/* evaluate buffer count argument */
if (count > RD_SIZ) {
count = RD_SIZ;
fprintf (stderr, "NFS_READ: truncating req. from %ld\n",
r_args->ra_count);
}
/* get attributes */
if (inattrget (r_args->ra_fhandle.f.fh_fno, &r_rslt.rr_attr) ==
(struct nfsfattr *) NULL)
r_rslt.rr_status = NFSERR_STALE;
else {
if ((bytes = file_read(r_args->ra_fhandle.f.fh_fno,
r_args->ra_offset, count,
r_rslt.rr_data)) == -1) {
DBGPRT1 (nfserr, "file_read error %d", errno);
r_rslt.rr_status = puterrno (errno);
}
else {
char name [MAXPATHNAMELEN];
DBGPRT4 (nfsread, "%s: %ld/%d bytes at %ld",
intopn (r_args->ra_fhandle.f.fh_fno, name),
r_args->ra_count, bytes, r_args->ra_offset);
r_rslt.rr_bufsize = RD_SIZ;
r_rslt.rr_count = bytes;
r_rslt.rr_status = NFS_OK;
r_rslt.rr_bp = NULL;
r_rslt.rr_vp = NULL;
}
}
if (! svc_sendreply(xprt, xdr_rdresult, &r_rslt))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_READ\n");
/* free arguments */
svc_freeargs(xprt, xdr_readargs, r_args);
}
/*
* void nfs_error(SVCXPRT *xprt, struct svc_req *req) --
* Returns nfs error message.
*/
void nfs_error(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
(void) fprintf(stderr,
">>> NFS_ERROR: procedure %d not supported\n", req->rq_proc);
svcerr_noproc(xprt); /* send server error reply msg */
}
/*
* void nfs_getattr(SVCXPRT *xprt, struct svc_req *req) --
* Gets file attributes.
*/
void nfs_getattr(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
fhandle_t *fhp; /* file handle is argument */
struct nfsattrstat attr; /* return attributes */
char *fullpath, path[MAXPATHNAMELEN]; /* full DOS path name */
fhp = (fhandle_t *) malloc(sizeof(fhandle_t));
if (fhp == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(fhp, sizeof(fhandle_t));
if (! svc_getargs(xprt, xdr_fhandle, fhp)) {
(void) fprintf(stderr, "nfs_getattr: cannot read args\n");
svcerr_decode(xprt);
(void) free(fhp);
return;
}
/* Check the validity of the file handle */
if (!checkfh (fhp))
attr.ns_status = NFSERR_STALE;
else {
/* clear out return attributes */
(void) bzero(&attr, sizeof(struct nfsattrstat));
fullpath = intopn(fhp->f.fh_fno, path); /* path from inode */
if (! file_getattr(fullpath, &(attr.ns_attr)))
attr.ns_status = NFSERR_NOENT;
else
attr.ns_status = NFS_OK;
}
#if 1
{
/* Hack: tell the caller he is the owner */
struct authunix_parms *unix_cred;
unix_cred = (struct authunix_parms *) req->rq_clntcred;
attr.ns_attr.na_uid = (u_long) unix_cred->aup_uid;
}
#endif
if (! svc_sendreply(xprt, xdr_attrstat, &attr))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_GETATTR: %s\n", fullpath);
svc_freeargs(xprt, xdr_fhandle, fhp);
}
/*
* void nfs_statfs(SVCXPRT *xprt, struct svc_req *req) --
* Returns file system status
*/
void nfs_statfs(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsstatfs fs;
fhandle_t *fhp;
fhp = (fhandle_t *) malloc(sizeof(fhandle_t));
if (fhp == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(fhp, sizeof(fhandle_t));
if (! svc_getargs(xprt, xdr_fhandle, fhp)) {
svcerr_decode(xprt);
(void) free(fhp);
return;
}
/* Check the validity of the file handle */
if (!checkfh (fhp))
fs.fs_status = NFSERR_STALE;
else {
/* clear out results struct */
(void) bzero(&fs, sizeof(struct nfsstatfs));
/* set up struct */
if (! file_freeblocks(fhp->f.fh_fsid, &(fs.fs_bfree),
&(fs.fs_blocks))) {
DBGPRT1 (nfserr, "statfs error %d", errno);
fs.fs_status = NFSERR_IO;
}
else {
fs.fs_tsize = NFS_MAXDATA;
fs.fs_bsize = FS_BLOCKSIZE;
fs.fs_status = NFS_OK;
fs.fs_bavail = fs.fs_bfree;
}
}
if (! svc_sendreply(xprt, xdr_statfs, &fs))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_STATFS: drive %d\n", fhp->f.fh_fsid);
svc_freeargs(xprt, xdr_fhandle, fhp);
}
/*
* void nfs_readdir(SVCXPRT *xprt, struct svc_req *req) --
* Read a directory.
*/
void nfs_readdir(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsrddirargs *args; /* args */
struct nfsrddirres res; /* results */
u_long nodeid; /* inode number */
static u_long offs; /* offset */
static int bytes; /* # of dir bytes read */
int maxbytes;
struct udirect *udp; /* directory cookie array */
#define SUD 32 /* increment for offsets */
static u_long prevfh_no; /* previous path handle */
static char prevudp[NFS_MAXDATA + sizeof (struct udirect)];
static u_long prevoffs; /* previous offset */
static int preveof; /* previous EOF flag */
args = (struct nfsrddirargs *) malloc(sizeof(struct nfsrddirargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfsrddirargs));
if (! svc_getargs(xprt, xdr_rddirargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
maxbytes = (args->rda_count > RD_SIZ ? RD_SIZ : args->rda_count);
if (maxbytes == 0)
maxbytes = RD_SIZ;
nodeid = args->rda_fh.f.fh_fno;
/* Check the validity of the file handle */
if (!checkfh (&args->rda_fh))
res.rd_status = NFSERR_STALE;
else {
/* clear out results */
(void) bzero(&res, sizeof(struct nfsrddirres)); /* zero results */
res.rd_bufsize = args->rda_count; /* size of clnt req */
res.rd_status = NFS_OK;
/* point to directory entries block */
res.rd_entries = (struct udirect *) prevudp;
udp = res.rd_entries;
/* see if this is an identical request */
if (args->rda_offset != 0L && args->rda_offset == prevoffs &&
prevfh_no == nodeid) {
res.rd_offset = offs;
res.rd_size = bytes;
res.rd_eof = preveof;
DBGPRT1 (nfsread, "READDIR (same %ld)", args->rda_offset);
}
else {
/* clear out the udp */
(void) bzero(prevudp, sizeof prevudp);
/* read until filled */
res.rd_eof = FALSE;
offs = args->rda_offset;
prevoffs = offs;
bytes = 0;
prevfh_no = nodeid;
while (bytes < maxbytes) {
int rstat; /* read status */
rstat = file_rddir(nodeid, offs, udp);
if (rstat == -1) { /* error reading */
res.rd_status = NFSERR_NOENT;
break;
}
/* space for more? */
if ((bytes + udp->d_reclen) <= maxbytes) {
bytes += udp->d_reclen;
/* Break out of loop if this is the last entry. */
if (rstat == 0) {
res.rd_eof = TRUE;
break;
}
/* Point to next entry */
udp = (struct udirect *) ((char *) udp + UDIRSIZ(udp));
offs += SUD; /* next offset */
}
else
break;
}
/* broke out of the loop */
if (res.rd_status == NFS_OK) { /* good read */
res.rd_offset = offs; /* next offset */
res.rd_size = bytes; /* # of bytes */
res.rd_bufsize = bytes + 128; /* Add enough extra for */
/* XDR routine */
}
preveof = res.rd_eof;
DBGPRT4 (nfsread, "READDIR offset = %ld..%ld, bytes = %d %s",
prevoffs / SUD, offs / SUD,
bytes, res.rd_eof ? "***EOF***" : "");
}
}
if (! svc_sendreply(xprt, xdr_putrddirres, &res))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_READDIR\n");
/* free space */
svc_freeargs(xprt, xdr_rddirargs, args);
#undef SUD
}
/*
* void nfs_lookup(SVCXPRT *xprt, struct svc_req *req) --
* Directory lookup.
*/
void nfs_lookup(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsdiropargs *args; /* arguments to call */
struct nfsdiropres res; /* and results */
struct nfsfattr attr; /* return attributes */
char *fullpath, path[MAXPATHNAMELEN]; /* path of file looked up */
args = (struct nfsdiropargs *) malloc(sizeof(struct nfsdiropargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfsdiropargs));
if (! svc_getargs(xprt, xdr_diropargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
/* Check the validity of the parent's handle */
if (!checkfh (&args->da_fhandle))
res.dr_status = NFSERR_STALE;
else {
/* clear out return struct */
(void) bzero(&res, sizeof(struct nfsdiropres));
fullpath = intopn(args->da_fhandle.f.fh_fno, path);/* path from */
/* inode of parent */
if (fullpath != NULL) {
/*
* extra code here to handle XCOPY's brain-damaged
* way of passing wildcards when it really shouldn't.
*/
int i;
int namelen;
namelen = strlen(args->da_name);
for(i = 0; i < namelen; i++) { /* scan the name */
if ((args->da_name)[i] == '*' ||
(args->da_name)[i] == '?') {
res.dr_status = NFSERR_NOENT;
goto end;
}
}
/* end of extra code */
if (strcmp(args->da_name, "..") == 0) { /* asking for parent */
fullpath = intopn(parentinode(
args->da_fhandle.f.fh_fno), path);
}
else if (strcmp(args->da_name , ".") != 0) {
(void) strcat(fullpath, "\\"); /* append seperator */
(void) strcat(fullpath, args->da_name);
(void) strtolower(fullpath); /* all lower case */
}
}
res.dr_status = validate_path (fullpath);
DBGPRT1 (nfslookup, "fullpath = %s", fullpath);
if (res.dr_status == NFS_OK) {
if ( ! file_getattr(fullpath, &attr)) {
DBGPRT0 (nfslookup, "no such file");
res.dr_status = NFSERR_NOENT;
}
else { /* copy the attributes over */
res.dr_attr = attr;
res.dr_status = NFS_OK; /* set proper status */
/* get a fhandle for it */
if (strcmp(args->da_name, ".") != 0)
res.dr_fhandle = pntofh(fullpath);
else
res.dr_fhandle = args->da_fhandle;
#if 1
{
/* Hack: tell the caller he is the owner */
struct authunix_parms *unix_cred;
unix_cred = (struct authunix_parms *) req->rq_clntcred;
res.dr_attr.na_uid = (u_long) unix_cred->aup_uid;
}
#endif
}
}
}
/* reply to caller */
end: if (NFS_VERBOSE)
(void) printf(">>> NFS_LOOKUP: %s\n", fullpath);
if (! svc_sendreply(xprt, xdr_diropres, &res))
(void) fprintf(stderr, reply_err);
/* free used space */
svc_freeargs(xprt, xdr_diropargs, args);
}
/*
* void nfs_write(SVCXPRT *xprt, struct svc_req *req) --
* Do an atomic write operation.
*/
void nfs_write(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfswriteargs *args; /* args */
struct nfsattrstat res; /* return stat */
/* alloc space for args */
args = (struct nfswriteargs *) malloc(sizeof(struct nfswriteargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfswriteargs));
if (! svc_getargs(xprt, xdr_writeargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
if (NFS_READONLYFS) {
nfserr_readonlyfs(xprt, xdr_writeargs, args);
return;
}
(void) bzero(&res, sizeof(struct nfsattrstat));
/* evaluate buffer count argument */
if (args->wa_count > NFS_MAXDATA) {
res.ns_status = NFSERR_IO;
goto reply;
}
res.ns_status = file_write(args->wa_fhandle.f.fh_fno, args->wa_offset,
args->wa_count, args->wa_data);
if (res.ns_status == NFS_OK) {
/* get file attributes */
if (inattrget (args->wa_fhandle.f.fh_fno, &res.ns_attr) ==
(struct nfsfattr *) NULL) {
res.ns_status = NFSERR_STALE;
}
}
else
DBGPRT2 (nfserr, "write %ld, error %d",
args->wa_fhandle.f.fh_fno, res.ns_status);
reply:
if (! svc_sendreply(xprt, xdr_attrstat, &res))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_WRITE: %ld\n",
args->wa_fhandle.f.fh_fno);
svc_freeargs(xprt, xdr_writeargs, args); /* free all data */
}
/*
* void nfs_create(SVCXPRT *xprt, struct svc_req *req) --
* Create a file.
*/
void nfs_create(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfscreatargs *args; /* create args */
struct nfsdiropres res; /* return result */
char *fullpath, path[MAXPATHNAMELEN]; /* full name */
int stat; /* create return stat */
struct authunix_parms *unix_cred;
args = (struct nfscreatargs *) malloc(sizeof(struct nfscreatargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfscreatargs));
if (! svc_getargs(xprt, xdr_creatargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
if (NFS_READONLYFS) { /* read only file system */
nfserr_readonlyfs(xprt, xdr_creatargs, args);
return;
}
/* Check the validity of the file handle */
if (!checkfh (&args->ca_da.da_fhandle))
res.dr_status = NFSERR_STALE;
else {
/* clear out return struct */
(void) bzero(&res, sizeof(struct nfsdiropres));
fullpath = intopn(args->ca_da.da_fhandle.f.fh_fno, path);
if (fullpath != NULL) {
(void) strcat(fullpath, "\\"); /* make rest of name */
(void) strcat(fullpath, args->ca_da.da_name);
(void) strtolower (fullpath); /* force lower case */
}
if (file_getattr(fullpath, &(res.dr_attr))) { /* file exists */
res.dr_status = NFSERR_EXIST;
}
/* fill in default UID/GID info */
unix_cred = (struct authunix_parms *) req->rq_clntcred;
if (args->ca_sa.sa_uid == -1)
args->ca_sa.sa_uid = (u_long) unix_cred->aup_uid;
if (args->ca_sa.sa_gid == -1)
args->ca_sa.sa_gid = (u_long) unix_cred->aup_gid;
/* create a file */
res.dr_status = file_create(fullpath, &(args->ca_sa), &res.dr_attr);
if (res.dr_status == NFS_OK) { /* no errors */
/* make file handle */
res.dr_fhandle = pntofh(fullpath);
}
}
if (! svc_sendreply(xprt, xdr_diropres, &res))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_CREATE: %s\n", fullpath);
/* free all data */
svc_freeargs(xprt, xdr_creatargs, args);
}
/*
* void nfs_mkdir(SVCXPRT *xprt, struct svc_req *req) --
* Make a directory request. All DOS directories are readable and
* writeable, hence the set attribute field is ignored.
*/
void nfs_mkdir(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfscreatargs *args;
struct nfsdiropres res;
char *fullpath, path[MAXPATHNAMELEN];
args = (struct nfscreatargs *) malloc(sizeof(struct nfscreatargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfscreatargs));
if (! svc_getargs(xprt, xdr_diropargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
if (NFS_READONLYFS) {
nfserr_readonlyfs(xprt, xdr_diropargs, args);
return;
}
/* construct path name of new directory */
fullpath = intopn(args->ca_da.da_fhandle.f.fh_fno, path);
if (fullpath != NULL) {
(void) strcat(fullpath, "\\");
(void) strcat(fullpath, args->ca_da.da_name);
(void) strtolower (fullpath); /* force lower case */
}
(void) bzero(&res, sizeof(struct nfsdiropres));
/* validate path name */
if ((res.dr_status = validate_path (fullpath)) == NFS_OK)
res.dr_status = mkdir(fullpath);
if (res.dr_status == NFS_OK) {
res.dr_status = !file_getattr(fullpath, &(res.dr_attr));
if (res.dr_status == NFS_OK) /* make new file handle */
res.dr_fhandle = pntofh(fullpath);
else
res.dr_status = puterrno(errno);
}
if (! svc_sendreply(xprt, xdr_diropres, &res))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_MKDIR: %s\n", fullpath);
/* free all data */
svc_freeargs(xprt, xdr_creatargs, args);
}
/*
* void nfs_remove(SVCXPRT *xprt, struct svc_req *req) --
* Remove a file specified by the handle.
*/
void nfs_remove(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsdiropargs *args; /* dir op arguments */
enum nfsstat stat; /* status of the remove */
char *fullpath, path[MAXPATHNAMELEN]; /* full path of file */
args = (struct nfsdiropargs *) malloc(sizeof(struct nfsdiropargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfsdiropargs)); /* zero it */
if (! svc_getargs(xprt, xdr_diropargs, args)) {
svcerr_decode(xprt);
(void) free(args); /* couldn't decode it */
return;
}
if (NFS_READONLYFS) {
nfserr_readonlyfs(xprt, xdr_diropargs, &args);
return;
}
/* get full directory name from inode number */
fullpath = intopn(args->da_fhandle.f.fh_fno, path);
if (fullpath == NULL)
stat = NFSERR_NOENT;
else {
(void) strcat(fullpath, "\\"); /* append the name */
(void) strcat(fullpath, args->da_name);
stat = file_unlink(fullpath);
}
/* now reply to request */
if (! svc_sendreply(xprt, xdr_enum, &stat))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_REMOVE: %s\n", fullpath);
svc_freeargs(xprt, xdr_diropargs, args);
}
/*
* void nfs_rmdir(SVCXPRT *xprt, struct svc_req *req) --
* Remove a directory specified by the handle.
*/
void nfs_rmdir(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsdiropargs *args; /* dir op arguments */
enum nfsstat stat; /* status of the remove */
char *fullpath, path[MAXPATHNAMELEN]; /* full path of file */
u_long node;
args = (struct nfsdiropargs *) malloc(sizeof(struct nfsdiropargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfsdiropargs)); /* zero it */
if (! svc_getargs(xprt, xdr_diropargs, args)) {
svcerr_decode(xprt);
(void) free(args); /* couldn't decode it */
return;
}
/* get full path name from inode number */
fullpath = intopn(args->da_fhandle.f.fh_fno, path);
if (fullpath == NULL)
stat = NFSERR_NOENT; /* doesn't exist */
else {
(void) strcat(fullpath, "\\"); /* append the name */
(void) strcat(fullpath, args->da_name);
if (rmdir(fullpath)) { /* remove it */
stat = (enum nfsstat) errno;
/* Translate the error code so the correct message */
/* will be displayed. */
if (stat == NFSERR_ACCES)
stat = NFSERR_EXIST;
}
else {
stat = NFS_OK;
/* Remove the inode if assigned */
if ((node = pntoin (fullpath)) != -1)
inremnode (node);
}
}
/* now reply to request */
if (! svc_sendreply(xprt, xdr_enum, &stat))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_RMDIR: %s\n", fullpath);
svc_freeargs(xprt, xdr_diropargs, args); /* free data */
}
/*
* void nfs_rename(SVCXPRT *xprt, struct svc_req *req) --
* Renames given file to new name specified in the args.
*/
void nfs_rename(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsrnmargs *args; /* arguments to rename */
enum nfsstat stat; /* thr reply status */
char *oldname, *newname, /* old and new filenames */
opath[MAXPATHNAMELEN], npath[MAXPATHNAMELEN];
args = (struct nfsrnmargs *) malloc(sizeof(struct nfsrnmargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfsrnmargs));
if (! svc_getargs(xprt, xdr_rnmargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
if (NFS_READONLYFS) {
nfserr_readonlyfs(xprt, xdr_rnmargs, args);
return;
}
/* make old name from inode */
oldname = intopn(args->rna_from.da_fhandle.f.fh_fno, opath);
newname = intopn(args->rna_to.da_fhandle.f.fh_fno, npath);
if (oldname == NULL || newname == NULL) /* cannot find path for file */
stat = NFSERR_STALE; /* ==> stale file handle */
else {
/* complete specification for names */
(void) strcat(oldname, "\\");
(void) strcat(oldname, args->rna_from.da_name);
(void) strcat(newname, "\\");
(void) strcat(newname, args->rna_to.da_name);
/* Perform the rename operation */
stat = file_rename(oldname, newname);
}
/* reply to rename request */
if (! svc_sendreply(xprt, xdr_enum, &stat))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) fprintf(stderr, ">>> NFS_RENAME: %s to %s\n",
oldname, newname);
/* free all data */
svc_freeargs(xprt, xdr_rnmargs, args);
}
/*
* void nfs_setattr(SVCXPRT *xprt, struct svc_req *req) --
* Set file attributes.
*/
void nfs_setattr(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfssaargs *args; /* arguments */
struct nfsattrstat res; /* results */
args = (struct nfssaargs *) malloc(sizeof(struct nfssaargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfssaargs));
if (! svc_getargs(xprt, xdr_saargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
DBGPRT4 (nfsdebug, "SETATTR: size = %ld mode = %o%05o time = %ld",
args->saa_sa.sa_size, (int) (args->saa_sa.sa_mode >> 15),
(int) args->saa_sa.sa_mode & 077777,
args->saa_sa.sa_mtime.tv_sec);
if (NFS_READONLYFS) {
nfserr_readonlyfs(xprt, xdr_saargs, args);
return;
}
/* If a parameter in the argument block is not -1, set the */
/* parameter within the file. */
/* File mode / protection */
res.ns_status = NFS_OK;
if (args->saa_sa.sa_mode != -1)
res.ns_status = file_setperm(args->saa_fh.f.fh_fno,
args->saa_sa.sa_mode);
/* Modification time */
if (res.ns_status == NFS_OK && args->saa_sa.sa_mtime.tv_sec > 0)
res.ns_status = file_settime(args->saa_fh.f.fh_fno,
args->saa_sa.sa_mtime.tv_sec);
/* Size */
if (res.ns_status == NFS_OK && args->saa_sa.sa_size != -1)
res.ns_status = file_setsize(args->saa_fh.f.fh_fno,
args->saa_sa.sa_size);
/* User ID / Group ID */
if (res.ns_status == NFS_OK && (args->saa_sa.sa_uid != -1 ||
args->saa_sa.sa_gid != -1))
res.ns_status = file_setowner(args->saa_fh.f.fh_fno,
args->saa_sa.sa_uid, args->saa_sa.sa_gid);
(void) bzero(&res, sizeof(struct nfsattrstat));
if (res.ns_status == NFS_OK &&
!inattrget (args->saa_fh.f.fh_fno, &res.ns_attr)) {
res.ns_status = NFSERR_NOENT;
}
if (! svc_sendreply(xprt, xdr_attrstat, &res))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) printf(">>> NFS_SETATTR\n");
/* free data */
svc_freeargs(xprt, xdr_saargs, args);
}
/*
* void nfs_link(SVCXPRT *xprt, struct svc_req *req) --
* Create file link (not supported under DOS)
*/
void nfs_link(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfslinkargs *args; /* arguments to link */
struct nfsdiropres res; /* return result */
enum nfsstat stat; /* the reply status */
char *oldname, *newname, /* old and new filenames */
opath[MAXPATHNAMELEN], npath[MAXPATHNAMELEN];
args = (struct nfslinkargs *) malloc(sizeof(struct nfslinkargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfslinkargs));
(void) bzero(&res, sizeof(struct nfsdiropres));
if (! svc_getargs(xprt, xdr_linkargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
if (NFS_READONLYFS) {
nfserr_readonlyfs(xprt, xdr_linkargs, args);
return;
}
/* Translate inodes into names */
oldname = intopn(args->la_from.f.fh_fno, opath);
newname = intopn(args->la_to.da_fhandle.f.fh_fno, npath);
if (oldname == NULL || newname == NULL) /* cannot find path for file */
stat = NFSERR_STALE; /* ==> stale file handle */
else {
/* not supported: return an error code */
stat = NFSERR_ACCES;
}
res.dr_status = stat;
if (! svc_sendreply(xprt, xdr_diropres, &res))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) fprintf(stderr, ">>> NFS_LINK: %s to %s\n",
oldname, newname);
svc_freeargs(xprt, xdr_linkargs, args);
}
/*
* void nfs_symlink(SVCXPRT *xprt, struct svc_req *req) --
* Create symbolic link (not supported under DOS)
*/
void nfs_symlink(xprt, req)
SVCXPRT *xprt;
struct svc_req *req;
{
struct nfsslargs *args; /* arguments to sym link */
struct nfsrdlnres res; /* return result */
enum nfsstat stat; /* the reply status */
char *oldname, opath[MAXPATHNAMELEN]; /* old filename */
args = (struct nfsslargs *) malloc(sizeof(struct nfsslargs));
if (args == NULL) {
(void) fprintf(stderr, mem_err);
abort();
}
(void) bzero(args, sizeof(struct nfsslargs));
(void) bzero(&res, sizeof(struct nfsrdlnres));
if (! svc_getargs(xprt, xdr_slargs, args)) {
svcerr_decode(xprt);
(void) free(args);
return;
}
/* Translate inode into name */
oldname = intopn(args->sla_from.da_fhandle.f.fh_fno, opath);
if (oldname == NULL) /* cannot find path for file */
stat = NFSERR_STALE; /* ==> stale file handle */
else {
/* not supported: return an error code */
stat = NFSERR_ACCES;
}
res.rl_status = stat;
if (! svc_sendreply(xprt, xdr_rdlnres, &res))
(void) fprintf(stderr, reply_err);
else if (NFS_VERBOSE)
(void) fprintf(stderr, ">>> NFS_SYMLINK\n");
svc_freeargs(xprt, xdr_linkargs, args);
}
/*
* void nfserr_readonlyfs(SVCXPRT *xprt, xdrproc_t xproc, void *args) --
* Return error status of NFSERR_ROFS. Write attempted on read only
* file system.
*/
void nfserr_readonlyfs(xprt, xproc, args)
SVCXPRT *xprt;
xdrproc_t xproc;
void *args;
{
enum nfsstat err;
err = NFSERR_ROFS;
if (! svc_sendreply(xprt, xdr_enum, &err))
(void) fprintf(stderr, reply_err);
svc_freeargs(xprt, xproc, args);
}