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

VxWorks

开发平台:

C/C++

  1. /* nfsDrv.c - Network File System (NFS) I/O driver */
  2. /* Copyright 1984 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 03l,07may02,kbw  man page edits
  8. 03k,06nov01,vvv  made max. path length configurable (SPR #63551)
  9. 03j,15oct01,rae  merge from truestack ver 03s, base 03h (SPR #9357 etc.)
  10. 03i,07feb01,spm  merged from version 03o of tor3_x branch (base 03h):
  11.                  fixed group validation in nfsMountAll (SPR #3524),
  12.                  added permission checks to nfsOpen() routine (SPR #21991)
  13. 03h,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  14. 03g,15dec98,cjtc added helper routine nfsDrvNumGet() to return the nfs
  15.  driver number in the io system. This is needed by the
  16.  WindView host to ensure that the upload is going via
  17.  the upload mechanism requested
  18. 03f,20nov97,gnn  fix for spr#5436, need to support FIOFSTATFSGET
  19. 03e,26aug97,spm  removed compiler warnings (SPR #7866)
  20. 03f,19aug97,cth  changed nfsCacheSize back to before 03e (SPR 7834) fixed by
  21.  fixing SPR 8460.
  22. 03e,15apr97,cth  added simsol specific fix for spr#7834 (for sirocco release), 
  23.            +dvs  at some pt this probably needs to be better integrated.
  24. 03d,06aug96,sgv  fix for spr#6468
  25. 02s,13feb95,jdi  doc tweaks.
  26. 02r,12jan95,rhp  doc: add FIOSYNC to list of NFS ioctl functions. 
  27.    Also, jdi doc tweaks to nfsDevListGet() and nfsDevInfoGet().
  28. 02q,01dec93,jag  added the routines nfsDevListGet(), and nfsDevInfoGet().  
  29.  These routines provide support for the SNMP demo.
  30. 02q,08sep94,jmm  changed NFS client to use new RPC genned xdr routines
  31. 02p,28jul93,jmm  added permission checking to nfsOpen () (spr 2046)
  32. 02o,01feb93,jdi  documentation cleanup for 5.1; added third param to
  33.  ioctl() examples.
  34. 02n,13nov92,dnw  added include of semLibP.h
  35. 02m,21oct92,jdi  removed mangen SECTION designation.
  36. 02l,02oct92,srh  added ioctl(FIOGETFL) to return file's open mode
  37. 02k,16sep92,jcf  added include of errnoLib.h.
  38. 02j,04sep92,jmm  changed nfsUnmount to make sure device names match exactly
  39.                    (spr 1564)
  40. 02i,19jul92,smb  added include fcntl.h.
  41. 02h,26may92,rrr  the tree shuffle
  42. 02g,19Mar92,jmm  changed nfsSeek to allow seeks beyond EOF
  43.                  added #include of pathLib.h
  44. 02f,20jan92,jmm  changed nfsOpen to not truncate path names after
  45.                  looking up symlinks
  46. 02e,16dec91,gae  added includes plus fixes for ANSI.
  47. 02d,04oct91,rrr  passed through the ansification filter
  48.                   -changed functions to ansi style
  49.   -changed includes to have absolute path from h/
  50.   -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ...
  51.   -changed VOID to void
  52.   -changed copyright notice
  53. 02c,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  54.  doc review by dnw.
  55. 02b,21feb91,jaa  documentation cleanup.
  56. 02a,08oct90,dnw  changed nfsMountAll verbose flag to quiet flag.
  57. 01z,08oct90,hjb  de-linted.
  58. 01y,02oct90,hjb  nfsWrite() changed to avoid reading data into cache to
  59.    keep cache up-to-date when size of data being written
  60.    is bigger than the nfs cache size.
  61. 01x,10aug90,dnw  added verbose arg to nfsMountAll().
  62. 01w,26jun90,jcf  changed semaphore types.
  63.  removed super semaphores.
  64. 01v,29may90,dnw  fixed nfsMount to free allocated memory if iosDevAdd returns
  65.    ERROR
  66. 01u,10may90,dnw  added nfsMountAll
  67.  change nfsClose() to not call nfsClientClose() (unless
  68.    nfsAutoClose is set TRUE)
  69.  made SSEMAPHORE include embedded SEM_BINARY which is inited
  70.    instead of a SEM_ID which is created (to reduce malloc).
  71.  changed NFS_MAXPATHLEN to (PATH_MAX + 1)
  72. 01t,01may90,llk  added FIOREADDIR and FIOFSTATGET ioctl calls.
  73.  deleted FIODIRENTRY ioctl call.
  74. 01s,01apr90,llk  changed nfsRead() to always return the number of bytes
  75.    requested by caller (up to the bytes left in the file).
  76.  changed name nfsFlushCache() to nfsCacheFlush().
  77.  added "DEFICIENCIES" documentation (and probably some
  78.    deficiencies).
  79.  made string arrays shorter than defined in the NFS spec.
  80.  fixed bug which didn't update file ptr correctly if cache
  81.    size was 0.
  82.  coalesced malloc of cache and fd into one malloc.
  83. 01r,14mar90,jdi  documentation cleanup.
  84. 01q,09aug89,dab  made nfsOpen() check for O_TRUNC flag.
  85.                  made nfsCreate() truncate file if file already exists.
  86. 01p,12jul89,llk  lint.
  87. 01o,24mar89,dab  caching disabled when nfsCacheSize is zero;
  88.            +gae  formerly a bug when nfsCacheSize was zero.
  89. 01n,23mar89,dab  added FIOSYNC option to nfsIoctl().
  90. 01m,21nov88,jcf  lint.
  91. 01l,19oct88,llk  documentation.
  92. 01k,28sep88,llk  documentation.
  93. 01j,24aug88,gae  documentation.  Made nfsMount() check hostname, and
  94.  allow default local name.
  95. 01i,07jul88,jcf  lint.
  96. 01h,30jun88,llk  changed to handle links.
  97.  added nfsDevShow().
  98. 01g,22jun88,dnw  changed taskIdGet() to taskIdSelf().
  99. 01f,16jun88,llk  changed to more v4 names.
  100. 01e,04jun88,llk  added rm, mkdir, rmdir.
  101.  changed how nfsOpen retrieves directory and file names.
  102. 01d,30may88,dnw  changed to v4 names.
  103. 01c,04may88,jcf  changed ssemaphores to be consistent with new semLib.
  104. 01b,22apr88,gae  fixed drvnum reference in nfsUnmount().
  105. 01a,19apr88,llk  written.
  106. */
  107. /*
  108. This driver provides facilities for accessing files transparently over the
  109. network via NFS (Network File System).  By creating a network device
  110. with nfsMount(), files on a remote NFS system (such as a UNIX system) can
  111. be handled as if they were local.
  112. USER-CALLABLE ROUTINES
  113. The nfsDrv() routine initializes the driver.  The nfsMount() and nfsUnmount()
  114. routines mount and unmount file systems.  The nfsMountAll() routine mounts
  115. all file systems exported by a specified host.
  116. INITIALIZATION
  117. Before using the network driver, it must be initialized by calling nfsDrv().
  118. This routine must be called before any reads, writes, or other NFS calls.
  119. This is done automatically when INCLUDE_NFS is defined..
  120. CREATING NFS DEVICES
  121. In order to access a remote file system, an NFS device must be created by
  122. calling nfsMount().  For example, to create the device `/myd0/' for the file
  123. system `/d0/' on the host `wrs', call:
  124. .CS
  125.     nfsMount ("wrs", "/d0/", "/myd0/");
  126. .CE
  127. The file `/d0/dog' on the host `wrs' can now be accessed as `/myd0/dog'.
  128. If the third parameter to nfsMount() is NULL, VxWorks creates a device with
  129. the same name as the file system.  For example, the call:
  130. .CS
  131.     nfsMount ("wrs", "/d0/", NULL);
  132. .CE
  133. or from the shell:
  134. .CS
  135.     nfsMount "wrs", "/d0/"
  136. .CE
  137. creates the device `/d0/'.  The file `/d0/dog' is accessed by the same name,
  138. `/d0/dog'.
  139. Before mounting a file system, the host must already have been created
  140. with hostAdd().  The routine nfsDevShow() displays the mounted NFS devices.
  141. IOCTL FUNCTIONS
  142. The NFS driver responds to the following ioctl() functions:
  143. .iP "FIOGETNAME" 18 3
  144. Gets the file name of <fd> and copies it to the buffer referenced 
  145. by <nameBuf>:
  146. .CS
  147.     status = ioctl (fd, FIOGETNAME, &nameBuf);
  148. .CE
  149. .iP "FIONREAD"
  150. Copies to <nBytesUnread> the number of bytes remaining in the file
  151. specified by <fd>:
  152. .CS
  153.     status = ioctl (fd, FIONREAD, &nBytesUnread);
  154. .CE
  155. .iP "FIOSEEK"
  156. Sets the current byte offset in the file to the position specified by
  157. <newOffset>.  If the seek goes beyond the end-of-file, the file grows.
  158. The end-of-file pointer gets moved to the new position, and the new space
  159. is filled with zeros:
  160. .CS
  161.     status = ioctl (fd, FIOSEEK, newOffset);
  162. .CE
  163. .iP "FIOSYNC"
  164. Flush data to the remote NFS file.  It takes no additional argument:
  165. .CS
  166.     status = ioctl (fd, FIOSYNC, 0);
  167. .CE
  168. .iP "FIOWHERE"
  169. Returns the current byte position in the file.  This is the byte offset of
  170. the next byte to be read or written.  It takes no additional argument:
  171. .CS
  172.     position = ioctl (fd, FIOWHERE, 0);
  173. .CE
  174. .iP "FIOREADDIR"
  175. Reads the next directory entry.  The argument <dirStruct> is a pointer to
  176. a directory descriptor of type DIR.  Normally, the readdir() routine is used to
  177. read a directory, rather than using the FIOREADDIR function directly.  See
  178. the manual entry for dirLib:
  179. .CS
  180.     DIR dirStruct;
  181.     fd = open ("directory", O_RDONLY);
  182.     status = ioctl (fd, FIOREADDIR, &dirStruct);
  183. .CE
  184. .iP "FIOFSTATGET"
  185. Gets file status information (directory entry data).  The argument
  186. <statStruct> is a pointer to a stat structure that is filled with data
  187. describing the specified file.  Normally, the stat() or fstat() routine is
  188. used to obtain file information, rather than using the FIOFSTATGET
  189. function directly.  See the manual entry for dirLib:
  190. .CS
  191.     struct stat statStruct;
  192.     fd = open ("file", O_RDONLY);
  193.     status = ioctl (fd, FIOFSTATGET, &statStruct);
  194. .CE
  195. .iP "FIOFSTATFSGET"
  196. Gets the file system parameters for and open file descriptor.  The argument
  197. <statfsStruct> is a pointer to a statfs structure that is filled with data
  198. describing the underlying filesystem.  Normally, the stat() or fstat() routine
  199. is used to obtain file information, rather than using the FIOFSTATGET function
  200. directly.  See the manual entry for dirLib:
  201. .CS
  202.     statfs statfsStruct;
  203.     fd = open ("directory", O_RDONLY);
  204.     status = ioctl (fd, FIOFSTATFSGET, &statfsStruct);
  205. .CE
  206. DEFICIENCIES
  207. There is only one client handle/cache per task.
  208. Performance is poor if a task is accessing two or more NFS files.
  209. Changing <nfsCacheSize> after a file is open could cause adverse effects.
  210. However, changing it before opening any NFS file descriptors should not
  211. pose a problem.
  212. INCLUDE FILES: nfsDrv.h, ioLib.h, dirent.h
  213. SEE ALSO: dirLib, nfsLib, hostAdd(), ioctl(),
  214. */
  215. #include "vxWorks.h"
  216. #include "iosLib.h"
  217. #include "ioLib.h"
  218. #include "memLib.h"
  219. #include "stdlib.h"
  220. #include "semLib.h"
  221. #include "string.h"
  222. #include "lstLib.h"
  223. #include "rpc/rpc.h"
  224. #include "xdr_nfs.h"
  225. #include "xdr_nfsserv.h"
  226. #include "hostLib.h"
  227. #include "sys/stat.h"
  228. #include "dirent.h"
  229. #include "errnoLib.h"
  230. #include "errno.h"
  231. #include "stdio.h"
  232. #include "nfsLib.h"
  233. #include "nfsDrv.h"
  234. #include "pathLib.h"
  235. #include "fcntl.h"
  236. #include "memPartLib.h"
  237. #include "private/semLibP.h"
  238. IMPORT unsigned int nfsMaxMsgLen; /* max. length of NFs read/write buf */
  239. IMPORT int          nfsMaxPath;         /* max. length of file path */
  240. /* XXX FD_MODE is defined in here and in netDrv */
  241. #define FD_MODE 3 /* mode mask for opened file */
  242. /* O_RDONLY, O_WRONLY or O_RDWR */
  243. #ifdef __GNUC__
  244. # ifndef alloca
  245. #  define alloca __builtin_alloca
  246. # endif
  247. #endif
  248. typedef struct /* NFS_DEV - nfs device structure */
  249.     {
  250.     DEV_HDR devHdr;   /* nfs device header */
  251.     char host[MAXHOSTNAMELEN];   /* host for this device */
  252.     nfs_fh fileHandle;   /* handle for mounted file system */
  253.     /*
  254.      * File system mounted on this dev - though it appears as a single 
  255.      * character, it is really a character array - the memory for the array
  256.      * is allocated when an NFS_DEV struct is allocated. This change was 
  257.      * required for configurable file path length support.
  258.      */
  259.     char fileSystem[1];            
  260.     } NFS_DEV;
  261. /* nfs file descriptor */
  262. typedef struct /* NFS_FD - NFS file descriptor */
  263.     {
  264.     NFS_DEV *nfsDev; /* pointer to this file's NFS device */
  265.     nfs_fh  fileHandle; /* file's file handle */
  266.     nfs_fh  dirHandle; /* file's directory file handle */
  267.     fattr  fileAttr; /* file's attributes */
  268.     unsigned int mode; /* (O_RDONLY, O_WRONLY, O_RDWR) */
  269.     unsigned int fileCurByte; /* number of current byte in file */
  270.     SEM_ID  nfsFdSem; /* accessing semaphore */
  271.     BOOL  cacheValid; /* TRUE: cache valid and remaining */
  272. /* fields in structure are valid. */
  273. /* FALSE: cache is empty or */
  274. /* cacheCurByte not the same as the */
  275. /* current byte in the file. */
  276.     char *cacheBuf; /* pointer to file's read cache */
  277.     char  *cacheCurByte; /* pointer to current byte in cache */
  278.     unsigned int cacheBytesLeft; /* number of bytes left in cache */
  279. /* between cacheCurByte and the end */
  280. /* of valid cache material.  NOTE: */
  281. /* This number may be smaller than */
  282. /* the amount of room left in for */
  283. /* the cache writing. */
  284.     BOOL  cacheDirty; /* TRUE: cache is dirty, not flushed */
  285.     } NFS_FD;
  286. /* globals */
  287. int mutexOptionsNfsDrv = SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE;
  288. unsigned int nfsCacheSize; /* size of an nfs cache */
  289. BOOL  nfsAutoClose; /* TRUE: close client after file close*/
  290. /* locals */
  291. LOCAL int nfsDrvNum; /* this particular driver number */
  292. /* forward declarations */
  293. LOCAL int nfsCacheFlush ();
  294. LOCAL STATUS nfsClose ();
  295. LOCAL int nfsCreate ();
  296. LOCAL int nfsDelete ();
  297. LOCAL int nfsIoctl ();
  298. LOCAL int nfsOpen ();
  299. LOCAL int nfsRead ();
  300. LOCAL int nfsSeek  ();
  301. LOCAL int nfsWrite ();
  302. LOCAL int nfsChkFilePerms ();
  303. /*******************************************************************************
  304. *
  305. * nfsDrv - install the NFS driver
  306. *
  307. * This routine initializes and installs the NFS driver.  It must be 
  308. * called before any reads, writes, or other NFS calls.
  309. * This is done automatically when INCLUDE_NFS is defined.
  310. *
  311. * VXWORKS AE PROTECTION DOMAINS
  312. * Under VxWorks AE, you can call this function from within the kernel 
  313. * protection domain only.  This restriction does not apply under non-AE 
  314. * versions of VxWorks.  
  315. *
  316. * RETURNS:
  317. * OK, or ERROR if there is no room for the driver.
  318. */
  319. STATUS nfsDrv (void)
  320.     {
  321.     if (nfsDrvNum == 0)
  322. {
  323. nfsCacheSize = nfsMaxMsgLen;
  324. nfsDrvNum = iosDrvInstall (nfsCreate, nfsDelete, nfsOpen, nfsClose,
  325.    nfsRead, nfsWrite, nfsIoctl);
  326. }
  327.     return (nfsDrvNum == ERROR ? ERROR : OK);
  328.     }
  329. /*******************************************************************************
  330. *
  331. * nfsDrvNumGet - return the IO system driver number for the nfs driver
  332. *
  333. * This routine returns the nfs driver number allocated by iosDrvInstall during
  334. * the nfs driver initialization. If the nfs driver has yet to be initialized,
  335. * or if initialization failed, nfsDrvNumGet will return ERROR.
  336. *
  337. * RETURNS: the nfs driver number or ERROR
  338. */
  339. int nfsDrvNumGet (void)
  340.     {
  341.     return (nfsDrvNum == 0 ? ERROR : nfsDrvNum);
  342.     }
  343. /*******************************************************************************
  344. *
  345. * nfsMount - mount an NFS file system
  346. *
  347. * This routine mounts a remote file system.  It creates a
  348. * local device <localName> for a remote file system on a specified host.
  349. * The host must have already been added to the local host table with
  350. * hostAdd().  If <localName> is NULL, the local name will be the same as
  351. * the remote name.
  352. *
  353. * RETURNS: OK, or ERROR if the driver is not installed,
  354. * <host> is invalid, or memory is insufficient.
  355. *
  356. * SEE ALSO: nfsUnmount(), hostAdd()
  357. */
  358. STATUS nfsMount
  359.     (
  360.     char *host,         /* name of remote host */
  361.     char *fileSystem,   /* name of remote directory to mount */
  362.     char *localName     /* local device name for remote dir */
  363.                         /* (NULL = use fileSystem name) */
  364.     )
  365.     {
  366.     FAST NFS_DEV *pNfsDev;
  367.     nfs_fh fileHandle;
  368.     if (nfsDrvNum < 1)
  369. {
  370. errnoSet (S_ioLib_NO_DRIVER);
  371. return (ERROR);
  372. }
  373.     if (strlen (fileSystem) >= nfsMaxPath)
  374. {
  375. errnoSet (S_nfsLib_NFSERR_NAMETOOLONG);
  376. return (ERROR);
  377. }
  378.     if ((pNfsDev = (NFS_DEV *) KHEAP_ALLOC(sizeof (NFS_DEV) + nfsMaxPath - 1)) 
  379.    == NULL)
  380. return (ERROR);
  381.     /* perform an nfs mount of the directory */
  382.     if (nfsDirMount (host, fileSystem, &fileHandle) != OK)
  383. {
  384. KHEAP_FREE((char *) pNfsDev);
  385. return (ERROR);
  386. }
  387.     /* fill in the nfs device descripter */
  388.     (void) strcpy (pNfsDev->host, host);
  389.     (void) strcpy (pNfsDev->fileSystem, fileSystem);
  390.     bcopy ((char *) &fileHandle, (char *) &pNfsDev->fileHandle, sizeof(nfs_fh));
  391.     /*
  392.      * If no device name was specified, use the name of the file system
  393.      * being mounted.  For instance, if the file system is called "/d0",
  394.      * the corresponding nfs device will be named "/d0".
  395.      */
  396.     if (localName == NULL)
  397. localName = fileSystem; /* name the same as remote fs */
  398.     /* add device to I/O system */
  399.     if (iosDevAdd ((DEV_HDR *) pNfsDev, localName, nfsDrvNum) != OK)
  400. {
  401. KHEAP_FREE((char *) pNfsDev);
  402. return (ERROR);
  403. }
  404.     return (OK);
  405.     }
  406. /*******************************************************************************
  407. *
  408. * nfsMountAll - mount all file systems exported by a specified host
  409. *
  410. * This routine mounts the file systems exported by the host <pHostName>
  411. * which are accessible by <pClientName>. A <pClientName> entry of NULL
  412. * will only mount file systems that are accessible by any client. 
  413. * The nfsMount() routine is called to mount each file system. It creates
  414. * a local device for each mount that has the same name as the remote file
  415. * system.
  416. *
  417. * If the <quietFlag> setting is FALSE, each file system is printed on
  418. * standard output after it is mounted successfully.
  419. *
  420. * RETURNS: OK, or ERROR if any mount fails.
  421. *
  422. * SEE ALSO: nfsMount()
  423. */
  424. STATUS nfsMountAll
  425.     (
  426.     char *pHostName,  /* name of remote host */
  427.     char *pClientName,  /* name of a client specified in access list, if any */
  428.     BOOL quietFlag      /* FALSE = print name of each mounted file system */
  429.     )
  430.     {
  431.     exports nfsExportBody;
  432.     exports  pExport;
  433.     groups  pGroup;
  434.     BOOL accessFlag;
  435.     STATUS status = OK;
  436.     if (nfsExportRead (pHostName, &nfsExportBody) != OK)
  437.         return (ERROR);
  438.     if (nfsExportBody)
  439.         {
  440.         /* Attempt to mount each file system in export list */
  441.         pExport = nfsExportBody;
  442.         while (pExport != NULL)
  443.             {
  444.             accessFlag = TRUE;      /* Allow mounting if not restricted. */
  445.             pGroup = pExport->ex_groups;
  446.             if (pGroup != NULL)
  447.                 {
  448.                 accessFlag = FALSE;    /* Limit mount to matching clients. */
  449.                 if (pClientName != NULL)
  450.                     {
  451.                     /* Check for match with client name. */
  452.                     while (!accessFlag && pGroup != NULL)
  453.                         {
  454.                         if (strcmp (pGroup->gr_name, pClientName))
  455.                             pGroup = pGroup->gr_next;
  456.                         else
  457.                             accessFlag = TRUE;
  458.                         }
  459.                     }
  460.                 }
  461.             if (accessFlag)
  462.                 {
  463.                 if (nfsMount (pHostName, pExport->ex_dir, (char *) NULL) != OK)
  464.                     status = ERROR;
  465.                 else
  466.                     {
  467.                     if (!quietFlag)
  468.                         printf ("%sn", pExport->ex_dir);
  469.                     }
  470.                 }
  471.             pExport = pExport->ex_next;
  472.             }
  473. }
  474.     nfsExportFree (&nfsExportBody);
  475.     return (status);
  476.     }
  477. /*******************************************************************************
  478. *
  479. * nfsDevShow - display the mounted NFS devices
  480. *
  481. * This routine displays the device names and their associated NFS file systems.
  482. *
  483. * EXAMPLE:
  484. * .CS
  485. *     -> nfsDevShow
  486. *     device name          file system
  487. *     -----------          -----------
  488. *     /yuba1/              yuba:/yuba1
  489. *     /wrs1/               wrs:/wrs1
  490. * .CE
  491. *
  492. * RETURNS: N/A
  493. */
  494. void nfsDevShow (void)
  495.     {
  496.     char    *fileSysName;
  497.     DEV_HDR *pDev0 = NULL;
  498.     DEV_HDR *pDev1;
  499.     if ((fileSysName = (char *) alloca (nfsMaxPath)) == NULL)
  500. {
  501. printf ("Memory allocation errorn");
  502. return;
  503. }
  504.     printf ("%-20.20s %-50.50sn", "device name", "file system");
  505.     printf ("%-20.20s %-50.50sn", "-----------", "-----------");
  506.     /* get entries from the I/O system's device list */
  507.     while ((pDev1 = iosNextDevGet (pDev0)) != NULL)
  508. {
  509. if (pDev1->drvNum == nfsDrvNum)
  510.     {
  511.     /* found an nfs device, print information */
  512.     (void) strcpy (fileSysName, ((NFS_DEV *) pDev1)->host);
  513.     (void) strcat (fileSysName, ":");
  514.     (void) strcat (fileSysName, ((NFS_DEV *) pDev1)->fileSystem);
  515.     printf ("%-20.20s %-50.50sn", pDev1->name, fileSysName);
  516.     }
  517. pDev0 = pDev1;
  518. }
  519.     }
  520. /*******************************************************************************
  521. *
  522. * nfsUnmount - unmount an NFS device
  523. *
  524. * This routine unmounts file systems that were previously mounted via NFS.
  525. *
  526. * RETURNS: OK, or ERROR if <localName> is not an NFS device or cannot
  527. * be mounted.
  528. * SEE ALSO: nfsMount()
  529. */
  530. STATUS nfsUnmount
  531.     (
  532.     char *localName     /* local of nfs device */
  533.     )
  534.     {
  535.     FAST NFS_DEV *pNfsDev;
  536.     char *dummy;
  537.     /* find the device in the I/O system */
  538. #ifdef _WRS_VXWORKS_5_X
  539.     if ((pNfsDev = (NFS_DEV *) iosDevFind (localName, 
  540.                                            (char **)&dummy)) == NULL)
  541. #else
  542.     if ((pNfsDev = (NFS_DEV *) iosDevFind (localName, 
  543.                                            (const char **)&dummy)) == NULL)
  544. #endif /* _WRS_VXWORKS_5_X */
  545.         
  546. {
  547. return (ERROR);
  548. }
  549.     /* make sure device is an nfs driver and the names match exactly */
  550.     if ((pNfsDev->devHdr.drvNum != nfsDrvNum) ||
  551. (strcmp (pNfsDev->devHdr.name, localName) != 0))
  552. {
  553. errnoSet (S_nfsDrv_NOT_AN_NFS_DEVICE);
  554. return (ERROR);
  555. }
  556.     /* perform an nfs unmount of the directory */
  557.     if (nfsDirUnmount (pNfsDev->host, pNfsDev->fileSystem) == ERROR)
  558. return (ERROR);
  559.     /* delete the device from the I/O system */
  560.     iosDevDelete ((DEV_HDR *) pNfsDev);
  561.     KHEAP_FREE((char *) pNfsDev);
  562.     return (OK);
  563.     }
  564. /*******************************************************************************
  565. *
  566. * nfsDevListGet - create list of all the NFS devices in the system
  567. *
  568. * This routine fills the array <nfsDevlist> up to <listSize>, with handles to
  569. * NFS devices currently in the system.
  570. *
  571. * RETURNS: The number of entries filled in the <nfsDevList> array.
  572. * SEE ALSO: nfsDevInfoGet()
  573. */
  574. int nfsDevListGet
  575.     (
  576.     unsigned long nfsDevList[], /* NFS dev list of handles */
  577.     int           listSize /* number of elements available in the list */
  578.     )
  579.     {
  580.     int       numMounted;
  581.     DEV_HDR * pDev0 = NULL;
  582.     DEV_HDR * pDev1;
  583.     /*  Collect information of all the NFS currently mounted.  */
  584.     numMounted = 0;
  585.     while ((numMounted < listSize) && ((pDev1 = iosNextDevGet (pDev0)) != NULL))
  586.         {
  587.         if (pDev1->drvNum == nfsDrvNum)
  588.             {
  589.             /* found an nfs device, save pointer to the device */
  590.             nfsDevList [numMounted] = (unsigned long) pDev1;
  591.             numMounted++;
  592.             }
  593.         pDev0 = pDev1;
  594.         }
  595.     return (numMounted);
  596.     }
  597. /*******************************************************************************
  598. *
  599. * nfsDevInfoGet - read configuration information from the requested NFS device
  600. *
  601. * This routine accesses the NFS device specified in the parameter <nfsDevHandle>
  602. * and fills in the structure pointed to by <pnfsInfo>. The calling function 
  603. * should allocate memory for <pnfsInfo> and for the two character buffers,
  604. * 'remFileSys' and 'locFileSys', that are part of <pnfsInfo>. These buffers 
  605. * should have a size of 'nfsMaxPath'.
  606. *
  607. * RETURNS: OK if <pnfsInfo> information is valid, otherwise ERROR.
  608. * SEE ALSO: nfsDevListGet()
  609. */
  610. STATUS nfsDevInfoGet
  611.     (
  612.     unsigned long   nfsDevHandle, /* NFS device handle */
  613.     NFS_DEV_INFO  * pnfsInfo /* ptr to struct to hold config info */
  614.     )
  615.     {
  616.     NFS_DEV *pnfsDev;
  617.     DEV_HDR *pDev0;
  618.     DEV_HDR *pDev1;
  619.     if (pnfsInfo == NULL)
  620. return (ERROR);
  621.     /* Intialize pointer variables */
  622.     pnfsDev = NULL;
  623.     pDev0   = NULL;
  624.     /* Verify that the device is still in the list of devices */
  625.     while ((pDev1 = iosNextDevGet (pDev0)) != NULL)
  626.         {
  627.         if (pDev1 == (DEV_HDR *) nfsDevHandle)
  628.     {
  629.     pnfsDev = (NFS_DEV *) pDev1;
  630.     break; /* Found Device */
  631.     }
  632.         pDev0 = pDev1;
  633.         }
  634.      if (pnfsDev != NULL)
  635. {
  636. strcpy (pnfsInfo->hostName,   pnfsDev->host);
  637. strcpy (pnfsInfo->remFileSys, pnfsDev->fileSystem);
  638. strcpy (pnfsInfo->locFileSys, pnfsDev->devHdr.name);
  639. return (OK);
  640. }
  641.     return (ERROR);
  642.     }
  643. /* routines supplied to the I/O system */
  644. /*******************************************************************************
  645. *
  646. * nfsCreate - create a remote NFS file
  647. *
  648. * Returns an open nfs file descriptor.
  649. *
  650. * Used for creating files only, not directories.
  651. * Called only by the I/O system.
  652. *
  653. * To give the file a particular mode (UNIX chmod() style), use nfsOpen().
  654. *
  655. * RETURNS: Pointer to NFS file descriptor, or ERROR.
  656. */
  657. LOCAL int nfsCreate
  658.     (
  659.     NFS_DEV *pNfsDev,   /* pointer to nfs device */
  660.     char *fileName,     /* nfs file name (relative to mount point) */
  661.     int mode            /* mode (O_RDONLY, O_WRONLY, or O_RDWR) */
  662.     )
  663.     {
  664.     /* file descriptor mode legality is checked for in nfsOpen */
  665.     /* don't allow null filenames */
  666.     if (fileName [0] == EOS)
  667. {
  668. errnoSet (S_ioLib_NO_FILENAME);
  669. return (ERROR);
  670. }
  671.     /* open the file being created,
  672.        give the file default UNIX file permissions */
  673.     return (nfsOpen (pNfsDev, fileName , O_CREAT | O_TRUNC | mode,
  674.                      DEFAULT_FILE_PERM));
  675.     }
  676. /*******************************************************************************
  677. *
  678. * nfsDelete - delete a remote file
  679. *
  680. * Deletes a file on a remote system.
  681. * Called only by the I/O system.
  682. *
  683. * RETURNS: OK or ERROR.
  684. */
  685. LOCAL int nfsDelete
  686.     (
  687.     NFS_DEV *pNfsDev,   /* pointer to nfs device */
  688.     char *fileName      /* remote file name */
  689.     )
  690.     {
  691.     /* don't allow null filenames */
  692.     if (fileName [0] == EOS)
  693. {
  694. errnoSet (S_ioLib_NO_FILENAME);
  695. return (ERROR);
  696. }
  697.     return (nfsFileRemove (pNfsDev->host, &pNfsDev->fileHandle, fileName));
  698.     }
  699. /*******************************************************************************
  700. *
  701. * nfsChkFilePerms - check the NFS file permissions with a given permission.
  702. *
  703. * This routine compares the NFS file permissions with a given permission.
  704. *
  705. * This routine is basically designed for nfsOpen() to verify
  706. * the target file's permission prior to deleting it due to O_TRUNC.
  707. *
  708. * The parameter "perm" will take 4(read), 2(write), 1(execute), or
  709. * combinations of them.
  710. *
  711. * OK means the file has valid permission whichever group is.
  712. * FOLLOW_LINK means this path name contains link.  ERROR means
  713. * the file doesn't have matched permissions.
  714. * Called only by the I/O system.
  715. *
  716. * RETURNS: OK, FOLLOW_LINK, ERROR
  717. */
  718. LOCAL int nfsChkFilePerms
  719.     (
  720.     NFS_DEV * pNfsDev, /* pointer to nfs device */
  721.     char * fullName, /* full file or directory name */
  722.     int perm /* 4:read 2:write 1:execute */
  723.     )
  724.     {
  725.     diropres dirResult; /* directory info returned via nfs */
  726.     nfs_fh dirHandle; /* file's directory file handle */
  727.     int retVal; /* return from nfsLookUpByName */
  728.     /* NFS permissions */
  729.  
  730.     int     nfsPerms; /* permissions of the opened file */
  731.     char    machineName [AUTH_UNIX_FIELD_LEN];
  732.     int     uid;         /* user ID */
  733.     int     gid;         /* group ID */
  734.     int     nGids;         /* number of groups */
  735.     int     gids [MAX_GRPS];         /* array of group IDs */
  736.     BOOL    sameUid = FALSE;         /* set to TRUE if users match */
  737.     BOOL    sameGid = FALSE;         /* set to TRUE if groups match */
  738.     bzero ((char *) &dirResult, sizeof (dirResult));
  739.     bzero ((char *) &dirHandle, sizeof (dirHandle));
  740.     bzero ((char *) &gids, sizeof (int) * MAX_GRPS);
  741.     if ((retVal = nfsLookUpByName (pNfsDev->host, fullName, 
  742.    &pNfsDev->fileHandle, 
  743.    &dirResult, &dirHandle)) != OK)
  744. return (retVal); /* ERROR/FOLLOW_LINK. errno has S_nfsLib prefix */ 
  745.     nfsPerms = dirResult.diropres_u.diropres.attributes.mode;
  746.     nfsAuthUnixGet (machineName, &uid, &gid, &nGids, gids);
  747.  
  748.     sameUid = (uid == dirResult.diropres_u.diropres.attributes.uid
  749.                ? TRUE : FALSE);
  750.  
  751.     if (gid == dirResult.diropres_u.diropres.attributes.gid)
  752. sameGid = TRUE;
  753.     else while (nGids)
  754. if (gids [--nGids] == dirResult.diropres_u.diropres.attributes.gid)
  755.             {
  756.             sameGid = TRUE;
  757.             break;
  758.     }
  759.     /* Check "other" permissions */
  760.     
  761.     if (!sameGid && !sameUid && ((nfsPerms & perm) == perm))
  762.         goto permission_ok;
  763.     /* check group permissions */
  764.     
  765.     else if (sameGid && ((nfsPerms & (perm << 3)) == (perm << 3)))
  766.         goto permission_ok;
  767.     /* check user permissions */
  768.  
  769.     else if (sameUid && ((nfsPerms & (perm << 6)) == (perm << 6)))
  770.         goto permission_ok;
  771.     else
  772. {
  773. errno = S_nfsDrv_PERMISSION_DENIED;
  774. return (ERROR); /* caller should set EACCES to errno */
  775. }
  776. permission_ok:
  777.     return (OK);
  778.     }
  779. /*******************************************************************************
  780. *
  781. * nfsOpen - open an NFS file
  782. *
  783. * This routine opens the remote file.
  784. * Called only by the I/O system.
  785. *
  786. * RETURNS: pointer to open network file descriptor || FOLLOW_LINK || ERROR
  787. */
  788. LOCAL int nfsOpen
  789.     (
  790.     NFS_DEV * pNfsDev, /* pointer to nfs device */
  791.     char *    fileName, /* remote file or directory name to open */
  792.     int       flags, /* O_RDONLY, O_WRONLY, or O_RDWR and O_CREAT */
  793.     int       mode /* UNIX chmod style */
  794.     )
  795.     {
  796.     int status = OK;
  797.     char *fullName;                 /* full file or directory name */
  798.     FAST NFS_FD * nfsFd;
  799.     diropres dirResult; /* directory info returned via nfs */
  800.     int retVal;
  801.     nfs_fh dirHandle; /* file's directory file handle */
  802.     int openMode = flags & FD_MODE; /* mode to open file with */
  803.      /* (O_RDONLY, O_WRONLY, or O_RDWR */
  804.     /* NFS permissions */
  805.     int     filePermissions;         /* permissions of the opened file */
  806.     int     requestPerms = 0; /* requested file permissions */
  807.     char    machineName [AUTH_UNIX_FIELD_LEN];
  808.     int     uid;         /* user ID */
  809.     int     gid;         /* group ID */
  810.     int     nGids;         /* number of groups */
  811.     int     gids [MAX_GRPS];         /* array of group IDs */
  812.     BOOL    correctPerms = FALSE;       /* set to TRUE if perms match */
  813.     BOOL    sameUid = FALSE;         /* set to TRUE if users match */
  814.     BOOL    sameGid = FALSE;         /* set to TRUE if groups match */
  815.     
  816.     if ((openMode != O_RDONLY) && (openMode != O_WRONLY) && 
  817.         (openMode != O_RDWR))
  818. {
  819. errnoSet (S_nfsDrv_BAD_FLAG_MODE);
  820. return (ERROR);
  821. }
  822.     if (strlen (fileName) >= nfsMaxPath)
  823. {
  824. errnoSet (S_nfsLib_NFSERR_NAMETOOLONG);
  825. return (ERROR);
  826. }
  827.     if ((fullName = (char *) alloca (nfsMaxPath)) == NULL)
  828. return (ERROR);
  829.     if (fileName [0] == EOS)
  830. {
  831. if (flags & O_CREAT)
  832.     {
  833.     errnoSet (S_nfsDrv_CREATE_NO_FILE_NAME);
  834.     return (ERROR);
  835.     }
  836. (void) strcpy (fullName, ".");
  837. }
  838.     else
  839. (void) strcpy (fullName, fileName);
  840.     /* truncate file - check the file has write-permission */
  841.     if (flags & O_TRUNC)
  842. {
  843. int err;
  844. #define READ_PERMISSION 2
  845.         if ((err = nfsChkFilePerms (pNfsDev, fullName,
  846.     READ_PERMISSION)) == FOLLOW_LINK)
  847.     return (FOLLOW_LINK);
  848. else if (err == ERROR && errno == S_nfsDrv_PERMISSION_DENIED)
  849.     return (ERROR); /* i.e. don't return if NFSERR_NOENT */
  850.         else if (err == OK)
  851.             {
  852.     /* the file has write-permission, go for deletion */
  853.     retVal = nfsDelete (pNfsDev, fullName);
  854.     if ((retVal == ERROR) && !(flags & O_CREAT))
  855. return (ERROR);
  856.     else
  857. {
  858. if (retVal == FOLLOW_LINK)
  859.     {
  860.     (void) strcpy (fileName, fullName);
  861.     return (FOLLOW_LINK);
  862.     }
  863. }
  864.     }
  865. } /* O_TRUNC */
  866.     if ((flags & O_CREAT) || (flags & O_TRUNC)) /* create file or directory */
  867.         {
  868.         retVal = nfsLookUpByName (pNfsDev->host, fullName, 
  869.                                   &pNfsDev->fileHandle, 
  870.                                   &dirResult, &dirHandle);
  871.         if (retVal == FOLLOW_LINK)
  872.             {
  873.             (void) strcpy (fileName, fullName);
  874.             return (FOLLOW_LINK);
  875.             }
  876.         status = nfsThingCreate (pNfsDev->host, fullName, &pNfsDev->fileHandle,
  877.                                  &dirResult, &dirHandle, (u_int)mode);
  878.         }
  879.     else                        /* open existing file or directory */
  880.         {
  881.         status = nfsLookUpByName (pNfsDev->host, fullName, 
  882.                                   &pNfsDev->fileHandle,
  883.                                   &dirResult, &dirHandle);
  884.         }
  885.     if (status == ERROR)
  886. return (ERROR);
  887.     /* Check file permissions */
  888.     filePermissions = dirResult.diropres_u.diropres.attributes.mode;
  889.     switch (openMode)
  890.         {
  891. case O_RDONLY: requestPerms = 4; break;
  892. case O_WRONLY: requestPerms = 2; break;
  893. case O_RDWR:   requestPerms = 6; break;
  894. }
  895.     /* Check if uid and gid match file uid and gid */
  896.     
  897.     nfsAuthUnixGet (machineName, &uid, &gid, &nGids, gids);
  898.     sameUid = (uid == dirResult.diropres_u.diropres.attributes.uid
  899.        ? TRUE : FALSE);
  900.     
  901.     if (gid == dirResult.diropres_u.diropres.attributes.gid)
  902.         sameGid = TRUE;
  903.     else while (nGids)
  904.         if (gids [--nGids] == dirResult.diropres_u.diropres.attributes.gid)
  905.     {
  906.     sameGid = TRUE;
  907.     break;
  908.     }
  909.     /* Check "other" permissions */
  910.     
  911.     if (!sameGid && !sameUid &&
  912. ((filePermissions & requestPerms) == requestPerms))
  913.         correctPerms = TRUE;
  914.     /* check group permissions */
  915.     
  916.     else if (sameGid &&
  917.      ((filePermissions & (requestPerms << 3)) == (requestPerms << 3)))
  918.         correctPerms = TRUE;
  919.     /* check user permissions */
  920.     else if (sameUid &&
  921.      ((filePermissions & (requestPerms << 6)) == (requestPerms << 6)))
  922.         correctPerms = TRUE;
  923.     else
  924. {
  925. errno = S_nfsDrv_PERMISSION_DENIED;
  926. return (ERROR);
  927. }
  928.     
  929.     /*
  930.      * If the name returned by nfsLookUpByName doesn't start with a
  931.      * slash, then nfsLookUpByName has changed the name to the link, but the
  932.      * name no longer includes the name of the correct device.  If you pass
  933.      * this to iosDevFind, it returns a path on the default device, which is
  934.      * wrong (unless, of course, you get lucky and you are in fact looking
  935.      * for something on the default device).  So, need to prepend the name of
  936.      * the NFS device if fullName doesn't include it already.
  937.      */
  938.     if (status == FOLLOW_LINK)
  939.         {
  940. if (fullName [0] != '/')
  941.     {
  942.     pathCat (pNfsDev->devHdr.name, fullName, fileName);
  943.     }
  944. else
  945.     {
  946.     (void) strcpy (fileName, fullName);
  947.     }
  948. }
  949.     if (status != OK)
  950. return (status);
  951.     if ((nfsFd = (NFS_FD *) KHEAP_ALLOC(sizeof (NFS_FD) + nfsCacheSize)) == NULL)
  952. return (ERROR);
  953.     /* fill in file descriptor with newly retrieved information */
  954.     bcopy ((char *) &dirResult.diropres_u.diropres.file,
  955.    (char *) &nfsFd->fileHandle, sizeof (nfs_fh));
  956.     bcopy ((char *) &dirHandle,
  957.    (char *) &nfsFd->dirHandle, sizeof (nfs_fh));
  958.     bcopy ((char *) &dirResult.diropres_u.diropres.attributes,
  959.    (char *) &nfsFd->fileAttr, sizeof (fattr));
  960.     nfsFd->fileCurByte = 0;
  961.     nfsFd->mode = openMode;
  962.     nfsFd->cacheValid = FALSE;
  963.     nfsFd->cacheBuf = (char *) ((u_int) nfsFd + sizeof (NFS_FD));
  964.     nfsFd->cacheCurByte = nfsFd->cacheBuf;
  965.     nfsFd->cacheDirty = FALSE;
  966.     nfsFd->cacheBytesLeft = 0;
  967.     nfsFd->nfsDev = pNfsDev;
  968.     nfsFd->nfsFdSem = semMCreate (mutexOptionsNfsDrv);
  969.     if (nfsFd->nfsFdSem == NULL)
  970.         {
  971.         free ( (char *)nfsFd);
  972.         return (ERROR);
  973.         }
  974.     return ((int) nfsFd);
  975.     }
  976. /*******************************************************************************
  977. *
  978. * nfsClose - close a remote file
  979. *
  980. * Called only by the I/O system.
  981. *
  982. * RETURNS: OK or ERROR if file failed to flush
  983. */
  984. LOCAL STATUS nfsClose
  985.     (
  986.     FAST NFS_FD *nfsFd          /* nfs file descriptor */
  987.     )
  988.     {
  989.     int status = OK;
  990.     semTake (nfsFd->nfsFdSem, WAIT_FOREVER);
  991.     if (nfsFd->cacheDirty)
  992. status = nfsCacheFlush (nfsFd);
  993.     semDelete (nfsFd->nfsFdSem); /* terminate nfs fd semaphore */
  994.     KHEAP_FREE((char *) nfsFd);
  995.     /* close client if "auto close" is selected */
  996.     if (nfsAutoClose)
  997. nfsClientClose ();
  998.     return (status == ERROR ? ERROR : OK);
  999.     }
  1000. /*******************************************************************************
  1001. *
  1002. * nfsRead - read bytes from remote file
  1003. *
  1004. * nfsRead reads the specified number of bytes from the open NFS
  1005. * file and puts them into a buffer.  Bytes are read starting
  1006. * from the point marked by the file pointer.  The file pointer is then
  1007. * updated to point immediately after the last character that was read.
  1008. *
  1009. * A cache is used for keeping nfs network reads and writes down to a minimum.
  1010. *
  1011. * Called only by the I/O system.
  1012. *
  1013. * SIDE EFFECTS: moves file pointer
  1014. *
  1015. * RETURNS: number of bytes read or ERROR.
  1016. */
  1017. LOCAL int nfsRead
  1018.     (
  1019.     FAST NFS_FD *nfsFd, /* pointer to open network file descriptor */
  1020.     char *buf,          /* pointer to buffer to receive bytes */
  1021.     FAST int maxBytes   /* max number of bytes to read into buffer */
  1022.     )
  1023.     {
  1024.     int nRead; /* number of bytes read from cache or net */
  1025.     int nCacheRead; /* number of bytes read into cache */
  1026.     int readCount; /* cum. no. of bytes read into user's buf */
  1027.     STATUS status = OK;
  1028.     /* check for valid maxBytes */
  1029.     if (maxBytes < 0)
  1030. {
  1031. errnoSet (S_nfsDrv_INVALID_NUMBER_OF_BYTES);
  1032. return (ERROR);
  1033. }
  1034.     if (maxBytes == 0)
  1035. return (0);
  1036.     /* if file opened for O_WRONLY, don't read */
  1037.     if (nfsFd->mode == O_WRONLY)
  1038. {
  1039. errnoSet (S_nfsDrv_WRITE_ONLY_CANNOT_READ);
  1040. return (ERROR);
  1041. }
  1042.     readCount = 0;
  1043.     semTake (nfsFd->nfsFdSem, WAIT_FOREVER);
  1044.     if (nfsCacheSize == 0)
  1045. {
  1046. /* no caching */
  1047. readCount = nfsFileRead (nfsFd->nfsDev->host, &nfsFd->fileHandle,
  1048.          nfsFd->fileCurByte, (unsigned) maxBytes, buf,
  1049.          &nfsFd->fileAttr);
  1050. if (readCount < 0)
  1051.     {
  1052.     semGive (nfsFd->nfsFdSem);
  1053.     return (ERROR);
  1054.     }
  1055. status = nfsSeek (nfsFd, (int) nfsFd->fileCurByte + readCount);
  1056. }
  1057.     else
  1058. {
  1059. /* read from cache */
  1060. while ((readCount < maxBytes) && (status != ERROR))
  1061.     {
  1062.     /* keep reading until all bytes requested are read,
  1063.      * or an error occurs,
  1064.      * or the end of file is hit
  1065.      */
  1066.     if (!nfsFd->cacheValid)
  1067. {
  1068. /* if the cache isn't valid,
  1069.  * freshen it by reading across the net.
  1070.  */
  1071. nCacheRead = nfsFileRead (nfsFd->nfsDev->host,
  1072.   &nfsFd->fileHandle,
  1073.   nfsFd->fileCurByte, nfsCacheSize,
  1074.   nfsFd->cacheBuf, &nfsFd->fileAttr);
  1075. if (nCacheRead < 0)
  1076.     {
  1077.     semGive (nfsFd->nfsFdSem);
  1078.     return (ERROR);
  1079.     }
  1080. nfsFd->cacheCurByte = nfsFd->cacheBuf; /* update cache ptrs */
  1081. nfsFd->cacheBytesLeft = nCacheRead;
  1082. nfsFd->cacheValid = TRUE; /* cache is valid */
  1083. }
  1084.     /* read as many bytes as possible from what's left in the cache,
  1085.      * up to the amount requested
  1086.      */
  1087.     if (nfsFd->cacheBytesLeft > 0)
  1088. {
  1089. if (maxBytes - readCount < nfsFd->cacheBytesLeft)
  1090.     nRead = maxBytes - readCount;
  1091. else
  1092.     nRead = nfsFd->cacheBytesLeft;
  1093. /* copy bytes into user's buffer */
  1094. bcopy (nfsFd->cacheCurByte, (char *) ((int) buf + readCount),
  1095.        nRead);
  1096. /* update file pointer */
  1097. status = nfsSeek (nfsFd, (int) nfsFd->fileCurByte + nRead);
  1098. /* how many bytes have we read so far? */
  1099. readCount += nRead;
  1100. }
  1101.     else
  1102. break; /* we've hit the end of the file */
  1103.     } /* while */
  1104. } /* else */
  1105.     semGive (nfsFd->nfsFdSem);
  1106.     return (status == ERROR ? ERROR : readCount);
  1107.     }
  1108. /*******************************************************************************
  1109. *
  1110. * nfsWrite - write bytes to remote file
  1111. *
  1112. * nfsWrite copies the specified number of bytes from the buffer
  1113. * to the nfs file.  Bytes are written starting at the current file pointer.
  1114. * The file pointer is updated to point immediately after the last
  1115. * character that was written.
  1116. *
  1117. * A cache is used for keeping nfs network reads and writes down to a minimum.
  1118. * If all goes well, the entire buffer is written to the cache and/or actual
  1119. * file.
  1120. *
  1121. * Called only by the I/O system.
  1122. *
  1123. * SIDE EFFECTS: moves file pointer
  1124. *
  1125. * RETURNS:
  1126. *    Number of bytes written (error if != nBytes)
  1127. *    ERROR if nBytes < 0, or nfs write is not successful
  1128. */
  1129. LOCAL int nfsWrite
  1130.     (
  1131.     FAST NFS_FD *nfsFd, /* open file descriptor */
  1132.     char *buf,          /* buffer being written from */
  1133.     FAST int nBytes     /* number of bytes to write to file */
  1134.     )
  1135.     {
  1136.     FAST unsigned int nWrite; /* number of bytes to write */
  1137.     FAST unsigned int newPos; /* new position of file pointer */
  1138.     unsigned int cacheMargin; /* margin left in cache for writing */
  1139.     int nCacheRead; /* number of bytes read into cache */
  1140.     FAST char *pBuf = buf; /* ptr to spot in user's buffer */
  1141.     FAST int writeCount = 0; /* number of bytes written so far */
  1142.     /* check for valid number of bytes */
  1143.     if (nBytes < 0)
  1144. {
  1145. errnoSet (S_nfsDrv_INVALID_NUMBER_OF_BYTES);
  1146. return (ERROR);
  1147. }
  1148.     /* if file opened for O_RDONLY, don't write */
  1149.     if (nfsFd->mode == O_RDONLY)
  1150. {
  1151. errnoSet (S_nfsDrv_READ_ONLY_CANNOT_WRITE);
  1152. return (ERROR);
  1153. }
  1154.     semTake (nfsFd->nfsFdSem, WAIT_FOREVER);
  1155.     /* do the write, until entire buffer has been written out */
  1156.     if (nfsCacheSize == 0)
  1157. {
  1158. writeCount = nfsFileWrite (nfsFd->nfsDev->host, &nfsFd->fileHandle,
  1159.        nfsFd->fileCurByte, (unsigned) nBytes, buf,
  1160.        &nfsFd->fileAttr);
  1161. if (writeCount == ERROR)
  1162.     {
  1163.     semGive (nfsFd->nfsFdSem);
  1164.     return (ERROR);
  1165.     }
  1166. /* where will the new file pointer be? */
  1167. newPos = nfsFd->fileCurByte + writeCount;
  1168. /* update the file pointer.  */
  1169. if (nfsSeek (nfsFd, (int) newPos) == ERROR)
  1170.     {
  1171.     semGive (nfsFd->nfsFdSem);
  1172.     return (ERROR);
  1173.     }
  1174. }
  1175.     else
  1176. {
  1177. while (writeCount < nBytes)
  1178.     {
  1179.     /* fill cache before writing to it, keep cache in sync w/file */
  1180.     if (!nfsFd->cacheValid)
  1181. {
  1182. if ((nBytes - writeCount) < nfsCacheSize)
  1183.     {
  1184.     nCacheRead = nfsFileRead (nfsFd->nfsDev->host,
  1185.       &nfsFd->fileHandle,
  1186.       nfsFd->fileCurByte,
  1187.       nfsCacheSize, nfsFd->cacheBuf,
  1188.       &nfsFd->fileAttr);
  1189.     if (nCacheRead < 0)
  1190. {
  1191. semGive (nfsFd->nfsFdSem);
  1192. return (ERROR);
  1193. }
  1194.     nfsFd->cacheBytesLeft = nCacheRead;
  1195.     }
  1196. else
  1197.     {
  1198.     nfsFd->cacheBytesLeft = nfsCacheSize;
  1199.     }
  1200. /* update cache pointers */
  1201. nfsFd->cacheCurByte = nfsFd->cacheBuf;
  1202. nfsFd->cacheDirty = FALSE;
  1203. nfsFd->cacheValid = TRUE;
  1204. }
  1205.     /* margin allowable for writing */
  1206.     cacheMargin = (unsigned) nfsFd->cacheBuf + nfsCacheSize
  1207.   - (unsigned) nfsFd->cacheCurByte;
  1208.     if (nBytes - writeCount < cacheMargin)
  1209. nWrite = nBytes - writeCount;
  1210.     else
  1211. nWrite = cacheMargin;
  1212.     /* copy the bytes into the cache */
  1213.     bcopy (pBuf, nfsFd->cacheCurByte, (int) nWrite);
  1214.     if (nWrite > nfsFd->cacheBytesLeft)
  1215. nfsFd->cacheBytesLeft = nWrite;
  1216.     /* cache has been written in, it is soiled */
  1217.     nfsFd->cacheDirty = TRUE;
  1218.     /* what's the new position of the file pointer? */
  1219.     newPos = nfsFd->fileCurByte + nWrite;
  1220.     /* if the new file pointer reaches past the end of the file,
  1221.      * the file has grown, update the size of the file
  1222.      */
  1223.     if (newPos > nfsFd->fileAttr.size)
  1224. nfsFd->fileAttr.size = newPos;
  1225.     /* update the file pointer.
  1226.      * any cache flushes will occur during the seek.
  1227.      */
  1228.     if (nfsSeek (nfsFd, (int) newPos) == ERROR)
  1229. {
  1230. semGive (nfsFd->nfsFdSem);
  1231. return (ERROR);
  1232. }
  1233.     writeCount += nWrite;
  1234.     pBuf += nWrite;
  1235.     } /* while entire buffer has not been written */
  1236. } /* else */
  1237.     semGive (nfsFd->nfsFdSem);
  1238.     return (writeCount);
  1239.     }
  1240. /*******************************************************************************
  1241. *
  1242. * nfsIoctl - do device specific control function
  1243. *
  1244. * Called only by the I/O system.
  1245. *
  1246. * RETURNS: whatever the called function returns
  1247. */
  1248. LOCAL int nfsIoctl
  1249.     (
  1250.     FAST NFS_FD *nfsFd, /* open nfs file descriptor */
  1251.     FAST int function,  /* function code */
  1252.     FAST int arg        /* argument for function */
  1253.     )
  1254.     {
  1255.     FAST struct stat *pStat;
  1256.     int status = OK;
  1257.     switch (function)
  1258. {
  1259. case FIOSYNC:
  1260.     semTake (nfsFd->nfsFdSem, WAIT_FOREVER);
  1261.     if (nfsFd->cacheDirty)
  1262. status = nfsCacheFlush (nfsFd);
  1263.     semGive (nfsFd->nfsFdSem);
  1264.     break;
  1265. case FIOSEEK:
  1266.     status = nfsSeek (nfsFd, arg);
  1267.     break;
  1268. case FIOWHERE:
  1269.          status = nfsFd->fileCurByte;
  1270.     break;
  1271. case FIONREAD:
  1272.          *((int *) arg) = nfsFd->fileAttr.size - nfsFd->fileCurByte;
  1273.     break;
  1274. case FIOREADDIR:
  1275.     /* read a directory entry */
  1276.     status = nfsDirReadOne (nfsFd->nfsDev->host, &nfsFd->fileHandle,
  1277.     (DIR *) arg);
  1278.     break;
  1279. case FIOFSTATGET:
  1280.     /* get status of a file */
  1281.     pStat = (struct stat *) arg;
  1282.     /* get file attributes returned in pStat */
  1283.     nfsFileAttrGet (&nfsFd->fileAttr, pStat);
  1284.     pStat->st_dev         = (ULONG) nfsFd->nfsDev;
  1285.     break;
  1286.         case FIOFSTATFSGET:
  1287.             status = nfsFsAttrGet(nfsFd->nfsDev->host, &nfsFd->fileHandle,
  1288.                                   (struct statfs *)arg);
  1289.             break;
  1290. case FIOGETFL:
  1291.     *((int *) arg) = nfsFd->mode;
  1292.     break;
  1293.     
  1294. default:
  1295.     errnoSet (S_ioLib_UNKNOWN_REQUEST);
  1296.     status = ERROR;
  1297.     break;
  1298. }
  1299.     return (status);
  1300.     }
  1301. /*******************************************************************************
  1302. *
  1303. * nfsSeek - change file's current character position
  1304. *
  1305. * This routine moves the file pointer by the offset to a new position.
  1306. * If the new position moves the file pointer out of the range of what's
  1307. * in the cache and the cache is dirty (i.e. the cache has been written
  1308. * in), then the cache is written out to the nfs file and the cache is
  1309. * marked as invalid.  If the new position is beyond EOF, then an empty
  1310. * area is created that will read as zeros.
  1311. *
  1312. * Called only by the I/O system.
  1313. *
  1314. * RETURNS: OK | ERROR
  1315. */
  1316. LOCAL int nfsSeek
  1317.     (
  1318.     FAST NFS_FD *nfsFd,
  1319.     FAST int newPos
  1320.     )
  1321.     {
  1322.     FAST int interval;
  1323.     if (newPos < 0)
  1324. return (ERROR);
  1325.     if (newPos == nfsFd->fileCurByte)
  1326. return (OK);
  1327.     semTake (nfsFd->nfsFdSem, WAIT_FOREVER);
  1328.     if (nfsFd->cacheValid) /* if cache is valid, update cache pointer */
  1329. {
  1330. /* how far will file pointer be moved? */
  1331. interval = newPos - nfsFd->fileCurByte;
  1332. /* if the new pointer precedes what's in the cache,
  1333.  * OR if the new ptr points past what's in the cache,
  1334.  * OR if the new ptr points past the end of the valid cache bytes,
  1335.  * THEN the cache is no longer valid.
  1336.  *
  1337.  * NOTE:  The cache is still valid if the new pointer points
  1338.  * IMMEDIATELY after the valid bytes in the cache, but still
  1339.  * hasn't reached the end of the cache buffer.  The cache can
  1340.  * still be written to and should not be flushed until it is full
  1341.  * or the file is closed (a similar technique is used in some states
  1342.  * during drought conditions).
  1343.  */
  1344. if (((interval < 0) && (nfsFd->cacheCurByte + interval <
  1345. nfsFd->cacheBuf))
  1346.     || ((interval > 0) && (interval > nfsFd->cacheBytesLeft))
  1347.     || ((nfsFd->cacheBuf + nfsCacheSize) <= (nfsFd->cacheCurByte +
  1348.     interval)))
  1349.     {
  1350.     /* if the new cache pointer goes out of range of the cache,
  1351.      * mark the cache as invalid, and flush if necessary.
  1352.      */
  1353.     if (nfsFd->cacheDirty)
  1354. if (nfsCacheFlush (nfsFd) == ERROR)
  1355.     {
  1356.     semGive (nfsFd->nfsFdSem);
  1357.     return (ERROR);
  1358.     }
  1359.     nfsFd->cacheValid = FALSE;
  1360.     nfsFd->cacheBytesLeft = 0;
  1361.     nfsFd->cacheCurByte = nfsFd->cacheBuf;
  1362.     nfsFd->cacheDirty = FALSE;
  1363.     }
  1364. else
  1365.     {
  1366.     /* if the new position stays within range of the cache,
  1367.      * update the cache pointers.
  1368.      */
  1369.     nfsFd->cacheCurByte += interval;
  1370.     nfsFd->cacheBytesLeft -= interval;
  1371.     }
  1372. }
  1373.     nfsFd->fileCurByte = newPos;
  1374.     semGive (nfsFd->nfsFdSem);
  1375.     return (OK);
  1376.     }
  1377. /*******************************************************************************
  1378. *
  1379. * nfsCacheFlush - flush the cache to the remote NFS file
  1380. *
  1381. * Called only by the I/O system.
  1382. *
  1383. * RETURNS: number of bytes written or ERROR
  1384. */
  1385. LOCAL int nfsCacheFlush
  1386.     (
  1387.     FAST NFS_FD *nfsFd
  1388.     )
  1389.     {
  1390.     int nWrite; /* how many bytes are written with nfs? */
  1391.     unsigned int offset;/* offset in the file where cache gets written */
  1392.     unsigned int count; /* number of bytes to write with nfs */
  1393.     unsigned int dist; /* distance between beginning of cache and current file
  1394.  * pointer (number of bytes) */
  1395.     if (!nfsFd->cacheValid)
  1396. {
  1397. errnoSet (S_nfsDrv_FATAL_ERR_FLUSH_INVALID_CACHE);
  1398. return (ERROR);
  1399. }
  1400.     dist   = nfsFd->cacheCurByte - nfsFd->cacheBuf;
  1401.     offset = nfsFd->fileCurByte - dist;
  1402.     count  = dist + nfsFd->cacheBytesLeft;
  1403.     nWrite = nfsFileWrite (nfsFd->nfsDev->host, &nfsFd->fileHandle,
  1404.    offset, count, nfsFd->cacheBuf, &nfsFd->fileAttr);
  1405.     return (nWrite);
  1406.     }