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

VxWorks

开发平台:

C/C++

  1. /* rt11FsLib.c - RT-11 media-compatible file system library */
  2. /* Copyright 1984-1995 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 06n,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  8. 06m,29mar95,kdl  removed obsolete date fields from stat structure.
  9. 06l,14sep93,kdl  fixed ignoring of driver error during rt11FsWrite (SPR #2516).
  10. 06k,03sep93,kdl  fixed use of standard skew & interleave (rtFmt) (SPR #959).
  11. 06j,25aug93,jmm  rt11FsFileStatGet() now sets atime, mtime, and ctime fields
  12. 06i,24jun93,kdl  fixed loss of fd if driver status check returns error during 
  13.  open() (SPR #2278).
  14. 06h,02feb93,jdi  documentation tweaks.
  15. 06g,02feb93,jdi  documentation cleanup for 5.1; added 3rd param to ioctl() examples.
  16. 06f,02oct92,srh  added ioctl(FIOGETFL) to return file's open mode
  17. 06e,07sep92,smb  added blksize and blocks to the stat structure initialisation.
  18. 06d,22jul92,kdl  changed from 4.0.2-style semaphores to mutexes.
  19. 06c,18jul92,smb  Changed errno.h to errnoLib.h.
  20. 06b,26may92,rrr  the tree shuffle
  21. 06a,13dec91,gae  ANSI cleanup.
  22. 05z,19nov91,rrr  shut up some ansi warnings.
  23. 05y,04oct91,rrr  passed through the ansification filter
  24.                   -changed functions to ansi style
  25.   -changed includes to have absolute path from h/
  26.   -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ...
  27.   -changed VOID to void
  28.   -changed copyright notice
  29. 05x,26jun91,wmd  modified rt11FsFindEntry() to use field comparisons instead of bcmp().
  30. 05w,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  31.  doc review by kdl.
  32. 05v,22feb91,jaa  documentation cleanup.
  33. 05u,08oct90,kdl  added forward declaration for rt11FsOpen().
  34. 05t,08oct90,kdl  made rt11FsOpen, rt11FsWrite, etc. routines LOCAL (again).
  35. 05s,10aug90,kdl  added forward declarations for functions returning void.
  36. 05r,09aug90,kdl  changed name from rt11Lib to rt11FsLib.
  37. 05q,19jul90,dnw  mangen fix
  38. 05p,15jul90,dnw  moved rt11Ls back to usrLib as oldLs since it is applicable
  39.    to the netDrv as well
  40. 05o,12jul90,kdl  added BLK_DEV statusChk routine hook.
  41. 05n,26jun90,jcf  changed semTake () calling sequeuece for 5.0.
  42. 05m,07may90,kdl  made rt11Read read all requested bytes, added bd_readyChanged
  43.  and bd_mode in BLK_DEV, added POSIX-style directory listing,
  44.  moved old "ls" routine from usrLib and renamed it "rt11Ls",
  45.  made rt11Create and rt11FindEntry ignore leading slashes
  46.  in filename.
  47.             jcc  rt11Squeeze now does multi-sector reads and writes.
  48. 05l,23mar90,kdl  lint, changed BLK_DEV field names.
  49. 05k,22mar90,kdl  made rt11Read, rt11Write, etc. global again (temporary).
  50. 05j,16mar90,kdl  added support for multi-filesystem device drivers (BLK_DEV),
  51.  added direct multi-block transfer to/from user's buffer.
  52. 05i,09oct89,dab  fixed stripping of O_CREAT and O_TRUNC from file mode in
  53.    rt11Open().
  54. 05h,04aug89,dab  fixed bug introduced in 05g that didn't free extra fd.
  55. 05g,21jun89,dab  made rt11Open() check for O_CREAT and O_TRUNC modes.
  56. 05f,07jul88,jcf  fixed mallocs to match new declaration.
  57. 05e,05jun88,dnw  changed from rtLib to rt11Lib.
  58. 05d,30may88,dnw  changed to v4 names.
  59. 05c,04may88,jcf  changed semaphores and sem calls for new semLib.
  60. 05b,09nov87,ecs  removed intemperate printErr from rtCreate.
  61. 05a,03nov87,ecs  documentation.
  62. 04z,20oct87,gae  made rtRename() cancel device portion of name, if present.
  63.  made rtDirEntry() return name for DES_TENTATIVE.
  64.  fixed bug in create() by flushing directory;
  65.  made create fail if create already active on device.
  66.  made rtSqueeze local.
  67. 04y,14sep87,dpg  moved squeeze to usrLib.c. changed FIOSQUEEZE call in rtIoctl
  68.  to use a fd rather than some aesoteric device pointer (i.e.
  69.  keep it looking the same).
  70. 04x,10sep87,dpg  deleted rtMaxRoom & maxRoom - we don't really need them now
  71.  renamed rtPack & pack to rtSqueeze & squeeze
  72. 04w,26aug87,dpg  added rtMaxRoom to find largest piece of free space on
  73.  a disk device, and a FIOMAXROOM to ioctl at it; together
  74.  with maxRoom - a user callable routine
  75. 04v,26jun87,dpg  added rtPack to compress free space on an RT-11 device into
  76.  one big block so that hard disks don't get too fragmented.
  77.  also added ioctl entry to provide uniform interface to
  78.  rtPack & pack (user callable routine)
  79. 04u,05may87,gae  fixed "the other" fatal bug introduced in 04t in rtRead().
  80.  changed constant N_RETRIES to rtMaxRetries to allow variation.
  81. 04u,28apr87,gae  fixed fatal bug introduced in 04t in rtVolMount().
  82. 04t,26mar87,gae  Made rtVolMount() fail on bad (unlikely) directory.
  83.  Got rid of rtVolFlush(), then renamed rtVFlush() to
  84.    rtVolFlush().
  85. 04s,07mar87,gae  Made the following LOCAL: rtGetEntry(), rtAbsSector(),
  86.    rtDirEntry(), rtRename(), rtFlush(), rtWhere(), rtSeek(),
  87.    rtVolFlush(), and rtVolInit().  Fixed documentation.
  88.  Made rtDevInit() return ERROR if out of memory.
  89. 04r,14feb87,dnw  Changed to accept null filename as special name for "raw disk"
  90.    instead of "-", now that ioLib protects against accidental
  91.    null filenames.
  92. 04q,03feb87,llk  Modified directory segments to handle any number of file
  93.    entries.  Directories are 1 segment long, with at least
  94.    2 blocks per segment.  2 block segments are still RT-11
  95.    compatible.  rtDevInit has a new parameter, the maximum
  96.    number of file entries that will go on the device.
  97.    See documentation below under RT-11 COMPATIBILITY.
  98.  Added FIODISKCHANGE to ioctl function codes.  Used for
  99.    manually issuing a ready change.
  100.  Fixed rtDirEntry so that it checks if the entry number passed
  101.    to it is less than the maximum possible entry number.
  102. 04p,14jan87,llk  changed to handle file size up to RT_MAX_BLOCKS_PER_FILE.
  103.  Changed rtVolInit to initialize disk with as many maximum
  104.  sized files as needed to cover all the disk space.
  105.  Changed rtCoalesce to coalesce files together iff the new
  106.  empty file would have less than RT_MAX_BLOCKS_PER_FILE blocks.
  107. ...deleted pre 87 history - see RCS
  108. */
  109. /*
  110. This library provides services for file-oriented device drivers which use
  111. the RT-11 file standard.  This module takes care of all the necessary 
  112. buffering, directory maintenance, and RT-11-specific details.
  113. USING THIS LIBRARY
  114. The various routines provided by the VxWorks RT-11 file system (rt11Fs) may
  115. be separated into three broad groups:  general initialization,
  116. device initialization, and file system operation.
  117. The rt11FsInit() routine is the principal initialization function;
  118. it need only be called once, regardless of how many rt11Fs devices
  119. will be used.
  120. Other rt11Fs routines are used for device initialization.  For
  121. each rt11Fs device, either rt11FsDevInit() or rt11FsMkfs() must be called
  122. to install the device and define its configuration.
  123. Several functions are provided to inform the file system of
  124. changes in the system environment.  The rt11FsDateSet() routine is used
  125. to set the date.  The rt11FsModeChange() routine is used to
  126. modify the readability or writability of a particular device.  The
  127. rt11FsReadyChange() routine is used to inform the file system that a
  128. disk may have been swapped, and that the next disk operation should first
  129. remount the disk.
  130. INITIALIZING RT11FSLIB
  131. Before any other routines in rt11FsLib can be used, rt11FsInit() must 
  132. be called to initialize this library.  This call specifies 
  133. the maximum number of rt11Fs files that can be open simultaneously 
  134. and allocates memory for that many rt11Fs file descriptors.
  135. Attempts to open more files than the specified maximum will result
  136. in errors from open() or creat().
  137. This initialization is enabled when the configuration macro
  138. INCLUDE_RT11FS is defined.
  139. DEFINING AN RT-11 DEVICE
  140. To use this library for a particular device, the device structure must
  141. contain, as the very first item, a BLK_DEV structure.  This must be
  142. initialized before calling rt11FsDevInit().  In the BLK_DEV structure, the
  143. driver includes the addresses of five routines which it must supply:  one
  144. that reads one or more sectors, one that writes one or more sectors, one
  145. that performs I/O control on the device (using ioctl()), one that checks the
  146. status of the device, and one that resets the device.  This structure also
  147. specifies various physical aspects of the device (e.g., number of sectors,
  148. sectors per track, whether the media is removable).  For more information about
  149. defining block devices, see the
  150. .I "VxWorks Programmer's Guide: I/O System."
  151. The device is associated with the rt11Fs file system by the
  152. rt11FsDevInit() call.  The arguments to rt11FsDevInit() include the name
  153. to be used for the rt11Fs volume, a pointer to the BLK_DEV structure,
  154. whether the device uses RT-11 standard skew and interleave, and the
  155. maximum number of files that can be contained in the device directory.
  156. Thereafter, when the file system receives a request from the I/O system, it
  157. simply calls the provided routines in the device driver to fulfill the
  158. request.
  159. RTFMT
  160. The RT-11 standard defines a peculiar software interleave and
  161. track-to-track skew as part of the format.  The <rtFmt> parameter passed
  162. to rt11FsDevInit() should be TRUE if this formatting is desired.  This
  163. should be the case if strict RT-11 compatibility is desired, or if files
  164. must be transferred between the development and target machines using the
  165. VxWorks-supplied RT-11 tools.  Software interleave and skew will
  166. automatically be dealt with by rt11FsLib.
  167. When <rtFmt> has been passed as TRUE and the maximum number of files is
  168. specified RT_FILES_FOR_2_BLOCK_SEG, the driver does not need to do
  169. anything else to maintain RT-11 compatibility (except to add the track 
  170. offset as described above).
  171. Note that if the number of files specified is different than
  172. RT_FILES_FOR_2_BLOCK_SEG under either a VxWorks system or an RT-11 system,
  173. compatibility is lost because VxWorks allocates a contiguous directory,
  174. whereas RT-11 systems create chained directories.
  175. MULTIPLE LOGICAL DEVICES AND RT-11 COMPATIBILITY
  176. The sector number passed to the sector read and write routines is an
  177. absolute number, starting from sector 0 at the beginning of the device.
  178. If desired, the driver may add an offset from the beginning of the
  179. physical device before the start of the logical device.  This would
  180. normally be done by keeping an offset parameter in the device-specific
  181. structure of the driver, and adding the proper number of sectors to the
  182. sector number passed to the read and write routines.
  183. The RT-11 standard defines the disk to start on track 1.  Track 0 is set
  184. aside for boot information.  Therefore, in order to retain true
  185. compatibility with RT-11 systems, a one-track offset (i.e., the number of
  186. sectors in one track) needs to be added to the sector numbers passed to
  187. the sector read and write routines, and the device size needs to be
  188. declared as one track smaller than it actually is.  This must be done by
  189. the driver using rt11FsLib; the library does not add such an offset
  190. automatically.
  191. In the VxWorks RT-11 implementation, the directory is a fixed size, able
  192. to contain at least as many files as specified in the call to
  193. rt11FsDevInit().  If the maximum number of files is specified to be
  194. RT_FILES_FOR_2_BLOCK_SEG, strict RT-11 compatibility is maintained,
  195. because this is the initial allocation in the RT-11 standard.
  196. RT-11 FILE NAMES
  197. File names in the RT-11 file system use six characters, followed
  198. by a period (.), followed by an optional three-character extension.
  199. DIRECTORY ENTRIES
  200. An ioctl() call with the FIODIRENTRY function returns information about a
  201. particular directory entry.  A pointer to a REQ_DIR_ENTRY structure is
  202. passed as the parameter.  The field `entryNum' in the REQ_DIR_ENTRY
  203. structure must be set to the desired entry number.  The name of the file,
  204. its size (in bytes), and its creation date are returned in the structure.
  205. If the specified entry is empty (i.e., if it represents an unallocated
  206. section of the disk), the name will be an empty string, the size will be
  207. the size of the available disk section, and the date will be meaningless.
  208. Typically, the entries are accessed sequentially, starting with `entryNum' = 0,
  209. until the terminating entry is reached, indicated by a return code of ERROR.
  210. DIRECTORIES IN MEMORY
  211. A copy of the directory for each volume is kept in memory (in the RT_VOL_DESC
  212. structure).  This speeds up directory accesses, but requires that rt11FsLib
  213. be notified when disks are changed (i.e., floppies are swapped).  If the
  214. driver can find this out (by interrogating controller status or by
  215. receiving an interrupt), the driver simply calls rt11FsReadyChange() when a
  216. disk is inserted or removed.  The library rt11FsLib will automatically try
  217. to remount the device next time it needs it.
  218. If the driver does not have access to the information that disk volumes
  219. have been changed, the <changeNoWarn> parameter should be set to TRUE
  220. when the device is defined using rt11FsDevInit().  This will cause the
  221. disk to be automatically remounted before each open(), creat(), delete(),
  222. and directory listing.
  223. The routine rt11FsReadyChange() can also be called by user tasks, by
  224. issuing an ioctl() call with FIODISKCHANGE as the function code.
  225. ACCESSING THE RAW DISK
  226. As a special case in open() and creat() calls, rt11FsLib recognizes a NULL
  227. file name to indicate access to the entire "raw" disk, as opposed to a
  228. file on the disk.  Access in raw mode is useful for a disk that has no
  229. file system.  For example, to initialize a new file system on the disk,
  230. use an ioctl() call with FIODISKINIT.  To read the directory of a disk for
  231. which no file names are known, open the raw disk and use an ioctl() call
  232. with the function FIODIRENTRY.
  233. HINTS
  234. The RT-11 file system is much simpler than the more common UNIX or MS-DOS
  235. file systems.  The advantage of RT-11 is its speed; file access is made in
  236. at most one seek because all files are contiguous.  Some of the most common
  237. errors for users with a UNIX background are:
  238. .iP "" 4
  239. Only a single create at a time may be active per device.
  240. .iP
  241. File size is set by the first create and close sequence;
  242. use lseek() to ensure a specific file size;
  243. there is no append function to expand a file.
  244. .iP
  245. Files are strictly block oriented; unused portions
  246. of a block are filled with NULLs -- there is no
  247. end-of-file marker other than the last block.
  248. .LP
  249. IOCTL FUNCTIONS
  250. The rt11Fs file system supports the following ioctl() functions.
  251. The functions listed are defined in the header ioLib.h.  Unless stated
  252. otherwise, the file descriptor used for these functions can be any file
  253. descriptor open to a file or to the volume itself.
  254. .iP "FIODISKFORMAT" 16 3
  255. Formats the entire disk with appropriate hardware track and sector marks.
  256. No file system is initialized on the disk by this request.
  257. Note that this is a driver-provided function:
  258. .CS
  259.     fd = open ("DEV1:", O_WRONLY);
  260.     status = ioctl (fd, FIODISKFORMAT, 0);
  261. .CE
  262. .iP "FIODISKINIT"
  263. Initializes an rt11Fs file system on the disk volume.
  264. This routine does not format the disk; formatting must be done by the driver.
  265. The file descriptor should be obtained by opening the entire volume in raw mode:
  266. .CS
  267.     fd = open ("DEV1:", O_WRONLY);
  268.     status = ioctl (fd, FIODISKINIT, 0);
  269. .CE
  270. .iP "FIODISKCHANGE"
  271. Announces a media change.  It performs the same function as rt11FsReadyChange().
  272. This function may be called from interrupt level:
  273. .CS
  274.     status = ioctl (fd, FIODISKCHANGE, 0);
  275. .CE
  276. .iP "FIOGETNAME"
  277. Gets the file name of the file descriptor and copies it to the buffer <nameBuf>:
  278. .CS
  279.     status = ioctl (fd, FIOGETNAME, &nameBuf);
  280. .CE
  281. .iP "FIORENAME"
  282. Renames the file to the string <newname>:
  283. .CS
  284.     status = ioctl (fd, FIORENAME, "newname");
  285. .CE
  286. .iP "FIONREAD"
  287. Copies to <unreadCount> the number of unread bytes in the file:
  288. .CS
  289.     status = ioctl (fd, FIONREAD, &unreadCount);
  290. .CE
  291. .iP "FIOFLUSH"
  292. Flushes the file output buffer.  It guarantees that any output that has been
  293. requested is actually written to the device.
  294. .CS
  295.     status = ioctl (fd, FIOFLUSH, 0);
  296. .CE
  297. .iP "FIOSEEK"
  298. Sets the current byte offset in the file to the position specified by
  299. <newOffset>:
  300. .CS
  301.     status = ioctl (fd, FIOSEEK, newOffset);
  302. .CE
  303. .iP "FIOWHERE"
  304. Returns the current byte position in the file.  This is the byte offset of
  305. the next byte to be read or written.  It takes no additional argument:
  306. .CS
  307.     position = ioctl (fd, FIOWHERE, 0);
  308. .CE
  309. .iP "FIOSQUEEZE"
  310. Coalesces fragmented free space on an rt11Fs volume:
  311. .CS
  312.     status = ioctl (fd, FIOSQUEEZE, 0);
  313. .CE
  314. .iP "FIODIRENTRY"
  315. Copies information about the specified directory entries to a
  316. %REQ_DIR_ENTRY structure that is defined in ioLib.h.  The argument <req>
  317. is a pointer to a %REQ_DIR_ENTRY structure.  On entry, the structure
  318. contains the number of the directory entry for which information is
  319. requested.  On return, the structure contains the information on the
  320. requested entry.  For example, after the following:
  321. .CS
  322.     REQ_DIR_ENTRY req;
  323.     req.entryNum = 0;
  324.     status = ioctl (fd, FIODIRENTRY, &req);
  325. .CE
  326. the request structure contains the name, size, and creation date of the
  327. file in the first entry (0) of the directory.
  328. .iP "FIOREADDIR"
  329. Reads the next directory entry.  The argument <dirStruct> is a DIR
  330. directory descriptor.  Normally, readdir() is used to read a
  331. directory, rather than using the FIOREADDIR function directly.  See dirLib.
  332. .CS
  333.     DIR dirStruct;
  334.     fd = open ("directory", O_RDONLY);
  335.     status = ioctl (fd, FIOREADDIR, &dirStruct);
  336. .CE
  337. .iP "FIOFSTATGET"
  338. Gets file status information (directory entry data).  The argument
  339. <statStruct> is a pointer to a stat structure that is filled with data
  340. describing the specified file.  Normally, the stat() or fstat() routine
  341. is used to obtain file information, rather than using the FIOFSTATGET
  342. function directly.  See dirLib.
  343. .CS
  344.     struct stat statStruct;
  345.     fd = open ("file", O_RDONLY);
  346.     status = ioctl (fd, FIOFSTATGET, &statStruct);
  347. .CE
  348. .LP
  349. Any other ioctl() function codes are passed to the block device driver
  350. for handling.
  351. INCLUDE FILES: rt11FsLib.h
  352. SEE ALSO: ioLib, iosLib, ramDrv,
  353. .pG "I/O System, Local File Systems"
  354. */
  355. /* LINTLIBRARY */
  356. #include "vxWorks.h"
  357. #include "ctype.h"
  358. #include "ioLib.h"
  359. #include "semLib.h"
  360. #include "rt11FsLib.h"
  361. #include "blkIo.h"
  362. #include "stdlib.h"
  363. #include "string.h"
  364. #include "dirent.h"
  365. #include "errnoLib.h"
  366. #include "time.h"
  367. #include "sys/stat.h"
  368. #define RT_NAME_LEN 11
  369. #ifndef WAIT_FOREVER
  370. #define WAIT_FOREVER    NULL
  371. #endif
  372. /* GLOBALS */
  373. int rt11FsDrvNum = ERROR; /* I/O system driver number for RT-11 */
  374. int rt11FsVolMutexOptions = (SEM_Q_PRIORITY | SEM_DELETE_SAFE);
  375. /* default mutex options */
  376. /* LOCALS */
  377. LOCAL char rad50 [] = " abcdefghijklmnopqrstuvwxyz$.3770123456789";
  378. LOCAL RT_FILE_DESC *rt11FsFd; /* pointer to list of file descriptors */
  379. LOCAL int rt11FsMaxFiles; /* max RT-11 files that can be open at once */
  380. LOCAL SEM_ID rt11FsFdSemId; /* interlock file descriptor list access */
  381. LOCAL int rt11FsDay = 0; /* day of month, default is 0 */
  382. LOCAL int rt11FsMonth = 0; /* month of year, default is 0 */
  383. LOCAL int rt11FsYear = 72; /* year, default is '72 (stored as 0) */
  384. /* forward static functions */
  385. static STATUS rt11FsClose (RT_FILE_DESC *pFd);
  386. static void rt11FsCoalesce (RT_VOL_DESC *vdptr, int entryNum);
  387. static RT_FILE_DESC *rt11FsCreate (RT_VOL_DESC *vdptr, char *name, int mode);
  388. static int rt11FsDate (int year, int month, int day);
  389. static STATUS rt11FsDelete (RT_VOL_DESC *vdptr, char *name);
  390. static STATUS rt11FsDirEntry (RT_VOL_DESC *vdptr, REQ_DIR_ENTRY *rdeptr);
  391. static STATUS rt11FsDirRead (RT_FILE_DESC *pFd, DIR *pDir);
  392. static STATUS rt11FsFileStatGet (RT_FILE_DESC *pFd, struct stat *pStat);
  393. static int rt11FsFindEntry (RT_VOL_DESC *vdptr, char *name, int *pstart);
  394. static STATUS rt11FsFlush (RT_FILE_DESC *pFd);
  395. static void rt11FsFreeFd (RT_FILE_DESC *pFd);
  396. static RT_FILE_DESC *rt11FsGetFd (void);
  397. static void rt11FsGetEntry (RT_VOL_DESC *vdptr, int entryNum, RT_DIR_ENTRY
  398. *pEntry);
  399. static void rt11FsInsEntry (RT_VOL_DESC *vdptr, int entryNum, RT_DIR_ENTRY
  400. *pEntry);
  401. static STATUS rt11FsIoctl (RT_FILE_DESC *pFd, int function, int arg);
  402. static void rt11FsNameR50 (char *string, RT_NAME *pName);
  403. static int rt11FsR50out (char *string);
  404. static void rt11FsNameString (RT_NAME name, char *string);
  405. static void rt11FsR50in (unsigned int r50, char *string);
  406. static RT_FILE_DESC *rt11FsOpen (RT_VOL_DESC *vdptr, char *name, int mode);
  407. static void rt11FsPutEntry (RT_VOL_DESC *vdptr, int entryNum, RT_DIR_ENTRY
  408. *pEntry);
  409. static int rt11FsRead (RT_FILE_DESC *pFd, char *pBuf, int maxBytes);
  410. static STATUS rt11FsRename (RT_FILE_DESC *pFd, char *newName);
  411. static STATUS rt11FsSeek (RT_FILE_DESC *pFd, int position);
  412. static STATUS rt11FsVolFlush (RT_VOL_DESC *vdptr);
  413. static STATUS rt11FsVolInit (RT_VOL_DESC *vdptr);
  414. static STATUS rt11FsVolMount (RT_VOL_DESC *vdptr);
  415. static int rt11FsWhere (RT_FILE_DESC *pFd);
  416. static int rt11FsWrite (RT_FILE_DESC *pFd, char *pBuf, int nbytes);
  417. static int rt11FsNewBlock (RT_FILE_DESC *pFd);
  418. static STATUS rt11FsRdBlock (RT_VOL_DESC *vdptr, int blockNum, int numBlocks,
  419. char *pBuf);
  420. static STATUS rt11FsWrtBlock (RT_VOL_DESC *vdptr, int blockNum, int
  421. numBlocks, char *pBuf);
  422. static int rt11FsAbsSector (ULONG secPerTrack, int sector);
  423. static STATUS rt11FsCheckVol (RT_VOL_DESC *vdptr, BOOL doMount);
  424. static STATUS rt11FsReset (RT_VOL_DESC *vdptr);
  425. static STATUS rt11FsVolMode (RT_VOL_DESC *vdptr);
  426. static STATUS rt11FsSqueeze (RT_VOL_DESC *vdptr);
  427. /*******************************************************************************
  428. *
  429. * rt11FsClose - close an RT-11 file
  430. *
  431. * This routine closes the specified RT-11 file.
  432. * The end of the buffer beyond the end of file is cleared out,
  433. * the buffer is flushed, and the directory is updated if necessary.
  434. *
  435. * RETURNS:
  436. * OK, or
  437. * ERROR if directory couldn't be flushed or
  438. * entry couldn't be found.
  439. */
  440. LOCAL STATUS rt11FsClose
  441.     (
  442.     FAST RT_FILE_DESC *pFd      /* file descriptor pointer */
  443.     )
  444.     {
  445.     FAST RT_DIR_ENTRY *pEntry = &pFd->rfd_dir_entry;
  446.     FAST int remaining_blocks;
  447.     FAST int nblocks;
  448.     int buf_index;
  449.     STATUS status;
  450.     char name[RT_NAME_LEN]; /* file name gets unpacked into here */
  451.     int entryNum; /* file's entry number in directory */
  452.     int start; /* for receiving rt11FsFindEntry side-effect */
  453.     /* if current buffer has been written to and contains end of file,
  454.      *   clear out end of buffer that lies beyond end of file. */
  455.     if (pFd->rfd_modified && ((pFd->rfd_curptr / RT_BYTES_PER_BLOCK) ==
  456.       (pFd->rfd_endptr / RT_BYTES_PER_BLOCK)))
  457. {
  458. buf_index = pFd->rfd_endptr - pFd->rfd_curptr;
  459. bzero (&pFd->rfd_buffer[buf_index], RT_BYTES_PER_BLOCK - buf_index);
  460. }
  461.     status = rt11FsFlush (pFd);
  462.     /* if file is new, update directory */
  463.     if (pEntry->de_status == DES_TENTATIVE)
  464. {
  465. /* update directory entry to be permanent with actual size */
  466. nblocks = ((pFd->rfd_endptr - 1) / RT_BYTES_PER_BLOCK) + 1;
  467. remaining_blocks = pEntry->de_nblocks - nblocks;
  468. pEntry->de_status  = DES_PERMANENT;
  469. pEntry->de_nblocks = nblocks;
  470. semTake (pFd->rfd_vdptr->vd_semId, WAIT_FOREVER);
  471. /* unpack name and find entry number */
  472. rt11FsNameString (pFd->rfd_dir_entry.de_name, name);
  473. entryNum = rt11FsFindEntry (pFd->rfd_vdptr, name, &start);
  474. if (entryNum == ERROR)
  475.     status = ERROR;
  476. else
  477.     {
  478.     rt11FsPutEntry (pFd->rfd_vdptr, entryNum, pEntry);
  479.     /* if unused blocks are left over, insert EMPTY entry in directory*/
  480.     if (remaining_blocks != 0)
  481. {
  482. pEntry->de_status  = DES_EMPTY;
  483. pEntry->de_nblocks = remaining_blocks;
  484. rt11FsInsEntry (pFd->rfd_vdptr, entryNum + 1, pEntry);
  485. rt11FsCoalesce (pFd->rfd_vdptr, entryNum + 1);
  486. }
  487.     /* make sure directory is written out */
  488.     if (rt11FsVolFlush (pFd->rfd_vdptr) != OK)
  489. status = ERROR;
  490.     }
  491. semGive (pFd->rfd_vdptr->vd_semId); /* release volume */
  492. }
  493.     rt11FsFreeFd (pFd); /* mark fd not in use */
  494.     return (status);
  495.     }
  496. /*******************************************************************************
  497. *
  498. * rt11FsCoalesce - merge empty directory entries
  499. *
  500. * This routine merges a directory entry with its empty neighbors, if any.
  501. * It stops when there are no more empty neighbors, or when adding
  502. * another empty file would cause it to have more than RT_MAX_BLOCKS_PER_FILE
  503. * blocks in an empty file.
  504. * The directory will be updated.
  505. *
  506. * Possession of the volume descriptor's semaphore must have been secured
  507. * before this routine is called.
  508. */
  509. LOCAL void rt11FsCoalesce
  510.     (
  511.     RT_VOL_DESC *vdptr,     /* pointer to volume descriptor */
  512.     int entryNum            /* number of empty entry to coalesce */
  513.     )
  514.     {
  515.     RT_DIR_ENTRY entry;     /* 1st of 1-3 empty directory entries */
  516.     RT_DIR_ENTRY nentry;    /* next entry */
  517.     int n = 0;     /* number of entries to merge into first */
  518.     rt11FsGetEntry (vdptr, --entryNum, &entry);
  519.     if ((entryNum < 0) || (entry.de_status != DES_EMPTY))
  520. rt11FsGetEntry (vdptr, ++entryNum, &entry);
  521.     rt11FsGetEntry (vdptr, entryNum + 1, &nentry); /* get next entry */
  522.     /* start coalescing -- don't coalesce 2 files if the new file would
  523.        have more than RT_MAX_BLOCKS_PER_FILE */
  524.     while (nentry.de_status == DES_EMPTY)
  525. {
  526.      if ((entry.de_nblocks + nentry.de_nblocks) > RT_MAX_BLOCKS_PER_FILE)
  527.     {
  528.     /* These two files can't be merged. The new file would be too big */
  529.     if (n > 0) /* don't change entry ptr w.o. coalescing */
  530. break;
  531.     else
  532. {
  533. /* Can't coalesce current empty entry.  Point to next one */
  534. entryNum++;
  535. entry = nentry;
  536. }
  537.     }
  538. else
  539.     {
  540.     entry.de_nblocks += nentry.de_nblocks; /* seize empty blocks */
  541.     ++n;
  542.     }
  543. rt11FsGetEntry (vdptr, entryNum + 1 + n, &nentry);/* get next entry */
  544. }
  545.     if (n > 0) /* any entries coalesced? */
  546. {
  547. rt11FsPutEntry (vdptr, entryNum, &entry); /* put empty entry */
  548. rt11FsPutEntry (vdptr, ++entryNum, &nentry); /* put nonempty entry */
  549. /* move rest of entries up by n places */
  550. while (nentry.de_status != DES_END)
  551.     {
  552.     rt11FsGetEntry (vdptr, ++entryNum + n, &nentry);
  553.     rt11FsPutEntry (vdptr, entryNum, &nentry);
  554.     }
  555. }
  556.     }
  557. /*******************************************************************************
  558. *
  559. * rt11FsCreate - create an RT-11 file
  560. *
  561. * This routine creates the file <name> with the specified <mode>.
  562. * If the file already exists, it is first deleted then recreated.
  563. * The largest empty space on the device is allocated to the new file.
  564. * Excess space will be recovered when the file is closed.
  565. * An RT-11 file descriptor is initialized for the file.
  566. *
  567. * A file <name> of zero length (i.e., "" is used to open an entire "raw" disk).
  568. * In this case, no attempt is made to access the disk's directory, so that
  569. * even un-initialized disks may be accessed.
  570. *
  571. * RETURNS
  572. * Pointer to RT-11 file descriptor, or
  573. * ERROR if error in create.
  574. */
  575. LOCAL RT_FILE_DESC *rt11FsCreate
  576.     (
  577.     RT_VOL_DESC *vdptr, /* pointer to volume descriptor */
  578.     char *name,         /* RT-11 string (ffffff.ttt) */
  579.     int mode            /* file mode (O_RDONLY/O_WRONLY/O_RDWR) */
  580.     )
  581.     {
  582.     RT_DIR_ENTRY entry;
  583.     int start;
  584.     FAST int e_num;
  585.     RT_DIR_ENTRY max_entry;
  586.     int max_start = 0; /* used only if max_e_num != NONE */
  587.     int max_e_num; /* maximum entry number */
  588.     FAST int nEntries; /* number of entries that will fit in segment */
  589.     FAST RT_FILE_DESC *pFd; /* file descriptor pointer */
  590.     /* Call driver check-status routine, if any */
  591.     if (vdptr->vd_pBlkDev->bd_statusChk != NULL)
  592. {
  593. if ((* vdptr->vd_pBlkDev->bd_statusChk) (vdptr->vd_pBlkDev) != OK)
  594.     {
  595.     return ((RT_FILE_DESC *) ERROR);
  596.     }
  597. }
  598.     /* Set up for re-mount if no disk change notification */
  599.     if (vdptr->vd_changeNoWarn == TRUE)
  600. rt11FsReadyChange (vdptr);
  601.     pFd = rt11FsGetFd ();  /* get file descriptor */
  602.     if (pFd == NULL)
  603. return ((RT_FILE_DESC *) ERROR); /* no free file descriptors */
  604.     nEntries = (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK
  605. - (sizeof (RT_DIR_SEG) - sizeof (RT_DIR_ENTRY)))
  606. / sizeof (RT_DIR_ENTRY);
  607.     /* check for create of raw device (null filename) */
  608.     if (name [0] == EOS)
  609. {
  610. /* check that volume is available */
  611. semTake (vdptr->vd_semId, WAIT_FOREVER);
  612. if (rt11FsCheckVol (vdptr, FALSE) != OK)
  613.     {
  614.     semGive (vdptr->vd_semId);
  615.     rt11FsFreeFd (pFd);
  616.     errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  617.     return ((RT_FILE_DESC *) ERROR);
  618.     }
  619. /* disk must be writable to create file */
  620. if (rt11FsVolMode (vdptr) == O_RDONLY)
  621.     {
  622.     semGive (vdptr->vd_semId);
  623.     rt11FsFreeFd (pFd);
  624.     errnoSet (S_ioLib_WRITE_PROTECTED);
  625.     return ((RT_FILE_DESC *) ERROR);
  626.     }
  627. semGive (vdptr->vd_semId);
  628. /* null name is special indicator for "raw" disk;
  629.  *   fabricate a bogus directory entry covering entire volume */
  630. pFd->rfd_dir_entry.de_status  = DES_BOGUS;
  631. pFd->rfd_dir_entry.de_date    = rt11FsDate (rt11FsYear, rt11FsMonth,
  632.     rt11FsDay);
  633. pFd->rfd_dir_entry.de_nblocks = vdptr->vd_nblocks;
  634. rt11FsNameR50 ("device.raw", &pFd->rfd_dir_entry.de_name);
  635. pFd->rfd_start = 0;
  636. pFd->rfd_endptr = vdptr->vd_nblocks * RT_BYTES_PER_BLOCK;
  637. }
  638.     else
  639. {
  640.      /* Ignore any leading "/" or ""'s in file name */
  641.      while ((*name == '/') || (*name == '\'))
  642.     name++;
  643. /* first delete any existing file with the specified name */
  644. (void) rt11FsDelete (vdptr, name);
  645. /* check that volume is available */
  646. semTake (vdptr->vd_semId, WAIT_FOREVER);
  647. if ((rt11FsCheckVol (vdptr, TRUE) != OK) || (vdptr->vd_status != OK))
  648.     {
  649.     semGive (vdptr->vd_semId); /* release volume */
  650.     rt11FsFreeFd (pFd);
  651.     errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  652.     return ((RT_FILE_DESC *) ERROR);
  653.     }
  654. /* disk must be writable to create file */
  655. if (rt11FsVolMode (vdptr) == O_RDONLY)
  656.     {
  657.     semGive (vdptr->vd_semId); /* release volume */
  658.     rt11FsFreeFd (pFd);
  659.     errnoSet (S_ioLib_WRITE_PROTECTED);
  660.     return ((RT_FILE_DESC *) ERROR);
  661.     }
  662. /* search entire directory for largest empty entry.
  663.  * keep track of start block by accumulating entry lengths.
  664.  */
  665. start = vdptr->vd_dir_seg->ds_start;
  666. max_e_num = NONE;
  667. for (e_num = 0; e_num < nEntries; e_num++)
  668.     {
  669.     rt11FsGetEntry (vdptr, e_num, &entry);
  670.     /* if this is the end of the directory, then quit. */
  671.     if (entry.de_status == DES_END)
  672. break;
  673.     /* check if create already in progress */
  674.     if (entry.de_status == DES_TENTATIVE)
  675. {
  676. semGive (vdptr->vd_semId); /* release volume */
  677. rt11FsFreeFd (pFd);
  678. errnoSet (S_rt11FsLib_NO_MORE_FILES_ALLOWED_ON_DISK);
  679. return ((RT_FILE_DESC *) ERROR);
  680. }
  681.     /* check if this is largest empty file so far */
  682.     if ((entry.de_status == DES_EMPTY) &&
  683. ((max_e_num == NONE) ||
  684.  (entry.de_nblocks > max_entry.de_nblocks)))
  685. {
  686. max_e_num = e_num;
  687. max_entry = entry;
  688. max_start = start;
  689. }
  690.     /* add file length to get start of next file */
  691.     start += entry.de_nblocks;
  692.     }
  693. /* check for running out of room for file entries
  694.  * (the last entry is a terminating entry) */
  695. if (e_num >= nEntries - 1)
  696.     {
  697.     semGive (vdptr->vd_semId); /* release volume */
  698.     rt11FsFreeFd (pFd);
  699.     errnoSet (S_rt11FsLib_NO_MORE_FILES_ALLOWED_ON_DISK);
  700.     return ((RT_FILE_DESC *) ERROR);
  701.     }
  702. /* check for no empty holes found */
  703. if (max_e_num == NONE)
  704.     {
  705.     semGive (vdptr->vd_semId); /* release volume */
  706.     rt11FsFreeFd (pFd);
  707.     errnoSet (S_rt11FsLib_DISK_FULL);
  708.     return ((RT_FILE_DESC *) ERROR);
  709.     }
  710. /* found an empty hole; initialize entry */
  711. max_entry.de_status = DES_TENTATIVE;
  712. max_entry.de_date   = rt11FsDate (rt11FsYear, rt11FsMonth, rt11FsDay);
  713. rt11FsNameR50 (name, &max_entry.de_name);
  714. rt11FsPutEntry (vdptr, max_e_num, &max_entry);
  715. (void) rt11FsVolFlush (vdptr);
  716. semGive (vdptr->vd_semId); /* release volume */
  717. pFd->rfd_dir_entry = max_entry;
  718. pFd->rfd_start    = max_start;
  719. pFd->rfd_endptr    = 0;
  720. }
  721.     /* initialize rest of file descriptor */
  722.     pFd->rfd_mode = mode;
  723.     pFd->rfd_vdptr = vdptr;
  724.     pFd->rfd_curptr = NONE;
  725.     pFd->rfd_newptr = 0;
  726.     pFd->rfd_modified = FALSE;
  727.     return (pFd);
  728.     }
  729. /*******************************************************************************
  730. *
  731. * rt11FsDate - generate RT-11 encoded date
  732. *
  733. * This routine encodes the specified date into RT-1 format.
  734. *
  735. * RETURNS: Encoded date.
  736. */
  737. LOCAL int rt11FsDate
  738.     (
  739.     int year,           /* 72, or 72...03 */
  740.     int month,          /* 0, or 1...12 */
  741.     int day             /* 0, or 1...31 */
  742.     )
  743.     {
  744.     if ((year -= 72) < 0)
  745. year += 100;
  746.     return ((month << 10) | (day << 5) | (year & 0x1f));
  747.     }
  748. /*******************************************************************************
  749. *
  750. * rt11FsDelete - delete RT-11 file
  751. *
  752. * This routine deletes the file <name> from the specified RT-11 volume.
  753. *
  754. * RETURNS:
  755. * OK, or
  756. * ERROR if file not found or volume not available.
  757. *
  758. */
  759. LOCAL STATUS rt11FsDelete
  760.     (
  761.     RT_VOL_DESC *vdptr, /* pointer to volume descriptor */
  762.     char *name          /* RT-11 filename (ffffff.ttt) */
  763.     )
  764.     {
  765.     int entryNum;
  766.     int start;
  767.     RT_DIR_ENTRY entry;
  768.     /* Set up for re-mount if no disk change notification */
  769.     if (vdptr->vd_changeNoWarn == TRUE)
  770. rt11FsReadyChange (vdptr);
  771.     semTake (vdptr->vd_semId, WAIT_FOREVER);
  772.     /* check that volume is available */
  773.     if ((rt11FsCheckVol (vdptr, TRUE) != OK) || (vdptr->vd_status != OK))
  774. {
  775. semGive (vdptr->vd_semId);
  776. errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  777. return (ERROR);
  778. }
  779.     if (rt11FsVolMode (vdptr) == O_RDONLY)
  780. {
  781. semGive (vdptr->vd_semId);
  782. errnoSet (S_ioLib_WRITE_PROTECTED);
  783. return (ERROR);
  784. }
  785.     /* search for entry with specified name */
  786.     if ((entryNum = rt11FsFindEntry (vdptr, name, &start)) == ERROR)
  787. {
  788. semGive (vdptr->vd_semId); /* release volume */
  789. return (ERROR);
  790. }
  791.     rt11FsGetEntry (vdptr, entryNum, &entry);
  792.     entry.de_status = DES_EMPTY;
  793.     entry.de_date = 0;
  794.     rt11FsPutEntry (vdptr, entryNum, &entry);
  795.     rt11FsCoalesce (vdptr, entryNum); /* merge with empty neighbors */
  796.     /* make sure directory is written out */
  797.     if (rt11FsVolFlush (vdptr) != OK)
  798. {
  799. semGive (vdptr->vd_semId); /* release volume */
  800. return (ERROR);
  801. }
  802.     semGive (vdptr->vd_semId); /* release volume */
  803.     return (OK);
  804.     }
  805. /*******************************************************************************
  806. *
  807. * rt11FsDevInit - initialize the rt11Fs device descriptor
  808. *
  809. * This routine initializes the device descriptor.  The <pBlkDev> parameter is
  810. * a pointer to an already-created BLK_DEV device structure.  This structure
  811. * contains definitions for various aspects of the physical device format,
  812. * as well as pointers to the sector read, sector write, ioctl(), status check,
  813. * and reset functions for the device.
  814. *
  815. * The <rt11Fmt> parameter is TRUE if the device is to be accessed using
  816. * standard RT-11 skew and interleave.
  817. *
  818. * The device directory will consist of one segment able to contain at
  819. * least as many files as specified by <nEntries>.
  820. * If <nEntries> is equal to RT_FILES_FOR_2_BLOCK_SEG, strict RT-11
  821. * compatibility is maintained.
  822. *
  823. * The <changeNoWarn> parameter is TRUE if the disk may be changed without
  824. * announcing the change via rt11FsReadyChange().  Setting <changeNoWarn> to
  825. * TRUE causes the disk to be regularly remounted, in case it has been
  826. * changed.  This results in a significant performance penalty.
  827. *
  828. * NOTE
  829. * An ERROR is returned if <rt11Fmt> is TRUE and the `bd_blksPerTrack'
  830. * (sectors per track) field in the BLK_DEV structure is odd.
  831. * This is because an odd number of sectors per track is incompatible with the
  832. * RT-11 interleaving algorithm.
  833. *
  834. * INTERNAL
  835. * The semaphore in the device is given, so the device is available for
  836. * use immediately.
  837. *
  838. * RETURNS:
  839. * A pointer to the volume descriptor (RT_VOL_DESC), or
  840. * NULL if invalid device parameters were specified,
  841. * or the routine runs out of memory.
  842. */
  843. RT_VOL_DESC *rt11FsDevInit
  844.     (
  845.     char            *devName,       /* device name */
  846.     FAST BLK_DEV    *pBlkDev,       /* pointer to block device info */
  847.     BOOL            rt11Fmt,        /* TRUE if RT-11 skew & interleave */
  848.     FAST int        nEntries,       /* no. of dir entries incl term entry */
  849.     BOOL            changeNoWarn    /* TRUE if no disk change warning */
  850.     )
  851.     {
  852.     FAST RT_VOL_DESC *vdptr; /* pointer to volume descriptor */
  853.     FAST int segmentLen; /* segment length in bytes */
  854.     FAST int i;
  855.     /* Return error if no BLK_DEV */
  856.     if (pBlkDev == NULL)
  857. {
  858. errnoSet (S_rt11FsLib_NO_BLOCK_DEVICE);
  859. return (NULL);
  860. }
  861.     /* Don't allow odd number of sectors/track if RT-11 interleave specified */
  862.     if (rt11Fmt && (pBlkDev->bd_blksPerTrack & 1))
  863. {
  864. errnoSet (S_rt11FsLib_INVALID_DEVICE_PARAMETERS);
  865. return (NULL);
  866. }
  867.     /* Allocate an RT-11 volume descriptor for device */
  868.     if ((vdptr = (RT_VOL_DESC *) calloc (sizeof (RT_VOL_DESC), 1)) == NULL)
  869. return (NULL); /* no memory */
  870.     /* Add device to system device table */
  871.     if (iosDevAdd ((DEV_HDR *) vdptr, devName, rt11FsDrvNum) != OK)
  872. {
  873. free ((char *) vdptr);
  874. return (NULL); /* can't add device */
  875. }
  876.     /* Initialize volume descriptor */
  877.     vdptr->vd_pBlkDev = pBlkDev;
  878.     vdptr->vd_rtFmt = rt11Fmt;
  879.     vdptr->vd_status = OK;
  880.     vdptr->vd_state = RT_VD_READY_CHANGED;
  881.     vdptr->vd_secBlock = RT_BYTES_PER_BLOCK /
  882.   pBlkDev->bd_bytesPerBlk;
  883.     vdptr->vd_nblocks = pBlkDev->bd_nBlocks / vdptr->vd_secBlock;
  884.     /* Set flag for disk change without warning (removable disks only) */
  885.     if (pBlkDev->bd_removable) /* if removable device */
  886.      vdptr->vd_changeNoWarn = changeNoWarn; /* get user's flag */
  887.     else
  888.      vdptr->vd_changeNoWarn = FALSE; /* always FALSE for fixed disk*/
  889.     /* how many bytes of space are needed for the segment? */
  890.     segmentLen = sizeof (RT_DIR_SEG) + (nEntries - 1) * sizeof (RT_DIR_ENTRY);
  891.     /* Allocate blocks for the segment.
  892.      * The smallest segment is 2 blocks long */
  893.     if  ((i = 1 + (segmentLen / RT_BYTES_PER_BLOCK)) < 2)
  894. vdptr->vd_nSegBlocks = 2;
  895.     else
  896.         vdptr->vd_nSegBlocks = i;
  897.     /* allocate segment blocks */
  898.     vdptr->vd_dir_seg = (RT_DIR_SEG *)
  899. malloc ((unsigned)
  900. (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK));
  901.     if (vdptr->vd_dir_seg == NULL)
  902. return (NULL);
  903.     vdptr->vd_semId = semMCreate (rt11FsVolMutexOptions);
  904.     if (vdptr->vd_semId == NULL)
  905. return (NULL); /* could not create semaphore */
  906.     return (vdptr);
  907.     }
  908. /*******************************************************************************
  909. *
  910. * rt11FsDirEntry - get info from a directory entry
  911. *
  912. * This routine returns information about a particular directory entry into
  913. * the REQ_DIR_ENTRY structure whose pointer is passed as a parameter.
  914. * The information put there is the name of the file, its size (in bytes),
  915. * and its creation date.  If the specified entry is an empty (keeps
  916. * track of empty space on the disk), the name will be an empty string,
  917. * the size will be correct, and the date will be meaningless.
  918. *
  919. * Before this routine is called, the field `entryNum' must set in
  920. * the REQ_DIR_ENTRY structure pointed to by rdeptr.  That is the entry
  921. * whose information will be returned.  Typically, the entries are accessed
  922. * sequentially starting with 0 until the terminating entry is reached
  923. * (indicated by a return code of ERROR).
  924. *
  925. * RETURNS:
  926. * OK, or
  927. * ERROR if no such entry.
  928. */
  929. LOCAL STATUS rt11FsDirEntry
  930.     (
  931.     RT_VOL_DESC *vdptr,         /* pointer to volume descriptor */
  932.     REQ_DIR_ENTRY *rdeptr       /* ptr to structure into which to put info */
  933.     )
  934.     {
  935.     RT_DIR_ENTRY *deptr; /* pointer to directory entry in question */
  936.     FAST int maxEntries; /* max number of entries allowed in directory */
  937.     /* Set up for re-mount if no disk change notification */
  938.     if (vdptr->vd_changeNoWarn == TRUE)
  939. rt11FsReadyChange (vdptr);
  940.     semTake (vdptr->vd_semId, WAIT_FOREVER);
  941.     if (rt11FsCheckVol (vdptr, TRUE) != OK)
  942. {
  943. semGive (vdptr->vd_semId);
  944. errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  945. return (ERROR);
  946. }
  947.     /* what is the maximum number of entries allowed in this directory? */
  948.     maxEntries = (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK
  949. - (sizeof (RT_DIR_SEG) - sizeof (RT_DIR_ENTRY)))
  950. / sizeof (RT_DIR_ENTRY);
  951.     if (rdeptr->entryNum >= maxEntries)
  952. {
  953. semGive (vdptr->vd_semId);
  954. errnoSet (S_rt11FsLib_ENTRY_NUMBER_TOO_BIG);
  955. return (ERROR);
  956. }
  957.     deptr = &(vdptr->vd_dir_seg->ds_entries[rdeptr->entryNum]);
  958.     switch (deptr->de_status)
  959. {
  960. case DES_TENTATIVE: /* - should indicate tentative somehow? */
  961. case DES_PERMANENT:
  962.     rt11FsNameString (deptr->de_name, rdeptr->name);
  963.     break;
  964. case DES_EMPTY:
  965.     rdeptr->name[0] = EOS; /* empty, no name */
  966.     break;
  967. default:
  968.     semGive (vdptr->vd_semId); /* release volume */
  969.     errnoSet (S_rt11FsLib_FILE_NOT_FOUND);
  970.     return (ERROR); /* no such entry */
  971. }
  972.     rdeptr->nChars = deptr->de_nblocks * RT_BYTES_PER_BLOCK;
  973.     rdeptr->day = (deptr->de_date >> 5) & 0x001f;
  974.     rdeptr->month = (deptr->de_date >> 10) & 0x000f;
  975.     rdeptr->year = (deptr->de_date & 0x001f) + 1972;
  976.     semGive (vdptr->vd_semId); /* release volume */
  977.     return (OK);
  978.     }
  979. /*******************************************************************************
  980. *
  981. * rt11FsDirRead - read directory and return next file name
  982. *
  983. * This routine support POSIX directory searches.  The directory is read,
  984. * and the name of the next file is returned in a "dirent" structure.
  985. * This routine is called via an ioctl() call with a function code of
  986. * FIOREADDIR.
  987. *
  988. * RETURNS: OK, or ERROR if end of dir (errno = OK) or real error (errno set).
  989. */
  990. LOCAL STATUS rt11FsDirRead
  991.     (
  992.     FAST RT_FILE_DESC   *pFd,           /* ptr to RT-11 file descriptor */
  993.     FAST DIR            *pDir           /* ptr to directory descriptor */
  994.     )
  995.     {
  996.     FAST int entryNum; /* position within dir */
  997.     FAST int maxEntries; /* number of entries in dir */
  998.     FAST char *pChar; /* ptr to char in filename string */
  999.     int nameLen; /* length of filename string */
  1000.     FAST RT_DIR_ENTRY *pEntry; /* ptr to directory entry in memory */
  1001.     FAST RT_VOL_DESC *vdptr = pFd->rfd_vdptr;
  1002. /* ptr to volume descriptor */
  1003.     semTake (vdptr->vd_semId, WAIT_FOREVER);
  1004.     if (rt11FsCheckVol (vdptr, TRUE) != OK)
  1005. {
  1006. semGive (vdptr->vd_semId);
  1007. errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  1008. return (ERROR);
  1009. }
  1010.     /* Check if cookie (entry number) is past end of directory */
  1011.     entryNum = pDir->dd_cookie; /* get marker from DIR */
  1012.     maxEntries = (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK
  1013.   - (sizeof (RT_DIR_SEG) - sizeof (RT_DIR_ENTRY)))
  1014.  / sizeof (RT_DIR_ENTRY);
  1015.     /* Read an entry, keep going if empty */
  1016.     do
  1017. {
  1018.      if (entryNum >= maxEntries)
  1019.     {
  1020.     semGive (vdptr->vd_semId);
  1021.     return (ERROR); /* end of directory */
  1022.     }
  1023.      pEntry = &(vdptr->vd_dir_seg->ds_entries[entryNum]);
  1024. /* find entry within dir */
  1025. if (pEntry->de_status == DES_END)
  1026.     {
  1027.     semGive (vdptr->vd_semId);
  1028.     return (ERROR); /* end of directory */
  1029.     }
  1030. entryNum++;
  1031. } while (pEntry->de_status == DES_EMPTY);
  1032.     /* Copy name to dirent struct */
  1033.    rt11FsNameString (pEntry->de_name, pDir->dd_dirent.d_name);
  1034.    /* Cancel trailing blanks or "." */
  1035.    nameLen = strlen (pDir->dd_dirent.d_name);
  1036.    if (nameLen > 0)
  1037. {
  1038. pChar = (pDir->dd_dirent.d_name + nameLen - 1);
  1039. while ((*pChar == ' ') || (*pChar == '.'))
  1040.     {
  1041.     *pChar = EOS;
  1042.     pChar--;
  1043.     }
  1044. }
  1045.     pDir->dd_cookie = entryNum; /* copy updated entry number */
  1046.     semGive (vdptr->vd_semId);
  1047.     return (OK);
  1048.     }
  1049. /*******************************************************************************
  1050. *
  1051. * rt11FsFileStatGet - get file status info from directory entry
  1052. *
  1053. * This routine is called via an ioctl() call, using the FIOFSTATGET
  1054. * function code.  The passed stat structure is filled, using data
  1055. * obtained from the directory entry which describes the file.
  1056. *
  1057. * RETURNS: OK (always).
  1058. */
  1059. LOCAL STATUS rt11FsFileStatGet
  1060.     (
  1061.     FAST RT_FILE_DESC   *pFd,           /* pointer to file descriptor */
  1062.     FAST struct stat    *pStat          /* structure to fill with data */
  1063.     )
  1064.     {
  1065.     struct tm          fileDate;
  1066.     bzero ((char *) pStat, sizeof (struct stat));
  1067. /* zero out stat struct */
  1068.     /* Fill stat structure */
  1069.     pStat->st_dev     = (ULONG) pFd->rfd_vdptr; /* device ID = DEV_HDR addr */
  1070.     pStat->st_ino     = 0; /* no file serial number */
  1071.     pStat->st_nlink   = 1; /* always only one link */
  1072.     pStat->st_uid     = 0; /* no user ID */
  1073.     pStat->st_gid     = 0; /* no group ID */
  1074.     pStat->st_rdev    = 0; /* no special device ID */
  1075.     pStat->st_size    = (pFd->rfd_dir_entry.de_nblocks * RT_BYTES_PER_BLOCK);
  1076. /* file size, in bytes */
  1077.     pStat->st_blksize = 0;
  1078.     pStat->st_blocks  = 0;
  1079.     pStat->st_attrib  = 0; /* no file attribute byte */
  1080.     /*
  1081.      * Fill in the timestamp fields
  1082.      */
  1083.     bzero ((char *) &fileDate, sizeof (fileDate));
  1084.     fileDate.tm_mday = (pFd->rfd_dir_entry.de_date >> 5) & 0x001f;
  1085.     /* Need to adjust if day == 0 ; ANSI days run 1-31, zero isn't valid */
  1086.     if (fileDate.tm_mday == 0)
  1087.         fileDate.tm_mday = 1;
  1088.     fileDate.tm_mon  = (pFd->rfd_dir_entry.de_date >> 10) & 0x000f;
  1089.     /* RT11 uses 1972 as the starting date, ANSI uses 1900; adjust by 72 yrs */
  1090.     
  1091.     fileDate.tm_year = (pFd->rfd_dir_entry.de_date & 0x001f) + 72;
  1092.     /* Set access, change, and modify times all to the value for de_date */
  1093.     
  1094.     pStat->st_atime = pStat->st_mtime = pStat->st_ctime = mktime (&fileDate);
  1095.     /* Set mode field (if whole volume opened, mark as directory) */
  1096.     if (pFd->rfd_dir_entry.de_status == DES_BOGUS)
  1097.      pStat->st_mode = S_IFDIR; /* raw vol = dir */
  1098.     else
  1099.      pStat->st_mode = S_IFREG; /* regular file */
  1100.     pStat->st_mode |= (S_IRWXU | S_IRWXG | S_IRWXO);
  1101. /* default privileges are
  1102.  * read-write-execute for all
  1103.  */
  1104.     return (OK);
  1105.     }
  1106. /*******************************************************************************
  1107. *
  1108. * rt11FsFindEntry - find a directory entry by name on an RT-11 volume
  1109. *
  1110. * This routines searches for the directory entry of the specified file
  1111. * <name> from the specified volume, if it exists.
  1112. *
  1113. * Possession of the volume descriptor semaphore must have been secured
  1114. * before this routine is called.
  1115. *
  1116. * RETURNS:
  1117. * Entry number if found, or
  1118. * ERROR if file not found.
  1119. */
  1120. LOCAL int rt11FsFindEntry
  1121.     (
  1122.     FAST RT_VOL_DESC *vdptr,    /* pointer to volume descriptor */
  1123.     char *name,                 /* RT-11 filename (ffffff.ttt) */
  1124.     int *pstart                 /* pointer where to return start block number */
  1125.     )
  1126.     {
  1127.     RT_DIR_ENTRY entry;
  1128.     RT_NAME name_r50;
  1129.     FAST int i;
  1130.     /* Ignore any leading "/" or ""'s in file name */
  1131.     while ((*name == '/') || (*name == '\'))
  1132. name++;
  1133.     /* search entire directory for active entry matching specified name.
  1134.      * keep track of start block by accumulating entry lengths.
  1135.      */
  1136.     rt11FsNameR50 (name, &name_r50);
  1137.     *pstart = vdptr->vd_dir_seg->ds_start;
  1138.     for (i = 0; ; i++)
  1139. {
  1140. rt11FsGetEntry (vdptr, i, &entry);
  1141. /* if this is the end of the directory, then file not found. */
  1142. if (entry.de_status == DES_END)
  1143.     {
  1144.     errnoSet (S_rt11FsLib_FILE_NOT_FOUND);
  1145.     return (ERROR);
  1146.     }
  1147. /* check if this is the desired file */
  1148.         if (((entry.de_status == DES_PERMANENT)             ||
  1149.      (entry.de_status == DES_TENTATIVE))            &&
  1150.      (entry.de_name.nm_name1 == name_r50.nm_name1)  &&
  1151.      (entry.de_name.nm_name2 == name_r50.nm_name2)  &&
  1152.      (entry.de_name.nm_type == name_r50.nm_type))
  1153.     {
  1154.     return (i);
  1155.     }
  1156. /* entry doesn't match;
  1157.  * add file length to get start of next file; bump to next entry */
  1158. *pstart += entry.de_nblocks;
  1159. }
  1160.     }
  1161. /*******************************************************************************
  1162. *
  1163. * rt11FsFlush - flush RT-11 file output buffer
  1164. *
  1165. * This routine guarantees that any output that has been requested
  1166. * is actually written to the disk.  In particular, writes that have
  1167. * been buffered are written to the disk.
  1168. *
  1169. * RETURNS:
  1170. * OK, or ERROR if unable to write.
  1171. */
  1172. LOCAL STATUS rt11FsFlush
  1173.     (
  1174.     FAST RT_FILE_DESC *pFd      /* pointer to file descriptor */
  1175.     )
  1176.     {
  1177.     int block;
  1178.     if (pFd->rfd_modified)
  1179. {
  1180. /* write out the current (dirty) block and reset 'modified' indicator */
  1181. block = pFd->rfd_start + (pFd->rfd_curptr / RT_BYTES_PER_BLOCK);
  1182. if (rt11FsWrtBlock (pFd->rfd_vdptr, block, 1, pFd->rfd_buffer) != OK)
  1183.     return (ERROR);
  1184. pFd->rfd_modified = FALSE;
  1185. }
  1186.     return (OK);
  1187.     }
  1188. /*******************************************************************************
  1189. *
  1190. * rt11FsFreeFd - free a file descriptor
  1191. */
  1192. LOCAL void rt11FsFreeFd
  1193.     (
  1194.     RT_FILE_DESC *pFd                   /* pointer to file descriptor to free */
  1195.     )
  1196.     {
  1197.     semTake (rt11FsFdSemId, WAIT_FOREVER);
  1198.     pFd->rfd_status = NOT_IN_USE;
  1199.     semGive (rt11FsFdSemId);
  1200.     }
  1201. /*******************************************************************************
  1202. *
  1203. * rt11FsGetFd - get an available file descriptor
  1204. *
  1205. * RETURNS: pointer to file descriptor, or NULL if none available.
  1206. */
  1207. LOCAL RT_FILE_DESC *rt11FsGetFd (void)
  1208.     {
  1209.     FAST RT_FILE_DESC *pRtFd;
  1210.     FAST int i;
  1211.     semTake (rt11FsFdSemId, WAIT_FOREVER);
  1212.     for (i = 0, pRtFd = &rt11FsFd [0]; i < rt11FsMaxFiles; i++, pRtFd++)
  1213. {
  1214. if (pRtFd->rfd_status == NOT_IN_USE)
  1215.     {
  1216.     pRtFd->rfd_status = OK;
  1217.     semGive (rt11FsFdSemId);
  1218.     return (pRtFd);
  1219.     }
  1220. }
  1221.     semGive (rt11FsFdSemId);
  1222.     errnoSet (S_rt11FsLib_NO_FREE_FILE_DESCRIPTORS);
  1223.     return (NULL);
  1224.     }
  1225. /*******************************************************************************
  1226. *
  1227. * rt11FsGetEntry - get a directory entry from an RT-11 volume
  1228. *
  1229. * This routines gets the specified directory entry from the specified
  1230. * volume.
  1231. *
  1232. * Possession of the volume descriptor semaphore must have been secured
  1233. * before this routine is called.
  1234. *
  1235. * RETURNS: a copy of the requested entry.
  1236. */
  1237. LOCAL void rt11FsGetEntry
  1238.     (
  1239.     RT_VOL_DESC *vdptr,    /* pointer to volume descriptor */
  1240.     int entryNum,          /* number of entry to get (first entry = 0) */
  1241.     RT_DIR_ENTRY *pEntry   /* pointer where to return directory entry */
  1242.     )
  1243.     {
  1244.     bcopy ((char *) &(vdptr->vd_dir_seg->ds_entries[entryNum]),
  1245.    (char *) pEntry, sizeof (RT_DIR_ENTRY));
  1246.     }
  1247. /*******************************************************************************
  1248. *
  1249. * rt11FsInit - prepare to use the rt11Fs library
  1250. *
  1251. * This routine initializes the rt11Fs library.  It must be called exactly
  1252. * once, before any other routine in the library.  The <maxFiles> parameter
  1253. * specifies the number of rt11Fs files that may be open at once.  This
  1254. * routine initializes the necessary memory structures and semaphores.
  1255. *
  1256. * This routine is called automatically from the root task, usrRoot(),
  1257. * in usrConfig.c when the configuration macro INCLUDE_RT11FS is defined.
  1258. *
  1259. * RETURNS:
  1260. * OK, or ERROR if memory is insufficient.
  1261. */
  1262. STATUS rt11FsInit
  1263.     (
  1264.     int maxFiles        /* max no. of simultaneously */
  1265. /* open rt11Fs files */
  1266.     )
  1267.     {
  1268.     int i;
  1269.     /* Install rt11FsLib routines in I/O system driver table */
  1270.     rt11FsDrvNum = iosDrvInstall ((FUNCPTR) rt11FsCreate, rt11FsDelete,
  1271.   (FUNCPTR) rt11FsOpen, rt11FsClose,
  1272.   rt11FsRead, rt11FsWrite, rt11FsIoctl);
  1273.     if (rt11FsDrvNum == ERROR)
  1274. return (ERROR); /* can't install as driver */
  1275.     /* initialize interlocking of file descriptor list access */
  1276.     rt11FsFdSemId = semCreate ();
  1277.     semGive (rt11FsFdSemId);
  1278.     rt11FsMaxFiles = maxFiles;
  1279.     rt11FsFd = (RT_FILE_DESC *) malloc ((unsigned)
  1280.       (rt11FsMaxFiles * sizeof (RT_FILE_DESC)));
  1281.     if (rt11FsFd == (RT_FILE_DESC *) NULL)
  1282. return (ERROR);
  1283.     for (i = 0; i < rt11FsMaxFiles; i++)
  1284. rt11FsFreeFd (&rt11FsFd[i]);
  1285.     return (OK);
  1286.     }
  1287. /*******************************************************************************
  1288. *
  1289. * rt11FsInsEntry - insert a new directory entry on an RT-11 volume
  1290. *
  1291. * This routines inserts the specified directory entry into the specified
  1292. * volume at the specified entry index.
  1293. *
  1294. * Possession of the volume descriptor semaphore must have been secured
  1295. * before this routine is called.
  1296. *
  1297. * NOTE: Currently this routine does not handle the case of attempting
  1298. * to add an entry to a full directory.
  1299. */
  1300. LOCAL void rt11FsInsEntry
  1301.     (
  1302.     RT_VOL_DESC *vdptr,   /* pointer to volume descriptor */
  1303.     int entryNum,         /* number of entry to insert (first entry = 0) */
  1304.     RT_DIR_ENTRY *pEntry  /* pointer to entry to insert */
  1305.     )
  1306.     {
  1307.     RT_DIR_ENTRY previous_entry;
  1308.     RT_DIR_ENTRY entry;
  1309.     /* replace current entry at entryNum with new */
  1310.     rt11FsGetEntry (vdptr, entryNum, &entry);
  1311.     rt11FsPutEntry (vdptr, entryNum, pEntry);
  1312.     /* replace each entry with the previous */
  1313.     while (entry.de_status != DES_END)
  1314. {
  1315. previous_entry = entry;
  1316. entryNum++;
  1317. rt11FsGetEntry (vdptr, entryNum, &entry);
  1318. rt11FsPutEntry (vdptr, entryNum, &previous_entry);
  1319. }
  1320.     /* put end-marker entry in next slot */
  1321.     rt11FsPutEntry (vdptr, entryNum + 1, &entry);
  1322.     }
  1323. /*******************************************************************************
  1324. *
  1325. * rt11FsIoctl - do device specific control function
  1326. *
  1327. * This routine performs the following ioctl() functions:
  1328. *
  1329. * .CS
  1330. *    FIODISKINIT:   Initialize the disk volume.  This routine does not
  1331. *                   format the disk, this must be done by the driver.
  1332. *    FIODIRENTRY:   Returns pointer to the next dir entry, into
  1333. *                   the REQ_DIR_ENTRY pointed to by arg.
  1334. *    FIORENAME:     Rename the file to the string pointed to by arg.
  1335. *    FIOSEEK:       Sets the file's current byte position to
  1336. *                   the position specified by arg.
  1337. *    FIOWHERE:      Returns the current byte position in the file.
  1338. *    FIOFLUSH:      Flush file output buffer.
  1339. *                   Guarantees that any output that has been requested
  1340. *                   is actually written to the device.
  1341. *    FIONREAD:      Return in arg the number of unread bytes.
  1342. *    FIODISKCHANGE: Indicate media change.  See rt11FsReadyChange().
  1343. *    FIOSQUEEZE:    Reclaim fragmented free space on RT-11 volume
  1344. *    FIOREADDIR:    Read one entry from directory and return file name.
  1345. *    FIOFSTATGET:   Get file status info from directory entry.
  1346. *    FIOGETFL:      Return in arg the file's open mode.
  1347. * .CE
  1348. *
  1349. * Any ioctl() functions which cannot be handled by rt11FsLib are passed to
  1350. * the device driver.
  1351. *
  1352. * If an ioctl() fails, the task status (see errnoGet()) indicates
  1353. * the nature of the error.
  1354. *
  1355. * RETURNS:
  1356. * OK, or
  1357. * ERROR if function failed or unknown function, or
  1358. * current byte pointer for FIOWHERE.
  1359. *
  1360. */
  1361. LOCAL STATUS rt11FsIoctl
  1362.     (
  1363.     RT_FILE_DESC *pFd,  /* file descriptor of file to control */
  1364.     int function,       /* function code */
  1365.     int arg             /* some argument */
  1366.     )
  1367.     {
  1368.     int where;
  1369.     switch (function)
  1370. {
  1371. case FIODISKINIT:
  1372.     return (rt11FsVolInit (pFd->rfd_vdptr));
  1373. case FIODIRENTRY:
  1374.     return (rt11FsDirEntry (pFd->rfd_vdptr, (REQ_DIR_ENTRY *)arg));
  1375. case FIORENAME:
  1376.     return (rt11FsRename (pFd, (char *)arg));
  1377. case FIOSEEK:
  1378.     return (rt11FsSeek (pFd, arg));
  1379. case FIOWHERE:
  1380.     return (rt11FsWhere (pFd));
  1381. case FIOFLUSH:
  1382.     return (rt11FsFlush (pFd));
  1383. case FIONREAD:
  1384.     if ((where = rt11FsWhere (pFd)) == ERROR)
  1385. return (ERROR);
  1386.     *((int *) arg) = pFd->rfd_endptr - where;
  1387.     return (OK);
  1388. case FIODISKCHANGE:
  1389.     rt11FsReadyChange (pFd->rfd_vdptr);
  1390.     return (OK);
  1391. case FIOSQUEEZE:
  1392.     return (rt11FsSqueeze (pFd->rfd_vdptr));
  1393. case FIOREADDIR:
  1394.     return (rt11FsDirRead (pFd, (DIR *) arg));
  1395. case FIOFSTATGET:
  1396.     return (rt11FsFileStatGet (pFd, (struct stat *) arg));
  1397. case FIOGETFL:
  1398.     *((int *) arg) = pFd->rfd_mode;
  1399.     return (OK);
  1400. default:
  1401.     /* Call device driver function */
  1402.     return ((* pFd->rfd_vdptr->vd_pBlkDev->bd_ioctl)
  1403.     (pFd->rfd_vdptr->vd_pBlkDev, function, arg));
  1404. }
  1405.     }
  1406. /*******************************************************************************
  1407. *
  1408. * rt11FsMkfs - initialize a device and create an rt11Fs file system
  1409. *
  1410. * This routine provides a quick method of creating an rt11Fs file system on
  1411. * a device.  It is used instead of the two-step procedure of calling
  1412. * rt11FsDevInit() followed by an ioctl() call with an FIODISKINIT function
  1413. * code.
  1414. *
  1415. * This routine provides defaults for the rt11Fs parameters expected by
  1416. * rt11FsDevInit().  The directory size is set to RT_FILES_FOR_2_BLOCK_SEG
  1417. * (defined in rt11FsLib.h).  No standard disk format is assumed; this
  1418. * allows the use of rt11Fs on block devices with an odd number of sectors per
  1419. * track.  The <changeNoWarn> parameter is defined as FALSE, 
  1420. * indicating that the disk will not be replaced without rt11FsReadyChange() 
  1421. * being called first.
  1422. *
  1423. * If different values are needed for any of these parameters, the routine
  1424. * rt11FsDevInit() must be used instead of this routine, followed by a
  1425. * request for disk initialization using the ioctl() function FIODISKINIT.
  1426. *
  1427. * RETURNS: A pointer to an rt11Fs volume descriptor (RT_VOL_DESC),
  1428. * or NULL if there is an error.
  1429. *
  1430. * SEE ALSO: rt11FsDevInit()
  1431. */
  1432. RT_VOL_DESC *rt11FsMkfs
  1433.     (
  1434.     char                *volName,       /* volume name to use */
  1435.     BLK_DEV             *pBlkDev        /* pointer to block device struct */
  1436.     )
  1437.     {
  1438.     FAST RT_VOL_DESC *vdptr; /* pointer to RT-11 volume descriptor */
  1439.     vdptr = rt11FsDevInit (volName,  /* name */
  1440.  pBlkDev,  /* device to use */
  1441.  FALSE,  /* no std RT11 format */
  1442.  RT_FILES_FOR_2_BLOCK_SEG, /* dir size */
  1443.  FALSE); /* no changeNoWarn */
  1444.     if (vdptr == NULL)
  1445. return (NULL);
  1446.     if (rt11FsVolInit (vdptr) != OK)
  1447. return (NULL);
  1448.     return (vdptr);
  1449.     }
  1450. /*******************************************************************************
  1451. *
  1452. * rt11FsNameR50 - convert ASCII string to radix-50 RT-11 name
  1453. *
  1454. * This routine converts the specified ASCII string to an RT-11 name.
  1455. * The <string> must be of the form "ffffff.ttt" and be null terminated.
  1456. *
  1457. * If characters are in <string> that don't exist in the radix-50 world,
  1458. * undefined things will happen.
  1459. */
  1460. LOCAL void rt11FsNameR50
  1461.     (
  1462.     char *string,       /* pointer to ASCII string to convert */
  1463.     RT_NAME *pName      /* pointer where to return RT-11 radix-50 name struct */
  1464.     )
  1465.     {
  1466.     char tstring [RT_NAME_LEN];
  1467.     FAST char *dot;
  1468.     /* get local copy of string and make sure it's terminated */
  1469.     (void) strncpy (tstring, string, RT_NAME_LEN - 1);
  1470.     tstring [RT_NAME_LEN - 1] = EOS;
  1471.     /* find the dot, if any; convert extension; and replace dot w/EOS */
  1472.     dot = index (tstring, '.');
  1473.     if (dot == 0)
  1474. pName->nm_type = 0;
  1475.     else
  1476. {
  1477. *dot = EOS;
  1478. pName->nm_type = rt11FsR50out (dot + 1);
  1479. }
  1480.     /* convert name part 1 then part 2 if more */
  1481.     pName->nm_name1 = rt11FsR50out (tstring);
  1482.     if (strlen (tstring) <= 3)
  1483. pName->nm_name2 = 0;
  1484.     else
  1485. pName->nm_name2 = rt11FsR50out (tstring + 3);
  1486.     }
  1487. /*******************************************************************************
  1488. *
  1489. * rt11FsR50out - convert up to 3 ASCII characters to radix-50
  1490. *
  1491. * RETURNS: radix-50 equivalent of first 3 chars of <string>.
  1492. */
  1493. LOCAL int rt11FsR50out
  1494.     (
  1495.     FAST char *string   /* string to convert */
  1496.     )
  1497.     {
  1498.     unsigned int r50 = 0;
  1499.     int r;
  1500.     int i;
  1501.     char ch;
  1502.     for (i = 0; i < 3; i++)
  1503. {
  1504. if (*string == EOS)
  1505.     r = 0;
  1506. else
  1507.     {
  1508.     ch = *string;
  1509.     if (isupper (ch))
  1510. ch = tolower (ch);
  1511.     r = (char *) index (rad50, ch) - rad50;
  1512.     string++;
  1513.     }
  1514. r50 = (r50 * 050) + r;
  1515. }
  1516.     return (r50);
  1517.     }
  1518. /*******************************************************************************
  1519. *
  1520. * rt11FsNameString - convert radix-50 RT-11 name to ASCII string
  1521. *
  1522. * This routine converts the specified RT-11 <name> into an ASCII string
  1523. * of the form "ffffff.ttt" and null terminated.
  1524. */
  1525. LOCAL void rt11FsNameString
  1526.     (
  1527.     RT_NAME name,       /* RT-11 radix-50 name structure */
  1528.     FAST char *string   /* pointer to receive ASCII string */
  1529.     )
  1530.     {
  1531.     FAST char *pStr; /* index into string */
  1532.     rt11FsR50in (name.nm_name1, string);
  1533.     rt11FsR50in (name.nm_name2, string + 3);
  1534.     for (pStr = string; (pStr < (string + 6)) && (*pStr != ' '); ++pStr)
  1535. ; /* prepare to overwrite trailing blanks */
  1536.     *pStr++ = '.';
  1537.     rt11FsR50in (name.nm_type, pStr);
  1538.     *(pStr + 3) = EOS;
  1539.     }
  1540. /*******************************************************************************
  1541. *
  1542. * rt11FsR50in - convert radix-50 to 3 ASCII characters
  1543. */
  1544. LOCAL void rt11FsR50in
  1545.     (
  1546.     unsigned int r50,   /* radix-50 number to convert */
  1547.     char *string        /* where to put resulting string */
  1548.     )
  1549.     {
  1550.     FAST int i;
  1551.     for (i = 2; i >= 0; i--)
  1552. {
  1553. string [i] = rad50 [r50 % 050];
  1554. r50 /= 050;
  1555. }
  1556.     }
  1557. /*******************************************************************************
  1558. *
  1559. * rt11FsOpen - open a file on an RT-11 volume
  1560. *
  1561. * This routine opens the file <name> with the specified <mode>.
  1562. * The volume directory is searched, and if the file is found
  1563. * an RT-11 file descriptor is initialized for it.
  1564. *
  1565. * The directory currently in memory for the volume is used unless there
  1566. * has been a ready change (rt11FsReadyChange()) or this is the very first
  1567. * open.  If that is the case, the directory will be read from the disk
  1568. * automatically.
  1569. *
  1570. * A null file <name> is treated specially, to open an entire disk.
  1571. * In this case, no attempt is made to access the disk directory, so that
  1572. * even un-initialized disks may be accessed.
  1573. *
  1574. * RETURNS:
  1575. * A pointer to the RT-11 file descriptor, or
  1576. * ERROR if the volume not available or
  1577. * no RT-11 file descriptors are available or
  1578. * there is no such file.
  1579. */
  1580. LOCAL RT_FILE_DESC *rt11FsOpen
  1581.     (
  1582.     RT_VOL_DESC *vdptr, /* pointer to volume descriptor */
  1583.     char *name,         /* RT-11 filename (ffffff.ttt) */
  1584.     int mode            /* file mode (O_RDONLY/O_WRONLY/O_RDWR) */
  1585.     )
  1586.     {
  1587.     int start;
  1588.     int entryNum;
  1589.     FAST RT_FILE_DESC *pFd; /* file descriptor pointer */
  1590.     /* Call driver check-status routine, if any */
  1591.     if (vdptr->vd_pBlkDev->bd_statusChk != NULL)
  1592. {
  1593. if ((* vdptr->vd_pBlkDev->bd_statusChk) (vdptr->vd_pBlkDev) != OK)
  1594.     {
  1595.     return ((RT_FILE_DESC *) ERROR);
  1596.     }
  1597. }
  1598.     /* Set up for re-mount if no disk change notification */
  1599.     if (vdptr->vd_changeNoWarn == TRUE)
  1600. rt11FsReadyChange (vdptr);
  1601.     /* get a free file descriptor */
  1602.     pFd = rt11FsGetFd (); /* file descriptor pointer */
  1603.     if (pFd == NULL)
  1604. return ((RT_FILE_DESC *) ERROR);
  1605.     /* check for O_CREAT and O_TRUNC mode */
  1606.     if ((mode & O_CREAT) || (mode & O_TRUNC))
  1607. {
  1608. /*XXX O_CREAT and O_TRUNC are masked off because several rt11FsLib
  1609.  * routines use rt11FsVolMode() to check the mode of a file by
  1610.  * arithmetic comparison instead of by boolean comparison of
  1611.  * specific bits.
  1612.  */
  1613. mode &= ~O_CREAT;
  1614. /* create the file if it does not exist or O_TRUNC is set */
  1615. if ((mode & O_TRUNC) ||
  1616.     (rt11FsFindEntry (vdptr, name, &start) == ERROR))
  1617.     {
  1618.     mode &= ~O_TRUNC;
  1619.     rt11FsFreeFd (pFd);
  1620.     return (rt11FsCreate (vdptr, name, mode));
  1621.     }
  1622. }
  1623.     /* check for open of raw device (null filename) */
  1624.     if (name [0] == EOS)
  1625. {
  1626. /* check that volume is available */
  1627. semTake (vdptr->vd_semId, WAIT_FOREVER);
  1628. if (rt11FsCheckVol (vdptr, FALSE) != OK)
  1629.     {
  1630.     semGive (vdptr->vd_semId);
  1631.     rt11FsFreeFd (pFd);
  1632.     errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  1633.     return ((RT_FILE_DESC *) ERROR);
  1634.     }
  1635. if (rt11FsVolMode (vdptr) < mode)
  1636.     {
  1637.     semGive (vdptr->vd_semId);
  1638.     rt11FsFreeFd (pFd);
  1639.     errnoSet (S_ioLib_WRITE_PROTECTED);
  1640.     return ((RT_FILE_DESC *) ERROR);
  1641.     }
  1642. semGive (vdptr->vd_semId);
  1643. /* null name is special indicator for "raw" disk;
  1644.  * fabricate a bogus directory entry covering entire volume */
  1645. start = 0;
  1646. pFd->rfd_dir_entry.de_status  = DES_BOGUS;
  1647. pFd->rfd_dir_entry.de_date    = rt11FsDate (rt11FsYear, rt11FsMonth,
  1648.     rt11FsDay);
  1649. pFd->rfd_dir_entry.de_nblocks = vdptr->vd_nblocks;
  1650. rt11FsNameR50 ("device.raw", &pFd->rfd_dir_entry.de_name);
  1651. }
  1652.     else
  1653. {
  1654. /* check that volume is available */
  1655. semTake (vdptr->vd_semId, WAIT_FOREVER);
  1656. if ((rt11FsCheckVol (vdptr, TRUE) != OK) || (vdptr->vd_status != OK))
  1657.     {
  1658.     semGive (vdptr->vd_semId);
  1659.     rt11FsFreeFd (pFd);
  1660.     errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  1661.     return ((RT_FILE_DESC *) ERROR);
  1662.     }
  1663. if (rt11FsVolMode (vdptr) < mode)
  1664.     {
  1665.     semGive (vdptr->vd_semId);
  1666.     rt11FsFreeFd (pFd);
  1667.     errnoSet (S_ioLib_WRITE_PROTECTED);
  1668.     return ((RT_FILE_DESC *) ERROR);
  1669.     }
  1670. /* find specified file name in directory */
  1671. if ((entryNum = rt11FsFindEntry (vdptr, name, &start)) == ERROR)
  1672.     {
  1673.     semGive (vdptr->vd_semId); /* release volume */
  1674.     rt11FsFreeFd (pFd);
  1675.     return ((RT_FILE_DESC *) ERROR);
  1676.     }
  1677. rt11FsGetEntry (vdptr, entryNum, &pFd->rfd_dir_entry);
  1678. semGive (vdptr->vd_semId); /* release volume */
  1679. }
  1680.     /* initialize file descriptor */
  1681.     pFd->rfd_mode = mode;
  1682.     pFd->rfd_vdptr = vdptr;
  1683.     pFd->rfd_start = start;
  1684.     pFd->rfd_curptr = NONE;
  1685.     pFd->rfd_newptr = 0;
  1686.     pFd->rfd_endptr = pFd->rfd_dir_entry.de_nblocks * RT_BYTES_PER_BLOCK;
  1687.     pFd->rfd_modified = FALSE;
  1688.     return (pFd);
  1689.     }
  1690. /*******************************************************************************
  1691. *
  1692. * rt11FsPutEntry - put directory entry of RT-11 file
  1693. *
  1694. * This routines puts the specified directory entry of the specified
  1695. * volume.  The first entry is #0.
  1696. *
  1697. * Posession of the volume descriptor's semaphore must have been secured
  1698. * before this routine is called.
  1699. */
  1700. LOCAL void rt11FsPutEntry
  1701.     (
  1702.     RT_VOL_DESC         *vdptr,         /* pointer to volume descriptor */
  1703.     int                 entryNum,       /* # of entry to get (first entry = 0)*/
  1704.     RT_DIR_ENTRY        *pEntry         /* pointer to entry to put */
  1705.     )
  1706.     {
  1707.     vdptr->vd_dir_seg->ds_entries [entryNum] = *pEntry;
  1708.     }
  1709. /*******************************************************************************
  1710. *
  1711. * rt11FsRead - read from an RT-11 file
  1712. *
  1713. * This routine reads from the file specified by the file descriptor
  1714. * (returned by rt11FsOpen ()) into the specified <buffer>.
  1715. * Up to <maxbytes> bytes will be read, if there is that much data in the file.
  1716. *
  1717. * RETURNS:
  1718. * Number of bytes read, or
  1719. * 0 if end of file, or
  1720. * ERROR if maxbytes <= 0 or unable to get next block.
  1721. */
  1722. LOCAL int rt11FsRead
  1723.     (
  1724.     FAST RT_FILE_DESC   *pFd,           /* file descriptor pointer */
  1725.     char                *pBuf,          /* buffer to receive data */
  1726.     FAST int            maxBytes        /* maximum bytes to read */
  1727.     )
  1728.     {
  1729.     FAST int bufIndex; /* offset to current position in buf */
  1730.     int startBlk; /* starting block for read */
  1731.     int numBlks; /* number of blocks to read */
  1732.     int curBlk; /* number of block currently in buf */
  1733.     STATUS status; /* number of blocks to read */
  1734.     FAST int nBytes; /* number of bytes read */
  1735.     FAST int bytesLeft; /* remaining bytes to read */
  1736.     /* check for valid maxBytes */
  1737.     if (maxBytes <= 0)
  1738. {
  1739. errnoSet (S_rt11FsLib_INVALID_NUMBER_OF_BYTES);
  1740. return (ERROR);
  1741. }
  1742.     /* Do successive reads until requested byte count or EOF */
  1743.     bytesLeft = maxBytes; /* init number remaining */
  1744.     while (bytesLeft > 0)
  1745. {
  1746. nBytes = 0; /* init individual read count */
  1747.      /* Do direct whole-block read if possible
  1748.       *   Transfer must be >= 1 block, must start on a block
  1749.       *   boundary, and must not extend past end-of-file.
  1750.       */
  1751.      if ((bytesLeft >= RT_BYTES_PER_BLOCK) &&
  1752.     (pFd->rfd_newptr % RT_BYTES_PER_BLOCK == 0) &&
  1753.     (pFd->rfd_newptr + bytesLeft <= (pFd->rfd_dir_entry.de_nblocks *
  1754.     RT_BYTES_PER_BLOCK)))
  1755.     {
  1756.     /* Determine max number of blocks to read */
  1757.          if (pFd->rfd_vdptr->vd_rtFmt) /* if using std skew/intleave */
  1758. numBlks = 1; /*  blocks are not contiguous */
  1759.     else
  1760.      numBlks = bytesLeft / RT_BYTES_PER_BLOCK;
  1761.     /* Determine starting block for read */
  1762.     startBlk = (pFd->rfd_newptr / RT_BYTES_PER_BLOCK) + pFd->rfd_start;
  1763.     /* Read block(s) directly into caller's buffer */
  1764.     if (rt11FsRdBlock (pFd->rfd_vdptr, startBlk, numBlks, pBuf) != OK)
  1765. { /* read error */
  1766. if (bytesLeft == maxBytes) /* if nothing read yet */
  1767.     return (ERROR); /*  indicate error */
  1768. else
  1769.          break; /* return number read OK */
  1770. }
  1771.     /* If file descriptor buffer contains modified data (O_RDWR mode)
  1772.      *  and the read included bufferred block, insert buffer contents
  1773.      *  into user's buffer at appropriate offset.
  1774.      */
  1775.     if (pFd->rfd_modified)
  1776. {
  1777.      curBlk = (pFd->rfd_curptr / RT_BYTES_PER_BLOCK) +
  1778.  pFd->rfd_start;
  1779.      if ((curBlk >= startBlk)  && (curBlk < (startBlk + numBlks)))
  1780.     {
  1781.               bcopy (pFd->rfd_buffer,
  1782.            pBuf + ((curBlk - startBlk) * RT_BYTES_PER_BLOCK),
  1783.            RT_BYTES_PER_BLOCK);
  1784.     }
  1785. }
  1786.     nBytes = numBlks * RT_BYTES_PER_BLOCK;
  1787.     }
  1788.         else
  1789.     {
  1790.          /* Get new pointer in buffer */
  1791.          if ((status = rt11FsNewBlock (pFd)) <= 0)
  1792. { /* probably end of file */
  1793. if (bytesLeft == maxBytes) /* if nothing read yet */
  1794.     return (status); /*  indicate error */
  1795. else
  1796.          break; /* return number read OK */
  1797. }
  1798.          /* Fill all of caller's buffer or rest of Fd block buffer,
  1799.      * whichever is less.  Since files are always an even multiple
  1800.      * of the block length, a separate check for EOF isn't needed.
  1801.      */
  1802.          bufIndex = pFd->rfd_newptr % RT_BYTES_PER_BLOCK;
  1803.          nBytes = min (bytesLeft, RT_BYTES_PER_BLOCK - bufIndex);
  1804.          bcopy (&pFd->rfd_buffer [bufIndex], pBuf, nBytes);
  1805.     }
  1806. /* Adjust count remaining, buffer pointer, and file pointer */
  1807. bytesLeft -= nBytes;
  1808. pBuf      += nBytes;
  1809.      pFd->rfd_newptr += nBytes;
  1810. }  /* end while */
  1811.     return (maxBytes - bytesLeft); /* number of bytes read */
  1812.     }
  1813. /*******************************************************************************
  1814. *
  1815. * rt11FsRename - change name of RT-11 file
  1816. *
  1817. * This routine changes the name of the specified stream to the specified
  1818. * <newName>.
  1819. *
  1820. * RETURNS:
  1821. * OK, or
  1822. * ERROR if newName already in use, or
  1823. * unable to write out new directory info.
  1824. */
  1825. LOCAL STATUS rt11FsRename
  1826.     (
  1827.     RT_FILE_DESC *pFd,          /* pointer to file descriptor */
  1828.     char *newName               /* change name of file to this */
  1829.     )
  1830.     {
  1831.     char oldName [RT_NAME_LEN]; /* current file name gets unpacked into here */
  1832.     char *tail; /* tail of newName */
  1833.     int entryNum; /* gets index into directory of oldname */
  1834.     int start; /* for receiving rt11FsFindEntry side-effect */
  1835.     RT_DIR_ENTRY entry; /* directory entry of oldname goes here */
  1836.     /* ensure newName doesn't include device name */
  1837.     if (iosDevFind (newName, &tail) != NULL)
  1838. (void) strcpy (newName, tail);
  1839.     semTake (pFd->rfd_vdptr->vd_semId, WAIT_FOREVER);
  1840.     /* be sure new name isn't already in use */
  1841.     if (rt11FsFindEntry (pFd->rfd_vdptr, newName, &start) != ERROR)
  1842. {
  1843. semGive (pFd->rfd_vdptr->vd_semId); /* release volume */
  1844. errnoSet (S_rt11FsLib_FILE_ALREADY_EXISTS);
  1845. return (ERROR); /* entry already exists */
  1846. }
  1847.     /* unpack name and find entry number */
  1848.     rt11FsNameString (pFd->rfd_dir_entry.de_name, oldName);
  1849.     if ((entryNum = rt11FsFindEntry (pFd->rfd_vdptr, oldName, &start)) == ERROR)
  1850. {
  1851. semGive (pFd->rfd_vdptr->vd_semId); /* release volume */
  1852. return (ERROR); /* entry not found */
  1853. }
  1854.     rt11FsGetEntry (pFd->rfd_vdptr, entryNum, &entry);
  1855.     rt11FsNameR50 (newName, &entry.de_name); /* put in new name */
  1856.     rt11FsNameR50 (newName, &pFd->rfd_dir_entry.de_name);
  1857. /* rename fd also */
  1858.     rt11FsPutEntry (pFd->rfd_vdptr, entryNum, &entry);
  1859.     /* make sure directory is written out */
  1860.     if (rt11FsVolFlush (pFd->rfd_vdptr) != OK)
  1861. {
  1862. semGive (pFd->rfd_vdptr->vd_semId); /* release volume */
  1863. return (ERROR); /* entry not found */
  1864. }
  1865.     semGive (pFd->rfd_vdptr->vd_semId); /* release volume */
  1866.     return (OK);
  1867.     }
  1868. /*******************************************************************************
  1869. *
  1870. * rt11FsSeek - change file's current character position
  1871. *
  1872. * This routine sets the specified file's current character position to
  1873. * the specified <position>.  This only changes the pointer; it does not affect
  1874. * the hardware.
  1875. *
  1876. * RETURNS: OK or ERROR.
  1877. */
  1878. LOCAL STATUS rt11FsSeek
  1879.     (
  1880.     FAST RT_FILE_DESC *pFd,     /* file descriptor pointer */
  1881.     int position                /* desired character position in file */
  1882.     )
  1883.     {
  1884.     if (pFd->rfd_status == NOT_IN_USE)
  1885. {
  1886. errnoSet (S_rt11FsLib_FILE_NOT_FOUND);
  1887. return (ERROR);
  1888. }
  1889.     if (position > (pFd->rfd_dir_entry.de_nblocks * RT_BYTES_PER_BLOCK))
  1890. {
  1891. errnoSet (S_rt11FsLib_BEYOND_FILE_LIMIT);
  1892. return (ERROR);
  1893. }
  1894.     /* update new file byte pointer; also end pointer if file just grew */
  1895.     pFd->rfd_newptr = position;
  1896.     if (pFd->rfd_endptr < position)
  1897. pFd->rfd_endptr = position;
  1898.     return (OK);
  1899.     }
  1900. /*******************************************************************************
  1901. *
  1902. * rt11FsDateSet - set the rt11Fs file system date
  1903. *
  1904. * This routine sets the date for the rt11Fs file system, which remains in
  1905. * effect until changed.  All files created are assigned this creation date.
  1906. *
  1907. * To set a blank date, invoke the command:
  1908. * .CS
  1909. *     rt11FsDateSet (72, 0, 0);    /@ a date outside RT-11's epoch @/
  1910. * .CE
  1911. *
  1912. * NOTE: No automatic incrementing of the date is performed; each new date must
  1913. * be set with a call to this routine.
  1914. *
  1915. * RETURNS: N/A
  1916. */
  1917. void rt11FsDateSet
  1918.     (
  1919.     int year,           /* year (72...03 (RT-11's days are numbered)) */
  1920.     int month,          /* month (0, or 1...12) */
  1921.     int day             /* day (0, or 1...31) */
  1922.     )
  1923.     {
  1924.     rt11FsYear  = year % 100;
  1925.     rt11FsMonth = month;
  1926.     rt11FsDay   = day;
  1927.     }
  1928. /*******************************************************************************
  1929. *
  1930. * rt11FsVolFlush - flush RT-11 volume directory
  1931. *
  1932. * This routine guarantees that any changes to the volume directory entry
  1933. * are actually written to disk.
  1934. *
  1935. * Posession of the volume descriptor's semaphore must have been secured
  1936. * before this routine is called.
  1937. *
  1938. * RETURNS: OK or ERROR.
  1939. */
  1940. LOCAL STATUS rt11FsVolFlush
  1941.     (
  1942.     FAST RT_VOL_DESC    *vdptr          /* pointer to volume descriptor */
  1943.     )
  1944.     {
  1945.     FAST int nSegBytes = vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK;
  1946.     FAST char  *psegTop = (char *) vdptr->vd_dir_seg;
  1947. /* top of directory segment */
  1948.     vdptr->vd_status = OK;
  1949.     swab (psegTop, psegTop, nSegBytes); /* swap bytes in entire segment */
  1950.     /* flush all blocks */
  1951.     if (rt11FsWrtBlock (vdptr, RT_DIR_BLOCK, vdptr->vd_nSegBlocks,
  1952. psegTop) != OK)
  1953. {
  1954. vdptr->vd_status = ERROR;
  1955. }
  1956.     swab (psegTop, psegTop, nSegBytes); /* swap bytes in segment back */
  1957.     return (vdptr->vd_status);
  1958.     }
  1959. /*******************************************************************************
  1960. *
  1961. * rt11FsVolInit - initialize an RT-11 volume
  1962. *
  1963. * This routine initializes a disk volume to be an RT-11 disk.  The volume
  1964. * structures in memory are initialized, the volume's in-memory directory
  1965. * is initialized, and then the empty directory is flushed to the disk
  1966. * itself, by calling rt11FsVolFlush.
  1967. *
  1968. * The volume descriptor itself should have already been initialized with
  1969. * rt11FsDevInit().
  1970. *
  1971. * This routine does not format the disk; that must have already been done.
  1972. *
  1973. * RETURNS:
  1974. * OK, or
  1975. * ERROR if can't flush to device.
  1976. */
  1977. LOCAL STATUS rt11FsVolInit
  1978.     (
  1979.     RT_VOL_DESC *vdptr          /* pointer to volume descriptor */
  1980.     )
  1981.     {
  1982.     STATUS status;
  1983.     FAST int freeBlocks; /* number of free file blocks left */
  1984.     FAST RT_DIR_SEG *pseg = vdptr->vd_dir_seg;
  1985.     FAST int i = 0;
  1986.     semTake (vdptr->vd_semId, WAIT_FOREVER);
  1987.     /* initialize directory segment */
  1988.     pseg->ds_nsegs = 1;
  1989.     pseg->ds_next_seg = 0;
  1990.     pseg->ds_last_seg = 1;
  1991.     pseg->ds_extra = 0;
  1992.     /* first data block starts after the directory segment */
  1993.     pseg->ds_start = RT_DIR_BLOCK + vdptr->vd_nSegBlocks;
  1994.     freeBlocks = vdptr->vd_nblocks - pseg->ds_start;
  1995.     /* make first directory entries be EMPTY covering entire remaining volume */
  1996.     /* first, make all files of size RT_MAX_BLOCKS_PER_FILE */
  1997.     while (freeBlocks > RT_MAX_BLOCKS_PER_FILE)
  1998. {
  1999. pseg->ds_entries[i].de_status = DES_EMPTY;
  2000. pseg->ds_entries[i++].de_nblocks = RT_MAX_BLOCKS_PER_FILE;
  2001. freeBlocks -= RT_MAX_BLOCKS_PER_FILE;
  2002. }
  2003.     /* make last empty directory entry */
  2004.     if (freeBlocks > 0)
  2005. {
  2006. pseg->ds_entries[i].de_status = DES_EMPTY;
  2007. pseg->ds_entries[i++].de_nblocks = freeBlocks;
  2008. }
  2009.     /* make terminating entry */
  2010.     pseg->ds_entries[i].de_status = DES_END;
  2011.     status = rt11FsVolFlush (vdptr); /* flush dir to disk */
  2012.     if (status == OK)
  2013. rt11FsReadyChange (vdptr); /* set up for remount */
  2014.     else
  2015. vdptr->vd_status = ERROR; /* could not flush */
  2016.     semGive (vdptr->vd_semId); /* release volume */
  2017.     return (status);
  2018.     }
  2019. /*******************************************************************************
  2020. *
  2021. * rt11FsVolMount - prepare to use RT-11 volume
  2022. *
  2023. * This routine prepares the library to use the RT-11 volume on the device
  2024. * specified.  The volume directory segment is read from the disk.
  2025. * This routine should be called every time a disk is changed (i.e., a floppy
  2026. * is swapped, or whatever), or before every open and create, if the driver
  2027. * can't tell when disks are changed.
  2028. *
  2029. * Eventually this routine could be taught to read the home
  2030. * block to get more initialization info.
  2031. *
  2032. * Note:  If an error occurs while reading, it's possible that the
  2033. * bytes in the directory segment will be swapped.
  2034. *
  2035. * RETURNS: OK or ERROR.
  2036. */
  2037. LOCAL STATUS rt11FsVolMount
  2038.     (
  2039.     FAST RT_VOL_DESC    *vdptr          /* pointer to volume descriptor */
  2040.     )
  2041.     {
  2042.     FAST char *pseg = (char *) vdptr->vd_dir_seg;
  2043. /* pointer to directory segment */
  2044.     vdptr->vd_status = ERROR;
  2045.     /* read in all blocks of directory segment */
  2046.     if (rt11FsRdBlock (vdptr, RT_DIR_BLOCK, vdptr->vd_nSegBlocks, pseg) != OK)
  2047. return (vdptr->vd_status);
  2048.     pseg = (char *) vdptr->vd_dir_seg;
  2049.     swab (pseg, pseg, vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK);
  2050.     /* check reasonableness of directory segment */
  2051.     if (vdptr->vd_dir_seg->ds_nsegs    == 1 &&
  2052. vdptr->vd_dir_seg->ds_next_seg == 0 &&
  2053. vdptr->vd_dir_seg->ds_last_seg == 1 &&
  2054. vdptr->vd_dir_seg->ds_extra    == 0)
  2055. {
  2056. vdptr->vd_status = OK;
  2057. }
  2058.     return (vdptr->vd_status);
  2059.     }
  2060. /*******************************************************************************
  2061. *
  2062. * rt11FsWhere - tell where file is (current character position)
  2063. *
  2064. * This routine tells you where the file pointer is for a file.
  2065. *
  2066. * RETURNS:
  2067. * Current character position of file, or
  2068. * ERROR if invalid file descriptor.
  2069. */
  2070. LOCAL int rt11FsWhere
  2071.     (
  2072.     FAST RT_FILE_DESC *pFd      /* file descriptor pointer */
  2073.     )
  2074.     {
  2075.     if (pFd->rfd_status == NOT_IN_USE)
  2076. {
  2077. errnoSet (S_rt11FsLib_FILE_NOT_FOUND);
  2078. return (ERROR);
  2079. }
  2080.     else
  2081. return (pFd->rfd_newptr);
  2082.     }
  2083. /*******************************************************************************
  2084. *
  2085. * rt11FsWrite - write to an RT-11 file
  2086. *
  2087. * This routine writes to the file specified by the file descriptor
  2088. * (returned by rt11FsOpen() or rt11FsCreate()) from the specified <buffer>.
  2089. * If the block containing the disk locations to be written is already
  2090. * in memory the block won't be flushed.  If another in-memory block is
  2091. * needed, any block already in memory will be flushed.
  2092. *
  2093. * RETURNS:
  2094. * Number of bytes written (error if != nbytes), or
  2095. * ERROR if nbytes < 0, or no more space for the file,
  2096. * or can't write block.
  2097. *
  2098. */
  2099. LOCAL int rt11FsWrite
  2100.     (
  2101.     FAST RT_FILE_DESC   *pFd,                   /* file descriptor pointer */
  2102.     char                *pBuf,                  /* data to be written */
  2103.     int                 nbytes                  /* number of bytes to write */
  2104.     )
  2105.     {
  2106.     FAST int bytesCopied;
  2107.     FAST int bufIndex;
  2108.     int startBlk; /* starting blk for write */
  2109.     FAST int numBlks; /* number of blocks to write */
  2110.     int curBlk; /* # of blk currently in buf */
  2111.     FAST int bytesLeft = nbytes; /* remaining bytes to write */
  2112.     /* check for valid nbytes */
  2113.     if (nbytes < 0)
  2114. {
  2115. errnoSet (S_rt11FsLib_INVALID_NUMBER_OF_BYTES);
  2116. return (ERROR);
  2117. }
  2118.     /* Write into successive blocks until all of caller's buffer written */
  2119.     while (bytesLeft > 0)
  2120. {
  2121.      /* Do direct whole-block write if possible
  2122.       *   Transfer must be >= 1 block, must start on a block
  2123.  *   boundary, and must not extend past end-of-file.
  2124.       */
  2125.      if ((bytesLeft >= RT_BYTES_PER_BLOCK) &&
  2126.     (pFd->rfd_newptr % RT_BYTES_PER_BLOCK == 0) &&
  2127.     (pFd->rfd_newptr + bytesLeft <= (pFd->rfd_dir_entry.de_nblocks *
  2128.      RT_BYTES_PER_BLOCK)))
  2129.     {
  2130.     /* Determine max number of blocks to write */
  2131.          if (pFd->rfd_vdptr->vd_rtFmt) /* if using std skew/intleave */
  2132. numBlks = 1; /*  blocks are not contiguous */
  2133.     else
  2134.      numBlks = bytesLeft / RT_BYTES_PER_BLOCK;
  2135.     /* Determine starting block for write */
  2136.     startBlk = (pFd->rfd_newptr / RT_BYTES_PER_BLOCK) + pFd->rfd_start;
  2137.     /* Write block(s) directly from caller's buffer */
  2138.     if (rt11FsWrtBlock (pFd->rfd_vdptr, startBlk, numBlks, pBuf) != OK)
  2139. return (ERROR);
  2140.     /* If write included bufferred block, invalidate buffer */
  2141.     curBlk = (pFd->rfd_curptr / RT_BYTES_PER_BLOCK) + pFd->rfd_start;
  2142.     if ((curBlk >= startBlk)  && (curBlk < (startBlk + numBlks)))
  2143. {
  2144.      pFd->rfd_curptr = NONE;
  2145.      pFd->rfd_modified = FALSE;
  2146. }
  2147.     bytesCopied = numBlks * RT_BYTES_PER_BLOCK;
  2148.     }
  2149. else
  2150.     {
  2151.     /* get new pointer in buffer */
  2152.     if (rt11FsNewBlock (pFd) <= 0)
  2153.      return (ERROR);
  2154.     /* copy length = rest of caller's buffer or rest of fd buffer,
  2155.      *   whichever is less.
  2156.      */
  2157.     bufIndex = pFd->rfd_newptr % RT_BYTES_PER_BLOCK;
  2158.     bytesCopied = min (bytesLeft, RT_BYTES_PER_BLOCK - bufIndex);
  2159.     bcopy (pBuf, &pFd->rfd_buffer [bufIndex], bytesCopied);
  2160.     pFd->rfd_modified = TRUE;
  2161.     }
  2162. /* update pointers and bytes remaining */
  2163. pFd->rfd_newptr += bytesCopied;
  2164. if (pFd->rfd_endptr < pFd->rfd_newptr)
  2165.     pFd->rfd_endptr = pFd->rfd_newptr;
  2166. pBuf += bytesCopied;
  2167. bytesLeft -= bytesCopied;
  2168. }
  2169.     return (nbytes);
  2170.     }
  2171. /*******************************************************************************
  2172. *
  2173. * rt11FsNewBlock - make file descriptor block buffer contain new pointer
  2174. *
  2175. * This routine does whatever is necessary to make the block buffer
  2176. * in the specified file descriptor contain the byte addressed by
  2177. * the current pointer in the descriptor.  In particular, if on entry
  2178. * the buffer already contains the desired byte, then no action is taken.
  2179. * Otherwise if the buffer is modified (contains data written by user
  2180. * but not yet on disk) then the block is written.  Then the correct
  2181. * block is read if the mode is O_RDONLY or O_RDWR.
  2182. *
  2183. * RETURNS:
  2184. * number of bytes in buffer if successful, or
  2185. * 0 if end of file, or
  2186. * ERROR if unable to read/write block.
  2187. */
  2188. LOCAL int rt11FsNewBlock
  2189.     (
  2190.     FAST RT_FILE_DESC *pFd      /* file descriptor pointer */
  2191.     )
  2192.     {
  2193.     FAST int new_block;
  2194.     int cur_block;
  2195.     /* calculate block num of desired new block and of current block if any */
  2196.     new_block = pFd->rfd_newptr / RT_BYTES_PER_BLOCK;
  2197.     cur_block = (pFd->rfd_curptr == NONE) ?
  2198.      NONE : (pFd->rfd_curptr / RT_BYTES_PER_BLOCK);
  2199.     /* check for new block already in current buffer */
  2200.     if (new_block == cur_block)
  2201. return (RT_BYTES_PER_BLOCK);
  2202.     /* check for end of file */
  2203.     if (new_block >= pFd->rfd_dir_entry.de_nblocks)
  2204. return (0);
  2205.     /* flush current block, read in new block, update current pointer */
  2206.     if (rt11FsFlush (pFd) != OK)
  2207. return (ERROR);
  2208.     if (pFd->rfd_mode != O_WRONLY)
  2209. {
  2210. if (rt11FsRdBlock (pFd->rfd_vdptr, new_block + pFd->rfd_start, 1,
  2211.          pFd->rfd_buffer) != OK)
  2212.     return (ERROR);
  2213. }
  2214.     pFd->rfd_curptr = new_block * RT_BYTES_PER_BLOCK;
  2215.     return (RT_BYTES_PER_BLOCK);
  2216.     }
  2217. /*******************************************************************************
  2218. *
  2219. * rt11FsRdBlock - read a block from an RT-11 volume
  2220. *
  2221. * This routine reads the specified block from the specified volume.
  2222. *
  2223. * RETURNS: OK or ERROR.
  2224. */
  2225. LOCAL STATUS rt11FsRdBlock
  2226.     (
  2227.     FAST RT_VOL_DESC    *vdptr,         /* pointer to volume descriptor */
  2228.     int                 blockNum,       /* starting block for read */
  2229.     int                 numBlocks,      /* number of blocks to read */
  2230.     char                *pBuf           /* buffer to receive block(s) */
  2231.     )
  2232.     {
  2233.     FAST int physSector;
  2234.     FAST int secNum = blockNum * vdptr->vd_secBlock;
  2235.     FAST BLK_DEV *pBlkDev = vdptr->vd_pBlkDev;
  2236. /* pointer to block device struct */
  2237.     if (vdptr->vd_rtFmt)
  2238. physSector = rt11FsAbsSector (vdptr->vd_pBlkDev->bd_blksPerTrack,
  2239.     secNum);
  2240.     else
  2241. physSector = secNum;
  2242.     /* Read each sector in block(s) */
  2243.     vdptr->vd_retry = 0;
  2244.     while (((* pBlkDev->bd_blkRd) (pBlkDev, physSector,
  2245.    (numBlocks * vdptr->vd_secBlock),
  2246.    pBuf)) != OK)
  2247. {
  2248. /* read error: reset volume and retry, up to device's retry limit */
  2249. if (rt11FsReset (vdptr) != OK)
  2250.     return (ERROR); /* drive won't reset! */
  2251.         if (++(vdptr->vd_retry) > pBlkDev->bd_retry)
  2252.     return (ERROR);
  2253. }
  2254.     return (OK);
  2255.     }
  2256. /*******************************************************************************
  2257. *
  2258. * rt11FsWrtBlock - write a block to an RT-11 volume
  2259. *
  2260. * This routine writes the specified block to the specified volume.
  2261. *
  2262. * RETURNS: OK or ERROR.
  2263. */
  2264. LOCAL STATUS rt11FsWrtBlock
  2265.     (
  2266.     FAST RT_VOL_DESC    *vdptr,         /* pointer to volume descriptor */
  2267.     int                 blockNum,       /* starting block number for write */
  2268.     int                 numBlocks,      /* number of blocks to write */
  2269.     char                *pBuf           /* buffer containing data to write */
  2270.     )
  2271.     {
  2272.     FAST int physSector; /* physcial sector number */
  2273.     FAST int secNum; /* logical sector number */
  2274.     FAST BLK_DEV *pBlkDev = vdptr->vd_pBlkDev;
  2275. /* pointer to block device struct */
  2276.     /* Get sector number corresponding to starting block */
  2277.     secNum = blockNum * vdptr->vd_secBlock;
  2278.     if (vdptr->vd_rtFmt)
  2279. physSector = rt11FsAbsSector (vdptr->vd_pBlkDev->bd_blksPerTrack,
  2280.     secNum);
  2281.     else
  2282. physSector = secNum;
  2283.     /* Write each sector in block(s) */
  2284.     vdptr->vd_retry = 0;
  2285.     while (((* pBlkDev->bd_blkWrt) (pBlkDev, physSector,
  2286.     (numBlocks * vdptr->vd_secBlock),
  2287.     pBuf)) != OK)
  2288. {
  2289. /* write error: reset volume and retry, up to device's retry limit */
  2290. if (rt11FsReset (vdptr) != OK)
  2291.     return (ERROR); /* drive won't reset! */
  2292.         if (++(vdptr->vd_retry) > pBlkDev->bd_retry)
  2293.     return (ERROR); /* retry limit reached */
  2294. }
  2295.     return (OK);
  2296.     }
  2297. /*******************************************************************************
  2298. *
  2299. * rt11FsAbsSector - determine absolute sector of logical sector
  2300. *
  2301. * This routine calculates the absolute sector number from the beginning of a
  2302. * medium using the RT-11 2:1 software interleave and 6 sector
  2303. * track-to-track skew.
  2304. *
  2305. * RETURNS: Absolute sector number of specified logical sector number.
  2306. */
  2307. LOCAL int rt11FsAbsSector
  2308.     (
  2309.     FAST ULONG  secPerTrack,    /* sectors per track */
  2310.     FAST int    sector          /* logical sector number
  2311.                                  * to calculate */
  2312.     )
  2313.     {
  2314.     int physical_sector;
  2315.     FAST int track = sector / secPerTrack;
  2316.     FAST int trk_sector = sector % secPerTrack;
  2317.     /* convert to actual offset by interleave and skew factors */
  2318.     physical_sector = ((trk_sector * 2) + (track * 6)) % secPerTrack;
  2319.     if (trk_sector >= (secPerTrack / 2))
  2320. physical_sector++;
  2321.     /* calculate absolute sector from start of disk */
  2322.     return (track * secPerTrack + physical_sector);
  2323.     }
  2324. /*******************************************************************************
  2325. *
  2326. * rt11FsCheckVol - verify that volume descriptor is current
  2327. *
  2328. * RETURNS: OK or ERROR.
  2329. */
  2330. LOCAL STATUS rt11FsCheckVol
  2331.     (
  2332.     FAST RT_VOL_DESC *vdptr,    /* pointer to device descriptor */
  2333.     BOOL doMount                /* mount the device, if necessary */
  2334.     )
  2335.     {
  2336.     /* Check if device driver announced ready-change */
  2337.     if (vdptr->vd_pBlkDev->bd_readyChanged)
  2338. {
  2339. vdptr->vd_state = RT_VD_READY_CHANGED;
  2340. vdptr->vd_pBlkDev->bd_readyChanged = FALSE;
  2341. }
  2342.     /* Check volume state */
  2343.     switch (vdptr->vd_state)
  2344. {
  2345. case RT_VD_CANT_RESET:
  2346.     /* this state means we tried to reset and failed so we
  2347.      * don't try again until a ready change occurs */
  2348.     return (ERROR); /* can't reset */
  2349. case RT_VD_CANT_MOUNT:
  2350.     /* this state means we tried to mount and failed so we
  2351.      * don't try again until a ready change occurs */
  2352.     if (doMount)
  2353. return (ERROR); /* can't mount */
  2354.     break; /* caller didn't want a mount anyway */
  2355. case RT_VD_READY_CHANGED:
  2356.     /* ready change occurred; try to reset volume */
  2357.     if (rt11FsReset (vdptr) != OK)
  2358. return (ERROR); /* can't reset */
  2359.     vdptr->vd_state = RT_VD_RESET; /* note volume reset */
  2360.     /* fall-through to try to mount */
  2361. case RT_VD_RESET:
  2362.     /* volume reset but not mounted; if caller requested, try mount */
  2363.     if (doMount)
  2364. {
  2365. if (rt11FsVolMount (vdptr) != OK)
  2366.     {
  2367.     vdptr->vd_state = RT_VD_CANT_MOUNT; /* don't try again */
  2368.     return (ERROR); /* can't mount */
  2369.     }
  2370. vdptr->vd_state = RT_VD_MOUNTED; /* note vol mounted */
  2371. }
  2372.     break;
  2373. case RT_VD_MOUNTED:
  2374.     break;
  2375. }
  2376.     return (OK); /* caller got what he wanted */
  2377.     }
  2378. /*******************************************************************************
  2379. *
  2380. * rt11FsReset - reset a volume
  2381. *
  2382. * This routine calls the specified volume's reset routine.
  2383. * If the reset fails, vd_state is set to (RT_VD_CANT_RESET)
  2384. * to indicate that disk won't reset.
  2385. */
  2386. LOCAL STATUS rt11FsReset
  2387.     (
  2388.     RT_VOL_DESC         *vdptr          /* pointer to device descriptor */
  2389.     )
  2390.     {
  2391.     FAST BLK_DEV *pBlkDev = vdptr->vd_pBlkDev;
  2392. /* pointer to block device struct */
  2393.     if (pBlkDev->bd_reset != NULL)
  2394. {
  2395. if ((* pBlkDev->bd_reset) (pBlkDev) != OK)
  2396.     {
  2397.     vdptr->vd_state = RT_VD_CANT_RESET;
  2398.     return (ERROR);
  2399.     }
  2400. }
  2401.     return (OK);
  2402.     }
  2403. /*******************************************************************************
  2404. *
  2405. * rt11FsVolMode - inquire the current volume mode (O_RDONLY/O_WRONLY/O_RDWR)
  2406. */
  2407. LOCAL STATUS rt11FsVolMode
  2408.     (
  2409.     FAST RT_VOL_DESC *vdptr     /* pointer to device descriptor */
  2410.     )
  2411.     {
  2412.     return (vdptr->vd_pBlkDev->bd_mode);
  2413.     }
  2414. /*******************************************************************************
  2415. *
  2416. * rt11FsReadyChange - notify rt11Fs of a change in ready status
  2417. *
  2418. * This routine sets the volume descriptor state to RT_VD_READY_CHANGED.
  2419. * It should be called whenever a driver senses that a device has come on-line
  2420. * or gone off-line (e.g., a disk has been inserted or removed).
  2421. *
  2422. * RETURNS: N/A
  2423. */
  2424. void rt11FsReadyChange
  2425.     (
  2426.     RT_VOL_DESC *vdptr  /* pointer to device descriptor */
  2427.     )
  2428.     {
  2429.     vdptr->vd_state = RT_VD_READY_CHANGED;
  2430.     }
  2431. /*******************************************************************************
  2432. *
  2433. * rt11FsModeChange - modify the mode of an rt11Fs volume
  2434. *
  2435. * This routine sets the volume descriptor mode to <newMode>.
  2436. * It should be called whenever the read and write capabilities are determined,
  2437. * usually after a ready change.  See the manual entry for rt11FsReadyChange().
  2438. *
  2439. * The rt11FsDevInit() routine initially sets the mode to O_RDWR,
  2440. * (e.g., both O_RDONLY and O_WRONLY).
  2441. *
  2442. * RETURNS: N/A
  2443. *
  2444. * SEE ALSO: rt11FsDevInit(), rt11FsReadyChange()
  2445. */
  2446. void rt11FsModeChange
  2447.     (
  2448.     RT_VOL_DESC *vdptr, /* pointer to volume descriptor */
  2449.     int newMode         /* O_RDONLY, O_WRONLY, or O_RDWR (both) */
  2450.     )
  2451.     {
  2452.     vdptr->vd_pBlkDev->bd_mode = newMode;
  2453.     }
  2454. /*******************************************************************************
  2455. *
  2456. * rt11FsSqueeze - reclaim fragmented free space on RT-11 volume
  2457. *
  2458. * This routine moves data around on an RT-11 volume so that all the
  2459. * little bits of free space left on the device are joined together.
  2460. *
  2461. * CAVEAT:
  2462. * There MUST NOT be any files open on the device when this procedure
  2463. * is called - if there are then their condition after the call will
  2464. * be unknown - almost certainly damaged, and writing to a file may
  2465. * destroy the entire disk.
  2466. */
  2467. LOCAL STATUS rt11FsSqueeze
  2468.     (
  2469.     FAST RT_VOL_DESC *vdptr     /* pointer to volume descriptor */
  2470.     )
  2471.     {
  2472. #define NUM_BLOCKS 16
  2473.     FAST int rdptr; /* number of next directory entry to read */
  2474.     FAST int wdptr; /* number of next directory entry to write */
  2475.     FAST int rbptr; /* number of next block to read */
  2476.     FAST int wbptr; /* number of next block to write */
  2477.     int nblk; /* number of blocks in file */
  2478.     int numToRead; /* number of blocks to transfer in this pass */
  2479.     int mtcount; /* number of empty blocks on device */
  2480.     RT_DIR_ENTRY dirEntry; /* directory entry for current file */
  2481.     FAST char *buffer = (char *) malloc (RT_BYTES_PER_BLOCK * NUM_BLOCKS);
  2482.     if (buffer == NULL)
  2483. return (ERROR); /* oops - couldn't do it */
  2484.     semTake (vdptr->vd_semId, WAIT_FOREVER);
  2485.     rdptr = wdptr = 0; /* start at first directory entry */
  2486.     rbptr = wbptr = vdptr->vd_dir_seg->ds_start;
  2487. /* blocks start at first one after directory */
  2488.     if ((rt11FsCheckVol (vdptr, TRUE) != OK) || (vdptr->vd_status != OK))
  2489. {
  2490. semGive (vdptr->vd_semId);
  2491. errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE);
  2492. free (buffer);
  2493. return (ERROR);
  2494. }
  2495.     if (rt11FsVolMode (vdptr) == O_RDONLY) /* check it's not write protected */
  2496. {
  2497. semGive (vdptr->vd_semId);
  2498. errnoSet (S_ioLib_WRITE_PROTECTED);
  2499. free (buffer);
  2500. return (ERROR);
  2501. }
  2502.     mtcount = 0; /* initially no empty blocks */
  2503.     /* now loop through the entire directory till we hit the end */
  2504.     while (rt11FsGetEntry (vdptr, rdptr++, &dirEntry),
  2505.    dirEntry.de_status != DES_END)
  2506. {
  2507. if (dirEntry.de_status == DES_PERMANENT)
  2508.     { /* we got an active file */
  2509.     rt11FsPutEntry (vdptr, wdptr++, &dirEntry);
  2510. /* write it back */
  2511.     nblk = dirEntry.de_nblocks;
  2512.     while (nblk) /* loop till all blocks transferred */
  2513. {
  2514. numToRead = min (nblk, NUM_BLOCKS);
  2515. nblk -= numToRead; /* read full buffer or file size */
  2516. if (rbptr != wbptr)
  2517.     {
  2518.     /* only move if it's at a different place */
  2519.     /* read another buffers worth */
  2520.     (void) rt11FsRdBlock (vdptr, rbptr, numToRead, buffer);
  2521.     /* write it back */
  2522.     (void) rt11FsWrtBlock (vdptr, wbptr, numToRead, buffer);
  2523.     }
  2524. rbptr += numToRead;
  2525. wbptr += numToRead;
  2526. }
  2527.     }
  2528. else
  2529.     {
  2530.     /* not active: just update block read pointer & empty block count */
  2531.     rbptr += dirEntry.de_nblocks;
  2532.     mtcount += dirEntry.de_nblocks;
  2533.     }
  2534. }
  2535.     dirEntry.de_status = DES_EMPTY;
  2536.     dirEntry.de_nblocks = mtcount; /* set count of empty blocks */
  2537.     rt11FsPutEntry (vdptr, wdptr++, &dirEntry); /* write DES_EMPTY entry */
  2538.     dirEntry.de_status = DES_END;
  2539.     rt11FsPutEntry(vdptr, wdptr, &dirEntry); /* write DES_END to terminate */
  2540.     (void) rt11FsVolFlush(vdptr); /* flush volume */
  2541.     semGive (vdptr->vd_semId); /* and release it */
  2542.     free (buffer); /* and release the memory */
  2543.     return (OK);
  2544.     }