home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / SOSS31.ZIP / SRC / NFS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-13  |  30.8 KB  |  1,062 lines

  1. /*
  2.  *  nfs.c --
  3.  *      NFS server implementation for PC.  Runs on top of the
  4.  *      net daemon (netd.c).
  5.  *
  6.  *  Author:
  7.  *      See-Mong Tan, 6/12/88.
  8.  *  Modified by:
  9.  *    Rich Braun @ Kronos, 2/15/91
  10.  *
  11.  *  Revision history:
  12.  *  
  13.  * $Log: nfs.c_v $
  14.  * Revision 1.6  1991/05/13  17:45:56  richb
  15.  * Correct the NFS_STATFS call so it doesn't return an error if there
  16.  * are 0 free blocks in a filesystem.
  17.  * Add support for '-b' command line option so the administrator can
  18.  * specify read/write block sizes.
  19.  *
  20.  * Revision 1.5  1991/04/11  20:41:26  richb
  21.  * Validate pathnames before invoking pntoin, to prevent crashes.
  22.  *
  23.  * Revision 1.4  1991/03/15  22:41:19  richb
  24.  * Numerous patches.
  25.  *
  26.  * Revision 1.3  1991/02/20  19:15:39  richb
  27.  * Minor changes for file_create; add RCS headers.
  28.  *
  29.  */
  30.  
  31. #ifdef RCSID
  32. static char _rcsid_ = "$Id: nfs.c_v 1.6 1991/05/13 17:45:56 richb Exp $";
  33. #endif
  34.  
  35. #include "common.h"
  36. #include "msc-dos.h"        /* dos and ... */
  37. #include <direct.h>        /* directory ops */
  38. #include "..\rpc\a_unix.h"
  39.  
  40. static char *reply_err = "RPC error:  cannot transmit\n";
  41. static char *mem_err   = "malloc:  no more memory\n";
  42.  
  43. /*
  44.  *  bool_t nfs_init() --
  45.  *      Initializes NFS server.  Creates and registers transport
  46.  *      handle for NFS server.  Returns TRUE if successful, or FALSE
  47.  *      if an error occurred.
  48.  */
  49. bool_t nfs_init()
  50. {
  51.     SVCXPRT *transp;
  52.     int nfs_sock;
  53.     struct sockaddr_in addr;
  54.     static void nfs_dispatch(struct svc_req *, SVCXPRT *);
  55.  
  56.     addr.sin_family = AF_INET;
  57.     addr.sin_port = htons(NFS_PORT);
  58.     addr.sin_addr.s_addr = INADDR_ANY;
  59.     if ((nfs_sock = sock_create(SOCK_DGRAM, IPPROTO_UDP, &addr)) < 0) {
  60.         (void) fprintf(stderr, "cannot create nfs socket\n");
  61.         return FALSE;
  62.     }
  63.     if ((transp = svcudp_create(nfs_sock, 1)) == (SVCXPRT *) NULL) {
  64.         (void) fprintf(stderr, "cannot create udp handle\n");
  65.         sock_close(nfs_sock);
  66.         return FALSE;
  67.     }
  68.     if (! svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_dispatch, 
  69.                IPPROTO_UDP)) {
  70.         (void) fprintf(stderr, "cannot register handle\n");
  71.         sock_close(nfs_sock);
  72.         return FALSE;
  73.     }
  74.  
  75.     return TRUE;
  76. }
  77.  
  78. /*
  79.  *  void nfs_dispatch(struct svc_req *req, SVCXPRT *transp) --
  80.  *      NFS server dispatch routine.
  81.  */
  82. static void nfs_dispatch(req, transp)
  83.      struct svc_req *req;
  84.      SVCXPRT *transp;
  85. {
  86. #if DEBUG
  87. static char *names[] = {"NULL", "GETATTR", "SETATTR", "ROOT", "LOOKUP",
  88.             "READLINK", "READ", "WRITECACHE", "WRITE", "CREATE",
  89.             "REMOVE", "RENAME", "LINK", "SYMLINK", "MKDIR",
  90.             "RMDIR", "READDIR", "STATFS", "<invalid>"};
  91.     DBGPRT1 (nfsdisp, ">>> NFS_%s", names[(req->rq_proc > NFS_STATFS) ?
  92.                   NFS_STATFS+1 : req->rq_proc]);
  93. #endif
  94.  
  95.     /* find which procedure to call */
  96.     switch((int) req->rq_proc) {    
  97.  
  98.       case NFS_GETATTR: nfs_getattr(transp, req);    break;
  99.       case NFS_NULL:    nfs_null(transp, req);        break;
  100.       case NFS_READ:    nfs_read(transp, req);        break;
  101.       case NFS_WRITE:    nfs_write(transp, req);        break;
  102.       case NFS_STATFS:    nfs_statfs(transp, req);    break;
  103.       case NFS_LOOKUP:    nfs_lookup(transp, req);    break;
  104.       case NFS_READDIR:    nfs_readdir(transp, req);    break;
  105.       case NFS_CREATE:    nfs_create(transp, req);    break;
  106.       case NFS_MKDIR:    nfs_mkdir(transp, req);        break;
  107.       case NFS_REMOVE:    nfs_remove(transp, req);    break;
  108.       case NFS_RMDIR:    nfs_rmdir(transp, req);        break;
  109.       case NFS_RENAME:    nfs_rename(transp, req);    break;
  110.       case NFS_SETATTR:    nfs_setattr(transp, req);    break;
  111.       case NFS_LINK:    nfs_link(transp, req);        break;
  112.       case NFS_SYMLINK:    nfs_symlink(transp, req);    break;
  113.       default:
  114.     DBGPRT1 (nfsdisp, "unsupp procedure %d",
  115.          req->rq_proc);
  116.     nfs_error(transp, req);
  117.     break;
  118.     }
  119. }
  120.  
  121. /*
  122.  *  void nfs_null(SVCXPRT *xprt, struct svc_req *req) --
  123.  *      Sends an empty reply.  Used for "ping-ing" the nfs server.
  124.  */
  125. void nfs_null(xprt, req)
  126.     SVCXPRT *xprt;
  127.     struct svc_req *req;
  128. {
  129.     if (! svc_sendreply(xprt, xdr_void, (char *) NULL))
  130.         (void) fprintf(stderr, reply_err);
  131. }
  132.  
  133. /*
  134.  *  void nfs_read(SVCXPRT *xprt, struct svc_req *req) --
  135.  *      Reads requested file and sends it over the wire.
  136.  */
  137. void nfs_read(xprt, req)
  138.     SVCXPRT *xprt;
  139.     struct svc_req *req;
  140. {
  141.     struct nfsreadargs *r_args;        /* the argument */
  142.     struct nfsrdresult r_rslt;        /* the read result */
  143.     char   databuf [NFS_MAXDATA];
  144.     u_long count;            /* request size */
  145.     int    bytes;            /* bytes read */
  146.  
  147.     r_args = (struct nfsreadargs *) malloc(sizeof(struct nfsreadargs));
  148.     if (r_args == NULL) {
  149.     (void) fprintf(stderr, mem_err);
  150.     abort();
  151.     }
  152.     (void) bzero(r_args, sizeof(struct nfsreadargs));
  153.     if (! svc_getargs(xprt, xdr_readargs, r_args)) {
  154.     svcerr_decode(xprt);
  155.     (void) free(r_args);
  156.     return;
  157.     }
  158.     (void) bzero(&r_rslt, sizeof(struct nfsrdresult));
  159.  
  160.     /* set pointer to data in results struct */
  161.     r_rslt.rr_data = databuf;
  162.     count = r_args->ra_count;
  163.  
  164.     /* evaluate buffer count argument */
  165.     if (count > nfsrd_size) {
  166.     count = nfsrd_size;
  167.     fprintf (stderr, "NFS_READ: truncating req. from %ld\n",
  168.          r_args->ra_count);
  169.     }
  170.  
  171.     /* get attributes */
  172.     if (inattrget (r_args->ra_fhandle.f.fh_fno, &r_rslt.rr_attr) ==
  173.     (struct nfsfattr *) NULL)
  174.       r_rslt.rr_status = NFSERR_STALE;
  175.     else  {
  176.     if ((bytes = file_read(r_args->ra_fhandle.f.fh_fno,
  177.                    r_args->ra_offset, count,
  178.                    r_rslt.rr_data)) == -1) {
  179.         DBGPRT1 (nfserr, "file_read error %d", errno);
  180.         r_rslt.rr_status = puterrno (errno);
  181.     }
  182.     else {
  183.         char name [MAXPATHNAMELEN];
  184.         DBGPRT4 (nfsread, "%s: %ld/%d bytes at %ld",
  185.              intopn (r_args->ra_fhandle.f.fh_fno, name),
  186.              r_args->ra_count, bytes, r_args->ra_offset);
  187.         r_rslt.rr_bufsize = nfsrd_size;
  188.         r_rslt.rr_count = bytes;
  189.         r_rslt.rr_status = NFS_OK;
  190.         r_rslt.rr_bp = NULL;
  191.         r_rslt.rr_vp = NULL;
  192.     }
  193.     }
  194.     if (! svc_sendreply(xprt, xdr_rdresult, &r_rslt))
  195.       (void) fprintf(stderr, reply_err);
  196.     else if (NFS_VERBOSE)
  197.       (void) printf(">>> NFS_READ\n");
  198.  
  199.     /* free arguments */    
  200.     svc_freeargs(xprt, xdr_readargs, r_args);
  201. }
  202.  
  203. /*
  204.  *  void nfs_error(SVCXPRT *xprt, struct svc_req *req) --
  205.  *      Returns nfs error message.
  206.  */
  207. void nfs_error(xprt, req)
  208.     SVCXPRT *xprt;
  209.     struct svc_req *req;
  210. {
  211.     (void) fprintf(stderr, 
  212.         ">>> NFS_ERROR: procedure %d not supported\n", req->rq_proc);
  213.     svcerr_noproc(xprt);        /* send server error reply msg */
  214. }
  215.  
  216. /*
  217.  *  void nfs_getattr(SVCXPRT *xprt, struct svc_req *req) --
  218.  *      Gets file attributes.
  219.  */
  220. void nfs_getattr(xprt, req)
  221.     SVCXPRT *xprt;
  222.     struct svc_req *req;
  223. {
  224.     fhandle_t *fhp;            /* file handle is argument */
  225.     struct nfsattrstat attr;    /* return attributes */    
  226.     char *fullpath, path[MAXPATHNAMELEN];    /* full DOS path name */
  227.  
  228.     fhp = (fhandle_t *) malloc(sizeof(fhandle_t));
  229.     if (fhp == NULL) {
  230.     (void) fprintf(stderr, mem_err);
  231.     abort();
  232.     }
  233.     (void) bzero(fhp, sizeof(fhandle_t));
  234.     if (! svc_getargs(xprt, xdr_fhandle, fhp)) {
  235.     (void) fprintf(stderr, "nfs_getattr: cannot read args\n");
  236.     svcerr_decode(xprt);
  237.     (void) free(fhp);
  238.     return;
  239.     }
  240.  
  241.     /* Check the validity of the file handle */
  242.     if (!checkfh (fhp))
  243.       attr.ns_status = NFSERR_STALE;
  244.     else {
  245.     /* clear out return attributes */
  246.     (void) bzero(&attr, sizeof(struct nfsattrstat));
  247.     fullpath = intopn(fhp->f.fh_fno, path);    /* path from inode */
  248.  
  249.     if (! file_getattr(fullpath, &(attr.ns_attr)))
  250.       attr.ns_status = NFSERR_NOENT;
  251.     else
  252.       attr.ns_status = NFS_OK;
  253.     }
  254. #if 1
  255.     {
  256.       /* Hack:  tell the caller he is the owner */
  257.       struct authunix_parms *unix_cred;
  258.       unix_cred = (struct authunix_parms *) req->rq_clntcred;
  259.       attr.ns_attr.na_uid =  (u_long) unix_cred->aup_uid;
  260.     }
  261. #endif
  262.  
  263.     if (! svc_sendreply(xprt, xdr_attrstat, &attr))
  264.       (void) fprintf(stderr, reply_err);
  265.     else if (NFS_VERBOSE)
  266.       (void) printf(">>> NFS_GETATTR: %s\n", fullpath);
  267.  
  268.     svc_freeargs(xprt, xdr_fhandle, fhp);
  269. }
  270.  
  271. /*
  272.  *  void nfs_statfs(SVCXPRT *xprt, struct svc_req *req) --
  273.  *      Returns file system status
  274.  */
  275. void nfs_statfs(xprt, req)
  276.     SVCXPRT *xprt;
  277.     struct svc_req *req;
  278. {
  279.     struct nfsstatfs fs;
  280.     fhandle_t *fhp;
  281.  
  282.     fhp = (fhandle_t *) malloc(sizeof(fhandle_t));
  283.     if (fhp == NULL) {
  284.     (void) fprintf(stderr, mem_err);
  285.     abort();
  286.     }
  287.     (void) bzero(fhp, sizeof(fhandle_t));
  288.     if (! svc_getargs(xprt, xdr_fhandle, fhp)) {
  289.     svcerr_decode(xprt);
  290.     (void) free(fhp);
  291.     return;
  292.     }
  293.  
  294.     /* Check the validity of the file handle */
  295.     if (!checkfh (fhp))
  296.       fs.fs_status = NFSERR_STALE;
  297.     else {
  298.     /* clear out results struct */
  299.     (void) bzero(&fs, sizeof(struct nfsstatfs));
  300.     /* set up struct */
  301.     if (file_freeblocks(fhp->f.fh_fsid, &(fs.fs_bfree), 
  302.                   &(fs.fs_blocks)) != 0) {
  303.         DBGPRT1 (nfserr, "statfs error %d", errno);
  304.         fs.fs_status = NFSERR_IO;
  305.     }
  306.     else {
  307.         fs.fs_tsize = NFS_MAXDATA;
  308.         fs.fs_bsize = FS_BLOCKSIZE;
  309.         fs.fs_status = NFS_OK;
  310.         fs.fs_bavail = fs.fs_bfree;
  311.     }
  312.     }
  313.     if (! svc_sendreply(xprt, xdr_statfs, &fs))
  314.       (void) fprintf(stderr, reply_err);
  315.     else if (NFS_VERBOSE)
  316.       (void) printf(">>> NFS_STATFS: drive %d\n", fhp->f.fh_fsid);
  317.     svc_freeargs(xprt, xdr_fhandle, fhp);
  318. }
  319.  
  320. /*
  321.  *  void nfs_readdir(SVCXPRT *xprt, struct svc_req *req) --
  322.  *      Read a directory.
  323.  */
  324. void nfs_readdir(xprt, req)
  325.     SVCXPRT *xprt;
  326.     struct svc_req *req;
  327. {
  328.     struct nfsrddirargs *args;        /* args */
  329.     struct nfsrddirres res;            /* results */
  330.     u_long nodeid;                /* inode number */
  331.     static u_long offs;                /* offset */
  332.     static int bytes;                /* # of dir bytes read */
  333.     int maxbytes;
  334.     struct udirect *udp;            /* directory cookie array */
  335. #define SUD    32                /* increment for offsets */
  336.     static u_long prevfh_no;            /* previous path handle */
  337.     static char prevudp[NFS_MAXDATA + sizeof (struct udirect)];
  338.     static u_long prevoffs;            /* previous offset */
  339.     static int  preveof;            /* previous EOF flag */
  340.  
  341.     args = (struct nfsrddirargs *) malloc(sizeof(struct nfsrddirargs));
  342.     if (args == NULL) {
  343.     (void) fprintf(stderr, mem_err);
  344.     abort();
  345.     }
  346.     (void) bzero(args, sizeof(struct nfsrddirargs));
  347.     if (! svc_getargs(xprt, xdr_rddirargs, args)) {
  348.     svcerr_decode(xprt);
  349.     (void) free(args);
  350.     return;
  351.     }
  352.     maxbytes = (args->rda_count > nfsrd_size ? nfsrd_size : args->rda_count);
  353.     if (maxbytes == 0)
  354.       maxbytes = nfsrd_size;
  355.  
  356.     nodeid   = args->rda_fh.f.fh_fno;
  357.  
  358.     /* Check the validity of the file handle */
  359.     if (!checkfh (&args->rda_fh))
  360.       res.rd_status = NFSERR_STALE;
  361.  
  362.     else {
  363.     /* clear out results */
  364.     (void) bzero(&res, sizeof(struct nfsrddirres));    /* zero results */
  365.     res.rd_bufsize = args->rda_count;             /* size of clnt req */
  366.     res.rd_status  = NFS_OK;
  367.  
  368.     /* point to directory entries block */
  369.     res.rd_entries = (struct udirect *) prevudp;
  370.     udp = res.rd_entries;
  371.  
  372.     /* see if this is an identical request */
  373.     if (args->rda_offset != 0L && args->rda_offset == prevoffs &&
  374.           prevfh_no == nodeid) {
  375.         res.rd_offset = offs;
  376.         res.rd_size   = bytes;
  377.         res.rd_eof    = preveof;
  378.         DBGPRT1 (nfsread, "READDIR (same %ld)", args->rda_offset);
  379.     }
  380.     else {
  381.         /* clear out the udp */
  382.         (void) bzero(prevudp, sizeof prevudp);
  383.  
  384.         /* read until filled */
  385.         res.rd_eof    = FALSE;
  386.         offs          = args->rda_offset;
  387.         prevoffs      = offs;
  388.         bytes          = 0;
  389.         prevfh_no     = nodeid;
  390.  
  391.         while (bytes < maxbytes) {
  392.         int rstat;        /* read status */
  393.  
  394.         rstat = file_rddir(nodeid, offs, udp);
  395.         if (rstat == -1) {            /* error reading */
  396.             res.rd_status = NFSERR_NOENT;
  397.             break;
  398.         }
  399.  
  400.         /* space for more? */
  401.         if ((bytes + udp->d_reclen) <= maxbytes) {
  402.             bytes += udp->d_reclen;
  403.  
  404.             /* Break out of loop if this is the last entry. */
  405.             if (rstat == 0) {
  406.             res.rd_eof = TRUE;
  407.             break;
  408.             }
  409.  
  410.             /* Point to next entry */
  411.             udp = (struct udirect *) ((char *) udp + UDIRSIZ(udp));
  412.             offs += SUD;            /* next offset */
  413.         }
  414.         else
  415.           break;
  416.         }
  417.         /* broke out of the loop */
  418.         if (res.rd_status == NFS_OK) {        /* good read */
  419.         res.rd_offset = offs;        /* next offset */
  420.         res.rd_size = bytes;        /* # of bytes */
  421.         res.rd_bufsize = bytes + 128;   /* Add enough extra for */
  422.                         /* XDR routine */
  423.         }
  424.         preveof = res.rd_eof;
  425.         DBGPRT4 (nfsread, "READDIR offset = %ld..%ld, bytes = %d  %s",
  426.              prevoffs / SUD, offs / SUD,
  427.              bytes, res.rd_eof ? "***EOF***" : "");
  428.     }
  429.     }
  430.  
  431.     if (! svc_sendreply(xprt, xdr_putrddirres, &res))
  432.       (void) fprintf(stderr, reply_err);
  433.     else if (NFS_VERBOSE)
  434.       (void) printf(">>> NFS_READDIR\n");
  435.  
  436.     /* free space */
  437.     svc_freeargs(xprt, xdr_rddirargs, args);
  438. #undef SUD
  439. }
  440.  
  441. /*
  442.  *  void nfs_lookup(SVCXPRT *xprt, struct svc_req *req) --
  443.  *      Directory lookup.
  444.  */
  445. void nfs_lookup(xprt, req)
  446.     SVCXPRT *xprt;
  447.     struct svc_req *req;
  448. {
  449.     struct nfsdiropargs *args;    /* arguments to call */
  450.     struct nfsdiropres res;        /* and results */
  451.     struct nfsfattr attr;        /* return attributes */
  452.     char *fullpath, path[MAXPATHNAMELEN]; /* path of file looked up */
  453.     
  454.     args = (struct nfsdiropargs *) malloc(sizeof(struct nfsdiropargs));
  455.     if (args == NULL) {
  456.         (void) fprintf(stderr, mem_err);
  457.         abort();
  458.     }
  459.     (void) bzero(args, sizeof(struct nfsdiropargs));
  460.     if (! svc_getargs(xprt, xdr_diropargs, args)) {
  461.         svcerr_decode(xprt);
  462.         (void) free(args);
  463.         return;
  464.     }
  465.  
  466.     /* Check the validity of the parent's handle */
  467.     if (!checkfh (&args->da_fhandle))
  468.       res.dr_status = NFSERR_STALE;
  469.     else {
  470.         /* clear out return struct */
  471.         (void) bzero(&res, sizeof(struct nfsdiropres));
  472.         fullpath = intopn(args->da_fhandle.f.fh_fno, path);/* path from */
  473.                                 /* inode of parent */
  474.         if (fullpath != NULL) {
  475.         /* 
  476.          * extra code here to handle XCOPY's brain-damaged
  477.          * way of passing wildcards when it really shouldn't.
  478.          */
  479.         int i;
  480.         int namelen;
  481.  
  482.         namelen = strlen(args->da_name);
  483.         for(i = 0; i < namelen; i++) {     /* scan the name */
  484.             if ((args->da_name)[i] == '*' || 
  485.                 (args->da_name)[i] == '?') {
  486.                 res.dr_status = NFSERR_NOENT;
  487.                 goto end;
  488.             }
  489.         }
  490.         /* end of extra code */
  491.         
  492.         if (strcmp(args->da_name, "..") == 0) {    /* asking for parent */
  493.             fullpath = intopn(parentinode(
  494.                     args->da_fhandle.f.fh_fno), path);
  495.         }
  496.         else if (strcmp(args->da_name , ".") != 0) {
  497.             (void) strcat(fullpath, "\\");    /* append seperator */
  498.             (void) strcat(fullpath, args->da_name);    
  499.             (void) strtolower(fullpath);    /* all lower case */
  500.         }
  501.         }
  502.         res.dr_status = validate_path (fullpath);
  503.  
  504.         DBGPRT1 (nfslookup, "fullpath = %s", fullpath);
  505.  
  506.         if (res.dr_status == NFS_OK) {
  507.         if ( ! file_getattr(fullpath, &attr)) {
  508.             DBGPRT0 (nfslookup, "no such file");
  509.             res.dr_status = NFSERR_NOENT;
  510.         }
  511.         else {        /* copy the attributes over */
  512.             res.dr_attr = attr;
  513.             res.dr_status = NFS_OK;        /* set proper status */
  514.             /* get a fhandle for it */
  515.             if (strcmp(args->da_name, ".") != 0)
  516.               res.dr_fhandle = pntofh(fullpath);
  517.             else
  518.               res.dr_fhandle = args->da_fhandle;
  519. #if 1
  520.             {
  521.             /* Hack:  tell the caller he is the owner */
  522.             struct authunix_parms *unix_cred;
  523.             unix_cred = (struct authunix_parms *) req->rq_clntcred;
  524.             res.dr_attr.na_uid =  (u_long) unix_cred->aup_uid;
  525.             }
  526. #endif
  527.         }
  528.         }
  529.     }
  530.     /* reply to caller */
  531. end:    if (NFS_VERBOSE)
  532.         (void) printf(">>> NFS_LOOKUP: %s\n", fullpath);
  533.     if (! svc_sendreply(xprt, xdr_diropres, &res))
  534.         (void) fprintf(stderr, reply_err);
  535.  
  536.     /* free used space */
  537.     svc_freeargs(xprt, xdr_diropargs, args);
  538. }
  539.  
  540. /*
  541.  *   void nfs_write(SVCXPRT *xprt, struct svc_req *req) --
  542.  *      Do an atomic write operation.
  543.  */
  544. void nfs_write(xprt, req)
  545.     SVCXPRT *xprt;
  546.     struct svc_req *req;
  547. {
  548.     struct nfswriteargs *args;        /* args */
  549.     struct nfsattrstat res;            /* return stat */
  550.  
  551.     /* alloc space for args */
  552.     args = (struct nfswriteargs *) malloc(sizeof(struct nfswriteargs));
  553.     if (args == NULL) {
  554.         (void) fprintf(stderr, mem_err);
  555.         abort();
  556.     }
  557.     (void) bzero(args, sizeof(struct nfswriteargs));
  558.     if (! svc_getargs(xprt, xdr_writeargs, args)) {
  559.         svcerr_decode(xprt);
  560.         (void) free(args);
  561.         return;
  562.     }
  563.     if (NFS_READONLYFS) {
  564.         nfserr_readonlyfs(xprt, xdr_writeargs, args);
  565.         return;
  566.     }
  567.     (void) bzero(&res, sizeof(struct nfsattrstat));
  568.     /* evaluate buffer count argument */
  569.     if (args->wa_count > nfswr_size) {
  570.         res.ns_status = NFSERR_IO;
  571.         goto reply;
  572.     }
  573.     res.ns_status = file_write(args->wa_fhandle.f.fh_fno, args->wa_offset,
  574.                    args->wa_count, args->wa_data);
  575.     if (res.ns_status == NFS_OK) {
  576.         /* get file attributes */
  577.         if (inattrget (args->wa_fhandle.f.fh_fno, &res.ns_attr) ==
  578.             (struct nfsfattr *) NULL) {
  579.             res.ns_status = NFSERR_STALE;
  580.         }
  581.     }
  582.     else
  583.         DBGPRT2 (nfserr, "write %ld, error %d",
  584.              args->wa_fhandle.f.fh_fno, res.ns_status);
  585.  
  586.       reply:
  587.     if (! svc_sendreply(xprt, xdr_attrstat, &res))
  588.         (void) fprintf(stderr, reply_err);
  589.     else if (NFS_VERBOSE)
  590.         (void) printf(">>> NFS_WRITE: %ld\n",
  591.                   args->wa_fhandle.f.fh_fno);
  592.  
  593.     svc_freeargs(xprt, xdr_writeargs, args);    /* free all data */
  594. }
  595.  
  596. /*
  597.  *  void nfs_create(SVCXPRT *xprt, struct svc_req *req) --
  598.  *      Create a file.
  599.  */
  600. void nfs_create(xprt, req)
  601.     SVCXPRT *xprt;
  602.     struct svc_req *req;
  603. {
  604.     struct nfscreatargs *args;            /* create args */
  605.     struct nfsdiropres res;            /* return result */
  606.     char *fullpath, path[MAXPATHNAMELEN];    /* full name */
  607.     int stat;                    /* create return stat */
  608.     struct authunix_parms *unix_cred;
  609.  
  610.     args = (struct nfscreatargs *) malloc(sizeof(struct nfscreatargs));
  611.     if (args == NULL) {
  612.         (void) fprintf(stderr, mem_err);
  613.         abort();
  614.     }
  615.     (void) bzero(args, sizeof(struct nfscreatargs));
  616.     if (! svc_getargs(xprt, xdr_creatargs, args)) {
  617.     svcerr_decode(xprt);
  618.     (void) free(args);
  619.     return;
  620.     }
  621.     if (NFS_READONLYFS) {        /* read only file system */
  622.     nfserr_readonlyfs(xprt, xdr_creatargs, args);
  623.     return;
  624.     }
  625.  
  626.     /* Check the validity of the file handle */
  627.     if (!checkfh (&args->ca_da.da_fhandle))
  628.       res.dr_status = NFSERR_STALE;
  629.     else {
  630.     /* clear out return struct */
  631.     (void) bzero(&res, sizeof(struct nfsdiropres));
  632.     fullpath = intopn(args->ca_da.da_fhandle.f.fh_fno, path);
  633.     if (fullpath != NULL) {
  634.         (void) strcat(fullpath, "\\");        /* make rest of name */
  635.         (void) strcat(fullpath, args->ca_da.da_name);
  636.         (void) strtolower (fullpath);        /* force lower case */
  637.     }
  638.     if (file_getattr(fullpath, &(res.dr_attr))) {    /* file exists */
  639.         res.dr_status = NFSERR_EXIST;
  640.     }
  641.     /* fill in default UID/GID info */
  642.     unix_cred = (struct authunix_parms *) req->rq_clntcred;
  643.     if (args->ca_sa.sa_uid == -1)
  644.       args->ca_sa.sa_uid = (u_long) unix_cred->aup_uid;
  645.     if (args->ca_sa.sa_gid == -1)
  646.       args->ca_sa.sa_gid = (u_long) unix_cred->aup_gid;
  647.  
  648.     /* create a file */
  649.     res.dr_status = file_create(fullpath, &(args->ca_sa), &res.dr_attr);
  650.     if (res.dr_status == NFS_OK) {            /* no errors */
  651.         /* make file handle */
  652.         res.dr_fhandle = pntofh(fullpath);
  653.     }
  654.     }
  655.     if (! svc_sendreply(xprt, xdr_diropres, &res))
  656.       (void) fprintf(stderr, reply_err);
  657.     else if (NFS_VERBOSE)
  658.       (void) printf(">>> NFS_CREATE: %s\n", fullpath);
  659.  
  660.     /* free all data */
  661.     svc_freeargs(xprt, xdr_creatargs, args);
  662. }
  663.     
  664. /*
  665.  *  void nfs_mkdir(SVCXPRT *xprt, struct svc_req *req) --
  666.  *      Make a directory request.  All DOS directories are readable and
  667.  *    writeable, hence the set attribute field is ignored.
  668.  */
  669. void nfs_mkdir(xprt, req)
  670.     SVCXPRT *xprt;
  671.     struct svc_req *req;
  672. {
  673.     struct nfscreatargs *args;
  674.     struct nfsdiropres res;
  675.     char *fullpath, path[MAXPATHNAMELEN];
  676.  
  677.     args = (struct nfscreatargs *) malloc(sizeof(struct nfscreatargs));
  678.     if (args == NULL) {
  679.         (void) fprintf(stderr, mem_err);
  680.         abort();
  681.     }
  682.     (void) bzero(args, sizeof(struct nfscreatargs));
  683.     if (! svc_getargs(xprt, xdr_diropargs, args)) {
  684.         svcerr_decode(xprt);
  685.         (void) free(args);
  686.         return;
  687.     }
  688.     if (NFS_READONLYFS) {
  689.         nfserr_readonlyfs(xprt, xdr_diropargs, args);
  690.         return;
  691.     }
  692.     /* construct path name of new directory */
  693.     fullpath = intopn(args->ca_da.da_fhandle.f.fh_fno, path);
  694.     if (fullpath != NULL) {
  695.         (void) strcat(fullpath, "\\");
  696.         (void) strcat(fullpath, args->ca_da.da_name);
  697.         (void) strtolower (fullpath);        /* force lower case */
  698.     }
  699.  
  700.     (void) bzero(&res, sizeof(struct nfsdiropres));
  701.  
  702.     /* validate path name */
  703.     if ((res.dr_status = validate_path (fullpath)) == NFS_OK)
  704.         res.dr_status = mkdir(fullpath);
  705.  
  706.     if (res.dr_status == NFS_OK) {
  707.         res.dr_status = !file_getattr(fullpath, &(res.dr_attr));
  708.  
  709.         if (res.dr_status == NFS_OK)    /* make new file handle */
  710.           res.dr_fhandle = pntofh(fullpath);
  711.         else
  712.           res.dr_status = puterrno(errno);
  713.     }
  714.     if (! svc_sendreply(xprt, xdr_diropres, &res)) 
  715.         (void) fprintf(stderr, reply_err);
  716.     else if (NFS_VERBOSE)
  717.         (void) printf(">>> NFS_MKDIR: %s\n", fullpath);
  718.  
  719.     /* free all data */
  720.     svc_freeargs(xprt, xdr_creatargs, args);
  721. }
  722.  
  723. /*
  724.  *  void nfs_remove(SVCXPRT *xprt, struct svc_req *req) --
  725.  *      Remove a file specified by the handle.
  726.  */
  727. void nfs_remove(xprt, req)
  728.     SVCXPRT *xprt;
  729.     struct svc_req *req;
  730. {
  731.     struct nfsdiropargs *args;        /* dir op arguments */
  732.     enum nfsstat stat;            /* status of the remove */
  733.     char *fullpath, path[MAXPATHNAMELEN];    /* full path of file */
  734.  
  735.     args = (struct nfsdiropargs *) malloc(sizeof(struct nfsdiropargs));
  736.     if (args == NULL) {
  737.         (void) fprintf(stderr, mem_err);
  738.         abort();
  739.     }
  740.     (void) bzero(args, sizeof(struct nfsdiropargs));    /* zero it */
  741.     if (! svc_getargs(xprt, xdr_diropargs, args)) {
  742.         svcerr_decode(xprt);
  743.         (void) free(args);        /* couldn't decode it */
  744.         return;
  745.     }
  746.     if (NFS_READONLYFS) {
  747.         nfserr_readonlyfs(xprt, xdr_diropargs, &args);
  748.         return;
  749.     }
  750.     /* get full directory name from inode number */
  751.     fullpath = intopn(args->da_fhandle.f.fh_fno, path);
  752.     if (fullpath == NULL)
  753.         stat = NFSERR_NOENT;
  754.     else {
  755.         (void) strcat(fullpath, "\\");    /* append the name */
  756.         (void) strcat(fullpath, args->da_name);
  757.         stat = file_unlink(fullpath);
  758.     }
  759.     /* now reply to request */
  760.     if (! svc_sendreply(xprt, xdr_enum, &stat))
  761.         (void) fprintf(stderr, reply_err);
  762.     else if (NFS_VERBOSE)
  763.         (void) printf(">>> NFS_REMOVE: %s\n", fullpath);
  764.  
  765.     svc_freeargs(xprt, xdr_diropargs, args);
  766. }
  767.  
  768. /*
  769.  *  void nfs_rmdir(SVCXPRT *xprt, struct svc_req *req) --
  770.  *      Remove a directory specified by the handle.
  771.  */
  772. void nfs_rmdir(xprt, req)
  773.     SVCXPRT *xprt;
  774.     struct svc_req *req;
  775. {
  776.     struct nfsdiropargs *args;        /* dir op arguments */
  777.     enum nfsstat stat;            /* status of the remove */
  778.     char *fullpath, path[MAXPATHNAMELEN];    /* full path of file */
  779.     u_long node;
  780.  
  781.     args = (struct nfsdiropargs *) malloc(sizeof(struct nfsdiropargs));
  782.     if (args == NULL) {
  783.         (void) fprintf(stderr, mem_err);
  784.         abort();
  785.     }
  786.     (void) bzero(args, sizeof(struct nfsdiropargs));    /* zero it */
  787.     if (! svc_getargs(xprt, xdr_diropargs, args)) {
  788.         svcerr_decode(xprt);
  789.         (void) free(args);        /* couldn't decode it */
  790.         return;
  791.     }
  792.     /* get full path name from inode number */
  793.     fullpath = intopn(args->da_fhandle.f.fh_fno, path);
  794.     if (fullpath == NULL)
  795.         stat = NFSERR_NOENT;            /* doesn't exist */
  796.     else {
  797.         (void) strcat(fullpath, "\\");        /* append the name */
  798.         (void) strcat(fullpath, args->da_name);
  799.         if (rmdir(fullpath)) {    /* remove it */
  800.             stat = (enum nfsstat) errno;
  801.  
  802.             /* Translate the error code so the correct message */
  803.             /* will be displayed. */
  804.             if (stat == NFSERR_ACCES)
  805.               stat = NFSERR_EXIST;
  806.         }
  807.         else {
  808.             stat = NFS_OK;
  809.             /* Remove the inode if assigned */
  810.             if ((node = pntoin (fullpath)) != -1)
  811.               inremnode (node);
  812.         }
  813.     }
  814.     /* now reply to request */
  815.     if (! svc_sendreply(xprt, xdr_enum, &stat))
  816.         (void) fprintf(stderr, reply_err);
  817.     else if (NFS_VERBOSE)
  818.         (void) printf(">>> NFS_RMDIR: %s\n", fullpath);
  819.  
  820.     svc_freeargs(xprt, xdr_diropargs, args);    /* free data */
  821. }
  822.  
  823. /*
  824.  *  void nfs_rename(SVCXPRT *xprt, struct svc_req *req) --
  825.  *      Renames given file to new name specified in the args.
  826.  */
  827. void nfs_rename(xprt, req)
  828.     SVCXPRT *xprt;
  829.     struct svc_req *req;
  830. {
  831.     struct nfsrnmargs *args;        /* arguments to rename */
  832.     enum nfsstat stat;            /* thr reply status */
  833.     char *oldname, *newname,        /* old and new filenames */
  834.       opath[MAXPATHNAMELEN], npath[MAXPATHNAMELEN];
  835.  
  836.     args = (struct nfsrnmargs *) malloc(sizeof(struct nfsrnmargs));
  837.     if (args == NULL) {
  838.         (void) fprintf(stderr, mem_err);
  839.         abort();
  840.     }
  841.     (void) bzero(args, sizeof(struct nfsrnmargs));
  842.     if (! svc_getargs(xprt, xdr_rnmargs, args)) {
  843.         svcerr_decode(xprt);
  844.         (void) free(args);
  845.         return;
  846.     }
  847.     if (NFS_READONLYFS) {
  848.         nfserr_readonlyfs(xprt, xdr_rnmargs, args);
  849.         return;
  850.     }
  851.     /* make old name from inode */
  852.     oldname = intopn(args->rna_from.da_fhandle.f.fh_fno, opath);
  853.     newname = intopn(args->rna_to.da_fhandle.f.fh_fno, npath);
  854.     if (oldname == NULL || newname == NULL)    /* cannot find path for file */
  855.         stat = NFSERR_STALE;        /* ==> stale file handle */
  856.     else {
  857.         /* complete specification for names */
  858.         (void) strcat(oldname, "\\");
  859.         (void) strcat(oldname, args->rna_from.da_name);
  860.         (void) strcat(newname, "\\");
  861.         (void) strcat(newname, args->rna_to.da_name);
  862.  
  863.         /* Perform the rename operation */
  864.  
  865.         stat = file_rename(oldname, newname);
  866.     }
  867.     /* reply to rename request */
  868.     if (! svc_sendreply(xprt, xdr_enum, &stat))
  869.         (void) fprintf(stderr, reply_err);
  870.     else if (NFS_VERBOSE)
  871.         (void) fprintf(stderr, ">>> NFS_RENAME: %s to %s\n", 
  872.                 oldname, newname);
  873.     
  874.     /* free all data */
  875.     svc_freeargs(xprt, xdr_rnmargs, args);
  876. }
  877.  
  878. /*
  879.  *  void nfs_setattr(SVCXPRT *xprt, struct svc_req *req) --
  880.  *      Set file attributes.
  881.  */
  882. void nfs_setattr(xprt, req)
  883.     SVCXPRT *xprt;
  884.     struct svc_req *req;
  885. {
  886.     struct nfssaargs *args;            /* arguments */
  887.     struct nfsattrstat res;            /* results */
  888.  
  889.     args = (struct nfssaargs *) malloc(sizeof(struct nfssaargs));
  890.     if (args == NULL) {
  891.     (void) fprintf(stderr, mem_err);
  892.     abort();
  893.     }
  894.     (void) bzero(args, sizeof(struct nfssaargs));
  895.     if (! svc_getargs(xprt, xdr_saargs, args)) {
  896.     svcerr_decode(xprt);
  897.     (void) free(args);
  898.     return;
  899.     }
  900.     DBGPRT4 (nfsdebug, "SETATTR: size = %ld  mode = %o%05o  time = %ld",
  901.          args->saa_sa.sa_size, (int) (args->saa_sa.sa_mode >> 15),
  902.          (int) args->saa_sa.sa_mode & 077777,
  903.          args->saa_sa.sa_mtime.tv_sec);
  904.     if (NFS_READONLYFS) {
  905.     nfserr_readonlyfs(xprt, xdr_saargs, args);
  906.     return;
  907.     }
  908.  
  909.     /* If a parameter in the argument block is not -1, set the  */
  910.     /* parameter within the file.                */
  911.  
  912.     /* File mode / protection */
  913.     res.ns_status = NFS_OK;
  914.     if (args->saa_sa.sa_mode != -1)
  915.       res.ns_status = file_setperm(args->saa_fh.f.fh_fno,
  916.                    args->saa_sa.sa_mode);
  917.  
  918.     /* Modification time */
  919.     if (res.ns_status == NFS_OK && args->saa_sa.sa_mtime.tv_sec > 0)
  920.       res.ns_status = file_settime(args->saa_fh.f.fh_fno,
  921.                    args->saa_sa.sa_mtime.tv_sec);
  922.  
  923.     /* Size */
  924.     if (res.ns_status == NFS_OK && args->saa_sa.sa_size != -1)
  925.       res.ns_status = file_setsize(args->saa_fh.f.fh_fno,
  926.                    args->saa_sa.sa_size);
  927.  
  928.     /* User ID / Group ID */
  929.     if (res.ns_status == NFS_OK && (args->saa_sa.sa_uid != -1 ||
  930.     args->saa_sa.sa_gid != -1))
  931.       res.ns_status = file_setowner(args->saa_fh.f.fh_fno,
  932.                     args->saa_sa.sa_uid, args->saa_sa.sa_gid);
  933.  
  934.     (void) bzero(&res, sizeof(struct nfsattrstat));
  935.     if (res.ns_status == NFS_OK &&
  936.     !inattrget (args->saa_fh.f.fh_fno, &res.ns_attr)) {
  937.     res.ns_status = NFSERR_NOENT;
  938.     }
  939.  
  940.     if (! svc_sendreply(xprt, xdr_attrstat, &res))
  941.       (void) fprintf(stderr, reply_err);
  942.     else if (NFS_VERBOSE)
  943.       (void) printf(">>> NFS_SETATTR\n");
  944.     
  945.     /* free data */
  946.     svc_freeargs(xprt, xdr_saargs, args);
  947. }
  948.  
  949. /*
  950.  *  void nfs_link(SVCXPRT *xprt, struct svc_req *req) --
  951.  *      Create file link (not supported under DOS)
  952.  */
  953. void nfs_link(xprt, req)
  954.      SVCXPRT *xprt;
  955.      struct svc_req *req;
  956. {
  957.     struct nfslinkargs *args;        /* arguments to link */
  958.     struct nfsdiropres res;        /* return result */
  959.     enum nfsstat stat;            /* the reply status */
  960.     char *oldname, *newname,        /* old and new filenames */
  961.           opath[MAXPATHNAMELEN], npath[MAXPATHNAMELEN];
  962.  
  963.     args = (struct nfslinkargs *) malloc(sizeof(struct nfslinkargs));
  964.     if (args == NULL) {
  965.     (void) fprintf(stderr, mem_err);
  966.     abort();
  967.     }
  968.     (void) bzero(args, sizeof(struct nfslinkargs));
  969.     (void) bzero(&res, sizeof(struct nfsdiropres));
  970.     if (! svc_getargs(xprt, xdr_linkargs, args)) {
  971.     svcerr_decode(xprt);
  972.     (void) free(args);
  973.     return;
  974.     }
  975.     if (NFS_READONLYFS) {
  976.     nfserr_readonlyfs(xprt, xdr_linkargs, args);
  977.     return;
  978.     }
  979.     /* Translate inodes into names */
  980.     oldname = intopn(args->la_from.f.fh_fno, opath);
  981.     newname = intopn(args->la_to.da_fhandle.f.fh_fno, npath);
  982.     if (oldname == NULL || newname == NULL)    /* cannot find path for file */
  983.       stat = NFSERR_STALE;        /* ==> stale file handle */
  984.     else {
  985.     /* not supported:  return an error code */
  986.  
  987.     stat = NFSERR_ACCES;
  988.     }
  989.     res.dr_status = stat;
  990.  
  991.     if (! svc_sendreply(xprt, xdr_diropres, &res))
  992.       (void) fprintf(stderr, reply_err);
  993.     else if (NFS_VERBOSE)
  994.       (void) fprintf(stderr, ">>> NFS_LINK: %s to %s\n", 
  995.              oldname, newname);
  996.     svc_freeargs(xprt, xdr_linkargs, args);
  997. }
  998.  
  999.  
  1000. /*
  1001.  *  void nfs_symlink(SVCXPRT *xprt, struct svc_req *req) --
  1002.  *      Create symbolic link (not supported under DOS)
  1003.  */
  1004. void nfs_symlink(xprt, req)
  1005.      SVCXPRT *xprt;
  1006.      struct svc_req *req;
  1007. {
  1008.     struct nfsslargs  *args;        /* arguments to sym link */
  1009.     struct nfsrdlnres res;        /* return result */
  1010.     enum nfsstat stat;            /* the reply status */
  1011.     char *oldname, opath[MAXPATHNAMELEN]; /* old filename */
  1012.  
  1013.     args = (struct nfsslargs *) malloc(sizeof(struct nfsslargs));
  1014.     if (args == NULL) {
  1015.     (void) fprintf(stderr, mem_err);
  1016.     abort();
  1017.     }
  1018.     (void) bzero(args, sizeof(struct nfsslargs));
  1019.     (void) bzero(&res, sizeof(struct nfsrdlnres));
  1020.     if (! svc_getargs(xprt, xdr_slargs, args)) {
  1021.     svcerr_decode(xprt);
  1022.     (void) free(args);
  1023.     return;
  1024.     }
  1025.  
  1026.     /* Translate inode into name */
  1027.     oldname = intopn(args->sla_from.da_fhandle.f.fh_fno, opath);
  1028.     if (oldname == NULL)        /* cannot find path for file */
  1029.       stat = NFSERR_STALE;        /* ==> stale file handle */
  1030.     else {
  1031.     /* not supported:  return an error code */
  1032.  
  1033.     stat = NFSERR_ACCES;
  1034.     }
  1035.     res.rl_status = stat;
  1036.  
  1037.     if (! svc_sendreply(xprt, xdr_rdlnres, &res))
  1038.       (void) fprintf(stderr, reply_err);
  1039.     else if (NFS_VERBOSE)
  1040.       (void) fprintf(stderr, ">>> NFS_SYMLINK\n");
  1041.     svc_freeargs(xprt, xdr_linkargs, args);
  1042. }
  1043.  
  1044.  
  1045. /*
  1046.  *  void nfserr_readonlyfs(SVCXPRT *xprt, xdrproc_t xproc, void *args) --
  1047.  *      Return error status of NFSERR_ROFS.   Write attempted on read only
  1048.  *    file system.
  1049.  */
  1050. void nfserr_readonlyfs(xprt, xproc, args)
  1051.     SVCXPRT *xprt;
  1052.     xdrproc_t xproc;
  1053.     void *args;
  1054. {
  1055.     enum nfsstat err;
  1056.  
  1057.     err = NFSERR_ROFS;
  1058.     if (! svc_sendreply(xprt, xdr_enum, &err))
  1059.         (void) fprintf(stderr, reply_err);
  1060.     svc_freeargs(xprt, xproc, args);
  1061. }
  1062.