memDrv.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:21k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* memDrv.c - pseudo memory device driver */
  2. /* Copyright 1984-1999 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01o,12mar99,p_m  fixed SPR# 20018 by documenting lseek and open interaction.
  8. 01n,22feb99,wsl  minor doc cleanup
  9. 01m,13aug98,rlp  added memDevDelete function.
  10. 01l,16jul98,ics  added support for multiple files, directory searches
  11. 01l,16jan98,sjw  clean up error reporting to improve diagnostics
  12. 01k,16jan98,sjw  add support for FIONREAD and FIOSTATGET
  13. 01l,07jan98,ics  allow multiple simultaneous reads of the same file: SPR 20180
  14. 01k,11apr97,ics  allow a read of more than the remaining size to succeed
  15. 01j,16jan95,rhp  improve ANSI conformance in declarations of user routines
  16. 01i,21oct92,jdi  removed mangen SECTION designation.
  17. 01h,02oct92,srh  added ioctl(FIOGETFL) to return file's open mode
  18. 01g,18jul92,smb  Changed errno.h to errnoLib.h.
  19. 01f,04jul92,jcf  scalable/ANSI/cleanup effort.
  20. 01e,26may92,rrr  the tree shuffle
  21. 01d,04oct91,rrr  passed through the ansification filter
  22.   -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and O_RDWR
  23.   -changed copyright notice
  24. 01c,11apr91,jdi  documentation cleanup; doc review by dnw.
  25. 01b,17apr90,jcf  lint.
  26. 01a,13jun89,gae  written.
  27. */
  28. /*
  29. DESCRIPTION
  30. This driver allows the I/O system to access memory directly as a
  31. pseudo-I/O device.  Memory location and size are specified when the
  32. device is created.  This feature is useful when data must be preserved
  33. between boots of VxWorks or when sharing data between CPUs.
  34. Additionally, it can be used to build some files into a VxWorks binary
  35. image (having first converted them to data arrays in C source files,
  36. using a utility such as memdrvbuild), and then mount them in the
  37. filesystem; this is a simple way of delivering some non-changing files
  38. with VxWorks.  For example, a system with an integrated web server may
  39. use this technique to build some HTML and associated content files
  40. into VxWorks.
  41. memDrv can be used to simply provide a high-level method of reading
  42. and writing bytes in absolute memory locations through I/O calls.  It
  43. can also be used to implement a simple, essentially read-only
  44. filesystem (exsisting files can be rewritten within their existing
  45. sizes); directory searches and a limited set of IOCTL calls (including
  46. stat()) are supported.
  47. USER-CALLABLE ROUTINES
  48. Most of the routines in this driver are accessible only through the
  49. I/O system.  Four routines, however, can be called directly: memDrv()
  50. to initialize the driver, memDevCreate() and memDevCreateDir() to
  51. create devices, and memDevDelete() to delete devices.
  52. Before using the driver, it must be initialized by calling memDrv().
  53. This routine should be called only once, before any reads, writes, or
  54. memDevCreate() calls.  It may be called from usrRoot() in usrConfig.c
  55. or at some later point.
  56. IOCTL FUNCTIONS
  57. The dosFs file system supports the following ioctl() functions.  The
  58. functions listed are defined in the header ioLib.h.  Unless stated
  59. otherwise, the file descriptor used for these functions may be any file
  60. descriptor which is opened to a file or directory on the volume or to 
  61. the volume itself.
  62. .iP "FIOGETFL"
  63. Copies to <flags> the open mode flags of the file (O_RDONLY,
  64. O_WRONLY, O_RDWR):
  65. .CS
  66.     int flags;
  67.     status = ioctl (fd, FIOGETFL, &flags);
  68. .CE
  69. .iP "FIOSEEK"
  70. Sets the current byte offset in the file to the position specified by
  71. <newOffset>:
  72. .CS
  73.     status = ioctl (fd, FIOSEEK, newOffset);
  74. .CE
  75. The FIOSEEK offset is always relative to the beginning of the file.  The
  76. offset, if any, given at open time by using pseudo-file name is overridden.
  77. .iP "FIOWHERE"
  78. Returns the current byte position in the file.  This is the byte offset of
  79. the next byte to be read or written.  It takes no additional argument:
  80. .CS
  81.     position = ioctl (fd, FIOWHERE, 0);
  82. .CE
  83. .iP "FIONREAD"
  84. Copies to <unreadCount> the number of unread bytes in the file:
  85. .CS
  86.     int unreadCount;
  87.     status = ioctl (fd, FIONREAD, &unreadCount);
  88. .CE
  89. .iP "FIOREADDIR"
  90. Reads the next directory entry.  The argument <dirStruct> is a DIR
  91. directory descriptor.  Normally, the readdir() routine is used to read a
  92. directory, rather than using the FIOREADDIR function directly.  See dirLib.
  93. .CS
  94.     DIR dirStruct;
  95.     fd = open ("directory", O_RDONLY);
  96.     status = ioctl (fd, FIOREADDIR, &dirStruct);
  97. .CE
  98. .iP "FIOFSTATGET"
  99. Gets file status information (directory entry data).  The argument
  100. <statStruct> is a pointer to a stat structure that is filled with data
  101. describing the specified file.  File inode numbers, user and group
  102. IDs, and times are not supported (returned as 0).
  103. Normally, the stat() or fstat() routine is used to obtain file
  104. information, rather than using the FIOFSTATGET function directly.  See
  105. dirLib.
  106. .CS
  107.     struct stat statStruct;
  108.     fd = open ("file", O_RDONLY);
  109.     status = ioctl (fd, FIOFSTATGET, &statStruct);
  110. .CE
  111. .LP
  112. Any other ioctl() function codes will return error status.
  113. SEE ALSO:
  114. .pG "I/O System"
  115. LINTLIBRARY
  116. */
  117. #include "vxWorks.h"
  118. #include "ioLib.h"
  119. #include "iosLib.h"
  120. #include "stat.h"
  121. #include "dirent.h"
  122. #include "memLib.h"
  123. #include "errnoLib.h"
  124. #include "string.h"
  125. #include "stdlib.h"
  126. #include "stdio.h"
  127. #include "memDrv.h"
  128. typedef struct   /* MEM_DEV - memory device descriptor */
  129.     {
  130.     DEV_HDR devHdr;
  131.     MEM_DRV_DIRENTRY dir; /* Contents of this memDrv device */
  132.     int allowOffset;   /* Allow files to be opened with an offset. */
  133.     } MEM_DEV;
  134. typedef struct   /* MEM_FILE_DESC - memory file descriptor */
  135.     {
  136.     MEM_DEV *pDevice;   /* The memory device of this file */
  137.     MEM_DRV_DIRENTRY *pDir;/* Directory entry for this file */
  138.     int offset;   /* current position */
  139.     int mode;   /* O_RDONLY, O_WRONLY, O_RDWR */
  140.     } MEM_FILE_DESC;
  141. LOCAL int memDrvNum;   /* driver number of memory driver */
  142. /* forward declarations */
  143. LOCAL MEM_DRV_DIRENTRY *memFindFile ();
  144. LOCAL MEM_FILE_DESC *memOpen ();
  145. LOCAL STATUS memFileStatGet ();
  146. LOCAL int memRead ();
  147. LOCAL int memWrite ();
  148. LOCAL int memClose ();
  149. LOCAL STATUS memIoctl ();
  150. /*******************************************************************************
  151. *
  152. * memDrv - install a memory driver
  153. *
  154. * This routine initializes the memory driver.  It must be called first,
  155. * before any other routine in the driver.
  156. *
  157. * RETURNS: OK, or ERROR if the I/O system cannot install the driver.
  158. */
  159. STATUS memDrv (void)
  160.     {
  161.     if (memDrvNum > 0)
  162. return (OK); /* driver already installed */
  163.     memDrvNum = iosDrvInstall ((FUNCPTR) memOpen, (FUNCPTR) NULL,
  164.        (FUNCPTR) memOpen, memClose,
  165.        memRead, memWrite, memIoctl);
  166.     return (memDrvNum == ERROR ? ERROR : OK);
  167.     }
  168. /*******************************************************************************
  169. *
  170. * memDevCreate - create a memory device
  171. *
  172. * This routine creates a memory device containing a single file.
  173. * Memory for the device is simply an absolute memory location
  174. * beginning at <base>.  The <length> parameter indicates the size of
  175. * memory.
  176. *
  177. * For example, to create the device "/mem/cpu0/", a device for accessing
  178. * the entire memory of the local processor, the proper call would be:
  179. * .CS
  180. *     memDevCreate ("/mem/cpu0/", 0, sysMemTop())
  181. * .CE
  182. * The device is created with the specified name, start location, and size.
  183. *
  184. * To open a file descriptor to the memory, use open().  Specify a
  185. * pseudo-file name of the byte offset desired, or open the "raw" file at the
  186. * beginning and specify a position to seek to.  For example, the following
  187. * call to open() allows memory to be read starting at decimal offset 1000.
  188. * .CS
  189. *     -> fd = open ("/mem/cpu0/1000", O_RDONLY, 0)
  190. * .CE
  191. * Pseudo-file name offsets are scanned with "%d".
  192. *
  193. * CAVEAT
  194. * The FIOSEEK operation overrides the offset given via the pseudo-file name
  195. * at open time.
  196. *
  197. * EXAMPLE
  198. * Consider a system configured with two CPUs in the backplane and a separate
  199. * dual-ported memory board, each with 1 megabyte of memory.  The first CPU
  200. * is mapped at VMEbus address 0x00400000 (4 Meg.), the second at bus
  201. * address 0x00800000 (8 Meg.), the dual-ported memory board at 0x00c00000
  202. * (12 Meg.).  Three devices can be created on each CPU as follows.  On
  203. * processor 0:
  204. * .CS
  205. *     -> memDevCreate ("/mem/local/", 0, sysMemTop())
  206. *     ...
  207. *     -> memDevCreate ("/mem/cpu1/", 0x00800000, 0x00100000)
  208. *     ...
  209. *     -> memDevCreate ("/mem/share/", 0x00c00000, 0x00100000)
  210. * .CE
  211. * On processor 1:
  212. * .CS
  213. *     -> memDevCreate ("/mem/local/", 0, sysMemTop())
  214. *     ...
  215. *     -> memDevCreate ("/mem/cpu0/", 0x00400000, 0x00100000)
  216. *     ...
  217. *     -> memDevCreate ("/mem/share/", 0x00c00000, 0x00100000)
  218. * .CE
  219. * Processor 0 has a local disk.  Data or an object module needs to be
  220. * passed from processor 0 to processor 1.  To accomplish this, processor 0
  221. * first calls:
  222. * .CS
  223. *     -> copy </disk1/module.o >/mem/share/0
  224. * .CE
  225. * Processor 1 can then be given the load command:
  226. * .CS
  227. *     -> ld </mem/share/0
  228. * .CE
  229. *
  230. * RETURNS: OK, or ERROR if memory is insufficient or the I/O system cannot add
  231. *          the device.
  232. *
  233. * ERRNO: S_ioLib_NO_DRIVER
  234. *
  235. */
  236. STATUS memDevCreate 
  237.     (
  238.     char * name, /* device name     */
  239.     char * base, /* where to start in memory */
  240.     int    length /* number of bytes     */
  241.     )
  242.     {
  243.     STATUS status;
  244.     FAST MEM_DEV *pMemDv;
  245.     if (memDrvNum < 1)
  246.         {
  247.         errnoSet (S_ioLib_NO_DRIVER);
  248.         return (ERROR);
  249.         }
  250.     if ((pMemDv = (MEM_DEV *) calloc (1, sizeof (MEM_DEV))) == NULL)
  251. return (ERROR);
  252.     pMemDv->dir.name  = "";
  253.     pMemDv->dir.base  = base;
  254.     pMemDv->dir.pDir  = NULL;
  255.     pMemDv->dir.length = length;
  256.     pMemDv->allowOffset = 1;
  257.     /*
  258.      * XXX
  259.      * Specify byte,word,long accesses.
  260.      * Semaphore read/write? */
  261.     status = iosDevAdd ((DEV_HDR *) pMemDv, name, memDrvNum);
  262.     if (status == ERROR)
  263. free ((char *) pMemDv);
  264.     return (status);
  265.     }
  266. /*******************************************************************************
  267. *
  268. * memDevCreateDir - create a memory device for multiple files
  269. *
  270. * This routine creates a memory device for a collection of files
  271. * organised into directories.  The given array of directory entry
  272. * records describes a number of files, some of which may be directories,
  273. * represented by their own directory entry arrays.  The structure may
  274. * be arbitrarily deep.  This effectively allows a filesystem to
  275. * be created and installed in VxWorks, for essentially read-only use.
  276. * The filesystem structure can be created on the host using the
  277. * memdrvbuild utility.
  278. *
  279. * Note that the array supplied is not copied; a reference to it is
  280. * kept.  This array should not be modified after being passed to
  281. * memDevCreateDir.
  282. *
  283. * RETURNS:  OK, or ERROR if memory is insufficient or the I/O system cannot
  284. *           add the device.
  285. *
  286. * ERRNO: S_ioLib_NO_DRIVER
  287. *
  288. */
  289. STATUS memDevCreateDir
  290.     (
  291.     char * name, /* device name     */
  292.     MEM_DRV_DIRENTRY * files, /* array of dir. entries - not copied */
  293.     int    numFiles /* number of entries     */
  294.     )
  295.     {
  296.     STATUS status;
  297.     FAST MEM_DEV *pMemDv;
  298.     if (memDrvNum < 1)
  299.         {
  300.         errnoSet (S_ioLib_NO_DRIVER);
  301.         return (ERROR);
  302.         }
  303.     if ((pMemDv = (MEM_DEV *) calloc (1, sizeof (MEM_DEV))) == NULL)
  304. return (ERROR);
  305.     pMemDv->dir.name  = "";
  306.     pMemDv->dir.base  = NULL;
  307.     pMemDv->dir.pDir  = files;
  308.     pMemDv->dir.length = numFiles;
  309.     /*
  310.      * Let's not allow the "offset" notation for opening files, at
  311.      * least for now, when we have "real" subdirectories.
  312.      */
  313.     pMemDv->allowOffset = 0;
  314.     /*
  315.      * XXX
  316.      * Specify byte,word,long accesses.
  317.      * Semaphore read/write?
  318.      */
  319.     status = iosDevAdd ((DEV_HDR *) pMemDv, name, memDrvNum);
  320.     if (status == ERROR)
  321. free ((char *) pMemDv);
  322.     return (status);
  323.     }
  324. /*******************************************************************************
  325. *
  326. * memDevDelete - delete a memory device
  327. *
  328. * This routine deletes a memory device containing a single file or a
  329. * collection of files. The device is deleted with it own name.
  330. *
  331. * For example, to delete the device created by memDevCreate ("/mem/cpu0/", 0,
  332. * sysMemTop()), the proper call would be:
  333. * .CS
  334. *  memDevDelete ("/mem/cpu0/");
  335. * .CE
  336. *  
  337. * RETURNS: OK, or ERROR if the device doesn't exist.
  338. */
  339. STATUS memDevDelete
  340.     (
  341.     char * name /* device name */
  342.     )
  343.     {
  344.     DEV_HDR * pDevHdr;
  345.     /* get the device pointer corresponding to the device name */
  346.  
  347.     if ((pDevHdr = iosDevFind (name, NULL)) == NULL)
  348.         return (ERROR);
  349.     /* delete the device from the I/O system */
  350.     iosDevDelete (pDevHdr);
  351.     /* free the device pointer */
  352.     free ((MEM_DEV *) pDevHdr);
  353.     return (OK);
  354.     }
  355. /*******************************************************************************
  356. *
  357. * memFindFile - find a memory file by name
  358. *
  359. * RETURNS: The file descriptor number, or ERROR if the name is not a
  360. *  valid number.
  361. */
  362. LOCAL MEM_DRV_DIRENTRY *memFindFile
  363.     (
  364.     MEM_DEV *pMemDv, /* Device we are looking in. */
  365.     char *name, /* name of file to find */
  366.     MEM_DRV_DIRENTRY *pDir, /* pointer to memory device descriptor */
  367.     int *pOffset /* returned file pOffset */
  368.     )
  369.     {
  370.     MEM_DRV_DIRENTRY *pFile = NULL;
  371.     *pOffset = 0;
  372.     /* Protect against NULL. */
  373.     if (name == NULL)
  374. name = "";
  375.     while (*name == '/')
  376. ++name;
  377.     if (strcmp (pDir->name, name) == 0)
  378. {
  379. pFile = pDir;
  380. }
  381.     else if (strncmp (pDir->name, name, strlen (pDir->name)) == 0)
  382. {
  383. int index;
  384. name += strlen (pDir->name);
  385. if (pDir->pDir != NULL)
  386.     {
  387.     /* Search for the referenced file in this directory. */
  388.     for (index = 0; index < pDir->length; ++index)
  389. {
  390. pFile = memFindFile (pMemDv, name, &pDir->pDir[index], pOffset);
  391. if (pFile != NULL) break;
  392. }
  393.     }
  394. else if (pMemDv->allowOffset)
  395.     {
  396.     int off = 0;
  397.     while (*name == '/')
  398. ++name;
  399.     if (sscanf (name, "%d", &off) == 1)
  400. {
  401. pFile = pDir;
  402. *pOffset = off;
  403. }
  404.     }
  405. }
  406.     return pFile;
  407.     }
  408. /*******************************************************************************
  409. *
  410. * memOpen - open a memory file
  411. *
  412. * RETURNS: The file descriptor number, or ERROR if the name is not a
  413. *          valid number.
  414. *
  415. * ERRNO: EINVAL
  416. *
  417. */
  418. LOCAL MEM_FILE_DESC *memOpen
  419.     (
  420.     MEM_DEV *pMemDv, /* pointer to memory device descriptor */
  421.     char *name, /* name of file to open (a number) */
  422.     int mode /* access mode (O_RDONLY,O_WRONLY,O_RDWR) */
  423.     )
  424.     {
  425.     MEM_DRV_DIRENTRY *pFile = NULL;
  426.     MEM_FILE_DESC *pMemFd = NULL;
  427.     int offset = 0;
  428.     int isDir = 0;
  429.     pFile = memFindFile (pMemDv, name, &pMemDv->dir, &offset);
  430.     if (pFile != NULL)
  431. {
  432. /* Directories open for read only. */
  433. isDir = (pFile->pDir != NULL);
  434. if (!isDir || mode == O_RDONLY)
  435.     {
  436.     /* Get a free file descriptor */
  437.     pMemFd = (MEM_FILE_DESC *) calloc (1, sizeof (MEM_FILE_DESC));
  438.     if (pMemFd != NULL)
  439. {
  440. pMemFd->pDevice = pMemDv;
  441. pMemFd->pDir = pFile;
  442. pMemFd->offset = offset;
  443. pMemFd->mode   = mode;
  444. }
  445.     }
  446. }
  447.     if (pMemFd != NULL)
  448. return pMemFd;
  449.     else
  450. {
  451. errnoSet (EINVAL);
  452. return (MEM_FILE_DESC *) ERROR;
  453. }
  454.     }
  455. /*******************************************************************************
  456. *
  457. * memFileStatGet - get file status (directory entry data)
  458. *
  459. * This routine is called via an ioctl() call, using the FIOFSTATGET
  460. * function code.  The passed stat structure is filled, using data
  461. * obtained from the directory entry which describes the file.
  462. *
  463. * RETURNS: ERROR or OK
  464. *
  465. * ERRNO: EINVAL
  466. *
  467. */
  468. LOCAL STATUS memFileStatGet
  469.     (
  470.     MEM_FILE_DESC * pfd, /* pointer to file descriptor */
  471.     struct stat * pStat /* structure to fill with data */
  472.     )
  473.     {
  474.     MEM_DEV *pMemDv = pfd->pDevice; /* pointer to device */
  475.     MEM_DRV_DIRENTRY *pDir = pfd->pDir; /* pointer to file info */
  476.     int isDir = 0;
  477.     if (pStat == NULL || pDir == NULL)
  478. {
  479. errnoSet (EINVAL);
  480. return ERROR;
  481. }
  482.     bzero ((char *) pStat, sizeof (struct stat)); /* zero out stat struct */
  483.     isDir = (pDir->pDir != NULL);
  484.     /* Fill stat structure */
  485.     pStat->st_dev     = (ULONG) pMemDv; /* device ID = DEV_HDR addr */
  486.     pStat->st_ino     = 0; /* no file serial number */
  487.     pStat->st_nlink   = 1; /* always only one link */
  488.     pStat->st_uid     = 0; /* no user ID */
  489.     pStat->st_gid     = 0; /* no group ID */
  490.     pStat->st_rdev    = 0; /* no special device ID */
  491.     pStat->st_size    = isDir ? 0 : pDir->length; /* file size, in bytes */
  492.     pStat->st_atime   = 0; /* no last-access time */
  493.     pStat->st_mtime   = 0; /* no last-modified time */
  494.     pStat->st_ctime   = 0; /* no last-change time */
  495.     pStat->st_attrib  = 0; /* file attribute byte */
  496.     
  497.     /*
  498.      * Set file access permissions to be read/write by all; for
  499.      * directories, add exec (search).
  500.      */
  501.     pStat->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | 
  502.        S_IWUSR | S_IWGRP | S_IWOTH);
  503.     if (isDir)
  504. pStat->st_mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
  505.     /* Is it a file or directory? */
  506.     if (isDir)
  507. pStat->st_mode |= S_IFDIR; /*  it is a directory */
  508.     else
  509. pStat->st_mode |= S_IFREG; /*  it is a regular file */
  510.     return (OK);
  511.     }
  512. /*******************************************************************************
  513. *
  514. * memRead - read from a memory file
  515. *
  516. * RETURNS: ERROR if the file open mode is O_WRONLY; otherwise, the number of
  517. *          bytes read (may be less than the amount requested), or 0 if the
  518. *          file is at EOF.
  519. *
  520. * ERRNO: EINVAL, EISDIR
  521. *
  522. */
  523. LOCAL int memRead
  524.     (
  525.     MEM_FILE_DESC *pfd, /* file descriptor of file to read */
  526.     char *buffer, /* buffer to receive data */
  527.     int maxbytes /* max bytes to read in to buffer */
  528.     )
  529.     {
  530.     MEM_DRV_DIRENTRY *pDir = pfd->pDir; /* pointer to file info */
  531.     int lLeft;
  532.     /* Fail if the mode is invalid, or if it's a directory. */
  533.     if (pfd->mode == O_WRONLY)
  534. {
  535. errnoSet (EINVAL);
  536. return (ERROR);
  537. }
  538.     if (pDir == NULL || pDir->pDir != NULL)
  539. {
  540. errnoSet (EISDIR);
  541. return (ERROR);
  542. }
  543.     /* calculate #bytes left to read */
  544.     lLeft = pDir->length - pfd->offset;
  545.     if (lLeft < 0) lLeft = 0;
  546.     /* limit maxbytes to minimum of bytes left or buffer length */
  547.     if (maxbytes > lLeft) maxbytes = lLeft;
  548.     if (maxbytes > 0)
  549.         {
  550.         bcopy (pDir->base + pfd->offset, buffer, maxbytes);
  551.         pfd->offset += maxbytes;
  552.         }
  553.     return (maxbytes);
  554.     }
  555. /*******************************************************************************
  556. *
  557. * memWrite - write to a memory file
  558. *
  559. * RETURNS: The number of bytes written, or ERROR if past the end of memory or
  560. *          is O_RDONLY only.
  561. *
  562. * ERRNO: EINVAL, EISDIR
  563. *
  564. */
  565. LOCAL int memWrite
  566.     (
  567.     MEM_FILE_DESC *pfd, /* file descriptor of file to write */
  568.     char *buffer, /* buffer to be written */
  569.     int nbytes /* number of bytes to write from buffer */
  570.     )
  571.     {
  572.     MEM_DRV_DIRENTRY *pDir = pfd->pDir; /* pointer to file info */
  573.     int lLeft;
  574.     /* Fail if the mode is invalid, or if it's a directory. */
  575.     if (pfd->mode == O_RDONLY)
  576. {
  577. errnoSet (EINVAL);
  578. return (ERROR);
  579. }
  580.     if (pDir == NULL || pDir->pDir != NULL)
  581. {
  582. errnoSet (EISDIR);
  583. return (ERROR);
  584. }
  585.     /* calculate #bytes left to write */
  586.     lLeft = pDir->length - pfd->offset;
  587.     if (lLeft < 0) lLeft = 0;
  588.     /* If write is too large, truncate it */
  589.     if (nbytes > lLeft) nbytes = lLeft;
  590.     if (nbytes > 0)
  591.         {
  592. bcopy (buffer, pDir->base + pfd->offset, nbytes);
  593. pfd->offset += nbytes;
  594.         }
  595.     return (nbytes);
  596.     }
  597. /*******************************************************************************
  598. *
  599. * memIoctl - do device specific control function
  600. *
  601. * Only the FIONREAD, FIOSEEK, FIOWHERE, FIOGETFL, FIOFSTATGET, and
  602. * FIOREADDIR options are supported.
  603. *
  604. * RETURNS: OK, or ERROR if seeking passed the end of memory.
  605. *
  606. * ERRNO: EINVAL, S_ioLib_UNKNOWN_REQUEST
  607. *
  608. */
  609. LOCAL STATUS memIoctl (pfd, function, arg)
  610.     FAST MEM_FILE_DESC *pfd; /* descriptor to control */
  611.     FAST int function; /* function code */
  612.     int arg; /* some argument */
  613.     {
  614.     MEM_DRV_DIRENTRY *pDir = pfd->pDir; /* pointer to file info */
  615.     DIR *dirp;
  616.     int isDir = 0;
  617.     int status = OK;
  618.     if (pDir == NULL)
  619. {
  620. errnoSet (EINVAL);
  621. status = ERROR;
  622. }
  623.     else
  624. {
  625. isDir = (pDir->pDir != NULL);
  626. switch (function)
  627.     {
  628.     case FIONREAD:
  629. if (isDir)
  630.     {
  631.     errnoSet (EINVAL);
  632.     status = ERROR;
  633.     }
  634. else
  635.     {
  636.     *((int *) arg) = pDir->length - pfd->offset;
  637.     }
  638. break;
  639.     case FIOSEEK:
  640. if (isDir || arg > pDir->length)
  641.     {
  642.     errnoSet (EINVAL);
  643.     status = ERROR;
  644.     }
  645. else
  646.     {
  647.     pfd->offset = arg;
  648.     }
  649. break;
  650.     case FIOWHERE:
  651. if (isDir)
  652.     status = 0;
  653. else
  654.     status = pfd->offset;
  655. break;
  656.     case FIOGETFL:
  657. *((int *) arg) = pfd->mode;
  658. break;
  659.     case FIOFSTATGET:
  660. status = memFileStatGet (pfd, (struct stat *) arg);
  661. break;
  662.     case FIOREADDIR:
  663. /*
  664.  * The index of the directory entry required is passed in via
  665.  * dirp->dd_cookie.  We're supposed to return the name in
  666.  * dirp->dd_dirent.
  667.  */
  668. dirp = (DIR *) arg;
  669. if (!isDir || dirp->dd_cookie >= pDir->length)
  670.     {
  671.     errnoSet (EINVAL);
  672.     status = ERROR;
  673.     }
  674. else
  675.     {
  676.     strcpy (dirp->dd_dirent.d_name, pDir->pDir[dirp->dd_cookie].name);
  677.     ++dirp->dd_cookie;
  678.     }
  679. break;
  680.     default:
  681. errnoSet (S_ioLib_UNKNOWN_REQUEST);
  682. status = ERROR;
  683. break;
  684.     }
  685. }
  686.     return (status);
  687.     }
  688. /*******************************************************************************
  689. *
  690. * memClose - close a memory file
  691. *
  692. * RETURNS: OK, or ERROR if file couldn't be flushed or entry couldn't 
  693. *  be found.
  694. */
  695. LOCAL STATUS memClose (pfd)
  696.     MEM_FILE_DESC *pfd; /* file descriptor of file to close */
  697.     {
  698.     free (pfd);
  699.     return OK;
  700.     }