nfsdLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:60k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* nfsdLib.c - Network File System (NFS) server library */
  2. /* Copyright 1994 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01s,07may02,kbw  man page edits
  8. 01r,06nov01,vvv  made max path length configurable (SPR #63551)
  9. 01q,15oct01,rae  merge from truestack ver 01r, base 01o (cleanup)
  10. 01p,21jun00,rsh  upgrade to dosFs 2.0
  11. 01o,05apr00,zl   fixed the fix in 01m (use retVal)
  12. 01m,15nov98,rjc  modifications for dosfs2 compatibility.
  13. 01o,03dec00,ijm  increased nfsdStackSize (SPR# 22650).  Corrected return
  14.  value if file exists (SPR# 31536)
  15. 01n,16mar99,spm  recovered orphaned code from tor1_0_1.sens1_1 (SPR #25770)
  16. 01m,06oct98,sgv  fixed nfsproc_create_2 to return NFSERR_EXIST when the file
  17.                  exists
  18. 01m,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  19. 01l,11mar97,dvs  added test for udp in nfsd (SPR #8183).
  20. 01k,10feb97,dbt  close file descriptors before leaving in nfsproc_setattr_2 () 
  21.  routine before leaving (SPR #6615).
  22. 01j,05jul96,ms   fixed SPR 6579 - only NFSPROC_CREATE if file doen't exist.
  23. 01i,27feb95,jdi  doc: changed dosFsMode to dosFsFileMode (doc only) (SPR 4085).
  24. 01h,11feb95,jdi  doc format repair.
  25. 01g,24jan95,jdi  doc cleanup.
  26. 01f,08sep94,jmm  final changes
  27. 01e,11may94,jmm  integrated Roland's doc changes
  28. 01d,25apr94,jmm  added nfsdFsReadOnly(), all routines that write now call it 1st
  29.                  added module documentation
  30. 01c,21apr94,jmm  reordered routines, documentation cleanup
  31. 01b,20apr94,jmm  formatting cleanup, nfsdFhNtoh and Hton calls fixed
  32. 01a,07mar94,jmm  written
  33. */
  34. /*
  35. DESCRIPTION
  36. This library is an implementation of version 2 of the Network File
  37. System Protocol Specification as defined in RFC 1094.  It is
  38. closely connected with version 1 of the mount protocol, also defined
  39. in RFC 1094 and implemented in turn by mountLib.
  40. The NFS server is initialized by calling nfsdInit().  
  41. This is done automatically at boot time if INCLUDE_NFS_SERVER is defined.
  42. Currently, only the dosFsLib file system is supported.
  43. File systems are exported with the nfsExport() call.
  44. To create and export a file system, define INCLUDE_NFS_SERVER and rebuild
  45. VxWorks.
  46. To export VxWorks file systems via NFS, you need facilities from both
  47. this library and from mountLib.  To include both, define
  48. INCLUDE_NFS_SERVER and rebuild VxWorks.
  49. Use the mountLib routine nfsExport() to export file systems.  For an
  50. example, see the manual page for mountLib.
  51. VxWorks does not normally provide authentication services for NFS
  52. requests, and the DOS file system does not provide file permissions.
  53. If you need to authenticate incoming requests, see the documentation
  54. for nfsdInit() and mountdInit() for information about authorization
  55. hooks.
  56. The following requests are accepted from clients.  For details of
  57. their use, see RFC 1094, "NFS: Network File System Protocol
  58. Specification."
  59. .TS
  60. center,tab(|);
  61. lf3 lf3
  62. l n.
  63. Procedure Name        |  Procedure Number
  64. _
  65.  NFSPROC_NULL         |  0
  66.  NFSPROC_GETATTR      |  1
  67.  NFSPROC_SETATTR      |  2
  68.  NFSPROC_ROOT         |  3
  69.  NFSPROC_LOOKUP       |  4
  70.  NFSPROC_READLINK     |  5
  71.  NFSPROC_READ         |  6
  72.  NFSPROC_WRITE        |  8
  73.  NFSPROC_CREATE       |  9
  74.  NFSPROC_REMOVE       |  10
  75.  NFSPROC_RENAME       |  11
  76.  NFSPROC_LINK         |  12
  77.  NFSPROC_SYMLINK      |  13
  78.  NFSPROC_MKDIR        |  14
  79.  NFSPROC_RMDIR        |  15
  80.  NFSPROC_READDIR      |  16
  81.  NFSPROC_STATFS       |  17
  82. .TE
  83. AUTHENTICATION AND PERMISSIONS
  84. Currently, no authentication is done on NFS requests.  nfsdInit()
  85. describes the authentication hooks that can be added should
  86. authentication be necessary.
  87. Note that the DOS file system does not provide information about ownership
  88. or permissions on individual files.  Before initializing a dosFs file
  89. system, three global variables--`dosFsUserId', `dosFsGroupId', and
  90. `dosFsFileMode'--can be set to define the user ID, group ID, and permissions
  91. byte for all files in all dosFs volumes initialized after setting these
  92. variables.  To arrange for different dosFs volumes to use different user
  93. and group ID numbers, reset these variables before each volume is
  94. initialized.  See the manual entry for dosFsLib for more information.
  95. TASKS
  96. Several NFS tasks are created by nfsdInit().  They are:
  97. .iP tMountd 11 3
  98. The mount daemon, which handles all incoming mount requests.
  99. This daemon is created by mountdInit(), which is automatically
  100. called from nfsdInit().
  101. .iP tNfsd
  102. The NFS daemon, which queues all incoming NFS requests.
  103. .iP tNfsdX
  104. The NFS request handlers, which dequeues and processes all incoming
  105. NFS requests.
  106. .LP
  107. Performance of the NFS file system can be improved by increasing the
  108. number of servers specified in the nfsdInit() call, if there are
  109. several different dosFs volumes exported from the same target system.
  110. The spy() utility can be called to determine whether this is useful for
  111. a particular configuration.
  112. INTERNAL:
  113. All of the nfsproc_*_2 routines follow the RPC naming convention
  114. rather than the WRS naming convention.  They return a pointer to
  115. malloced space, which is freed by nfsdRequestProcess().
  116. */
  117. #include "vxWorks.h"
  118. #include "dirent.h"
  119. #include "dosFsLib.h"
  120. #include "errno.h"
  121. #include "fcntl.h"
  122. #include "ioLib.h"
  123. #include "limits.h"
  124. #include "mountLib.h"
  125. #include "msgQLib.h"
  126. #include "netinet/in.h"
  127. #include "nfsdLib.h"
  128. #include "pathLib.h"
  129. #include "rpcLib.h"
  130. #include "rpc/pmap_clnt.h"
  131. #include "rpc/rpc.h"
  132. #include "semLib.h"
  133. #include "sockLib.h"
  134. #include "stdio.h"
  135. #include "stdio.h"
  136. #include "stdlib.h"
  137. #include "string.h"
  138. #include "sys/socket.h"
  139. #include "sys/stat.h"
  140. #include "sys/types.h"
  141. #include "taskLib.h"
  142. #include "tickLib.h"
  143. #include "utime.h"
  144. #include "xdr_nfs.h"
  145. #include "iosLib.h"
  146. #include "private/nfsHashP.h"
  147. #include "memPartLib.h"
  148. /* defines */
  149. #define NAME_LEN               40
  150. #if !defined(S_dosFsLib_FILE_EXISTS)
  151. #define S_dosFsLib_FILE_EXISTS  (S_dosFsLib_FILE_ALREADY_EXISTS)
  152. #endif
  153. #define QLEN_PER_SRVR           10
  154. #ifdef __GNUC__
  155. # ifndef alloca
  156. #  define alloca __builtin_alloca
  157. # endif
  158. #endif
  159. /* DATA STRUCTURES */
  160. /* svcudp_data is copied directly from svc_udp.c - DO NOT MODIFY */
  161. struct svcudp_data {
  162. u_int   su_iosz; /* byte size of send.recv buffer */
  163. u_long su_xid; /* transaction id */
  164. XDR su_xdrs; /* XDR handle */
  165. char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
  166. char   *su_cache; /* cached data, NULL if no cache - 4.0 */
  167. };
  168. typedef struct
  169.     {
  170.     FUNCPTR            routine;   /* nfsproc_*_2 routine to call */
  171.     int                procNum;   /* NFS procedure number */
  172.     NFSD_ARGUMENT *    argument;  /* argument to pass to nfsproc_*_2 */
  173.     FUNCPTR            xdrArg;   /* XDR function pointer to convert argument */
  174.     FUNCPTR            xdrResult; /* XDR function pointer to convert result */
  175.     struct sockaddr_in sockAddr;  /* Address of the client socket */
  176.     int                xid;   /* RPC XID of client request */
  177.     int                socket;   /* Socket to use to send reply */
  178.     } NFS_Q_REQUEST;
  179. /* IMPORTS */
  180. IMPORT int nfsMaxPath;           /* Max. file path length */
  181. /* GLOBALS */
  182. int nfsdStackSize = 14000;   /* Default stack size for NFS processes */
  183. int nfsdNServers = 4;   /* Default number of NFS servers */
  184. int nfsdPriorityDefault = 55;   /* Default priority of the NFS server */
  185. int nfsdNFilesystemsDefault = 10; /* Default max. num. filesystems */
  186. /* LOCALS */
  187. LOCAL NFS_SERVER_STATUS nfsdServerStatus;    /* Status of the NFS server */
  188. LOCAL FUNCPTR           nfsdAuthHook = NULL; /* Authentication hook */
  189. MSG_Q_ID                nfsRequestQ;         /* Message Q for NFS requests */
  190. /* forward LOCAL functions */
  191. LOCAL void nfsdRequestEnqueue (struct svc_req * rqstp, SVCXPRT * transp);
  192. LOCAL int nfsdFsReadOnly (NFS_FILE_HANDLE * fh);
  193. /******************************************************************************
  194. *
  195. * nfsdInit - initialize the NFS server
  196. * This routine initializes the NFS server.  <nServers>  specifies the number of
  197. * tasks to be spawned to handle NFS requests.  <priority> is the priority that
  198. * those tasks will run at.  <authHook> is a pointer to an authorization
  199. * routine.  <mountAuthHook> is a pointer to a similar routine, passed to
  200. * mountdInit().  <options> is provided for future expansion.
  201. * Normally, no authorization is performed by either mountd or nfsd.
  202. * If you want to add authorization, set <authHook> to a
  203. * function pointer to a routine declared as follows:
  204. * .CS
  205. * nfsstat routine
  206. *     (
  207. *     int                progNum, /@ RPC program number @/
  208. *     int                versNum, /@ RPC program version number @/
  209. *     int                procNum, /@ RPC procedure number @/
  210. *     struct sockaddr_in clientAddr,    /@ address of the client @/
  211. *     NFSD_ARGUMENT *    nfsdArg    /@ argument of the call @/
  212. *     )
  213. * .CE
  214. * The <authHook> routine should return NFS_OK if the request is authorized,
  215. * and NFSERR_ACCES if not.  (NFSERR_ACCES is not required; any legitimate
  216. * NFS error code can be returned.)
  217. * See mountdInit() for documentation on <mountAuthHook>.  Note that
  218. * <mountAuthHook> and <authHook> can point to the same routine.
  219. * Simply use the <progNum>, <versNum>, and <procNum> fields to decide
  220. * whether the request is an NFS request or a mountd request.
  221. * VXWORKS AE PROTECTION DOMAINS
  222. * Under VxWorks AE, you can call this function from within the kernel 
  223. * protection domain only.  In addition, all arguments to this function can  
  224. * reference only that data which is valid in the kernel protection domain. 
  225. * This restriction does not apply under non-AE versions of VxWorks.  
  226. *
  227. * RETURNS: OK, or ERROR if the NFS server cannot be started.
  228. *
  229. * SEE ALSO: nfsExport(), mountdInit()
  230. */
  231. STATUS nfsdInit
  232.     (
  233.     int nServers, /* the number of NFS servers to create */
  234.     int nExportedFs, /* maximum number of exported file systems */
  235.     int priority, /* the priority for the NFS servers */
  236.     FUNCPTR authHook, /* authentication hook */
  237.     FUNCPTR mountAuthHook, /* authentication hook for mount daemon */
  238.     int options /* currently unused */
  239.     )
  240.     {
  241.     char serverName [50]; /* Synthetic name for NFS servers */
  242.     int  mountTask; /* taskId of the mountd task */
  243.     int  queuingTask; /* taskId of the task that queues NFS calls */
  244.     /*
  245.      * Scaling stack with change in NFS_MAXPATH since multiple arrays of size 
  246.      * NFS_MAXPATH are allocated from stack. Difference is computed from 
  247.      * default max. path of 255.
  248.      */
  249.     nfsdStackSize += 4 * (nfsMaxPath - 255);
  250.     /* Set up call statistics */
  251.     memset (&nfsdServerStatus, 0, sizeof (nfsdServerStatus));
  252.     /* Set up authorization hook */
  253.     nfsdAuthHook = authHook;
  254.     
  255.     /* If number and priority of servers isn't specified, set it to default */
  256.     
  257.     if (nServers == 0)
  258.         nServers = nfsdNServers;
  259.     if (priority == 0)
  260.         priority = nfsdPriorityDefault;
  261.     if (nExportedFs == 0)
  262.         nExportedFs = nfsdNFilesystemsDefault;
  263.     /* Create the request queue */
  264.     if ((nfsRequestQ = msgQCreate (nServers * QLEN_PER_SRVR, sizeof (NFS_Q_REQUEST),
  265.       MSG_Q_FIFO)) == NULL)
  266. return (ERROR);
  267.     /* Spawn the mount task */
  268.     if ((mountTask = mountdInit (0, 0, mountAuthHook, 0, 0)) == ERROR)
  269. {
  270. msgQDelete (nfsRequestQ);
  271. return (ERROR);
  272. }
  273.     /* spawn the queuing task */
  274.     
  275.     if ((queuingTask = taskSpawn ("tNfsd", priority, VX_FP_TASK, nfsdStackSize,
  276.     (FUNCPTR) nfsd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
  277. == ERROR)
  278. {
  279. taskDelete (mountTask);
  280. msgQDelete (nfsRequestQ);
  281. return (ERROR);
  282. }
  283.     /* spawn the call processing tasks */
  284.     
  285.     while (nServers-- > 0)
  286. {
  287. /* Create names of the form tNfsdX */
  288. sprintf (serverName, "tNfsd%d", nServers);
  289. if ((taskSpawn (serverName, priority + 5, VX_FP_TASK, nfsdStackSize,
  290. (FUNCPTR) nfsdRequestProcess, 0, 0, 0, 0, 0, 0, 0, 0,
  291. 0, 0)) == ERROR)
  292.     {
  293.     taskDelete (mountTask);
  294.     taskDelete (queuingTask);
  295.     msgQDelete (nfsRequestQ);
  296.     return (ERROR);
  297.     }
  298. }
  299.     return (OK);
  300.     }
  301. /******************************************************************************
  302. *
  303. * nfsdRequestEnqueue - queue up NFS requests from clients
  304. *
  305. * Called only via svc_run(), via nfsd().  Puts an incoming NFS request
  306. * into the message queue for processing by nfsdRequestProcess().
  307. *
  308. * Some of this routine was generated by rpcgen.
  309. * RETURNS:  N/A
  310. * NOMANUAL
  311. */
  312. LOCAL void nfsdRequestEnqueue
  313.     (
  314.     struct svc_req * rqstp, /* Request */
  315.     SVCXPRT *        transp /* Transport */
  316.     )
  317.     {
  318.     NFSD_ARGUMENT *     argument;     /* Client call argument */
  319.     FUNCPTR             xdr_result;   /* XDR result conversion routine */
  320.     FUNCPTR             xdr_argument; /* XDR argument conversion routine */
  321.     char *              (*local)();   /* Local routine to call */
  322.     NFS_Q_REQUEST       request;      /* Request to queue up */
  323.     /* Allocate space for the argument */
  324.     argument = KHEAP_ALLOC((NFS_MAXDATA + sizeof (argument) + nfsMaxPath));
  325.     if (NULL != argument)
  326. {
  327. bzero((char *) argument,(NFS_MAXDATA + sizeof (argument) + nfsMaxPath));
  328. }
  329.     /* Beginning of code generated by rpcgen */
  330.     switch (rqstp->rq_proc) {
  331.     case NFSPROC_NULL:
  332.     xdr_argument = xdr_void;
  333.     xdr_result = xdr_void;
  334.     local = (char *(*)()) nfsproc_null_2;
  335.     break;
  336.     case NFSPROC_GETATTR:
  337.     xdr_argument = xdr_nfs_fh;
  338.     xdr_result = xdr_attrstat;
  339.     local = (char *(*)()) nfsproc_getattr_2;
  340.     break;
  341.     case NFSPROC_SETATTR:
  342.     xdr_argument = xdr_sattrargs;
  343.     xdr_result = xdr_attrstat;
  344.     local = (char *(*)()) nfsproc_setattr_2;
  345.     break;
  346.     case NFSPROC_ROOT:
  347.     xdr_argument = xdr_void;
  348.     xdr_result = xdr_void;
  349.     local = (char *(*)()) nfsproc_root_2;
  350.     break;
  351.     case NFSPROC_LOOKUP:
  352.     xdr_argument = xdr_diropargs;
  353.     xdr_result = xdr_diropres;
  354.     local = (char *(*)()) nfsproc_lookup_2;
  355.     break;
  356.     case NFSPROC_READLINK:
  357.     xdr_argument = xdr_nfs_fh;
  358.     xdr_result = xdr_readlinkres;
  359.     local = (char *(*)()) nfsproc_readlink_2;
  360.     break;
  361.     case NFSPROC_READ:
  362.     xdr_argument = xdr_readargs;
  363.     xdr_result = xdr_readres;
  364.     local = (char *(*)()) nfsproc_read_2;
  365.     break;
  366.     case NFSPROC_WRITECACHE:
  367.     xdr_argument = xdr_void;
  368.     xdr_result = xdr_void;
  369.     local = (char *(*)()) nfsproc_writecache_2;
  370.     break;
  371.     case NFSPROC_WRITE:
  372.     xdr_argument = xdr_writeargs;
  373.     xdr_result = xdr_attrstat;
  374.     local = (char *(*)()) nfsproc_write_2;
  375.     break;
  376.     case NFSPROC_CREATE:
  377.     xdr_argument = xdr_createargs;
  378.     xdr_result = xdr_diropres;
  379.     local = (char *(*)()) nfsproc_create_2;
  380.     break;
  381.     case NFSPROC_REMOVE:
  382.     xdr_argument = xdr_diropargs;
  383.     xdr_result = xdr_nfsstat;
  384.     local = (char *(*)()) nfsproc_remove_2;
  385.     break;
  386.     case NFSPROC_RENAME:
  387.     xdr_argument = xdr_renameargs;
  388.     xdr_result = xdr_nfsstat;
  389.     local = (char *(*)()) nfsproc_rename_2;
  390.     break;
  391.     case NFSPROC_LINK:
  392.     xdr_argument = xdr_linkargs;
  393.     xdr_result = xdr_nfsstat;
  394.     local = (char *(*)()) nfsproc_link_2;
  395.     break;
  396.     case NFSPROC_SYMLINK:
  397.     xdr_argument = xdr_symlinkargs;
  398.     xdr_result = xdr_nfsstat;
  399.     local = (char *(*)()) nfsproc_symlink_2;
  400.     break;
  401.     case NFSPROC_MKDIR:
  402.     xdr_argument = xdr_createargs;
  403.     xdr_result = xdr_diropres;
  404.     local = (char *(*)()) nfsproc_mkdir_2;
  405.     break;
  406.     case NFSPROC_RMDIR:
  407.     xdr_argument = xdr_diropargs;
  408.     xdr_result = xdr_nfsstat;
  409.     local = (char *(*)()) nfsproc_rmdir_2;
  410.     break;
  411.     case NFSPROC_READDIR:
  412.     xdr_argument = xdr_readdirargs;
  413.     xdr_result = xdr_readdirres;
  414.     local = (char *(*)()) nfsproc_readdir_2;
  415.     break;
  416.     case NFSPROC_STATFS:
  417.     xdr_argument = xdr_nfs_fh;
  418.     xdr_result = xdr_statfsres;
  419.     local = (char *(*)()) nfsproc_statfs_2;
  420.     break;
  421.     default:
  422.             KHEAP_FREE((char *)argument);
  423.     svcerr_noproc(transp);
  424.     return;
  425.     }
  426.     if (!svc_getargs(transp, xdr_argument, argument)) {
  427. svcerr_decode(transp);
  428. return;
  429.     }
  430.     
  431.     /* end of code generated by rpcgen */
  432.     
  433.     /* Build the request and put it into the message queue */
  434.     
  435.     request.routine   = (FUNCPTR) local;
  436.     request.procNum   = rqstp->rq_proc;
  437.     request.argument  = argument;
  438.     request.xdrArg    = xdr_argument;
  439.     request.xdrResult = xdr_result;
  440.     request.sockAddr  = transp->xp_raddr;
  441.     /* only use xp_p2 for udp requests */
  442.     if (transp->xp_p2 != NULL)
  443. request.xid       = ((struct svcudp_data *) transp->xp_p2)->su_xid;
  444.     request.socket    = transp->xp_sock;
  445.     
  446.     if (msgQSend (nfsRequestQ, (char *) &request, sizeof (request),
  447.   WAIT_FOREVER, MSG_PRI_NORMAL) != OK)
  448. {
  449. KHEAP_FREE((char *)argument);
  450. perror ("nfsd aborted");
  451. return;
  452. }
  453.     }
  454. /******************************************************************************
  455. *
  456. * nfsdRequestProcess - process client NFS requests
  457. * nfsdRequestProcess is started as a task by nfsdInit().  It sits in a loop
  458. * reading nfsdRequestQ and responding to all requests that are put into this
  459. * queue.
  460. * Multiple processes can be spawned with this entry point.  Normally,
  461. * nfsdNServers are started when nfsdInit() is called.
  462. * RETURNS:  N/A
  463. *
  464. * NOMANUAL
  465. */
  466. void nfsdRequestProcess
  467.     (
  468.     void
  469.     )
  470.     {
  471.     SVCXPRT *     transp; /* Dummy transport for RPC */
  472.     int           sock; /* Transmission socket for reply */
  473.     NFS_Q_REQUEST request; /* Client request */
  474.     NFSD_ARGUMENT * argument; /* Argument from client request */
  475.     char *        result; /* Result of NFS call */
  476.     FUNCPTR       xdr_argument; /* XDR argument conversion routine */
  477.     FUNCPTR       xdr_result; /* XDR result conversion routine */
  478.     FUNCPTR       local; /* Local NFS routine to call */
  479.     struct sockaddr_in * addr; /* Address of client socket */
  480.     int           xid; /* XID from client request */
  481.     nfsstat       authorized; /* request is authorized if == NFS_OK*/
  482.     
  483.     /* Initialize task for VxWorks RPC work */
  484.     
  485.     rpcTaskInit ();
  486.     transp = svcudp_create(-1);
  487.     /* Work loop is repeated until catastrophic error encountered */
  488.     
  489.     FOREVER
  490. {
  491. /* Get the next message */
  492. if (msgQReceive (nfsRequestQ, (char *) &request, sizeof(request),
  493.  WAIT_FOREVER) == ERROR)
  494.     {
  495.     perror ("NFS server aborted abnormally");
  496.     return;
  497.     }
  498. /* Break down the incoming message */
  499. local        = request.routine;
  500. argument     = request.argument;
  501. xdr_argument = request.xdrArg;  
  502. xdr_result   = request.xdrResult;
  503. addr         = &request.sockAddr;
  504. xid          = request.xid;
  505. sock         = request.socket;
  506. /* Create a new RPC transport to reply.  Need to do this as
  507.  * next incoming client request will alter xid field of old
  508.  * transport, and replies won't match the correct request.
  509.  */
  510. transp->xp_sock = sock;
  511. ((struct svcudp_data *) transp->xp_p2)->su_xid = xid;
  512. transp->xp_raddr = *addr;
  513. memset (&transp->xp_verf, 0, sizeof(transp->xp_verf));
  514. transp->xp_addrlen = sizeof (transp->xp_raddr);
  515. /* Authenticate the request, then call the correct NFS routine */
  516. if (nfsdAuthHook)
  517.     {
  518.     authorized = (*nfsdAuthHook) (NFS_PROGRAM, NFS_VERSION,
  519.   request.procNum, request.sockAddr,
  520.   argument);
  521.     }
  522. else
  523.     authorized = NFS_OK;
  524. if (authorized  != NFS_OK)
  525.     {
  526.     result = KHEAP_ALLOC(sizeof (nfsstat));
  527.     if (NULL != result)
  528. {
  529. bzero ((char *)result, sizeof (nfsstat));
  530. }
  531.     *((nfsstat *) result) = authorized;
  532.     }
  533. else
  534.     result = (char *) (*local)(argument);
  535. /* Send the result */
  536. if (result != NULL && !svc_sendreply(transp, xdr_result, result))
  537.     {
  538.     svcerr_systemerr(transp);
  539.     }
  540. /* Free any space used by RPC/XDR */
  541. if (!svc_freeargs(transp, xdr_argument, argument))
  542.     {
  543.     perror ("unable to free arguments for NFS server");
  544.     return;
  545.     }
  546. /* Free space allocated when request was queued up */
  547. KHEAP_FREE((char *)result);
  548. KHEAP_FREE((char *)argument);
  549. /* Unfortunately, there's no way to tell svc_destroy() to not close
  550.  * the socket.  So, set the socket to -1. svc_destroy() doesn't
  551.  * check the value of the close() anyway.  If errno is set to
  552.  * S_iosLib_INVALID_FILE_DESCRIPTOR due to the close (-1), reset it
  553.  * to OK.  (svc_destroy() returns NULL, so there's no way to check
  554.  * its return value.)
  555.  */
  556. }
  557.     transp->xp_sock = -1;
  558.     svc_destroy (transp);
  559.     if (errno == S_iosLib_INVALID_FILE_DESCRIPTOR)
  560.         errno = OK;
  561.     }
  562. /******************************************************************************
  563. *
  564. * nfsd - NFS daemon process
  565. *
  566. * Used as the entrypoint to a task spawned from nfsdInit().  This task
  567. * sets up the NFS RPC service, and calls svc_run(), which should never return.
  568. * nfsdRequestEnqueue() is called from the svc_run() call.
  569. *
  570. * This routine is not declared LOCAL only because the symbol for its entry
  571. * point should be displayed by i().
  572. * NOTE:  Some of this routine was generated by rpcgen.
  573. * RETURNS:  Never returns unless an error is encountered.
  574. * SEE ALSO: nfsdRequestEnqueue().
  575. * NOMANUAL
  576. */
  577. void nfsd
  578.     (
  579.     void
  580.     )
  581.     {
  582.     register SVCXPRT * transp; /* RPC transport */
  583.     int                sock; /* NFS socket */
  584.     struct sockaddr_in addr; /* Address of NFS (port 2049 */
  585.     int                optVal = NFS_MAXDATA * 2 + sizeof (struct rpc_msg) * 2;
  586.                                 /* XXX - too much space is wasted here */
  587.     
  588.     /* Initialize the task to use VxWorks RPC code */
  589.     
  590.     rpcTaskInit();
  591.     /* Create NFS socket and bind it to correct address */
  592.     
  593.     sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  594.     /* Set up the socket address */
  595.     
  596.     addr.sin_family             = AF_INET;
  597.     addr.sin_addr.s_addr        = INADDR_ANY;
  598.     addr.sin_port               = htons (NFS_PORT);
  599.     bzero (addr.sin_zero, sizeof (addr.sin_zero));
  600.     if (bind (sock, (struct sockaddr *) &addr, sizeof (addr)) == ERROR)
  601. {
  602. perror ("Could not bind to NFS port address");
  603. return;
  604. }
  605.     /* Unset any previous NFS services */
  606.     pmap_unset(NFS_PROGRAM, NFS_VERSION);
  607.     /* Set socket buffer large enough to accommodate max NFS message */
  608.     if ((setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&optVal,
  609.      sizeof (optVal)) == ERROR)
  610. || (setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)&optVal,
  611. sizeof (optVal)) == ERROR))
  612.         return;
  613.     /* Create RPC transport */
  614.     transp = svcudp_create(sock);
  615.     if (transp == NULL)
  616. {
  617. fprintf(stderr, "cannot create udp service.");
  618. exit(1);
  619. }
  620.     /* Register NFS */
  621.     if (!svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfsdRequestEnqueue,
  622.       IPPROTO_UDP))
  623. {
  624. perror ("unable to register (NFS_PROGRAM, NFS_VERSION, udp).n");
  625. return;
  626. }
  627.     /* Start the RPC service, and never come back */
  628.     svc_run();
  629.     /* Should never get to this point */
  630.     
  631.     perror ("NFS svc_run returned");
  632.     }
  633. /******************************************************************************
  634. *
  635. * nfsproc_null_2 - do nothing
  636. *
  637. * RETURNS: A pointer to malloced spaced that contains no information.
  638. *
  639. * NOMANUAL
  640. */
  641. void * nfsproc_null_2
  642.     (
  643.     void
  644.     )
  645.     {
  646.     nfsdServerStatus.nullCalls++;
  647.     
  648.     return ((void *) KHEAP_ALLOC(0));
  649.     }
  650. /******************************************************************************
  651. *
  652. * nfsproc_getattr_2 - get file attributes
  653. *
  654. * If the reply status is NFS_OK, then the reply attributes contains the
  655. * attributes for the file given by the input fhandle.
  656. * RETURNS: A pointer to an attrstat struct.
  657. *
  658. * NOMANUAL
  659. */
  660. attrstat * nfsproc_getattr_2
  661.     (
  662.     nfs_fh *   fh /* File handle to get attributes of */
  663.     )
  664.     {
  665.     attrstat * retVal = KHEAP_ALLOC(sizeof (attrstat)); /* Struct to fill in */
  666.     nfsdServerStatus.getattrCalls++;
  667.     nfsdFhNtoh ((NFS_FILE_HANDLE *) fh);
  668.     
  669.     if (retVal == NULL)
  670.         return (NULL);
  671.     /* Get the attributes for the file */
  672.     
  673.     if (nfsdFattrGet ((NFS_FILE_HANDLE *) fh,
  674.  &retVal->attrstat_u.attributes) == ERROR)
  675. {
  676. retVal->status = nfsdErrToNfs (errno);
  677. return (retVal);
  678. }
  679.     else
  680.         retVal->status = NFS_OK;
  681.     
  682.     return (retVal);
  683.     }
  684. /******************************************************************************
  685. *
  686. * nfsproc_setattr_2 - set the attributes for a file
  687. * The "attr" argument contains fields which are either -1 or are
  688. * the new value for the attributes of "file".  If the reply status is
  689. * NFS_OK, then the reply attributes have the attributes of the file
  690. * after the "SETATTR" operation has completed.
  691. * Notes:  The use of -1 to indicate an unused field in "attributes" is
  692. * changed in the next version of the protocol.
  693. *
  694. * NOMANUAL
  695. */
  696. attrstat * nfsproc_setattr_2
  697.     (
  698.     sattrargs *    attr /* Attributes to change */
  699.     )
  700.     {
  701.     attrstat *     retVal = KHEAP_ALLOC(sizeof (attrstat));/* Return info */
  702.     char *         fileName;    /* Name of the file being changed */
  703.     int     fd; /* File descriptor for file being changed */
  704.     struct utimbuf timeBuf; /* New time settings for file */
  705.     if (retVal == NULL)
  706.         return (NULL);
  707.      
  708.     if ((fileName = (char *) alloca (nfsMaxPath)) == NULL)
  709. return (NULL);
  710.     nfsdServerStatus.setattrCalls++;
  711.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &attr->file);
  712.     /* Make sure the file system is writeable */
  713.     if (nfsdFsReadOnly((NFS_FILE_HANDLE *) &attr->file))
  714. {
  715. retVal->status = NFSERR_ACCES;
  716. return (retVal);
  717. }
  718.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &attr->file, fileName) == ERROR)
  719. {
  720. retVal->status = nfsdErrToNfs (errno);
  721. return (retVal);
  722. }
  723.     if (attr->attributes.mode != -1)
  724.         /* Currently don't have any way to set the mode */
  725.         ;
  726.         
  727.     if (attr->attributes.uid != -1)
  728.         /* Currently don't have any way to set the uid */
  729.         ;
  730.         
  731.     if (attr->attributes.gid != -1)
  732.         /* Currently don't have any way to set the gid */
  733.         ;
  734.         
  735.     if (attr->attributes.size != -1)
  736. {
  737. /* Set the size of the file using FIOTRUNC ioctl, as VxWorks
  738.  * doesn't have ftruncate() */
  739.         fd = open (fileName, O_RDWR, 0666);
  740. if (fd != ERROR)
  741.     {
  742.     if (ioctl (fd, FIOTRUNC, attr->attributes.size) == ERROR)
  743. {
  744. retVal->status = nfsdErrToNfs (errno);
  745. close (fd);
  746. return (retVal);
  747. }
  748.     else
  749.         close (fd);
  750.     }
  751. else
  752.     {
  753.     retVal->status = nfsdErrToNfs (errno);
  754.     close (fd);
  755.     return (retVal);
  756.     }
  757. }
  758.     /* Set file time.
  759.      *
  760.      * As there's no way to set only one of these fields, if only one
  761.      * is set, set the other one to the same value.
  762.      */
  763.     
  764.     if (attr->attributes.atime.seconds != -1)
  765. timeBuf.modtime = timeBuf.actime = attr->attributes.atime.seconds;
  766.     
  767.     if (attr->attributes.mtime.seconds != -1)
  768. {
  769. timeBuf.modtime = attr->attributes.mtime.seconds;
  770. if (attr->attributes.atime.seconds == -1)
  771.     timeBuf.actime = timeBuf.modtime;
  772. }
  773.     if ((attr->attributes.atime.seconds != -1) ||
  774. (attr->attributes.mtime.seconds != -1))
  775.         if (utime (fileName, &timeBuf) == ERROR)
  776.     {
  777.     retVal->status = nfsdErrToNfs (errno);
  778.     return (retVal);
  779.     }
  780.     
  781.     /* Get the status information for the file to return */
  782.     
  783.     if (nfsdFattrGet ((NFS_FILE_HANDLE *) &attr->file,
  784.  &retVal->attrstat_u.attributes) != OK)
  785. {
  786. retVal->status = nfsdErrToNfs (errno);
  787. return (retVal);
  788. }
  789.     retVal->status = NFS_OK;
  790.     return (retVal);
  791.     }
  792. /******************************************************************************
  793. *
  794. * nfsproc_root_2 - obsolete
  795. * Obsolete.  This procedure is no longer used because finding the root
  796. * file handle of a filesystem requires moving pathnames between client
  797. * and server.  To do this right, we would have to define a network
  798. * standard representation of pathnames.  Instead, the function of
  799. * looking up the root file handle is done by the MNTPROC_MNT procedure.
  800. * RETURNS:  A pointer to no information.
  801. *
  802. * NOMANUAL
  803. */
  804. void * nfsproc_root_2
  805.     (
  806.     void
  807.     )
  808.     {
  809.     nfsdServerStatus.setattrCalls++;
  810.     return ((void *) KHEAP_ALLOC(0));
  811.     }
  812. /******************************************************************************
  813. *
  814. * nfsproc_lookup_2 -
  815. * If the reply "status" is NFS_OK, then the reply "file" and reply
  816. * "attributes" are the file handle and attributes for the file "name"
  817. * in the directory given by "dir" in the argument.
  818. * RETURNS:  A pointer to a diropres struct, or NULL.
  819. *
  820. * NOMANUAL
  821. */
  822. diropres * nfsproc_lookup_2
  823.     (
  824.     diropargs * dir /* The direcory and file to look up */
  825.     )
  826.     {
  827.     diropres *  retVal = KHEAP_ALLOC(sizeof (diropres)); /* return status */
  828.     if (retVal == NULL)
  829.         return (NULL);
  830.     
  831.     nfsdServerStatus.lookupCalls++;
  832.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &dir->dir);
  833.     
  834.     /* Build file handle for new file */
  835.     if (nfsdFhCreate ((NFS_FILE_HANDLE *) &dir->dir, dir->name,
  836.  (NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file)
  837. == ERROR)
  838. {
  839. retVal->status = nfsdErrToNfs (errno);
  840. return (retVal);
  841. }
  842.     /* Get the attributes for the newly created file handle */
  843.     if (nfsdFattrGet ((NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file,
  844.  &retVal->diropres_u.diropres.attributes) == ERROR)
  845. {
  846. retVal->status = nfsdErrToNfs (errno);
  847. return (retVal);
  848. }
  849.     retVal->status = NFS_OK;
  850.     nfsdFhHton ((NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file);
  851.     
  852.     return (retVal);
  853.     }
  854. /******************************************************************************
  855. *
  856. * nfsproc_readlink_2 - read from a symbolic link
  857. * VxWorks does not support symbolic links.
  858. * RETURNS:  A pointer to an EOPNOTSUPP error.
  859. *
  860. * NOMANUAL
  861. */
  862. readlinkres * nfsproc_readlink_2
  863.     (
  864.     nfs_fh * fh /* File handle to read */
  865.     )
  866.     {
  867.     readlinkres * retVal = KHEAP_ALLOC(sizeof (retVal->status));
  868.     if (retVal == NULL)
  869.         return (NULL);
  870.     /* Increment statistics */
  871.     nfsdServerStatus.readlinkCalls++;
  872.     /* symbolic links not supported */
  873.     retVal->status = EOPNOTSUPP;
  874.     return (retVal);
  875.     }
  876. /******************************************************************************
  877. *
  878. * nfsproc_read_2 - read data from a file
  879. * Returns up to "count" bytes of "data" from the file given by "file",
  880. * starting at "offset" bytes from the beginning of the file.  The first
  881. * byte of the file is at offset zero.  The file attributes after the
  882. * read takes place are returned in "attributes".
  883. * Notes:  The argument "totalcount" is unused, and is removed in the
  884. * next protocol revision.
  885. *
  886. * NOMANUAL
  887. */
  888. readres * nfsproc_read_2
  889.     (
  890.     readargs * readFile /* File, offset, and count information */
  891.     )
  892.     {
  893.     char *     fileName;        /* Name of the file being read */
  894.     readres *  retVal = KHEAP_ALLOC(sizeof (readres) + readFile->count);
  895. /* Return information, including read data */
  896.     char *     readData; /* Address of read data in retVal */
  897.     int        fd; /* File descriptor for file being read */
  898.     int        nBytes; /* Number of bytes actually read */
  899.     if (retVal == NULL)
  900.         return (NULL);
  901.     if ((fileName = (char *) alloca (nfsMaxPath)) == NULL)
  902. return (NULL);
  903.     /* Increment statistics */
  904.     nfsdServerStatus.readCalls++;
  905.     /* set readData to point to the correct position in the return value */
  906.     readData = (char *) retVal + sizeof (readres);
  907.     
  908.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &readFile->file);
  909.     
  910.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &readFile->file, fileName)
  911. == ERROR)
  912. {
  913. retVal->status = nfsdErrToNfs (errno);
  914. return (retVal);
  915. }
  916.     if ((fd = open (fileName, O_RDONLY, 0)) == ERROR)
  917. {
  918. retVal->status = nfsdErrToNfs (errno);
  919. return (retVal);
  920. }
  921.     if (lseek (fd, readFile->offset, SEEK_SET) == ERROR)
  922. {
  923. retVal->status = nfsdErrToNfs (errno);
  924. close (fd);
  925. return (retVal);
  926. }
  927.     if ((nBytes = read (fd, readData, readFile->count)) == ERROR)
  928.      {
  929. retVal->status = nfsdErrToNfs (errno);
  930. close (fd);
  931. return (retVal);
  932. }
  933.     else
  934. {
  935.         retVal->readres_u.reply.data.data_val = readData;
  936. retVal->readres_u.reply.data.data_len = nBytes;
  937. }
  938.     if (close (fd) == ERROR)
  939. {
  940. retVal->status = nfsdErrToNfs (errno);
  941. return (retVal);
  942. }
  943.     if (nfsdFattrGet ((NFS_FILE_HANDLE *) &readFile->file,
  944.  &retVal->readres_u.reply.attributes) == ERROR)
  945.      {
  946. retVal->status = nfsdErrToNfs (errno);
  947. return (retVal);
  948. }
  949.     retVal->status = NFS_OK;
  950.     return (retVal);
  951.     }
  952. /******************************************************************************
  953. *
  954. * nfsproc_writecache_2 - unused
  955. *
  956. * NOMANUAL
  957. */
  958. void * nfsproc_writecache_2
  959.     (
  960.     void
  961.     )
  962.     {
  963.     /* Increment statistics */
  964.     nfsdServerStatus.writecacheCalls++;
  965.     return ((void *) KHEAP_ALLOC(0));
  966.     }
  967. /******************************************************************************
  968. *
  969. * nfsproc_write_2 -
  970. * Writes "data" beginning "offset" bytes from the beginning of "file".
  971. * The first byte of the file is at offset zero.  If the reply "status"
  972. * is NFS_OK, then the reply "attributes" contains the attributes of the
  973. * file after the write has completed.  The write operation is atomic.
  974. * Data from this "WRITE" will not be mixed with data from another
  975. * client's "WRITE".
  976. * Notes:  The arguments "beginoffset" and "totalcount" are ignored and
  977. * are removed in the next protocol revision.
  978. *
  979. * NOMANUAL
  980. */
  981. attrstat * nfsproc_write_2
  982.     (
  983.     writeargs * wrArgs /* File, write data, and offset information */
  984.     )
  985.     {
  986.     char *      fileName;       /* Name of the file to write */
  987.     attrstat *  retVal; /* Return value */
  988.     int         fd; /* File descriptor for file to write */
  989.     int nBytes; /* Number of bytes actually written */
  990.     int         writeCount;     /* Number of bytes to write */
  991.     BOOL        writeError = FALSE;
  992.     
  993.     if ((retVal = KHEAP_ALLOC(sizeof (*retVal))) == NULL)
  994. return (NULL);
  995.     
  996.     if ((fileName = (char *) alloca (nfsMaxPath)) == NULL)
  997. return (NULL);
  998.     /* Increment statistics */
  999.     nfsdServerStatus.writeCalls++;
  1000.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &wrArgs->file);
  1001.     
  1002.     /* Make sure the file system is writeable */
  1003.     if (nfsdFsReadOnly((NFS_FILE_HANDLE *) &wrArgs->file))
  1004. {
  1005. retVal->status = NFSERR_ACCES;
  1006. return (retVal);
  1007. }
  1008.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &wrArgs->file, fileName) == ERROR)
  1009. {
  1010. retVal->status = nfsdErrToNfs (errno);
  1011. return (retVal);
  1012. }
  1013.     if ((fd = open (fileName, O_WRONLY, 0)) == ERROR)
  1014. {
  1015. retVal->status = nfsdErrToNfs (errno);
  1016. return (retVal);
  1017. }
  1018.     
  1019.     if (lseek (fd, wrArgs->offset, SEEK_SET) != wrArgs->offset)
  1020.      {
  1021. retVal->status = nfsdErrToNfs (errno);
  1022. close (fd);
  1023. return (retVal);
  1024. }
  1025.     errno = OK;
  1026.     writeCount = wrArgs->data.data_len;
  1027.     if ((nBytes = write (fd, wrArgs->data.data_val, writeCount)) != writeCount)
  1028. {
  1029. if (errno == OK)
  1030.     {
  1031.     /* Try this twice to get around a dosFs bug */
  1032.     writeCount -= nBytes;
  1033.     if (write (fd, wrArgs->data.data_val, writeCount) != writeCount)
  1034. writeError = TRUE;
  1035.     }
  1036. else
  1037.     writeError = TRUE;
  1038. if (writeError)
  1039.     {
  1040.     retVal->status = nfsdErrToNfs (errno);
  1041.     close (fd);
  1042.     return (retVal);
  1043.     }
  1044. }
  1045.     
  1046.     if (close (fd) == ERROR)
  1047.      {
  1048. retVal->status = nfsdErrToNfs (errno);
  1049. return (retVal);
  1050. }
  1051.     if (nfsdFattrGet ((NFS_FILE_HANDLE *) &wrArgs->file,
  1052.  &retVal->attrstat_u.attributes) == ERROR)
  1053. {
  1054. retVal->status = nfsdErrToNfs (errno);
  1055. return (retVal);
  1056. }
  1057.     retVal->status = NFS_OK;
  1058.     return (retVal);
  1059.     }
  1060. /******************************************************************************
  1061. *
  1062. * nfsproc_create_2 - create a file
  1063. * The file "name" is created in the directory given by "dir".  The
  1064. * initial attributes of the new file are given by "attributes".  A
  1065. * reply "status" of NFS_OK indicates that the file was created, and
  1066. * reply "file" and reply "attributes" are its file handle and
  1067. * attributes.  Any other reply "status" means that the operation failed
  1068. * and no file was created.
  1069. * Notes:  This routine should pass an exclusive create flag, meaning
  1070. * "create the file only if it is not already there".
  1071. * NOMANUAL
  1072. */
  1073. diropres * nfsproc_create_2
  1074.     (
  1075.     createargs * newFile  /* File to create */
  1076.     )
  1077.     {
  1078.     diropres *   retVal = KHEAP_ALLOC(sizeof (diropres)); /* Return value */
  1079.     char *       newName;       /* Name of file to create */
  1080.     int          fd; /* File descriptor for file to create */
  1081.     if (retVal == NULL)
  1082.         return (NULL);
  1083.     
  1084.     if ((newName = (char *) alloca (nfsMaxPath)) == NULL)
  1085. return (NULL);
  1086.     /* Increment statistics */
  1087.     nfsdServerStatus.createCalls++;
  1088.     /* Create the name for the new file by getting the name of the directory,
  1089.      * followed by "/" and the name of the new file
  1090.      */
  1091.     
  1092.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &newFile->where.dir);
  1093.     
  1094.     /* Make sure the file system is writeable */
  1095.     if (nfsdFsReadOnly((NFS_FILE_HANDLE *) &newFile->where.dir))
  1096. {
  1097. retVal->status = NFSERR_ACCES;
  1098. return (retVal);
  1099. }
  1100.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &newFile->where.dir, newName)
  1101. == ERROR)
  1102. {
  1103. retVal->status = nfsdErrToNfs (errno);
  1104. return (retVal);
  1105. }
  1106.     strcat (newName, "/");
  1107.     strcat (newName, newFile->where.name);
  1108.     /* Check if the file has been created already */
  1109.     if ((fd = open (newName, O_RDWR, 0)) != ERROR)
  1110. {
  1111. retVal->status = NFSERR_EXIST;
  1112. close(fd);
  1113. return (retVal);
  1114. }
  1115.     /* Create the file */
  1116.     
  1117.     if ((fd = open (newName, O_RDWR | O_CREAT, 0)) == ERROR)
  1118.      {
  1119. retVal->status = nfsdErrToNfs (errno);
  1120. return (retVal);
  1121. }
  1122.     
  1123.     if (close (fd) == ERROR)
  1124. {
  1125. retVal->status = nfsdErrToNfs (errno);
  1126. return (retVal);
  1127. }
  1128.     /* Create its file handle */
  1129.     if (nfsdFhCreate ((NFS_FILE_HANDLE *) &newFile->where.dir,
  1130.  newFile->where.name,
  1131.  (NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file)
  1132. == ERROR)
  1133.      {
  1134. retVal->status = nfsdErrToNfs (errno);
  1135. return (retVal);
  1136. }
  1137.     /* Get its attributes */
  1138.     if (nfsdFattrGet ((NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file,
  1139.      &retVal->diropres_u.diropres.attributes) == ERROR)
  1140.      {
  1141. retVal->status = nfsdErrToNfs (errno);
  1142. return (retVal);
  1143. }
  1144.     retVal->status = NFS_OK;
  1145.     nfsdFhHton ((NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file);
  1146.     
  1147.     return (retVal);
  1148.     }
  1149. /******************************************************************************
  1150. *
  1151. * nfsproc_remove_2 - remove a file
  1152. * The file "name" is removed from the directory given by "dir".  A
  1153. * reply of NFS_OK means the directory entry was removed.
  1154. * Notes:  possibly non-idempotent operation.
  1155. * NOMANUAL
  1156. */
  1157. nfsstat * nfsproc_remove_2
  1158.     (
  1159.     diropargs * removeFile /* File to be removed */
  1160.     )
  1161.     {
  1162.     nfsstat * retVal = KHEAP_ALLOC(sizeof (nfsstat)); /* Return value */
  1163.     char *    newName;          /* Name of the file to be removed */
  1164.     if (retVal == NULL)
  1165.         return NULL;
  1166.     if ((newName = (char *) alloca (nfsMaxPath)) == NULL)
  1167. return (NULL);
  1168.     /* Increment statistics */
  1169.     nfsdServerStatus.removeCalls++;
  1170.     /* Create the name for removed file by getting the name of the directory,
  1171.      * followed by "/" and the name of the new file
  1172.      */
  1173.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &removeFile->dir);
  1174.     
  1175.     /* Make sure the file system is writeable */
  1176.     if (nfsdFsReadOnly((NFS_FILE_HANDLE *) &removeFile->dir))
  1177. {
  1178. *retVal = NFSERR_ACCES;
  1179. return (retVal);
  1180. }
  1181.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &removeFile->dir, newName)
  1182. == ERROR)
  1183. {
  1184. *retVal = nfsdErrToNfs (errno);
  1185. return (retVal);
  1186. }
  1187.     strcat (newName, "/");
  1188.     strcat (newName, removeFile->name);
  1189.     /* Do the removal */
  1190.     if (unlink (newName) == ERROR)
  1191. *retVal = nfsdErrToNfs (errno);
  1192.     else
  1193. *retVal = NFS_OK;
  1194.     return (retVal);
  1195.     }
  1196. /******************************************************************************
  1197. *
  1198. * nfsproc_rename_2 - rename a file
  1199. * The existing file "from.name" in the directory given by "from.dir" is
  1200. * renamed to "to.name" in the directory given by "to.dir".  If the
  1201. * reply is NFS_OK, the file was renamed.  The RENAME operation is
  1202. * atomic on the server; it cannot be interrupted in the middle.
  1203. * Notes:  possibly non-idempotent operation.
  1204. * NOMANUAL
  1205. */
  1206. nfsstat * nfsproc_rename_2
  1207.     (
  1208.     renameargs * names /* New and old file names */
  1209.     )
  1210.     {
  1211.     nfsstat * retVal = KHEAP_ALLOC(sizeof (nfsstat)); /* Return value */
  1212.     char *    oldName;                                /* Old file name */
  1213.     char *    newName;                                /* New file name */
  1214.     /* Increment statistics */
  1215.     nfsdServerStatus.renameCalls++;
  1216.     if (retVal == NULL)
  1217.         return (NULL);
  1218.     
  1219.     if ((oldName = (char *) alloca (nfsMaxPath)) == NULL)
  1220. return (NULL);
  1221.     if ((newName = (char *) alloca (nfsMaxPath)) == NULL)
  1222. return (NULL);
  1223.     /* Create strings for the old and new file names */
  1224.     
  1225.     nfsdFhNtoh ((NFS_FILE_HANDLE *)  &names->from.dir);
  1226.     nfsdFhNtoh ((NFS_FILE_HANDLE *)  &names->to.dir);
  1227.     
  1228.     /* Make sure the file system is writeable */
  1229.     if (nfsdFsReadOnly((NFS_FILE_HANDLE *) &names->from.dir))
  1230. {
  1231. *retVal = NFSERR_ACCES;
  1232. return (retVal);
  1233. }
  1234.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &names->from.dir, oldName)
  1235. == ERROR)
  1236. {
  1237. *retVal = nfsdErrToNfs (errno);
  1238. return (retVal);
  1239. }
  1240.     strcat (oldName, "/");
  1241.     strcat (oldName, names->from.name);
  1242.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &names->to.dir, newName)
  1243. == ERROR)
  1244. {
  1245. *retVal = nfsdErrToNfs (errno);
  1246. return (retVal);
  1247. }
  1248.     strcat (newName, "/");
  1249.     strcat (newName, names->to.name);
  1250.     /* Do the rename() */
  1251.     if (rename (oldName, newName) == ERROR)
  1252. {
  1253. *retVal = nfsdErrToNfs (errno);
  1254. return (retVal);
  1255. }
  1256.     else
  1257.         *retVal = NFS_OK;
  1258.     
  1259.     return (retVal);
  1260.     }
  1261. /******************************************************************************
  1262. *
  1263. * nfsproc_link_2 - create a link - not supported by VxWorks
  1264. *
  1265. * NOMANUAL
  1266. */
  1267. nfsstat * nfsproc_link_2
  1268.     (
  1269.     void
  1270.     )
  1271.     {
  1272.     nfsstat * notSupported = KHEAP_ALLOC(sizeof (nfsstat));
  1273.     *notSupported = EOPNOTSUPP;
  1274.     return ((nfsstat *) notSupported);
  1275.     }
  1276. /******************************************************************************
  1277. *
  1278. * nfsproc_symlink_2 - create a symbolic link - not supported by VxWorks
  1279. *
  1280. * NOMANUAL
  1281. */
  1282. nfsstat * nfsproc_symlink_2
  1283.     (
  1284.     void
  1285.     )
  1286.     {
  1287.     nfsstat * notSupported = KHEAP_ALLOC(sizeof (nfsstat));
  1288.     /* Increment statistics */
  1289.     nfsdServerStatus.symlinkCalls++;
  1290.     *notSupported = EOPNOTSUPP;
  1291.     return ((nfsstat *) notSupported);
  1292.     }
  1293. /******************************************************************************
  1294. *
  1295. * nfsproc_mkdir_2 - create a directory
  1296. * The new directory "where.name" is created in the directory given by
  1297. * "where.dir".  The initial attributes of the new directory are given
  1298. * by "attributes".  A reply "status" of NFS_OK indicates that the new
  1299. * directory was created, and reply "file" and reply "attributes" are
  1300. * its file handle and attributes.  Any other reply "status" means that
  1301. * the operation failed and no directory was created.
  1302. * Notes:  possibly non-idempotent operation.
  1303. *
  1304. * NOMANUAL
  1305. */
  1306. diropres * nfsproc_mkdir_2
  1307.     (
  1308.     createargs * crArgs
  1309.     )
  1310.     {
  1311.     diropres *      retVal = KHEAP_ALLOC(sizeof (diropres));
  1312.     char *          newName;
  1313.     if (retVal == NULL)
  1314.         return (NULL);
  1315.     
  1316.     if ((newName = (char *) alloca (nfsMaxPath)) == NULL)
  1317. return (NULL);
  1318.     /* Increment statistics */
  1319.     nfsdServerStatus.mkdirCalls++;
  1320.     retVal->status = NFS_OK;
  1321.     /* Create the string for the name of the directory to make */
  1322.     
  1323.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &crArgs->where.dir);
  1324.     
  1325.     /* Make sure the file system is writeable */
  1326.     if (nfsdFsReadOnly((NFS_FILE_HANDLE *) &crArgs->where.dir))
  1327. {
  1328. retVal->status = NFSERR_ACCES;
  1329. return (retVal);
  1330. }
  1331.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &crArgs->where.dir, newName)
  1332. == ERROR)
  1333. {
  1334. retVal->status = nfsdErrToNfs (errno);
  1335. return (retVal);
  1336. }
  1337.     strcat (newName, "/");
  1338.     strcat (newName, crArgs->where.name);
  1339.     /* make the directory */
  1340.     if (mkdir (newName) == ERROR)
  1341.      {
  1342. retVal->status = nfsdErrToNfs (errno);
  1343. return (retVal);
  1344. }
  1345.     /* Create a file handle for the new directory */
  1346.     if (nfsdFhCreate ((NFS_FILE_HANDLE *) &crArgs->where.dir,
  1347.  crArgs->where.name,
  1348.  (NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file)
  1349. == ERROR)
  1350.      {
  1351. retVal->status = nfsdErrToNfs (errno);
  1352. return (retVal);
  1353. }
  1354.     /* Get the file attributes for the new directory */
  1355.     if (nfsdFattrGet ((NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file,
  1356.      &retVal->diropres_u.diropres.attributes) == ERROR)
  1357.      {
  1358. retVal->status = nfsdErrToNfs (errno);
  1359. return (retVal);
  1360. }
  1361.     nfsdFhHton ((NFS_FILE_HANDLE *) &retVal->diropres_u.diropres.file);
  1362.     return (retVal);
  1363.     }
  1364. /******************************************************************************
  1365. *
  1366. * nfsproc_rmdir_2 - remove a directory
  1367. * The existing empty directory "name" in the directory given by "dir"
  1368. * is removed.  If the reply is NFS_OK, the directory was removed.
  1369. * Notes:  possibly non-idempotent operation.
  1370. *
  1371. * NOMANUAL
  1372. */
  1373. nfsstat * nfsproc_rmdir_2
  1374.     (
  1375.     diropargs * removeDir /* Directory to remove */
  1376.     )
  1377.     {
  1378.     nfsstat * retVal = KHEAP_ALLOC(sizeof (nfsstat)); /* Return value */
  1379.     char *    newName;          /* Path name of directory to remove */
  1380.     if (retVal == NULL)
  1381.         return NULL;
  1382.     if ((newName = (char *) alloca (nfsMaxPath)) == NULL)
  1383. return (NULL);
  1384.     /* Increment statistics */
  1385.     nfsdServerStatus.rmdirCalls++;
  1386.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &removeDir->dir);
  1387.     
  1388.     /* Make sure the file system is writeable */
  1389.     if (nfsdFsReadOnly((NFS_FILE_HANDLE *) &removeDir->dir))
  1390. {
  1391. *retVal = NFSERR_ACCES;
  1392. return (retVal);
  1393. }
  1394.     /* Create the name of the doomed directory */
  1395.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &removeDir->dir, newName) == ERROR)
  1396. {
  1397. *retVal = nfsdErrToNfs (errno);
  1398. return (retVal);
  1399. }
  1400.     strcat (newName, "/");
  1401.     strcat (newName, removeDir->name);
  1402.     /* Remove it */
  1403.     if (rmdir (newName) == ERROR)
  1404. *retVal = nfsdErrToNfs (errno);
  1405.     else
  1406. *retVal = NFS_OK;
  1407.     return (retVal);
  1408.     }
  1409. /******************************************************************************
  1410. *
  1411. * nfsproc_readdir_2 - read from a directory
  1412. * Returns a variable number of directory entries, with a total size of
  1413. * up to "count" bytes, from the directory given by "dir".  If the
  1414. * returned value of "status" is NFS_OK, then it is followed by a
  1415. * variable number of "entry"s.  Each "entry" contains a "fileid" which
  1416. * consists of a unique number to identify the file within a filesystem,
  1417. * the "name" of the file, and a "cookie" which is an opaque pointer to
  1418. * the next entry in the directory.  The cookie is used in the next
  1419. * READDIR call to get more entries starting at a given point in the
  1420. * directory.  The special cookie zero (all bits zero) can be used to
  1421. * get the entries starting at the beginning of the directory.  The
  1422. * "fileid" field should be the same number as the "fileid" in the the
  1423. * attributes of the file.  (See section "2.3.5. fattr" under "Basic
  1424. * Data Types".)  The "eof" flag has a value of TRUE if there are no
  1425. * more entries in the directory.
  1426. * NOMANUAL
  1427. */
  1428. readdirres * nfsproc_readdir_2
  1429.     (
  1430.     readdirargs * readDir /* Directory to read */
  1431.     )
  1432.     {
  1433.     struct entry *  dirEntries;
  1434.     filename *      fileNames;
  1435.     int             fileNameSize;
  1436.     int             entrySpace;
  1437.     char *          currentName;
  1438.     char *          dirName;
  1439.     DIR *     theDir = NULL;
  1440.     struct dirent * localEntry;
  1441.     readdirres *    retVal;
  1442.     int     dirCount = 0;
  1443.     char *          newFile;
  1444.     int             numEntries;
  1445.     int             entryCurrent;
  1446.     if ((dirName = (char *) alloca (nfsMaxPath)) == NULL)
  1447. return (NULL);
  1448.     if ((newFile = (char *) alloca (nfsMaxPath)) == NULL)
  1449. return (NULL);
  1450.     /* Increment statistics */
  1451.     nfsdServerStatus.readdirCalls++;
  1452.     /* Compute the amount of space needed for each directory entry */
  1453.     fileNameSize = MEM_ROUND_UP (NAME_LEN + 1);
  1454.     entrySpace = MEM_ROUND_UP (sizeof (readdirres)) +
  1455.          MEM_ROUND_UP (sizeof (entry)) +
  1456.          fileNameSize;
  1457.     
  1458.     /* Compute the number of possible entries to return */
  1459.     
  1460.     numEntries = readDir->count / entrySpace;
  1461.     /* Allocate space for the entries */
  1462.     
  1463.     if ((retVal = KHEAP_ALLOC(numEntries * entrySpace)) == NULL)
  1464. {
  1465.         return (NULL);
  1466. }
  1467.     else
  1468. {
  1469. bzero ((char *) retVal, numEntries * entrySpace);
  1470. dirEntries = ((struct entry *) retVal) + 1;
  1471. fileNames = (filename *) (dirEntries + numEntries);
  1472. }
  1473.     nfsdFhNtoh ((NFS_FILE_HANDLE *) &readDir->dir);
  1474.     
  1475.     /* Create the directory name */
  1476.     if (nfsdFhToName ((NFS_FILE_HANDLE *) &readDir->dir, dirName) == ERROR)
  1477.      {
  1478. retVal->status = nfsdErrToNfs (errno);
  1479. return (retVal);
  1480. }
  1481.     /* Open the directory and set the cookie field to what was
  1482.      * passed in readDir
  1483.      */
  1484.     if ((theDir = opendir (dirName)) == NULL)
  1485.      {
  1486. retVal->status = nfsdErrToNfs (errno);
  1487. return (retVal);
  1488. }
  1489.     else
  1490.         theDir->dd_cookie = *((int *) &readDir->cookie);
  1491.     retVal->readdirres_u.reply.eof = FALSE;
  1492.     
  1493.     /* Read through all the files in the directory */
  1494.     for (entryCurrent = 0; entryCurrent < numEntries; entryCurrent++)
  1495. {
  1496. errno = OK;
  1497. localEntry = readdir (theDir);
  1498. if (localEntry == NULL)
  1499.     {
  1500.     if (errno != OK)
  1501. {
  1502. retVal->status = nfsdErrToNfs (errno);
  1503. closedir (theDir);
  1504. return (retVal);
  1505. }
  1506.     else
  1507. {
  1508. retVal->readdirres_u.reply.eof = TRUE;
  1509. if (entryCurrent != 0)
  1510.     dirEntries[entryCurrent - 1].nextentry = NULL;
  1511. else
  1512.     retVal->readdirres_u.reply.entries = NULL;
  1513.         break;
  1514. }
  1515.     }
  1516. strcpy (newFile, dirName);
  1517. strcat (newFile, "/");
  1518. strcat (newFile, localEntry->d_name);
  1519. dirEntries[entryCurrent].fileid = 
  1520.    nameToInode (((NFS_FILE_HANDLE *) &readDir->dir)->volumeId, newFile);
  1521. if (dirEntries[entryCurrent].fileid == ERROR)
  1522.     {
  1523.     retVal->status = nfsdErrToNfs (errno);
  1524.     closedir (theDir);
  1525.     return (retVal);
  1526.     }
  1527. currentName = ((char *) fileNames) + entryCurrent * fileNameSize;
  1528. strcpy(currentName, localEntry->d_name);
  1529. dirEntries[entryCurrent].name = currentName;
  1530. *((int *) dirEntries[entryCurrent].cookie) = theDir->dd_cookie;
  1531. if (entryCurrent == numEntries - 1)
  1532.     dirEntries[entryCurrent].nextentry = NULL;
  1533. else
  1534.     dirEntries[entryCurrent].nextentry = &dirEntries[entryCurrent + 1];
  1535.     
  1536. dirCount++;
  1537. }
  1538.     retVal->status = NFS_OK;
  1539.     if (dirCount != 0)
  1540. retVal->readdirres_u.reply.entries = dirEntries;
  1541.     else
  1542. retVal->readdirres_u.reply.entries = NULL;
  1543.     closedir (theDir);
  1544.     return (retVal);
  1545.     }
  1546. /******************************************************************************
  1547. *
  1548. * nfsproc_statfs_2 - Get filesystem attributes
  1549. * Return information about the filesystem.  The NFS equivalent of statfs().
  1550. *
  1551. * NOMANUAL
  1552. */
  1553. statfsres * nfsproc_statfs_2
  1554.     (
  1555.     nfs_fh * fh
  1556.     )
  1557.     {
  1558.     char *        fileName;
  1559.     struct statfs statInfo;
  1560.     statfsres *   retVal = KHEAP_ALLOC(sizeof (statfsres));
  1561.     if (retVal == NULL)
  1562.         return (NULL);
  1563.     if ((fileName = (char *) alloca (nfsMaxPath)) == NULL)
  1564. return (NULL);
  1565.     /* Increment statistics */
  1566.     nfsdServerStatus.statfsCalls++;
  1567.     nfsdFhNtoh ((NFS_FILE_HANDLE *) fh);
  1568.     if (nfsdFhToName ((NFS_FILE_HANDLE *) fh, fileName) == ERROR)
  1569.      {
  1570. retVal->status = nfsdErrToNfs (errno);
  1571. return (retVal);
  1572. }
  1573.     if (statfs (fileName, &statInfo) == ERROR)
  1574.      {
  1575. retVal->status = nfsdErrToNfs (errno);
  1576. return (retVal);
  1577. }
  1578.     retVal->status = NFS_OK;
  1579.     retVal->statfsres_u.reply.tsize  = 8 * 1024;
  1580.     retVal->statfsres_u.reply.bsize  = statInfo.f_bsize;
  1581.     retVal->statfsres_u.reply.blocks = statInfo.f_blocks;
  1582.     retVal->statfsres_u.reply.bfree  = statInfo.f_bfree;
  1583.     retVal->statfsres_u.reply.bavail = statInfo.f_bavail;
  1584.     return (retVal);
  1585.     }
  1586. /******************************************************************************
  1587. *
  1588. * nfsdStatusGet - get the status of the NFS server
  1589. * This routine gets status information about the NFS server.
  1590. * RETURNS: OK, or ERROR if the information cannot be obtained.
  1591. */
  1592. STATUS nfsdStatusGet
  1593.     (
  1594.     NFS_SERVER_STATUS * serverStats /* pointer to status structure */
  1595.     )
  1596.     {
  1597.     memcpy (serverStats, &nfsdServerStatus, sizeof (nfsdServerStatus));
  1598.     return (OK);
  1599.     }
  1600. /******************************************************************************
  1601. *
  1602. * nfsdStatusShow - show the status of the NFS server
  1603. * This routine shows status information about the NFS server.
  1604. * RETURNS: OK, or ERROR if the information cannot be obtained.
  1605. */
  1606. STATUS nfsdStatusShow
  1607.     (
  1608.     int options /* unused */
  1609.     )
  1610.     {
  1611.     NFS_SERVER_STATUS serverStat;
  1612.     char*             outputFormat = "%15s %8dn";
  1613.     if (nfsdStatusGet (&serverStat) == ERROR)
  1614.         return (ERROR);
  1615.     printf ("%15s    %8sn", "Service", "Number of Calls");
  1616.     printf ("%15s    %8sn", "-------", "---------------");
  1617.     printf (outputFormat, "null", serverStat.nullCalls);
  1618.     printf (outputFormat, "getattr", serverStat.getattrCalls);
  1619.     printf (outputFormat, "setattr", serverStat.setattrCalls);
  1620.     printf (outputFormat, "root", serverStat.rootCalls);
  1621.     printf (outputFormat, "lookup", serverStat.lookupCalls);
  1622.     printf (outputFormat, "readlink", serverStat.readlinkCalls);
  1623.     printf (outputFormat, "read", serverStat.readCalls);
  1624.     printf (outputFormat, "writecache", serverStat.writecacheCalls);
  1625.     printf (outputFormat, "write", serverStat.writeCalls);
  1626.     printf (outputFormat, "create", serverStat.createCalls);
  1627.     printf (outputFormat, "remove", serverStat.removeCalls);
  1628.     printf (outputFormat, "rename", serverStat.renameCalls);
  1629.     printf (outputFormat, "link", serverStat.linkCalls);
  1630.     printf (outputFormat, "symlink", serverStat.symlinkCalls);
  1631.     printf (outputFormat, "mkdir", serverStat.mkdirCalls);
  1632.     printf (outputFormat, "rmdir", serverStat.rmdirCalls);
  1633.     printf (outputFormat, "readdir", serverStat.readdirCalls);
  1634.     printf (outputFormat, "statfs", serverStat.statfsCalls);
  1635.     return (OK);
  1636.     }
  1637. /******************************************************************************
  1638. *
  1639. * nfsdFhCreate - Create an NFS file handle
  1640. *
  1641. * Given a handle to the parent directory, and the name of a file inside that
  1642. * directory, create a new file handle that specifies the file.
  1643. * RETURNS:  OK, or ERROR if a file handle for the specified file could not be
  1644. * created.
  1645. *
  1646. * NOMANUAL
  1647. */
  1648. STATUS nfsdFhCreate
  1649.     (
  1650.     NFS_FILE_HANDLE * parentDir,
  1651.     char *            fileName,
  1652.     NFS_FILE_HANDLE * fh
  1653.     )
  1654.     {
  1655.     struct stat       str;
  1656.     char *            fullName;
  1657.     char              *p;       /* to remove slash from end of fileName */
  1658.     if ((fullName = (char *) alloca (nfsMaxPath)) == NULL)
  1659. return (ERROR);
  1660.     memset (fh, 0, NFS_FHSIZE);
  1661.     
  1662.     if (nfsdFhToName (parentDir, fullName) == ERROR)
  1663.         return (ERROR);
  1664.     
  1665.     /* build fullname, but remove slash from the end of fileName */
  1666.     /* in order to lkup correspond name from nfsHash             */
  1667.  
  1668.     strcat (fullName, "/");
  1669.     strcat (fullName, fileName);
  1670.     pathCondense (fullName);
  1671.     for (p = strchr (fullName, EOS); p != fullName && *--p == '/'; )
  1672.          *p = EOS;
  1673.     if (stat (fullName, &str) == ERROR)
  1674.         return (ERROR);
  1675.     fh->volumeId = parentDir->volumeId;
  1676.     fh->fsId     = parentDir->fsId;
  1677.     fh->inode    = nfsNmLkupIns (parentDir->volumeId, fullName);
  1678.     if (fh->inode == ERROR)
  1679. return (ERROR);
  1680.     return (OK);
  1681.     }
  1682. /******************************************************************************
  1683. *
  1684. * nfsdFhToName - Convert a file handle to a complete file name
  1685. * Given a file handle, fill in the variable fileName with a string specifying
  1686. * that file.
  1687. * RETURNS:  OK, or ERROR if the file name could not be created.
  1688. *
  1689. * NOMANUAL
  1690. */
  1691. STATUS nfsdFhToName
  1692.     (
  1693.     NFS_FILE_HANDLE * fh,
  1694.     char *            fileName
  1695.     )
  1696.     {
  1697.     NFS_EXPORT_ENTRY *  fileSys;
  1698.     if ((fileSys = nfsExportFindById (fh->volumeId)) == NULL)
  1699.         return (ERROR);
  1700.     if (nfsFhLkup (fh, fileName) == ERROR)
  1701.         {
  1702. errno = NFSERR_STALE;
  1703.         return (ERROR);
  1704. }
  1705.     return (OK);
  1706.     }
  1707. /******************************************************************************
  1708. *
  1709. * nfsdFattrGet - Get the file attributes for a file specified by a file handle
  1710. * Given a file handle, fill in the file attribute structure pointed to by
  1711. * fileAttributes.
  1712. * RETURNS:  OK, or ERROR if the file attributes could not be obtained.
  1713. *
  1714. * NOMANUAL
  1715. */
  1716. STATUS nfsdFattrGet
  1717.     (
  1718.     NFS_FILE_HANDLE * fh,
  1719.     struct fattr *    fileAttributes
  1720.     )
  1721.     {
  1722.     char *         fileName;
  1723.     struct stat    str;
  1724.     
  1725.     if ((fileName = (char *) alloca (nfsMaxPath)) == NULL)
  1726. return (ERROR);
  1727.     if (nfsdFhToName (fh, fileName) == ERROR)
  1728.         return (ERROR);
  1729.     
  1730.     if (stat (fileName, &str) == ERROR)
  1731.         return (ERROR);
  1732.     /* set the type */
  1733.     switch (str.st_mode & S_IFMT)
  1734. {
  1735. case S_IFIFO:
  1736.     fileAttributes->type = NFFIFO;
  1737.     break;
  1738. case S_IFCHR:
  1739.     fileAttributes->type = NFCHR;
  1740.     break;
  1741. case S_IFDIR:
  1742.     fileAttributes->type = NFDIR;
  1743.     break;
  1744. case S_IFBLK:
  1745.     fileAttributes->type = NFBLK;
  1746.     break;
  1747. case S_IFREG:
  1748.     fileAttributes->type = NFREG;
  1749.     break;
  1750. case S_IFLNK:
  1751.     fileAttributes->type = NFLNK;
  1752.     break;
  1753. case S_IFSOCK:
  1754.     fileAttributes->type = NFSOCK;
  1755.     break;
  1756. }
  1757.     fileAttributes->mode      = str.st_mode;
  1758.     fileAttributes->nlink     = str.st_nlink;
  1759.     fileAttributes->uid       = str.st_uid;
  1760.     fileAttributes->gid       = str.st_gid;
  1761.     fileAttributes->size      = str.st_size;
  1762.     fileAttributes->blocksize = str.st_blksize;
  1763.     fileAttributes->rdev      = str.st_rdev;
  1764.     fileAttributes->blocks    = str.st_blocks + 1;
  1765.     fileAttributes->fileid    = fh->inode;
  1766.     fileAttributes->fsid      = str.st_dev;
  1767.     fileAttributes->rdev      = str.st_rdev;
  1768.     fileAttributes->atime.seconds = str.st_atime;
  1769.     fileAttributes->mtime.seconds = str.st_mtime;
  1770.     fileAttributes->ctime.seconds = str.st_ctime;
  1771.     fileAttributes->atime.useconds = 0;
  1772.     fileAttributes->mtime.useconds = 0;
  1773.     fileAttributes->ctime.useconds = 0;
  1774.     return (OK);
  1775.     }
  1776. /******************************************************************************
  1777. *
  1778. * nfsdErrToNfs - Convert a VxWorks error number to an NFS error number
  1779. * Given a VxWorks error number, find the equivalent NFS error number.
  1780. * If an exact match is not found, return NFSERR_IO.
  1781. * RETURNS:  The NFS error number.
  1782. *
  1783. * NOMANUAL
  1784. */
  1785. nfsstat nfsdErrToNfs
  1786.     (
  1787.     int theErr /* The error number to convert  */
  1788.     )
  1789.     {
  1790.     switch (theErr)
  1791. {
  1792. case EPERM:
  1793. case S_dosFsLib_READ_ONLY:
  1794. case S_dosFsLib_WRITE_ONLY:
  1795.     return (NFSERR_PERM);
  1796.     break;
  1797.     
  1798. case ENOENT:
  1799. case S_dosFsLib_FILE_NOT_FOUND:
  1800.     return (NFSERR_NOENT);
  1801.     break;
  1802. case EIO:
  1803.     return (NFSERR_IO);
  1804.     break;
  1805.     
  1806. case ENXIO:
  1807. case S_dosFsLib_VOLUME_NOT_AVAILABLE:
  1808.     return (NFSERR_NXIO);
  1809.     break;
  1810.     
  1811. case EACCES:
  1812.     return (NFSERR_ACCES);
  1813.     break;
  1814.     
  1815. case EEXIST:
  1816. case S_dosFsLib_FILE_EXISTS:
  1817.     return (NFSERR_EXIST);
  1818.     break;
  1819. case ENODEV:
  1820.     return (NFSERR_NODEV);
  1821.     break;
  1822.     
  1823. case ENOTDIR:
  1824. case S_dosFsLib_NOT_DIRECTORY:
  1825.     return (NFSERR_NOTDIR);
  1826.     break;
  1827.     
  1828. case EISDIR:
  1829.     return (NFSERR_ISDIR);
  1830.     break;
  1831.     
  1832. case EFBIG:
  1833.     return (NFSERR_FBIG);
  1834.     break;
  1835.     
  1836. case ENOSPC:
  1837. case S_dosFsLib_DISK_FULL:
  1838.     return (NFSERR_NOSPC);
  1839.     break;
  1840.     
  1841. case EROFS:
  1842.     return (NFSERR_ROFS);
  1843.     break;
  1844.     
  1845. case ENAMETOOLONG:
  1846. case S_dosFsLib_ILLEGAL_NAME:
  1847.     return (NFSERR_NAMETOOLONG);
  1848.     break;
  1849.     
  1850. case S_dosFsLib_DIR_NOT_EMPTY:
  1851. case ENOTEMPTY:
  1852.     return (NFSERR_NOTEMPTY);
  1853.     break;
  1854.     
  1855.         default:
  1856.     /* If the error number is less than 100, just return it.
  1857.      * NFS client implementations should understand anything
  1858.      * that looks like a UNIX error number.  If it's greater than
  1859.      * 100, return NFSERR_IO.
  1860.      */
  1861.     if (theErr < 100)
  1862. return theErr;
  1863.     else
  1864. return (NFSERR_IO);
  1865.     break;
  1866. }
  1867.     }
  1868. /******************************************************************************
  1869. *
  1870. * nfsdFhHton - convert a file handle from host to network byte order
  1871. *
  1872. * NOMANUAL
  1873. */
  1874. void nfsdFhHton
  1875.     (
  1876.     NFS_FILE_HANDLE * fh
  1877.     )
  1878.     {
  1879.     fh->volumeId = htonl (fh->volumeId);
  1880.     fh->fsId = htonl (fh->fsId);
  1881.     fh->inode = htonl (fh->inode);
  1882.     }
  1883. /******************************************************************************
  1884. *
  1885. * nfsdFhNtoh - convert a file handle from host to network byte order
  1886. *
  1887. * NOMANUAL
  1888. */
  1889. void nfsdFhNtoh
  1890.     (
  1891.     NFS_FILE_HANDLE * fh
  1892.     )
  1893.     {
  1894.     fh->volumeId = ntohl (fh->volumeId);
  1895.     fh->fsId = ntohl (fh->fsId);
  1896.     fh->inode = ntohl (fh->inode);
  1897.     }
  1898. /******************************************************************************
  1899. *
  1900. * nfsdFsReadOnly - get the mode of the NFS file system
  1901. * This routine returns TRUE if the filesystem that contains the file
  1902. * pointed to by <fh> is exported read-only.
  1903. * RETURNS: TRUE, or FALSE if the filesystem is exported read-write.
  1904. * NOMANUAL
  1905. */
  1906. LOCAL BOOL nfsdFsReadOnly
  1907.     (
  1908.     NFS_FILE_HANDLE * fh
  1909.     )
  1910.     {
  1911.     NFS_EXPORT_ENTRY *  fileSys;
  1912.     if ((fileSys = nfsExportFindById (fh->volumeId)) == NULL)
  1913.         return (ERROR);
  1914.     else
  1915. return (fileSys->readOnly);
  1916.     }