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

VxWorks

开发平台:

C/C++

  1. /* cdromFsLib.c - ISO 9660 CD-ROM read-only file system library */
  2. /* Copyright 1989-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 05a,03jun99,pfl  fixed directory and file month entries (SPR# 26756)
  8. 04r,15nov98,jdi  added instructions on modifying BSP to include cdromFS.
  9. 04e,14jul98,cn   added prototype for cdromFsWrite().
  10. 04d,10jul98,cn   updated documentation, changed cdromFS to cdromFsLib 
  11.  (SPR# 21732). Also removed every reference to Rock 
  12.  Ridge extensions support (SPR# 21590). Moved cdromFsInit()
  13.  to the beginning of the file.
  14. 04c,08apr98,kbw  made minor man page edits
  15. 04b,30apr97,jdi  doc: cleanup.
  16. 04a,10apr97,dds  SPR#7538: add CDROM file system support to vxWorks.
  17. 03f,17jul96,rst  productized for release.
  18. 03e,25jun96,vld  file was compiled with "Tornado". All warnings were
  19.  fixed up.
  20. 03c,25jun96,vld  new functionality: uppercase names may be reached via
  21.  case insensitive path string.
  22. 03b,23jun96,leo  the bug in cdromFsFixPos() was fixed up (type of second
  23.  argument was changed to long).
  24. 03a,23jun96,leo  the bug in cdromFsFindFileInDir() was fixed up
  25.  (the bug came from ASCI order, wwhere ';' > '.').
  26. 02a,23jan96,vld  the new interpretation of ISO_DIR_REC_EAR_LEN
  27.  and ISO_PT_REC_EAR_LEN: it is assumed now that 
  28.  the length of EAR is counted in logical blocks.
  29.  Data always starts from LB bound.
  30. 01e,23jan96,vld  the bug in cdromFsFixPos was fixed up
  31. 01d,12oct95,rst  FCS release, ported to 5.2
  32. 01c,03jul95,rst  Beta release, code revew.
  33. 01b,10apr95,rst  alex, vlad total revision of the joined text
  34. 01a,22feb95,rst  initial version
  35. */
  36. /*
  37. DESCRIPTION
  38. This library defines cdromFsLib, a utility that lets you use standard POSIX 
  39. I/O calls to read data from a CD-ROM formatted according to the ISO 9660 
  40. standard file system.
  41. It provides access to CD-ROM file systems using any standard
  42. BLOCK_DEV structure (that is, a disk-type driver). 
  43.  
  44. The basic initialization sequence is similar to installing a DOS file system
  45. on a SCSI device.
  46.  
  47. 1. Initialize the cdrom file system library
  48. (preferably in sysScsiConfig() in sysScsi.c):
  49. .CS
  50.     cdromFsInit ();
  51. .CE
  52.  
  53. 2. Locate and create a SCSI physical device:
  54. .CS
  55.     pPhysDev=scsiPhysDevCreate(pSysScsiCtrl,0,0,0,NONE,1,0,0);
  56. .CE
  57.  
  58. 3. Create a SCSI block device on the physical device:
  59. .CS
  60.     pBlkDev = (SCSI_BLK_DEV *) scsiBlkDevCreate (pPhysDev, 0, 0);
  61. .CE
  62.  
  63. 4. Create a CD-ROM file system on the block device:
  64. .CS
  65.     cdVolDesc = cdromFsDevCreate ("cdrom:", (BLK_DEV *) pBlkDev);
  66. .CE
  67.  
  68. Call cdromFsDevCreate() once for each CD-ROM drive attached to your target.
  69. After the successful completion of cdromFsDevCreate(), the CD-ROM 
  70. file system will be available like any DOS file system, and 
  71. you can access data on the named CD-ROM device using open(), close(), read(), 
  72. ioctl(), readdir(), and stat().  A write() always returns an error.  
  73. The cdromFsLib utility supports multiple drives, concurrent access from 
  74. multiple tasks, and multiple open files.
  75. FILE AND DIRECTORY NAMING
  76. The strict ISO 9660 specification allows only uppercase file names 
  77. consisting of 8 characters plus a 3 character suffix.  To support multiple
  78. versions of the same file, the ISO 9660 specification also supports version
  79. numbers.  When specifying a file name in an open() call, you can select the
  80. file version by appending the file name with a semicolon (;) followed by a 
  81. decimal number indicating the file version.  If you omit the version number,
  82. cdromFsLib opens the latest version of the file.
  83. To accommodate users familiar with MS-DOS, cdromFsLib lets you use lowercase 
  84. name arguments to access files with names consisting entirely of uppercase 
  85. characters.  Mixed-case file and directory names are accessible only if you
  86. specify their exact case-correct names. 
  87. For the time being, cdromFsLib further accommodates MS-DOS users by 
  88. allowing "e" (backslash) instead of "/" in pathnames.  However, the use 
  89. of the backslash is discouraged because it may not be supported in
  90. future versions of cdromFsLib.
  91. Finally, cdromFsLib uses an 8-bit clean implementation of ISO 9660.  Thus, 
  92. cdromFsLib is compatible with CD-ROMs using either Latin or Asian characters in 
  93. the file names.
  94. IOCTL CODES SUPPORTED
  95. .iP `FIOGETNAME' 20
  96. Returns the file name for a specific file descriptor.
  97. .iP `FIOLABELGET'
  98. Retrieves the volume label.  This code can be used to verify that a 
  99. particular volume has been inserted into the drive.
  100. .iP `FIOWHERE'
  101. Determines the current file position.
  102. .iP `FIOSEEK'
  103. Changes the current file position.
  104. .iP `FIONREAD'
  105. Tells you the number of bytes between the current location and the end of 
  106. this file.
  107. .iP `FIOREADDIR'
  108. Reads the next directory entry.
  109. .iP `FIODISKCHANGE'
  110. Announces that a disk has been replaced (in case the block driver is
  111. not able to provide this indication).
  112. .iP `FIOUNMOUNT'
  113. Announces that the a disk has been removed (all currently open file 
  114. descriptors are invalidated).
  115. .iP `FIOFSTATGET'
  116. Gets the file status information (directory entry data).
  117. MODIFYING A BSP TO USE CDROMFS
  118. The following example describes mounting cdromFS on a SCSI device.
  119. Edit your BSP's config.h to make the following changes:
  120. .IP 1.
  121. Insert the following macro definition: 
  122. .CS
  123.     #define INCLUDE_CDROMFS
  124. .CE
  125. .IP 2.
  126. Change FALSE to TRUE in the section under the following comment:
  127. .CS
  128.     /@ change FALSE to TRUE for SCSI interface @/
  129. .CE
  130. .LP
  131. Make the following changes in sysScsi.c
  132. (or sysLib.c if your BSP has no sysScsi.c):
  133. .IP 1.
  134. Add the following declaration to the top of the file: 
  135. .CS
  136.     #ifdef INCLUDE_CDROMFS
  137.     #include "cdromFsLib.h"
  138.     STATUS cdromFsInit (void);
  139.     #endif
  140. .CE
  141. .IP 2.
  142. Modify the definition of sysScsiInit() to include the following:
  143. .CS
  144.     #ifdef INCLUDE_CDROMFS
  145.     cdromFsInit();
  146.     #endif
  147. .CE
  148. The call to cdromFsInit() initializes cdromFS.  This call must
  149. be made only once and must complete successfully before you can
  150. call any other cdromFsLib routines, such as cdromFsDevCreate().
  151. Typically, you make the cdromFSInit() call at system startup.
  152. Because cdromFS is used with SCSI CD-ROM devices, it is natural
  153. to call cdromFSInit() from within sysScsiInit().
  154. .IP 3.
  155. Modify the definition of sysScsiConfig() (if included in your BSP)
  156. to include the following: 
  157. .CS
  158. /@ configure a SCSI CDROM at busId 6, LUN = 0 @/
  159. #ifdef INCLUDE_CDROMFS
  160. if ((pSpd60 = scsiPhysDevCreate (pSysScsiCtrl, 6, 0, 0, NONE, 0, 0, 0)) == 
  161.     (SCSI_PHYS_DEV *) NULL)
  162.     {
  163.     SCSI_DEBUG_MSG ("sysScsiConfig: scsiPhysDevCreate failed for CDROM.n",
  164.                     0, 0, 0, 0, 0, 0);
  165.     return (ERROR);
  166.     }
  167. else if ((pSbdCd = scsiBlkDevCreate (pSpd60, 0, 0) ) == NULL)
  168.     {
  169.     SCSI_DEBUG_MSG ("sysScsiConfig: scsiBlkDevCreate failed for CDROM.n",
  170.                     0, 0, 0, 0, 0, 0);
  171.     return (ERROR);
  172.     }
  173. /@
  174.  * Create an instance of a CD-ROM device in the I/O system.
  175.  * A block device must already have been created.  Internally,
  176.  * cdromFsDevCreate() calls iosDrvInstall(), which enters the
  177.  * appropriate driver routines in the I/O driver table.
  178.  @/
  179. if ((cdVolDesc = cdromFsDevCreate ("cdrom:", (BLK_DEV *) pSbdCd )) == NULL)
  180.     {
  181.     return (ERROR);
  182.     }
  183. #endif /@ end of #ifdef INCLUDE_CDROMFS @/
  184. .CE
  185. .IP 4.
  186. Before the definition of sysScsiConfig(), declare the following
  187. global variables used in the above code fragment:
  188. .CS
  189.     SCSI_PHYS_DEV *pSpd60;
  190.     BLK_DEV *pSbdCd;
  191.     CDROM_VOL_DESC_ID cdVolDesc;
  192. .CE
  193. .LP
  194. The main goal of the above code fragment is to call cdromFsDevCreate().
  195. As input, cdromFsDevCreate() expects a pointer to a block device.
  196. In the example above, the scsiPhysDevCreate() and scsiBlkDevCreate()
  197. calls set up a block device interface for a SCSI CD-ROM device. 
  198. After the successful completion of cdromFsDevCreate(), the device called 
  199. "cdrom" is accessible using the standard open(), close(), read(), ioctl(),
  200. readdir(), and stat() calls.
  201. INCLUDE FILES: cdromFsLib.h
  202. CAVEATS
  203. The cdromFsLib utility does not support CD sets containing multiple disks.
  204. SEE ALSO: ioLib, ISO 9660 Specification
  205. */
  206. /* includes */
  207. #include <string.h>
  208. #include <memLib.h>
  209. #include <errnoLib.h>
  210. #include <sysLib.h>
  211. #include <stdlib.h>
  212. #include <stdio.h>
  213. #include <logLib.h>
  214. #include <errnoLib.h>
  215. #include <usrLib.h>
  216. #include <iosLib.h>
  217. #include <dirent.h>
  218. #include <ctype.h>
  219. #include "cdromFsLib.h"
  220. /* defines */
  221.     
  222. #ifdef  DEBUG
  223. #undef  LOCAL
  224. #define LOCAL
  225.     int         cdromFsDbg = 0;
  226.     u_char dbgvBuf[2048];
  227. #define DBG_MSG(level)
  228. if((level)<=cdromFsDbg)printf
  229. #define DBG_COP_TO_BUF(str, len)
  230. {
  231.         bzero(dbgvBuf, sizeof(dbgvBuf));
  232. bcopy((str), dbgvBuf, (len));
  233.         }
  234. #else
  235. #define DBG_MSG(level)      if (0)printf
  236. #define DBG_COP_TO_BUF(str, len) (str,len)
  237. #endif /* DEBUG */
  238. #include <assert.h>
  239. #define CDROM_LIB_MAX_PT_SIZE (64 KB) /* maximum path table size supported */
  240. #define SLASH '/'
  241. #define BACK_SLASH '\'
  242. #define POINT '.'
  243. #define SEMICOL ';'
  244. /* SEC_BUF struct constant */
  245. #define BUF_EMPTY (-1)
  246. #define CDROM_COM_BUF_SIZE   3 /* sectors to read via single access */
  247. /* 
  248.  * All character variables in the module are defined as u_char (*).
  249.  * Following macros are defined to prevent compilation warnings
  250.  */
  251. #define bzero(a,b) bzero((char *)(a), (b))
  252. #define bcopy(a,b,c) bcopy((char *)(a), (char *)(b), (c))
  253. #define bcmp(a,b,c) bcmp((char *)(a), (char *)(b), (c))
  254. #define strlen(a) strlen((char *)(a))
  255. #define strncpy(a,b,c) strncpy((char *)(a), (char *)(b), (c))
  256. #define strcpy(a,b) strcpy((char *)(a), (char *)(b))
  257. #define strncmp(a,b,c) strncmp((char *)(a), (char *)(b), (c))
  258. #define strcmp(a,b) strcmp((char *)(a), (char *)(b))
  259. #define strchr(a,b) strchr((char *)(a), (b))
  260. #define strtok_r(a,b,c) ((u_char *)strtok_r((char *)(a), (char *)(b),
  261.            (char **)(c)))
  262. #define strspn(a,b) strspn((char *)(a), (char *)(b))
  263. /* 
  264.  * Over development all errors are not set to <errno> directly, but
  265.  * logged on the console with some comments
  266.  */
  267. #ifdef ERR_SET_SELF
  268. #define errnoSet(a) errnoSetOut(__LINE__, (u_char *)#a)
  269. #endif
  270. /* data fields in buffer may not be bounded correctly */
  271. #define C_BUF_TO_SHORT(dest, source, start)
  272. {
  273.         CDROM_SHORT buf;
  274. bcopy((u_char *)(source)+ (start), (u_char *)&buf, 2);
  275.         (dest) = buf;
  276.         }
  277. #define C_BUF_TO_LONG(dest, source, start)
  278. {
  279.         CDROM_LONG buf;
  280.         bcopy((u_char *)(source)+ (start), (u_char *)&buf, 4);
  281.         (dest) = buf;
  282.         }
  283. #define LAST_BITS(val,bitNum) ((~((u_long)(-1)<<(bitNum)))&((u_long)val))
  284. #define A_PER_B(a,b) (((a)+(b)-1)/(a))
  285. /* to get some fields from path table records */
  286. #define PT_REC_SIZE(size, pPT)  ((size)=((u_char)(*(pPT)+(*(pPT)&1))+8))
  287. #define PT_PARENT_REC(prev, pPT)
  288.         C_BUF_TO_SHORT (prev, pPT, ISO_PT_REC_PARENT_DIR_N)
  289. /* 
  290.  * they are use the same data buffer within
  291.  * <sectBuf> fields, but different copies of
  292.  * <sectBuf> 
  293.  */
  294. #define RESTORE_FD(buf, dest, retErrCode)
  295.     {
  296.     (buf).sectBuf.startSecNum = (dest).sectBuf.startSecNum;
  297.     (dest)   = (buf);
  298.     (dest).FCDirRecPtr = cdromFsGetLB((dest).pVDList,
  299.     (dest).FCDirRecLB, &((dest).sectBuf));
  300.     if ((dest).FCDirRecPtr == NULL)
  301. return retErrCode;
  302.     (dest).FCDirRecPtr += (dest).FCDirRecOffInLB;
  303.     }
  304. /* to assign secBuf as empty */
  305. #define LET_SECT_BUF_EMPTY(pSecBuf) ((pSecBuf)->startSecNum=BUF_EMPTY)
  306.     
  307. /* typedefs */
  308. typedef u_short CDROM_SHORT; /* 2-bytes fields */
  309. typedef u_long CDROM_LONG; /* 4-bytes fields */
  310. /* globals */
  311. STATUS cdromFsInit (void);
  312. /* cdrom file system number in driver table */
  313. int cdromFsDrvNum = ERROR;
  314. /* locals */
  315. /* forward declarations */
  316. #ifdef ERR_SET_SELF
  317. LOCAL VOID errnoSetOut(int line, const u_char * str);
  318. #endif
  319. LOCAL T_CDROM_FILE_ID   cdromFsFDAlloc (CDROM_VOL_DESC_ID pVolDesc);
  320. LOCAL void              cdromFsFDFree (T_CDROM_FILE_ID pFD);
  321. LOCAL STATUS            cdromFsSectBufAlloc (CDROM_VOL_DESC_ID pVolDesc,
  322.      SEC_BUF_ID pSecBuf, 
  323.      int numSectInBuf);
  324. LOCAL STATUS            cdromFsSectBufAllocBySize (CDROM_VOL_DESC_ID pVolDesc,
  325.    SEC_BUF_ID pSecBuf, 
  326.    int size);
  327. LOCAL void              cdromFsSectBufFree (SEC_BUF_ID pSecBuf);
  328. LOCAL u_char *          cdromFsGetLB (T_CDROMFS_VD_LST_ID pVDLst, u_long LBNum,
  329.       SEC_BUF_ID secBuf);
  330. LOCAL u_char *          cdromFsGetLS (CDROM_VOL_DESC_ID pVolDesc, u_long LSNum,
  331.       SEC_BUF_ID secBuf);
  332. LOCAL u_char            cdromFsShiftCount (u_long source, u_long dest);
  333. LOCAL u_char *          cdromFsPTGet (T_CDROMFS_VD_LST_ID pVdLst, 
  334.       SEC_BUF_ID pSecBuf);
  335. LOCAL u_long            cdromFsNextPTRec (u_char ** ppPT, u_long offset, 
  336.   u_long PTSize);
  337. LOCAL STATUS            cdromFsVDAddToList (CDROM_VOL_DESC_ID pVolDesc, 
  338.     u_char * pVDData,
  339.     u_int VDPseudoLBNum, 
  340.     u_char VDSizeToLSSizeShift);
  341. LOCAL void              cdromFsVolUnmount (CDROM_VOL_DESC_ID pVolDesc);
  342. LOCAL STATUS            cdromFsVolMount (CDROM_VOL_DESC_ID pVolDesc);
  343. LOCAL T_CDROM_FILE_ID   cdromFsOpen (CDROM_VOL_DESC_ID pVolDesc, 
  344.      u_char * path, int options);
  345. LOCAL STATUS            cdromFsClose (T_CDROM_FILE_ID pFD);
  346. LOCAL int               cdromFsFindDirOnLevel (T_CDROMFS_VD_LST_ID pVDList, 
  347.        u_char * name, u_char * pPT, 
  348.        u_int parDirNum, u_int pathLev,
  349.        u_char ** ppRecord);
  350. LOCAL STATUS            cdromFsFindPathInDirHierar(T_CDROMFS_VD_LST_ID pVDList,
  351.    u_char * path, 
  352.    u_int numPathLevs,
  353.    T_CDROM_FILE_ID pFD, 
  354.    int options);
  355. LOCAL T_CDROM_FILE_ID   cdromFsFindPath (CDROM_VOL_DESC_ID pVolDesc,
  356.  u_char * path, int options);
  357. LOCAL STATUS            cdromFsFillFDForDir (T_CDROMFS_VD_LST_ID pVDList,
  358.      T_CDROM_FILE_ID pFD, 
  359.      u_char * pPTRec,
  360.      u_int dirRecNumInPT, 
  361.      u_int dirRecOffInPT);
  362. LOCAL STATUS            cdromFsFindFileInDir (T_CDROMFS_VD_LST_ID pVDList,
  363.       T_CDROM_FILE_ID pFD, 
  364.       u_char * name,
  365.       u_char * pPTRec, 
  366.       u_int dirRecNumInPT,
  367.       u_int dirRecOffInPT);
  368. LOCAL int               cdromFsSplitPath(u_char * path);
  369. LOCAL STATUS            cdromFsReadyChange (CDROM_VOL_DESC_ID pVDList);
  370. LOCAL STATUS            cdromFsIoctl (T_CDROM_FILE_ID fd, int function, 
  371.       int arg);
  372. LOCAL STATUS            cdromFsRead (int desc, u_char * buffer, 
  373.      size_t maxBytes);
  374. LOCAL STATUS            cdromFsWrite (void);
  375. LOCAL STATUS            cdromFsSkipDirRec (T_CDROM_FILE_ID fd, u_char flags);
  376. LOCAL STATUS            cdromFsCountMdu (T_CDROM_FILE_ID fd, int prevabsoff);
  377. LOCAL STATUS            cdromFsFillStat (T_CDROM_FILE_ID fd,struct stat * arg);
  378. LOCAL STATUS            cdromFsSkipDirRec (T_CDROM_FILE_ID fd, u_char flags);
  379. LOCAL STATUS            cdromFsFillPos (T_CDROM_FILE_ID fd,u_char *PrevDirPtr, 
  380. short i, int len, int NewOffs);
  381. LOCAL STATUS            cdromFsDirBound (T_CDROM_FILE_ID fd);   
  382. LOCAL void              cdromFsFixPos (T_CDROM_FILE_ID fd, u_long length, 
  383.        u_long absLb);
  384. LOCAL void              cdromFsFixFsect (T_CDROM_FILE_ID fd);
  385. LOCAL void              cdromFsSkipGap (T_CDROM_FILE_ID fd , u_long * absLb,
  386. long absPos);
  387. /*******************************************************************************
  388. * cdromFsInit - initialize cdromFsLib
  389. *
  390. * This routine initializes cdromFsLib.  It must be called exactly
  391. * once before calling any other routine in cdromFsLib. 
  392. *
  393. * ERRNO: S_cdromFsLib_ALREADY_INIT
  394. *
  395. * RETURNS: OK or ERROR, if cdromFsLib has already been initialized.
  396. *
  397. * SEE ALSO: cdromFsDevCreate(), iosLib.h
  398. */
  399. STATUS cdromFsInit (void)
  400.     {
  401.     if (cdromFsDrvNum != ERROR)
  402. {
  403. return cdromFsDrvNum;
  404. }
  405.     /* install cdromFs into driver table */
  406.     cdromFsDrvNum = iosDrvInstall (
  407.  (FUNCPTR) NULL,  /* pointer to driver create function */
  408.          (FUNCPTR) NULL,  /* pointer to driver delete function */
  409.          (FUNCPTR) cdromFsOpen,    /* pointer to driver open function   */
  410.          (FUNCPTR) cdromFsClose,   /* pointer to driver close function  */
  411.          (FUNCPTR) cdromFsRead,    /* pointer to driver read function   */
  412.          (FUNCPTR) cdromFsWrite,   /* pointer to driver write function  */
  413.          (FUNCPTR) cdromFsIoctl    /* pointer to driver ioctl function  */
  414.         );
  415.     if (cdromFsDrvNum == ERROR)
  416. {
  417. printf("cdromFsLib: iosDrvInstall failedn");
  418. printErrno(errnoGet());
  419. }
  420.     else
  421. {
  422. #ifdef DEBUG
  423. printf("cdromFsLib: Initializedn");
  424. #endif
  425. }
  426.     return cdromFsDrvNum;
  427.     } /* cdromFsInit() */
  428. #ifdef ERR_SET_SELF
  429. /*******************************************************************************
  430. *
  431. * errnoSetOut - put error message
  432. *
  433. * This routine is called instead of errnoSet() during module creation.
  434. *
  435. * RETURNS: N/A
  436. */
  437. LOCAL VOID errnoSetOut(int line, const u_char * str)
  438.     {
  439.     printf("ERROR: line %d %sn", line, str);
  440.     }
  441. #endif /* ERR_SET_SELF */
  442. /*******************************************************************************
  443. *
  444. * cdromFsFDAlloc - allocate file descriptor structure
  445. *
  446. * This routine allocates a file descriptor structure and initializes some 
  447. * of its base members, such as 'magic' and 'sectBuf'.  Later, you can use 
  448. * this file descriptor structure when opening a file.  However, be aware that 
  449. * the file descriptor allocated here is not yet connected to the volume's file 
  450. * descriptor list.  To free the file descriptor structure allocated here, 
  451. * use cdromFsFDFree().
  452. * RETURNS: ptr to FD or NULL.
  453. */
  454. LOCAL T_CDROM_FILE_ID cdromFsFDAlloc
  455.     (
  456.     CDROM_VOL_DESC_ID pVolDesc /* processed volume */
  457.     )
  458.     {
  459.     T_CDROM_FILE_ID pFD = malloc(sizeof(T_CDROM_FILE));
  460.     
  461.     if (pFD == NULL)
  462.      return NULL;
  463.     
  464.     bzero (pFD, sizeof (T_CDROM_FILE));
  465.     
  466.     /* allocate sector reading buffer (by default size) */
  467.     if (cdromFsSectBufAlloc (pVolDesc, & (pFD->sectBuf), 0) == ERROR)
  468.         {
  469.         free (pFD);
  470.         return (NULL);
  471.         }
  472.     
  473.     pFD->inList = 0; /* FD not included to volume FD list yet */
  474.     pFD->magic = FD_MAG;
  475.     return (pFD);
  476.     }
  477. /*******************************************************************************
  478. * cdromFsFDFree - deallocate a file descriptor structure
  479. *
  480. * This routine deallocates all allocated memory associated with the specified
  481. * file descriptor structure.
  482. *
  483. * RETURN: N/A.
  484. */
  485. LOCAL void cdromFsFDFree
  486.     (
  487.     T_CDROM_FILE_ID pFD
  488.     )
  489.     {
  490.     pFD->magic = 0;
  491.     cdromFsSectBufFree (&(pFD->sectBuf));
  492.     
  493.     if (pFD->FRecords != NULL)
  494.         free (pFD->FRecords);
  495.         
  496.     if (pFD->inList)
  497.      lstDelete (&(pFD->pVDList->pVolDesc->FDList), (NODE *)pFD);
  498.     
  499.     pFD->inList = 0;
  500.     free (pFD);
  501.     }
  502. /*******************************************************************************
  503. * cdromFsSectBufAlloc - allocate a buffer for reading volume sectors
  504. *
  505. * This routine is designed to allocate a buffer for reading volume data 
  506. * by Logical Sectors.  If the <numSectInBuf> parameter is a value greater 
  507. * than zero, the buffer size is assumed to be equal to <numSectInBuf> 
  508. * times the sector size.  If you specify a <numSectInBuf> of 0, the buffer
  509. * size is CDROM_COM_BUF_SIZE.
  510. * The buffer may already have been connected with given control structure. 
  511. * If one is large enough, but not two, it is just left intact, if not, - 
  512. * free it.
  513. *
  514. * After use, buffer must be deallocated by means of cdromFsSectBufFree ().
  515. *
  516. * RETURNS: OK or ERROR;
  517. */
  518. LOCAL STATUS cdromFsSectBufAlloc
  519.     (
  520.     CDROM_VOL_DESC_ID pVolDesc,
  521.     SEC_BUF_ID pSecBuf, /* buffer control structure */
  522.                                 /* to which buffer is connected */
  523.     int numSectInBuf /* LS in buffer */
  524.     )
  525.     {
  526.     assert (pVolDesc != NULL);
  527.     assert (pSecBuf != NULL);
  528.     numSectInBuf = (numSectInBuf == 0)?  CDROM_COM_BUF_SIZE: numSectInBuf;
  529.     /* 
  530.      * may be, any buffer has already been connected with given
  531.      * control structure. Check its size.
  532.      */
  533.     if (pSecBuf->magic == SEC_BUF_MAG && pSecBuf->sectData != NULL)
  534. {
  535. if (pSecBuf->numSects >= numSectInBuf &&
  536.     pSecBuf->numSects <= numSectInBuf + 1)
  537.     return OK;
  538. free(pSecBuf->sectData);
  539. pSecBuf->magic = 0;
  540. }
  541.     /* newly init control structure */
  542.     LET_SECT_BUF_EMPTY (pSecBuf);
  543.     pSecBuf->numSects = numSectInBuf;
  544.     /* allocation */
  545.     pSecBuf->sectData = malloc(numSectInBuf * pVolDesc->sectSize);
  546.     if (pSecBuf->sectData == NULL)
  547. return ERROR;
  548.     pSecBuf->magic = SEC_BUF_MAG; 
  549.     return (OK);
  550.     } 
  551. /*******************************************************************************
  552. * cdromFsSectBufAllocBySize - allocate buffer for reading volume.
  553. *
  554. * After use, buffer must be deallocated by means of cdromFsSectBufFree ().
  555. * This routine calls cdromFsSectBufAlloc() with sufficient
  556. * number of sectors covers <size>.
  557. * If <size> == 0, allocated buffer is  1 sector size.
  558. *
  559. * RETURNS: OK or ERROR;
  560. */
  561. LOCAL STATUS cdromFsSectBufAllocBySize
  562.     (
  563.     CDROM_VOL_DESC_ID pVolDesc,
  564.     SEC_BUF_ID pSecBuf, /* buffer control structure */
  565. /* to which buffer is connected */
  566.     int size /* minimum buffer size in bytes */
  567.     )
  568.     {
  569.     assert (pVolDesc != NULL);
  570.     assert (pSecBuf != NULL);
  571.     
  572.     return (cdromFsSectBufAlloc (pVolDesc , pSecBuf,
  573.  A_PER_B(pVolDesc->sectSize, size) + 1));
  574.     }
  575. #ifdef DEBUG
  576. /*******************************************************************************
  577. *
  578. * cdromFsSectBufAllocByLB - allocate by number of LB buffer for reading volume.
  579. *
  580. * After using, buffer must be deallocated by means of cdromFsSectBufFree().
  581. * This routine calls cdromFsSectBufAllocBySize() with
  582. * size equals to total <numLB> logical blocks size.
  583. * If <numLB> == 0, allocated buffer is of 1 sectors size.
  584. *
  585. * RETURNS: OK or ERROR;
  586. */
  587. LOCAL STATUS cdromFsSectBufAllocByLB
  588.     (
  589.     T_CDROMFS_VD_LST_ID pVDList,
  590.     SEC_BUF_ID pSecBuf, /* buffer control structure */
  591. /* to which buffer is connected */
  592.     int numLB /* minimum LS in buffer */
  593.     )
  594.     {
  595.     assert (pVDList != NULL);
  596.     assert (pVDList->pVolDesc != NULL);
  597.     assert (pSecBuf != NULL);
  598.     
  599.     return (cdromFsSectBufAllocBySize (pVDList->pVolDesc , pSecBuf,
  600.        numLB * pVDList->LBSize));
  601.     }
  602. #endif /*DEBUG*/
  603. /*******************************************************************************
  604. *
  605. * cdromFsSectBufFree - deallocate volume sector buffer.
  606. *
  607. * RETURN: N/A
  608. */
  609. LOCAL void cdromFsSectBufFree
  610.     (
  611.     SEC_BUF_ID pSecBuf /* buffer control structure */
  612.     )
  613.     {
  614.     assert (pSecBuf != NULL);
  615.     if (pSecBuf->magic == SEC_BUF_MAG && pSecBuf->sectData != NULL)
  616. free (pSecBuf->sectData);
  617.     /* buffer structure is unusable now */
  618.     pSecBuf->sectData = NULL;
  619.     pSecBuf->magic = 0;
  620.     } 
  621. /*******************************************************************************
  622. *
  623. * cdromFsGetLS - read logical sector from volume.
  624. *
  625. * This routine tries to find requested LS in <pSecBuf> and, if failed,
  626. * reads sector from device. Number of read sectors equal to buffer size.
  627. *
  628. * ERRNO: S_cdromFsLib_DEVICE_REMOVED, if cdrom disk has not been ejected;
  629. * or any, may be set by block device driver read function.
  630. *
  631. * RETURNS: ptr on LS within buffer or NULL if error accessing device.
  632. */
  633. LOCAL u_char * cdromFsGetLS
  634.     (
  635.     CDROM_VOL_DESC_ID pVolDesc,
  636.     u_long LSNum, /* logical sector to get */
  637.     SEC_BUF_ID pSecBuf /* sector data control structure, */
  638. /* to put data to */
  639.     )
  640.     {
  641.     assert (pVolDesc != NULL);
  642.     assert (pSecBuf->sectData != NULL);
  643.     assert (pSecBuf->magic == SEC_BUF_MAG);
  644.     assert (LSNum < pVolDesc->pBlkDev->bd_nBlocks / pVolDesc->LSToPhSSizeMult);
  645.     DBG_MSG (400)("access for sector %lun", LSNum);
  646.     
  647.     /* check for disk has not been ejected */
  648.     if (pVolDesc->pBlkDev->bd_readyChanged)
  649.      {
  650.      cdromFsVolUnmount (pVolDesc);
  651.      errnoSet (S_cdromFsLib_DEVICE_REMOVED);
  652.      return (NULL);
  653.      }
  654.     
  655.     /* may be sector already in buffer ('if' for negative condition) */
  656.     if (pSecBuf->startSecNum == BUF_EMPTY ||
  657. LSNum < pSecBuf->startSecNum ||
  658. LSNum >= pSecBuf->startSecNum + pSecBuf->numSects)
  659. {
  660. /* sector not in the buffer, read it from disk */
  661. BLK_DEV * pBlkDev = pVolDesc->pBlkDev;
  662. u_long   numLSRead;
  663. assert (pBlkDev != NULL);
  664. /* num read sects must not exceed last volume sector */
  665. numLSRead = min (pBlkDev->bd_nBlocks / pVolDesc->LSToPhSSizeMult -
  666.  LSNum, pSecBuf->numSects);
  667. if (pBlkDev->bd_blkRd (pBlkDev, LSNum * pVolDesc->LSToPhSSizeMult,
  668.        numLSRead * pVolDesc->LSToPhSSizeMult,
  669.        pSecBuf->sectData) == ERROR)
  670.     {
  671.     LET_SECT_BUF_EMPTY (pSecBuf);
  672.     DBG_MSG(0)(" CDROM ERROR: error reading volume sect %lu - %luan",
  673.        LSNum, pSecBuf->numSects);
  674.     return (NULL);
  675.     }
  676. /* successfully read */
  677. pSecBuf->startSecNum = LSNum;
  678. }
  679.     return (pSecBuf->sectData +
  680.           (LSNum - pSecBuf->startSecNum) * pVolDesc->sectSize);
  681.     } 
  682. /*******************************************************************************
  683. *
  684. * cdromFsGetLB - get logical block
  685. *
  686. * This routine tries to find requested LB in <pSecBuf> and, if it fails,
  687. * reads sector, containing the LB from device.
  688. * <pSecBuf> is used as sector buffer. If <pSecBuf> is NULL, global
  689. * volume buffer is used.
  690. *
  691. * RETURNS: ptr on LB within buffer or NULL if error with set errno
  692. * to appropriate value.
  693. */
  694. LOCAL u_char * cdromFsGetLB
  695.     (
  696.     T_CDROMFS_VD_LST_ID pVDList,
  697.     u_long LBNum, /* logical block to get */
  698.     SEC_BUF_ID pSecBuf /* sector data control structure, */
  699.      /* to put data to */
  700.     )
  701.     {
  702.     u_int secNum; /* LS, contane LB */
  703.     u_char * pData; /* ptr to LB within read data buffer */
  704.     CDROM_VOL_DESC_ID pVolDesc;
  705.     assert (pVDList != NULL);
  706.     assert (LBNum > 15);
  707.     pVolDesc = pVDList->pVolDesc;
  708.     assert (pVolDesc != NULL);
  709.     if (pSecBuf == NULL) /* to use common buffer */
  710. pSecBuf = &(pVDList->pVolDesc->sectBuf);
  711.     assert (pSecBuf->sectData != NULL);
  712.     DBG_MSG(300)("access for LB %lun", LBNum);
  713.     secNum = LBNum >> pVDList->LBToLSShift; /* LS, contane LB  */
  714.     pData = cdromFsGetLS (pVolDesc, secNum, pSecBuf);
  715.     if (pData == NULL)
  716.      return NULL;
  717.     
  718.     DBG_MSG(400)("offset in buf: %lu(last bits = %lu)n",
  719.  pVDList->LBSize * LAST_BITS(LBNum, pVDList->LBToLSShift),
  720.  LAST_BITS(LBNum, pVDList->LBToLSShift));
  721.     
  722.     return (pData + pVDList->LBSize *
  723.      LAST_BITS (LBNum, pVDList->LBToLSShift));
  724.     }
  725. /*******************************************************************************
  726. *
  727. * cdromFsPTGet - retrieve Path Table for given VD from volume.
  728. *
  729. * By default, if pSecBuf == NULL, volume dir hierarchy PT buffer
  730. * is used for storing path table. It is allocated only once and
  731. * is deallocated over volume unmounting.
  732. *
  733. * Only if pSecBuf != NULL required space for PT automaticly allocated in it.
  734. *
  735. * RETURNS: ptr to PT or NULL if any error occurred.
  736. */
  737. LOCAL u_char * cdromFsPTGet
  738.     (
  739.     T_CDROMFS_VD_LST_ID pVdLst,
  740.     SEC_BUF_ID pSecBuf /* may be NULL. Ptr to buffer control */
  741.      /* structure to read PT to */
  742.     )
  743.     {
  744.     assert (pVdLst != NULL);
  745.     
  746.     if (pSecBuf == NULL) /* use volume dir hierarchy PT buffer */
  747.         pSecBuf = &(pVdLst->PTBuf);
  748.      
  749.     /* if buffer already has been allocated, following call do nothing */
  750.     if (cdromFsSectBufAllocBySize (pVdLst->pVolDesc, pSecBuf,
  751.    pVdLst->PTSize) == ERROR)
  752. return NULL;
  753.     /* if PT already in buffer, following call do nothing */
  754.     return (cdromFsGetLB(pVdLst, pVdLst->PTStartLB, pSecBuf));
  755.     }
  756. /*******************************************************************************
  757. *
  758. * cdromFsNextPTRec - pass to a next PT record.
  759. *
  760. * As result, *ppPT points to the next PT record.
  761. *
  762. * RETURNS: offset of record from PT start or 0 if last record encounted
  763. */
  764. LOCAL u_long cdromFsNextPTRec
  765.     (
  766.     u_char ** ppPT, /* address of ptr to current record */
  767.      /* within buffer, containing PT */
  768.     u_long offset, /* offset of current record from PT start */
  769.     u_long PTSize /* path table size (stored in volume */
  770.      /* descriptor */
  771.     )
  772.     {
  773.     short size; /* current PT record size */
  774.     /* skip current PT record */
  775.     PT_REC_SIZE(size, *ppPT);
  776.     offset += size;
  777.     *ppPT += size;
  778.     /* 
  779.      * set of zero bytes may follow PT record, if that is last record in LB.
  780.      * First non zero byte starts next record
  781.      */
  782.     for (; offset < PTSize; offset ++, *ppPT += 1)
  783. if (**ppPT != 0)
  784.     break;
  785.     return (offset);
  786.     }
  787. /*******************************************************************************
  788. *
  789. * cdromFsShiftCount - count shift for transfer <source> to <dest>.
  790. *
  791. * This routine takes two values, that are power of two and counts
  792. * the difference of powers, which is, for instance, the number of
  793. * bits to shift <source> in order to get <dest>.
  794. * Because <dest> may be less, than <source>, (-1) may not be
  795. * used as error indication return code, so an impossible value of
  796. * 100 is taken for this purpose.
  797. *
  798. * ERRNO: S_cdromFsLib_ONE_OF_VALUES_NOT_POWER_OF_2.
  799. *
  800. * RETURNS: number of bits to shift <source>, in order to get <dest>
  801. * or a value of (100) if it is impossible to calculate shift count.
  802. */
  803. LOCAL u_char cdromFsShiftCount
  804.     (
  805.     u_long source,
  806.     u_long dest
  807.     )
  808.     {
  809.     u_char i;
  810.     if (source <= dest)
  811. {
  812. for (i = 0; i < sizeof (u_long) * 8; i++)
  813.     if ((source << i) == dest)
  814. return i;
  815. }
  816.     else /* source > dest */
  817. {
  818. for (i = 1; i < sizeof (u_long) * 8; i++)
  819.     if ((source >> i) == dest)
  820. return (-i);
  821. }
  822.     
  823.     errnoSet (S_cdromFsLib_ONE_OF_VALUES_NOT_POWER_OF_2);
  824.     return (100);
  825.     }
  826. /*******************************************************************************
  827. *
  828. * cdromFsVDAddToList - add VD to VD list.
  829. *
  830. * Allocate VD list structure, fill in its fields (from <pVDData> buffer)
  831. * and add to VD list.
  832. *
  833. * RETURNS: OK or ERROR if any failed.
  834. */
  835. LOCAL STATUS cdromFsVDAddToList
  836.     (
  837.     CDROM_VOL_DESC_ID pVolDesc,
  838.     u_char * pVDData, /* data, has been got from disk */
  839.     u_int VDPseudoLBNum, /* LB number, contains given VD, */
  840.      /* if let (LB size = VD size) */
  841.     u_char VDSizeToLSSizeShift /* relation between VD size */
  842.      /* and LS size */
  843.     )
  844.     {
  845.     T_CDROMFS_VD_LST_ID pVDList;
  846.     assert (pVolDesc != NULL);
  847.     assert (pVDData != NULL);
  848.     pVDList = malloc (sizeof (T_CDROMFS_VD_LST));
  849.     if (pVDList == NULL)
  850. return (ERROR);
  851.     bzero((u_char *) pVDList, sizeof (T_CDROMFS_VD_LST));
  852.     
  853.     pVDList->pVolDesc = pVolDesc;
  854.     
  855.     C_BUF_TO_LONG (pVDList->volSize, pVDData, ISO_VD_VOL_SPACE_SIZE);
  856.     
  857.     /* since PT is stored in memory, max PT size is restricted */
  858.     C_BUF_TO_LONG (pVDList->PTSize, pVDData, ISO_VD_PT_SIZE);
  859.     if (pVDList->PTSize > CDROM_LIB_MAX_PT_SIZE)
  860.         {
  861.         errnoSet (S_cdromFsLib_SUCH_PATH_TABLE_SIZE_NOT_SUPPORTED);
  862.         free (pVDList);
  863.      return (ERROR);
  864.      }
  865.     
  866.     C_BUF_TO_LONG (pVDList->PTStartLB, pVDData, ISO_VD_PT_OCCUR);
  867.     C_BUF_TO_LONG (pVDList->rootDirSize, pVDData,
  868.    ISO_VD_ROOT_DIR_REC + ISO_DIR_REC_DATA_LEN);
  869.     C_BUF_TO_LONG (pVDList->rootDirStartLB, pVDData,
  870.    ISO_VD_ROOT_DIR_REC + ISO_DIR_REC_EXTENT_LOCATION);
  871.     C_BUF_TO_SHORT (pVDList->volSetSize, pVDData, ISO_VD_VOL_SET_SIZE);
  872.     C_BUF_TO_SHORT (pVDList->volSeqNum, pVDData, ISO_VD_VOL_SEQUENCE_N);
  873.     C_BUF_TO_SHORT (pVDList->LBSize, pVDData, ISO_VD_LB_SIZE);
  874.     pVDList->LBToLSShift = cdromFsShiftCount (pVDList->LBSize,
  875.       pVolDesc->sectSize);
  876.     
  877.     pVDList->type = ((T_ISO_VD_HEAD_ID)pVDData)->type;
  878.     pVDList->fileStructVersion = *(pVDData + ISO_VD_FILE_STRUCT_VER);
  879.     pVDList->VDInSector = VDPseudoLBNum >> VDSizeToLSSizeShift;
  880.     pVDList->VDOffInSect = LAST_BITS (VDPseudoLBNum,
  881.      VDSizeToLSSizeShift) *
  882.   ISO_VD_SIZE;
  883.     /* 
  884.      * read PT to buffer and init dirLevBorders...[].
  885.      * In accordance with ISO9660 all directories records in
  886.      * PT are sorted by hierarchy levels and are numbered from 1.
  887.      * (only root has number 1 and lays on level 1).
  888.      * Number of levels restricted to 8.
  889.      * dirLevBordersOff[ n ] contains offset of first PT record on level
  890.      * (n+2) (root excluded and array encounted from 0) from PT start.
  891.      * dirLevLastRecNum[ n ] contains number of last PT record on level
  892.      * (n+2).
  893.      * Base of algorithm:
  894.      * Storing number of last PT rec on hierarchy level <n> in
  895.      * <prevLevLastRecNum>, will skip level <n+1>, on which all
  896.      * directories have parent only within n; first directory
  897.      * which parent dir number exceeds <prevLevLastRecNum>
  898.      * starts level n+2.
  899.      */
  900.     {
  901.     u_char * pPT;
  902.     u_int  offset, /* absolute offset from PT start */
  903.          level,          /* hierarchy level (minus 2) */
  904.             prevLevLastRecNum, /* number of last PT rec on */
  905.          /* previous hierarchy level */
  906.           prevRecNum ; /* previous PT record number */
  907.     
  908.     pPT = cdromFsPTGet (pVDList, NULL);
  909.     if (pPT == NULL)
  910. {
  911. free (pVDList);
  912. return (ERROR);
  913. }
  914.     
  915.     /* 
  916.      * pass over root dir entry, dir hierarchy level 1;
  917.      * root dir record is first PT record and its number is 1
  918.      */
  919.     
  920.     offset = cdromFsNextPTRec (&pPT, 0, pVDList->PTSize);
  921.     
  922.     level = 0; /* not put to array data for root directory */
  923.     prevRecNum = 1; /*  root number in PT */
  924.     prevLevLastRecNum = 1;
  925.     bzero ((u_char *)(pVDList->dirLevBordersOff),
  926.    sizeof(pVDList->dirLevBordersOff));
  927.     bzero ((u_char *)(pVDList->dirLevLastRecNum),
  928.    sizeof(pVDList->dirLevLastRecNum));
  929.     
  930.     /* 
  931.      * over this loop all dir hierarchy levels' bounds in PT
  932.      * will be found.
  933.      */
  934.     
  935.     pVDList->dirLevBordersOff[0] = offset;
  936.     for(; offset < pVDList->PTSize && level < CDROM_MAX_DIR_LEV - 1;)
  937. {
  938. u_int prev; /* parent dir number for current record */
  939. PT_PARENT_REC (prev, pPT);
  940. #ifdef DEBUG
  941. /* debugging */
  942. DBG_COP_TO_BUF(pPT + ISO_PT_REC_DI, *pPT);
  943. DBG_MSG(200)("%4dt%20stparent # %3d, D_ID_LEN %2d  level %dn",
  944.      prevRecNum + 1, dbgvBuf, (int)prev, (int)*pPT,
  945.      level + 2);
  946. #endif
  947. /* if directory level overed */
  948.          
  949. if(prev > prevLevLastRecNum)
  950.     {
  951.     /* close level */
  952.     
  953.     pVDList->dirLevLastRecNum[level] = prevRecNum;
  954.     
  955.     level++;
  956.     if (level > CDROM_MAX_DIR_LEV - 1)
  957. break;
  958.     
  959.     /* current level first record offset within PT */
  960.     
  961.     pVDList->dirLevBordersOff[level] = offset;
  962.     prevLevLastRecNum = prevRecNum;
  963.     }
  964. prevRecNum ++;
  965. offset = cdromFsNextPTRec (&pPT, offset, pVDList->PTSize);
  966. }
  967.     
  968.     /* close last level */
  969.     
  970.     pVDList->dirLevLastRecNum[level] = prevRecNum;
  971.     
  972.     /* 
  973.      * may be loop breaking only because CDROM_MAX_DIR_LEV overloading
  974.      * before fully PT exhausting, that is an error
  975.      */
  976.     
  977.     if (offset < pVDList->PTSize)
  978. {
  979. free (pVDList);
  980. errnoSet (S_cdromFsLib_MAX_DIR_HIERARCHY_LEVEL_OVERFLOW);
  981. return (ERROR);
  982. }
  983.     
  984.     pVDList->numDirLevs = level + 1;       /* <level> starts from 0 */
  985.     pVDList->numPTRecs = prevRecNum;
  986.     }  /* hierarchy bounds init */
  987.     
  988.     /* VD have been built. Add it to VD list */
  989.     
  990.     pVDList->magic = VD_LIST_MAG;
  991.     
  992.     lstAdd  (&(pVolDesc->VDList), (NODE *)pVDList);
  993.     return (OK);
  994.     }
  995. /*******************************************************************************
  996. *
  997. * cdromFsVolUnmount - mark in all device depends data, that volume unmounted.
  998. * All volume descriptors are deallocated.
  999. * FDList not deallocated, but only marked as "file unaccessible.
  1000. *
  1001. * RETURN: N/A
  1002. */
  1003. LOCAL void cdromFsVolUnmount
  1004.     (
  1005.     CDROM_VOL_DESC_ID pVolDesc  /* cdrom volume decriptor id */
  1006.     )
  1007.     {
  1008.     T_CDROM_FILE_ID pFDList;
  1009.     T_CDROMFS_VD_LST_ID pVDList;
  1010.     assert (pVolDesc != NULL);
  1011.     assert (pVolDesc->mDevSem != NULL);
  1012.     if (pVolDesc->unmounted)
  1013.      return;
  1014.     
  1015.     if (semTake(pVolDesc->mDevSem, WAIT_FOREVER) == ERROR)
  1016. return;
  1017.     /* free VD list with PT buffers */
  1018.     for (pVDList = (T_CDROMFS_VD_LST_ID)lstFirst(&(pVolDesc->VDList));
  1019.  pVDList != NULL;
  1020.  pVDList = (T_CDROMFS_VD_LST_ID)lstNext((NODE *)pVDList))
  1021. {
  1022. cdromFsSectBufFree(&(pVDList->PTBuf));
  1023. }
  1024.     lstFree (&(pVolDesc->VDList));
  1025.     /* mark all opened  files as unaccessible */
  1026.     
  1027.     for (pFDList = (T_CDROM_FILE_ID)lstFirst(&(pVolDesc->FDList));
  1028.  pFDList != NULL;
  1029.  pFDList = (T_CDROM_FILE_ID)lstNext((NODE *)pFDList))
  1030. {
  1031. pFDList->volUnmount = 1;
  1032. }
  1033.     
  1034.     /* mark in VD, that volume unmounted */
  1035.     pVolDesc->unmounted = 1;
  1036.     if (semGive(pVolDesc->mDevSem) == ERROR)
  1037. errnoSet (S_cdromFsLib_SEMGIVE_ERROR);
  1038.     }
  1039. /*******************************************************************************
  1040. *
  1041. * cdromFsVolMount - mount cdrom volume.
  1042. *
  1043. * This routine reads volume descriptors and creates VD list.
  1044. *
  1045. * ERRNO: S_cdromFsLib_UNNOWN_FILE_SYSTEM or any errno may be set by
  1046. * supplementary functions (such as malloc).
  1047. *
  1048. * RETURNS: OK or ERROR
  1049. */
  1050. LOCAL STATUS cdromFsVolMount
  1051.     (
  1052.     CDROM_VOL_DESC_ID pVolDesc  /* cdrom volume decriptor id */
  1053.     )
  1054.     {
  1055.     T_CDROMFS_VD_LST VDList;        /* volume descriptor list  */
  1056.     u_long       LBRead;        /* logical blk to read     */
  1057.     u_char         VDLast = 0;
  1058.     u_char              primVDMounted; /* primary VD mounted flag */
  1059.     assert (pVolDesc != NULL);
  1060.     assert (pVolDesc->mDevSem != NULL);
  1061.     /* private semaphore */
  1062.     if (semTake (pVolDesc->mDevSem, WAIT_FOREVER) == ERROR)
  1063. return ERROR;
  1064.     /* before mount new volume, it have to unmount previous */
  1065.     if (! pVolDesc->unmounted)
  1066. cdromFsVolUnmount (pVolDesc);
  1067.     pVolDesc->pBlkDev->bd_readyChanged = FALSE;
  1068.     /* 
  1069.      * before VD was read let LB size equal to VD size, since
  1070.      * each VD defines its own LB size. Because VD size and LS size are
  1071.      * powers of 2, one may be get from second by means of shift.
  1072.      */
  1073.     VDList.LBSize = ISO_VD_SIZE;
  1074.     VDList.LBToLSShift = cdromFsShiftCount (ISO_VD_SIZE, pVolDesc->sectSize);
  1075.     VDList.pVolDesc = pVolDesc;
  1076.     
  1077.     /* data in buffer remain from unmounted volume, so invalid */
  1078.     LET_SECT_BUF_EMPTY (&(VDList.pVolDesc->sectBuf));
  1079.     
  1080.     /* no one primary VD was found yet */
  1081.     primVDMounted = 0;
  1082.     /* by ISO, first volume descriptor always lays in ISO_PVD_BASE_LS */
  1083.     for (LBRead = ISO_PVD_BASE_LS << VDList.LBToLSShift; ! VDLast ; LBRead ++)
  1084. {
  1085. u_char * pVDData;
  1086. /* read VD from disk */
  1087. pVDData = cdromFsGetLB (&VDList, LBRead, NULL);
  1088. if (pVDData == NULL)
  1089.     {
  1090.     cdromFsVolUnmount (pVolDesc);
  1091.     semGive (pVolDesc->mDevSem);
  1092.     return ERROR;
  1093.     }
  1094. /* check standard ISO volume ID */
  1095. if (strncmp(((T_ISO_VD_HEAD_ID)pVDData)->stdID, ISO_STD_ID ,
  1096.     ISO_STD_ID_SIZE))
  1097.     {
  1098.     /* not ISO volume ID */    
  1099.     /*
  1100.      * may be any unknown VD in set, but not first, that must be
  1101.      * ISO primary VD only (at least in current version)
  1102.      */
  1103.     if (primVDMounted) /* primary have been found already */
  1104. continue;
  1105.     else
  1106. {
  1107. cdromFsVolUnmount (pVolDesc);
  1108.         semGive (pVolDesc->mDevSem);
  1109. logMsg ("Warning: unknown CR-ROM format detected, ignored.n",
  1110. 0,0,0,0,0,0);
  1111. errnoSet (S_cdromFsLib_UNNOWN_FILE_SYSTEM);
  1112. return ERROR;
  1113. }
  1114.     } /* check VD ID */
  1115. /* 
  1116.  * only VD set termination, primary and supplementary VD are 
  1117.  * interesting; and not process secondary copies of primary VD
  1118.  */
  1119. if (((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_SETTERM)
  1120.     VDLast = 1;
  1121. else if ((((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_PRIMARY &&
  1122.   ! primVDMounted) ||
  1123.  ((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_SUPPLEM)
  1124.     {
  1125.     /* first VD on volume must be primary (look ISO 9660) */
  1126.     
  1127.     if (((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_SUPPLEM &&
  1128. ! primVDMounted)
  1129. {
  1130. cdromFsVolUnmount (pVolDesc);
  1131.         semGive (pVolDesc->mDevSem);
  1132. logMsg ("Warning: unknown CR-ROM format detected, ignored.n",
  1133. 0,0,0,0,0,0);
  1134. errnoSet (S_cdromFsLib_UNNOWN_FILE_SYSTEM);
  1135. return ERROR;
  1136. }
  1137.     if (cdromFsVDAddToList (pVolDesc, pVDData, LBRead,
  1138.     VDList.LBToLSShift) == ERROR)
  1139.         {
  1140.         cdromFsVolUnmount (pVolDesc);
  1141.         semGive (pVolDesc->mDevSem);
  1142.         return ERROR;
  1143.         }
  1144.         
  1145.     /* if primary VD found in VD set */
  1146.     
  1147.     if (((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_PRIMARY)
  1148.         primVDMounted = 1;
  1149.     } /* else if */
  1150. } /* for */
  1151.     
  1152.     /* each volume contains at least one, primary volume descriptor. */
  1153.     
  1154.     if (lstFirst(&(pVolDesc->VDList)) == NULL)
  1155. {
  1156. semGive (pVolDesc->mDevSem);
  1157. logMsg ("Warning: unknown CD-ROM format detected, ignored.n",
  1158. 0,0,0,0,0,0);
  1159. errnoSet (S_cdromFsLib_UNNOWN_FILE_SYSTEM);
  1160. return ERROR;
  1161. }
  1162.     /* device successfully mounted */
  1163.     pVolDesc->unmounted = 0;
  1164.     /* return semaphore */
  1165.     if (semGive (pVolDesc->mDevSem) == ERROR)
  1166. {
  1167. cdromFsVolUnmount (pVolDesc);
  1168. errnoSet (S_cdromFsLib_SEMGIVE_ERROR);
  1169. return ERROR;
  1170. }
  1171.     return OK;
  1172.     }
  1173. /*******************************************************************************
  1174. *
  1175. * cdromFsSplitPath - split path to sequential directories/file names.
  1176. *
  1177. * Names in <path> must be separate by '' or '/'. Content of path
  1178. * is changed by the routine.
  1179. * The routine overwrites '/' and '' by '', to break the path to
  1180. * distinct directorys/file names, counting path levels by the way.
  1181. * xx//yy and  xx/./yy cases are just truncated from the path;
  1182. * in xx/../yy case level xx/.. is "caved" from path.
  1183. * As result path looks like just d1d2---dnf.
  1184. *
  1185. * RETURNS: number of names within path or (-1).
  1186. */
  1187. LOCAL int cdromFsSplitPath
  1188.     (
  1189.     u_char * path   /* file / directory path */
  1190.     )
  1191.     {
  1192.     u_char * prevPathLev;
  1193.     u_char      * curName;
  1194.     u_char      * ptr;
  1195.     int lev, pathLen, len;
  1196.     
  1197.     if (*path == EOS)
  1198.      return 0;
  1199.     
  1200.     pathLen = strlen(path) + 1;  /* include EOS */
  1201.     /* 
  1202.      * truncate from path some special cases such as
  1203.      * xx//yy, xx/./yy, xx/../yy and replace '/', '' to ''
  1204.      */
  1205.     curName = path;
  1206.     
  1207.     for (ptr = path, lev = 0 ; ptr != NULL;)
  1208.         {
  1209.         /* find '/' */
  1210.         ptr = (u_char *) strchr (curName, SLASH);
  1211.         if (ptr == NULL)
  1212.             ptr = (u_char *) strchr (curName, BACK_SLASH);
  1213.         
  1214.         if (ptr != NULL)
  1215.             *ptr = EOS;
  1216.      len = strlen (curName) + 1; /* include EOS */
  1217.      pathLen = max (pathLen - len, 0); /* length of the rest */
  1218.     
  1219.         /* xx//yy, xx/./yy */
  1220.      if ((*curName == POINT && *(curName + 1) == EOS) ||
  1221.     (*curName == EOS))
  1222.          {
  1223.          memmove(curName, curName + len, pathLen);
  1224.          }
  1225.      /* xx/../yy, in this case 'xx' will be deleted from path */
  1226.     
  1227. else if (*curName == POINT && *(curName + 1) == POINT &&
  1228.  *(curName + 2) == EOS)
  1229.          {
  1230.          /* return to the previous level name (if it may be done) */
  1231.          if (lev > 0)
  1232.           {
  1233. for (prevPathLev = curName - 2;
  1234.      *(prevPathLev - 1) != EOS && prevPathLev != path;
  1235.      prevPathLev --);
  1236.           }
  1237.          else
  1238. {
  1239. *path = EOS;
  1240.              return (0);
  1241.              }
  1242.  
  1243.          /* go one level down */
  1244.     
  1245.          memmove (prevPathLev, curName + len, pathLen);
  1246.          curName = prevPathLev;
  1247.          lev --;
  1248.          }
  1249.      /* normal case */
  1250. else
  1251.     {
  1252.     lev ++;
  1253.     curName += len;
  1254.     }
  1255. } /* for */
  1256.     
  1257.     return lev;
  1258.     }
  1259. /*******************************************************************************
  1260. * cdromFsFillFDForDir - fill T_CDROM_FILE for directory (only from PT record).
  1261. *
  1262. * This routine fill in fields of T_CDROM_FILE structure (ptr on with
  1263. * comes in <pFD>) for directory, that is described by <pPTRec> PT record
  1264. *
  1265. * RETURNS: OK or ERROR if malloc() or disk access error occur.
  1266. */
  1267. LOCAL STATUS cdromFsFillFDForDir
  1268.     (
  1269.     T_CDROMFS_VD_LST_ID pVDList,        /* ptr to VD list               */
  1270.     T_CDROM_FILE_ID pFD, /* FD to fill                   */
  1271.     u_char *         pPTRec, /* directory PT record          */
  1272.     u_int         dirRecNumInPT, /* dir number in PT             */
  1273.     u_int         dirRecOffInPT /* dir rec offset from PT start */
  1274.     )
  1275.     {
  1276.     u_short EARSize;
  1277.     
  1278.     assert (pVDList != NULL);
  1279.     assert (pVDList->magic == VD_LIST_MAG);
  1280.     assert (pVDList->pVolDesc != NULL);
  1281.     assert (pVDList->pVolDesc->magic == VD_SET_MAG);
  1282.     assert (pFD != NULL);
  1283.     assert (pPTRec != NULL);
  1284.     assert (*pPTRec != 0); /* DIR ID Length */
  1285.         
  1286.     /* 
  1287.      * These fields are not needed to be filled for a directory:
  1288.      * pFD->parentDirPTOffset;
  1289.      * pFD->parentDirStartLB;
  1290.      * pFD->FFirstRecLBNum;
  1291.      * pFD->FFirstDirRecOffInDir;
  1292.      * pFD->FFirstDirRecOffInLB;
  1293.      * pFD->FRecords;
  1294.      * pFD->FCSStartLB;
  1295.      * pFD->FCSFUSizeLB;
  1296.      * pFD->FCSGapSizeLB;
  1297.      * pFD->FCDOffInMDU;
  1298.      * pFD->FCMDUStartLB;
  1299.      */
  1300.     
  1301.     bzero (pFD->name, sizeof (pFD->name));
  1302.     bcopy (pPTRec + ISO_PT_REC_DI, pFD->name, *pPTRec);
  1303.     
  1304.     PT_PARENT_REC (pFD->parentDirNum, pPTRec);
  1305.     C_BUF_TO_LONG (pFD->FStartLB, pPTRec, ISO_PT_REC_EXTENT_LOCATION);
  1306.     EARSize = *(pPTRec + ISO_PT_REC_EAR_LEN);
  1307.     pFD->FStartLB += EARSize;
  1308.     pFD->FDataStartOffInLB = 0;
  1309.     
  1310.     /* 
  1311.      * Directory is stored as one extension, without records and 
  1312.      * interleaving 
  1313.      */
  1314.     pFD->FMDUType = EAR_REC_FORM_IGNORE;
  1315.     pFD->FMDUSize = 0;
  1316.     pFD->FCSInterleaved = CDROM_NOT_INTERLEAVED;
  1317.     
  1318.     pFD->FType = S_IFDIR;
  1319.     
  1320.     /* init buffer for device access */
  1321.     if (cdromFsSectBufAlloc (pVDList->pVolDesc, &(pFD->sectBuf), 0) == ERROR)
  1322.      return ERROR;
  1323.     
  1324.     /* current condition for readDir call */
  1325.     pFD->FCDirRecNum = 0;
  1326.     pFD->FCDirRecAbsOff = 0;
  1327.     pFD->FCDirRecOffInLB= 0;
  1328.     pFD->FCDirRecLB = pFD->FStartLB;
  1329.     pFD->FCSAbsOff = 0;           /* start position */
  1330.     pFD->FCSSequenceSetNum  = pVDList->volSeqNum;
  1331.     pFD->FDType = (u_short)(-1);  /* not one request was served */
  1332.     pFD->FCDAbsLB = pFD->FStartLB;
  1333.     pFD->FCDAbsPos = 0;
  1334.     pFD->FCDOffInLB = 0;
  1335.     pFD->FNumRecs = 0;
  1336.     pFD->FCEOF = 0;
  1337.     
  1338.     /* some directory specific fields */
  1339.     pFD->DNumInPT = dirRecNumInPT;
  1340.     pFD->DRecOffInPT = dirRecOffInPT;
  1341.     pFD->DRecLBPT = 0; /* 
  1342.  * TBD: not need currently. May be counted in
  1343.       * principal by parent function 
  1344.  */
  1345.     pFD->DRecOffLBPT = 0;
  1346.     /* read first directory record and get special dir descriptions */
  1347.     pPTRec = cdromFsGetLB (pVDList, pFD->FStartLB, &(pFD->sectBuf));
  1348.     if (pPTRec == NULL)
  1349.      {
  1350.      cdromFsSectBufFree (&(pFD->sectBuf));
  1351.         return ERROR;
  1352.         }
  1353.     pFD->FCDirRecPtr = pPTRec;
  1354.     
  1355.     /* first directory record must contain 0x00 as name */
  1356.     if (*(pPTRec + ISO_DIR_REC_FI) != 0)
  1357.         {
  1358.         errnoSet (S_cdromFsLib_INVALID_DIRECTORY_STRUCTURE);
  1359.      cdromFsSectBufFree (&(pFD->sectBuf));
  1360.         return ERROR;
  1361.         }
  1362.     
  1363.     C_BUF_TO_LONG (pFD->FSize, pPTRec, ISO_DIR_REC_DATA_LEN);
  1364.     pFD->FCSSize = pFD->FSize;
  1365.     pFD->FCSSizeLB = A_PER_B (pVDList->LBSize, pFD->FCSSize);
  1366.     pFD->FCSFlags = *(pPTRec + ISO_DIR_REC_FLAGS);
  1367.     
  1368.     /* fill FAbsTime field (u_long time format) */
  1369.     pFD->FDateTime = *(T_FILE_DATE_TIME_ID)(pPTRec +
  1370.  ISO_DIR_REC_DATA_TIME);
  1371.     pFD->pVDList = pVDList;
  1372.     pFD->volUnmount = 0;    
  1373.     pFD->magic = FD_MAG;
  1374.     
  1375.     /* connect to volume's FD list */
  1376.     if (!pFD->inList)
  1377.      lstAdd (&(pVDList->pVolDesc->FDList), (NODE *)pFD);
  1378.     pFD->inList = 1;
  1379.     
  1380.     return OK;
  1381.     }
  1382. /*******************************************************************************
  1383. *
  1384. * cdromFsFillFDForFile - fill T_CDROM_FILE for file (from file's dir record).
  1385. *
  1386. * At the beginning, pFD points to FD, which contains description of file
  1387. * parent directory, and exact file's entry as encounted over
  1388. * internal cdromFsIoctl readDir calls.
  1389. * This routine fill in the fields of T_CDROM_FILE structure, pointed by <pFD>,
  1390. * for file, exchanging its previous content.
  1391. *
  1392. * RETURNS: OK or ERROR.
  1393. */
  1394. LOCAL STATUS cdromFsFillFDForFile
  1395.     (
  1396.     T_CDROMFS_VD_LST_ID pVDList,        /* ptr to vol desc list */
  1397.     T_CDROM_FILE_ID pFD /* FD to fill, containing parent */
  1398.      /* directory description currently */
  1399.     )
  1400.     {
  1401.     T_CDROM_FILE   workFD;
  1402.     u_short    EARSize;
  1403.     u_char *    pDirRec;
  1404.     u_long    dirRecsTotSize; /* all file's dir records total size */
  1405.     struct tm    recTime;
  1406.     
  1407.     assert (pVDList != NULL);
  1408.     assert (pVDList->magic == VD_LIST_MAG);
  1409.     assert (pFD != NULL);
  1410.         
  1411.     /* count total size file's dir records */
  1412.     
  1413.     /* for return to current state, let store pFD */
  1414.     workFD = *pFD;
  1415.     
  1416.     /* skip all records */
  1417.     do
  1418.      {
  1419. dirRecsTotSize = *(pFD->FCDirRecPtr);
  1420.     while (cdromFsSkipDirRec (pFD, DRF_LAST_REC) == OK);
  1421.     
  1422.     /* restore initial state */
  1423.     RESTORE_FD (workFD, *pFD, ERROR);
  1424.     
  1425.     /* ptr to first file's dir record */
  1426.     pDirRec = pFD->FCDirRecPtr;
  1427.     /* init workFD */
  1428.     bzero (&workFD, sizeof(workFD));
  1429.     workFD.sectBuf = pFD->sectBuf;
  1430.     workFD.FRecords = malloc (dirRecsTotSize);
  1431.     if (workFD.FRecords == NULL)
  1432.      return ERROR;
  1433.     
  1434.     /* fill static file data */
  1435.     bcopy (pDirRec + ISO_DIR_REC_FI, workFD.name,
  1436.    *(pDirRec + ISO_DIR_REC_LEN_FI));
  1437.     
  1438.     C_BUF_TO_LONG (workFD.FStartLB, pDirRec, ISO_DIR_REC_EXTENT_LOCATION);
  1439.     EARSize = *(pDirRec + ISO_DIR_REC_EAR_LEN);
  1440.     
  1441.     workFD.FStartLB += EARSize;
  1442.     workFD.FDataStartOffInLB = 0;
  1443.     workFD.FFirstRecLBNum = pFD->FCDirRecLB;
  1444.     workFD.FFirstDirRecOffInLB = pFD->FCDirRecOffInLB;
  1445.     
  1446.     workFD.FType = S_IFREG;
  1447.     
  1448.     /* fill FAbsTime field (u_long time format) */
  1449.     workFD.FDateTime = *(T_FILE_DATE_TIME_ID)(pDirRec +
  1450.  ISO_DIR_REC_DATA_TIME);
  1451.     
  1452.     recTime.tm_sec =  pFD->FDateTime.seconds;
  1453.     recTime.tm_min =  pFD->FDateTime.minuts;
  1454.     recTime.tm_hour =  pFD->FDateTime.hour;
  1455.     recTime.tm_mday =  pFD->FDateTime.day;
  1456.     recTime.tm_mon =  pFD->FDateTime.month - 1;
  1457.     recTime.tm_year =  pFD->FDateTime.year;
  1458.     
  1459.     workFD.FDateTimeLong = mktime(&recTime);
  1460.     
  1461.     /* parent directory description */
  1462.     workFD.parentDirNum = pFD->DNumInPT;
  1463.     workFD.parentDirPTOffset = pFD->DRecOffInPT;
  1464.     workFD.parentDirStartLB = pFD->FStartLB;
  1465.     
  1466.     /* current file section description */
  1467.     C_BUF_TO_LONG (workFD.FCSSize, pDirRec, ISO_DIR_REC_DATA_LEN);
  1468.     workFD.FCSSizeLB = A_PER_B(pVDList->LBSize, workFD.FCSSize);
  1469.     workFD.FCSFlags = *(pDirRec + ISO_DIR_REC_FLAGS);
  1470.     
  1471.     /*  interleaving */
  1472.     workFD.FCSFUSizeLB = *(pDirRec + ISO_DIR_REC_FU_SIZE);
  1473.     workFD.FCSGapSizeLB = *(pDirRec + ISO_DIR_REC_IGAP_SIZE);
  1474.     workFD.FCSInterleaved = (workFD.FCSFUSizeLB)? CDROM_INTERLEAVED :
  1475.                                                 CDROM_NOT_INTERLEAVED;
  1476.     /* TBD: read EAR and time and permissions init */
  1477.     
  1478.     workFD.FCDirRecNum = 0;
  1479.     workFD.FCSAbsOff = 0; /* start position */
  1480.     C_BUF_TO_SHORT (workFD.FCSSequenceSetNum, pDirRec, ISO_DIR_REC_VOL_SEQU_N);
  1481.     
  1482.     workFD.FCSStartLB = workFD.FStartLB;
  1483.     
  1484.     /* current data position */
  1485.     workFD.FCDAbsLB = workFD.FStartLB;
  1486.     workFD.FCDAbsPos = 0;
  1487.     workFD.FCDOffInLB = 0; /* only EAR prefaces data itself */
  1488.     workFD.FCEOF = 0;
  1489.     
  1490.     /* fill in file's dir records buffer and count file length */
  1491.     assert (workFD.FRecords != NULL);
  1492.     pDirRec = workFD.FRecords;
  1493.     workFD.FSize = 0;
  1494.     do
  1495.      {
  1496. bcopy (pFD->FCDirRecPtr, pDirRec, *(pFD->FCDirRecPtr));
  1497. C_BUF_TO_LONG (dirRecsTotSize, pDirRec, ISO_DIR_REC_DATA_LEN);
  1498. workFD.FSize += dirRecsTotSize;
  1499. pDirRec += *(pFD->FCDirRecPtr);
  1500. }
  1501.     while (cdromFsSkipDirRec(pFD, DRF_LAST_REC) == OK);
  1502.     
  1503.     workFD.FCDirRecPtr = workFD.FRecords;
  1504.     workFD.pVDList = pVDList;
  1505.     workFD.volUnmount = 0;    
  1506.     workFD.magic = FD_MAG;
  1507.     
  1508.     /* pFD already in FD-list (so comes) */
  1509.     workFD.list = pFD->list;
  1510.     workFD.inList = 1;
  1511.     
  1512.     *pFD = workFD;    
  1513.     
  1514.     return OK;
  1515.     }
  1516. /*******************************************************************************
  1517. *
  1518. * cdromFsStrUp - to convert string to upper case.
  1519. *
  1520. * RETURNS: N/A.
  1521. */
  1522. LOCAL void cdromFsStrUp
  1523.     (
  1524.     u_char * str,  /* string */
  1525.     int len           /* length */
  1526.     )
  1527.     {
  1528.     for (len --; len >= 0; len --)
  1529.      str[len] = toupper(str[len]);
  1530.     }
  1531. /*******************************************************************************
  1532. *
  1533. * cdromFsFindFileInDir - to find file in given directory.
  1534. *
  1535. * This routine searches directory, described by <pFD> for name <name>.
  1536. * If <name> includes version number (xxx{;ver num}), it's considered
  1537. * as absolute file name, If no version supplied (xx[;]),
  1538. * routine searches directory for last file version.
  1539. * If file found, cdromFsFillFDForFile() is called, to refill
  1540. * <pFD> fields for file.
  1541. *
  1542. * RETURNS: OK if file found and <pFD> refilled, or ERROR.
  1543. */
  1544. LOCAL STATUS cdromFsFindFileInDir
  1545.     (
  1546.     T_CDROMFS_VD_LST_ID pVDList,  /* ptr to volume descriptor list */
  1547.     T_CDROM_FILE_ID pFD,      /* cdrom file descriptor ID */
  1548.     u_char * name,             /* file name */
  1549.     u_char * pPTRec,           /* ptr to path table record */
  1550.     u_int dirRecNumInPT,    /* dir record no. in path table */
  1551.     u_int dirRecOffInPT     /* dir record offset in path table */
  1552.     )
  1553.     {
  1554.     DIR            dir;
  1555.     BOOL absName = FALSE;
  1556.     T_CDROM_FILE   bufFD;
  1557.     char *    pChar;
  1558.     char           found;
  1559.     
  1560.     assert (pVDList != NULL);
  1561.     assert (pFD != NULL);
  1562.     assert (name != NULL);
  1563.     
  1564.     DBG_MSG(300)("name = %sn", name);
  1565.     
  1566.     /* what is the name, - absolute or to find last version? */
  1567.     pChar = strchr (name, SEMICOL);
  1568.     if (pChar != NULL) 
  1569. {
  1570. if (isdigit (*(pChar + 1)))
  1571.     absName = TRUE;
  1572. else
  1573.     *(pChar) = EOS;
  1574. }
  1575.     found = 0;
  1576. retry:
  1577.     while (cdromFsIoctl (pFD, FIOREADDIR, (int)&dir) == OK)
  1578.      {
  1579.      int compRes;
  1580.     
  1581. /* truncate current name in case last version search */
  1582. if (!absName)
  1583.     {
  1584.     pChar = strchr(dir.dd_dirent.d_name, SEMICOL);
  1585.     if (pChar != NULL)
  1586.         *pChar = EOS;
  1587.     }
  1588. compRes = strcmp (name, dir.dd_dirent.d_name);
  1589.     
  1590. /* names in dir are sorted lexicographically */
  1591. if (!absName && compRes < 0)
  1592.     break;
  1593. /* any version of file found */
  1594. if (compRes == 0)
  1595.     {
  1596.     found = 1;
  1597.     /* if requested version */
  1598.     if (absName)
  1599.              return (cdromFsFillFDForFile (pVDList, pFD));
  1600.          
  1601.     bufFD = *pFD; /* safe found */
  1602.          }
  1603.      } /* while */
  1604.     
  1605.     if (found == 0)
  1606.      {
  1607. /* case sensitive not found */
  1608.         if (cdromFsFillFDForDir (pVDList, pFD, pPTRec, dirRecNumInPT,
  1609.           dirRecOffInPT) == ERROR)
  1610.     return ERROR;
  1611. cdromFsStrUp (name, strlen(name));
  1612.      found = (char)(-1); /* case insensitive */
  1613. goto retry;
  1614. }
  1615.     
  1616.     if(found == (char)(-1))
  1617.      return ERROR; /* not case sensitive nor insensitive found */
  1618.     RESTORE_FD (bufFD, *pFD, ERROR); /* return to a last found version */
  1619.     return (cdromFsFillFDForFile(pVDList, pFD));
  1620.     }
  1621.     
  1622. /*******************************************************************************
  1623. *
  1624. * cdromFsFindDirOnLevel - find directory within given PT dir hierarchy level.
  1625. *
  1626. * This routine trys to find <name> within <dirLev>
  1627. * PT dir hierarchy level, that have parent dir number <parDirNum>.
  1628. * <pPT> points to PT buffer.
  1629. * In <pPTRec> will be returned ptr to found PT record (if will).
  1630. *
  1631. * RETURNS: record number or 0 if not found.
  1632. */
  1633. LOCAL int cdromFsFindDirOnLevel
  1634.     (
  1635.     T_CDROMFS_VD_LST_ID pVDList, /* ptr to volume descriptor list */
  1636.     u_char * name,    /* dir name to search for (EOS terminated) */
  1637.     u_char * pPT,  /* PT buffer */
  1638.     u_int parDirNum,  /* evidently */
  1639.     u_int pathLev,  /* level of <name> within path */
  1640.       /* first path name lays on */
  1641.       /* zero path level, but on second dir */
  1642.       /* hierarchy level, so */
  1643.     u_char ** ppRecord  /* address of current PT record ptr */
  1644.     )
  1645.     {
  1646.     int offset;        /* abs offset from PT start */
  1647.     u_char * pUpCaseName = NULL;   /* ptr to upper case name found */
  1648.     u_short recNum;    /* current record number */
  1649.     u_short upCaseRecNum = 0;  /* record number of upper case name found */
  1650.     u_short curRecParent;    /* current record's parent record number */
  1651.     u_short nameLen;    /* <name> length */
  1652.     u_char upCaseName[100] = {EOS};
  1653.     
  1654.     /* 
  1655.      * let us path = "/d0/d1/---[/fname]"
  1656.      * first path name <d0> lays on zero path level, but on second directory
  1657.      * hierarchy level, so if Level is dir hierarchy level, on which
  1658.      * lays <name>, Level = <pathLev>+2, and therefore <pathLev> may
  1659.      * be used for encounting  dir hierarchy levels' bounds arrays.
  1660.      */
  1661.     offset = pVDList->dirLevBordersOff[ pathLev ]; 
  1662.     pPT += offset;
  1663.     recNum = (pathLev == 0)? 2: pVDList->dirLevLastRecNum[ pathLev -1 ] + 1;
  1664.     nameLen = strlen(name);
  1665.     strncpy (upCaseName, name, nameLen + 1);
  1666.     cdromFsStrUp (upCaseName, nameLen);
  1667.     
  1668.     for (; recNum <= pVDList->dirLevLastRecNum[ pathLev ]; 
  1669.  recNum ++, offset = cdromFsNextPTRec(&pPT, offset, pVDList->PTSize))
  1670. {
  1671. int compRes; /* strncmp result */
  1672. PT_PARENT_REC (curRecParent, pPT);
  1673. if (curRecParent != parDirNum || nameLen != (u_short)*pPT)
  1674.     continue;
  1675. compRes = strncmp(name, pPT + ISO_PT_REC_DI, nameLen);
  1676. if (compRes == 0)
  1677.     {
  1678.     *ppRecord = pPT;
  1679.     return recNum;
  1680.     }
  1681. else if (strncmp(upCaseName, pPT + ISO_PT_REC_DI, nameLen) == 0)
  1682.     {
  1683.     pUpCaseName = pPT;
  1684.     upCaseRecNum = recNum;
  1685.     }
  1686. else if (compRes < 0) /* PT records are sorted by name increasing */
  1687.     break;
  1688. }
  1689.     
  1690.     if (pUpCaseName == NULL) /* not found */
  1691.      return 0;
  1692.     
  1693.     /* name found in upper case only */
  1694.     *ppRecord = pUpCaseName;
  1695.     return (upCaseRecNum);
  1696.     }
  1697.     
  1698. /*******************************************************************************
  1699. *
  1700. * cdromFsFindPathInDirHierar - find file/directory within given dir hierarchy.
  1701. *
  1702. * This routine tries to find <path> within given VD dir hierarchy.
  1703. * and fill in T_CDROM_FILE structure.
  1704. * Path levels (dir/file names) have to be splitted by EOS.
  1705. *
  1706. * RETURNS: OK or ERROR if path not found.
  1707. */
  1708. LOCAL STATUS cdromFsFindPathInDirHierar
  1709.     (
  1710.     T_CDROMFS_VD_LST_ID pVDList, /* ptr to volume desc list */
  1711.     u_char * path,            /* path */
  1712.     u_int numPathLevs,   /* number of names in path */
  1713.     T_CDROM_FILE_ID pFD,  /* FD to fill if full path found */
  1714.     int options  /* not used currently */
  1715.     )
  1716.     {
  1717.     int curPathLev, parDirNum;
  1718.     u_char * pPT;
  1719.     u_char * pPTRec;
  1720.     STATUS retStat = ERROR;
  1721.     
  1722.     assert (pVDList != NULL);
  1723.     assert (path != NULL);
  1724.     assert (pFD != NULL);
  1725.     
  1726.     /* 
  1727.      * numPathLevs may not exceed number of directory hierarchy levels
  1728.      * plus one for file name
  1729.      */
  1730.     if(numPathLevs > pVDList->numDirLevs + 1)
  1731.         return ERROR;
  1732.         
  1733.     pPT = cdromFsPTGet (pVDList, NULL);
  1734.     if (pPT == NULL)
  1735. goto ret;
  1736.     for (curPathLev = 0, parDirNum = 1, pPTRec = pPT;
  1737.  curPathLev < numPathLevs && curPathLev < pVDList->numDirLevs;
  1738.  path += strlen(path) + 1)
  1739. {
  1740. parDirNum = cdromFsFindDirOnLevel (pVDList, path, pPT, parDirNum,
  1741.    curPathLev, &pPTRec);
  1742. curPathLev++;
  1743. if (parDirNum == 0) /* last name not found */
  1744.     break;
  1745. }
  1746.     
  1747.     if (curPathLev == numPathLevs ||
  1748. (curPathLev == numPathLevs - 1 && parDirNum != 0 &&
  1749.  curPathLev == pVDList->numDirLevs)
  1750. )
  1751. {
  1752.         retStat = cdromFsFillFDForDir (pVDList, pFD, pPTRec, parDirNum,
  1753.        0 /* not use now, since PT is read
  1754.   * wholly */
  1755.        );
  1756.           
  1757.         if (retStat == ERROR || (parDirNum != 0 && curPathLev == numPathLevs))
  1758.     /* path found */
  1759.     goto ret;
  1760.         }
  1761.     else
  1762.      goto ret;
  1763.     
  1764.     retStat = cdromFsFindFileInDir (pVDList, pFD, path, pPTRec, parDirNum, 0);
  1765.     
  1766. ret:
  1767.     return retStat;
  1768.     }
  1769.     
  1770. /*******************************************************************************
  1771. *
  1772. * cdromFsFindPath - find file/directory on given volume.
  1773. *
  1774. * This routine trys to find <path> within all volume
  1775. * primary/supplementary directory hierarcies and creates and fills in
  1776. * T_CDROM_FILE structure for following accsess.
  1777. * levels in path have to be splitted by '' or '/'.
  1778. *
  1779. * ERRNO: S_cdromFsLib_MAX_DIR_LEV_OVERFLOW
  1780. * S_cdromFsLib_NO_SUCH_FILE_OR_DIRECTORY
  1781. *
  1782. * RETURNS: T_CDROM_FILE_ID or NULL if any error encounted.
  1783. */
  1784. LOCAL T_CDROM_FILE_ID cdromFsFindPath
  1785.     (
  1786.     CDROM_VOL_DESC_ID pVolDesc,   /* ptr to volume descriptor */
  1787.     u_char * path,               /* path */
  1788.     int options                     /* search options */
  1789.     )
  1790.     {
  1791.     T_CDROMFS_VD_LST_ID pVDList;
  1792.     T_CDROM_FILE_ID pFD;
  1793.     u_char pPath[ CDROM_MAX_PATH_LEN + 1 ] = {EOS};
  1794.     u_int numPathLevs;
  1795.     
  1796.     assert (pVolDesc != NULL);
  1797.     assert (path != NULL);
  1798.     
  1799. #ifndef ERR_SET_SELF
  1800.     errnoSet(OK);
  1801. #else
  1802.     errno = OK;
  1803. #endif
  1804.     
  1805.     /* prepare path for processing (split to distinct directorys/file names) */
  1806.     strncpy (pPath, path, CDROM_MAX_PATH_LEN);
  1807.     path = pPath;
  1808.     
  1809.     numPathLevs = cdromFsSplitPath (path);
  1810.     
  1811.     if (numPathLevs == (-1))
  1812. return (T_CDROM_FILE_ID)ERROR;
  1813.     
  1814.     if (numPathLevs > CDROM_MAX_DIR_LEV + 1) /* one for file */
  1815.      {
  1816.      errnoSet (S_cdromFsLib_MAX_DIR_HIERARCHY_LEVEL_OVERFLOW);
  1817. return (T_CDROM_FILE_ID) ERROR;
  1818.      }
  1819.     
  1820.     /* allocate T_CDROM_FILE structure */
  1821.     pFD = cdromFsFDAlloc (pVolDesc);
  1822.     if (pFD == NULL)
  1823. return (T_CDROM_FILE_ID)ERROR;
  1824.     
  1825.     for (pVDList = (T_CDROMFS_VD_LST_ID) lstFirst (&(pVolDesc->VDList));
  1826.        pVDList != NULL;
  1827.        pVDList = (T_CDROMFS_VD_LST_ID) lstNext ((NODE *)pVDList))
  1828.      {
  1829. if (cdromFsFindPathInDirHierar (pVDList, path, numPathLevs,
  1830. pFD, options) == OK)
  1831.     return pFD;
  1832. }
  1833.     
  1834.     /* file/directory not found */
  1835.     cdromFsFDFree (pFD);
  1836.     if (errnoGet() == OK)
  1837. errnoSet (S_cdromFsLib_NO_SUCH_FILE_OR_DIRECTORY);
  1838.     return (T_CDROM_FILE_ID)ERROR;
  1839.     }
  1840. /*******************************************************************************
  1841. *
  1842. * cdromFsFillStat - filling of stat structure 
  1843. *
  1844. * This routine transfers data from T_CDROM_FILE structure to stat structure
  1845. * defined in <sys/stat.h>
  1846. *
  1847. * RETURNS: OK or ERROR if it cannot fill stat structure
  1848. */
  1849. LOCAL STATUS cdromFsFillStat
  1850.     (
  1851.     T_CDROM_FILE_ID fd,                 /* File descriptor */
  1852.     struct stat * arg                   /* Pointer to stat structure */
  1853.     )
  1854.     {
  1855.     u_char *ptr;                        /* pointer to LogBlock       */
  1856.     struct tm recTime; /* temp. structure           */
  1857.     short tmp = 0;         /* to form permission flags  */
  1858.     short tmp2 = 0;         /* to convert flags from EAR */
  1859.     
  1860.     arg->st_blksize = fd->pVDList->LBSize;   /* We read by LogBlocks */
  1861.     
  1862.     if (fd->FType == S_IFDIR) /* In the case of directory */
  1863.         {
  1864.         ptr = cdromFsGetLB (fd->pVDList, fd->FStartLB, &(fd->sectBuf));
  1865.         if (ptr == NULL)
  1866.             return ERROR;
  1867.         /* pointer to a sequence of Dir. Records, not data */
  1868.         ptr += fd->FDataStartOffInLB;
  1869.         }
  1870.     else
  1871. {
  1872. ptr = fd->FRecords; /* In the case of File Section */
  1873. }    
  1874.     arg->st_size = fd->FSize;    
  1875.     arg->st_blocks = A_PER_B (fd->pVDList->LBSize, fd->FSize);
  1876.     
  1877.     /* time fields */
  1878.     recTime.tm_sec = fd->FDateTime.seconds;
  1879.     recTime.tm_min = fd->FDateTime.minuts;
  1880.     recTime.tm_hour = fd->FDateTime.hour;
  1881.     recTime.tm_mday = fd->FDateTime.day;
  1882.     recTime.tm_mon = fd->FDateTime.month - 1;
  1883.     recTime.tm_year = fd->FDateTime.year;
  1884.     fd->FDateTimeLong = mktime (&recTime);
  1885.     /*
  1886.      * The DOS-FS time fields are not supported from VxWorks 5.2
  1887.      * and above, but REQUIRED for 5.1.1 and lower to see valid
  1888.      * file dates.
  1889.      */
  1890. #ifdef VXWORKS_511
  1891.     arg->st_fYear = fd->FDateTime.year + 1900;
  1892.     arg->st_fMonth = fd->FDateTime.month;
  1893.     arg->st_fDay = fd->FDateTime.day;
  1894.     arg->st_fHour = fd->FDateTime.hour;
  1895.     arg->st_fMinute = fd->FDateTime.minuts;
  1896.     arg->st_fSecond = fd->FDateTime.seconds;
  1897.     fd->FDateTimeLong = 0;
  1898. #endif /* VXWORKS_511 */
  1899.     arg->st_atime = arg->st_mtime = arg->st_ctime = fd->FDateTimeLong;
  1900.     
  1901.     /* bits of permissions  processing */
  1902.     
  1903.     if (*(ptr + ISO_DIR_REC_FLAGS) & DRF_PROTECT)
  1904.         {
  1905.         if (*(ptr + ISO_DIR_REC_EAR_LEN) == 0) /* EAR must appear */
  1906.             {
  1907.             errnoSet (S_cdromFsLib_INVALID_DIR_REC_STRUCT);
  1908.             return ERROR;
  1909.             }
  1910.         /* Read ExtAttrRecord */
  1911.         ptr = cdromFsGetLB (fd->pVDList,
  1912.     fd->FStartLB - *(ptr + ISO_DIR_REC_EAR_LEN),
  1913.     &(fd->sectBuf));
  1914.         if (ptr == NULL)
  1915.             return ERROR;
  1916.             
  1917.         /*
  1918.  * Now we should transfer permission bits from ExtAttrRec    
  1919.  * Sequential reading of two bytes (processor independent)       
  1920.  */
  1921.         tmp2 = (*(ptr + ISO_EAR_PERMIT) << 8) |
  1922.                *(ptr + ISO_EAR_PERMIT + 1);
  1923.         tmp |= (tmp2 & 0x01) ? 0 : S_IROTH;
  1924.         tmp |= (tmp2 & 0x04) ? 0 : S_IXOTH;  
  1925.         tmp |= (tmp2 & 0x10) ? 0 : S_IRUSR;
  1926.         tmp |= (tmp2 & 0x40) ? 0 : S_IXUSR;
  1927.         tmp |= (tmp2 & 0x100) ? 0 : S_IRGRP;
  1928.         tmp |= (tmp2 & 0x400) ? 0 : S_IXGRP;
  1929.         tmp |= (tmp2 & 0x1000) ? 0 : S_IROTH;
  1930.         tmp |= (tmp2 & 0x4000) ? 0 : S_IXOTH;  
  1931.         }
  1932.     else
  1933.         {
  1934. /* Every user has rights to read and execute */
  1935.         tmp = S_ISUID | S_ISGID | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
  1936.               S_IXGRP | S_IROTH | S_IXOTH;
  1937.         }
  1938.     arg->st_mode = fd->FType | tmp;             /* not fd->FDType */
  1939.     return OK;
  1940.     }
  1941. /*******************************************************************************
  1942. *
  1943. * cdromFsCountMdu - counts current position offset in MDU 
  1944. *
  1945. * This function counts only one value contained in a file descriptor of
  1946. * cdromFs system - FCDOffInMDU. For this purpose reading of the file itself
  1947. * is necessary (sequential, record after record). It is assumed that
  1948. * absolute position of file pointer is written in the fd, and the previous
  1949. * file pointer position is the second parametr
  1950. * NOW WE DON'T SUPPORT RECORD STRUCTURES IN FILES.
  1951. *
  1952. * RETURNS : OK or ERROR 
  1953. */
  1954. LOCAL STATUS cdromFsCountMdu
  1955.     (
  1956.     T_CDROM_FILE_ID fd,                         /* File descriptor        */
  1957.     int prevOffs  /* AbsPos before "seek"   */ 
  1958.     )
  1959.     {
  1960.     u_long lowBound;                            /*  low bound of a record */ 
  1961.     
  1962.     if (fd->FCDAbsPos >= prevOffs)                  /* Initial settings */
  1963.         {
  1964.         /* to the beginning of current MDU */
  1965.         lowBound = prevOffs - fd->FCDOffInMDU; 
  1966.         if (fd->FMDUType & CDROM_MDU_TYPE_FIX)
  1967.             lowBound -= 0;  /* fixed length record has only even last byte */
  1968.         else if (fd->FMDUType & CDROM_MDU_TYPE_VAR_LE || 
  1969.  fd->FMDUType & CDROM_MDU_TYPE_VAR_BE)
  1970.             lowBound -= 0;    /* variable-length record */
  1971.         else
  1972.             return ERROR;          /* Unknown type of records */
  1973. }
  1974.     /*  THAT'S ALL: WE DON'T SUPPORT RECORD STRUCTURES NOW ! */
  1975.     
  1976.     return OK;       
  1977.     }
  1978. /*******************************************************************************
  1979. *
  1980. *  cdromFsFillPos - fills some fields in fd after executing "seek"
  1981. *
  1982. * That's the very simple function. The only thing it implements -
  1983. * filling of fields in T_CDROM_FILE structure after changing of 
  1984. * a file pointer position
  1985. *
  1986. * RETURNS: OK
  1987. */
  1988. LOCAL STATUS cdromFsFillPos
  1989.     (
  1990.     T_CDROM_FILE_ID fd,  /* pointer to the file descriptor                */  
  1991.     u_char *PrevDirPtr,  /* pointer to DirRec includes point requested    */
  1992.     short i,             /* The seq.number of DirRec with requested point */ 
  1993.     int len,             /* length of all File Sections from 0 to current */
  1994.     int NewOffs          /* the offset (arg from ioctl).It's always < len */
  1995.     )
  1996.     {
  1997.     int tmp = 0;         /* temp.buffer */
  1998.     int tmp2 = 0;        /* temp.buffer */
  1999.     /*  We know the only File Section, contains the position needed       */
  2000.     fd->FCDirRecPtr = PrevDirPtr;
  2001.     fd->FCDirRecNum = i;
  2002.                
  2003.     /* absolute number of LB, which contains current FileDirRec */
  2004.     C_BUF_TO_LONG (fd->FCSStartLB, PrevDirPtr, ISO_DIR_REC_EXTENT_LOCATION);
  2005.     /* Section data start LB depends on ExtAttrRec inclusion in FileSect  */
  2006.     fd->FCSStartLB += *(PrevDirPtr + ISO_DIR_REC_EAR_LEN);
  2007.     C_BUF_TO_LONG (fd->FCSSize, PrevDirPtr, ISO_DIR_REC_DATA_LEN);
  2008.     fd->FCSSizeLB = A_PER_B(fd->pVDList->LBSize, fd->FCSSize);
  2009.     fd->FCSAbsOff = len - fd->FCSSize;
  2010.     tmp = (NewOffs - fd->FCSAbsOff) / fd->pVDList->LBSize; 
  2011.     if (fd->FCSInterleaved)
  2012.         {
  2013.         /* Now we should insert 'logical block gaps' if interleaved */
  2014.         
  2015. tmp2 = A_PER_B(fd->FCSFUSizeLB, tmp);         /* Number of gaps */
  2016.         tmp += (tmp2 - 1)  * fd->FCSGapSizeLB;        /* Full gap */
  2017.         }
  2018.     fd->FCDAbsLB = fd->FCSStartLB + tmp;
  2019.           
  2020.     fd->FCDOffInLB = (NewOffs - fd->FCSAbsOff) %  fd->pVDList->LBSize;
  2021.     fd->FCDAbsPos = NewOffs;
  2022.     /* MDU (file records structures) are not supported */
  2023.     return OK;      
  2024.     }
  2025. /*******************************************************************************
  2026. *
  2027. * cdromFsSkipDirRec - skipping current directory entry
  2028. *
  2029. * This routine skips all DirRecs belongs to the same directory entry
  2030. *
  2031. * RETURNS: OK or ERROR
  2032. */
  2033. LOCAL STATUS cdromFsSkipDirRec
  2034.     (
  2035.     T_CDROM_FILE_ID fd,                         /* File descriptor         */
  2036.     u_char flags                                /* Flags tested in DirRecs */
  2037.     )
  2038.     {
  2039.     u_char last = 0;                      /* NOT the last DirRec for entry */
  2040.     
  2041.     if (fd->FCEOF == 1)
  2042. /* If an end of file was found out already */ 
  2043. return ERROR;
  2044.     /* Last directory record of the current entry ? */
  2045.     
  2046.     if (((*(fd->FCDirRecPtr + ISO_DIR_REC_FLAGS) & flags) ^ flags) != 0)
  2047.         last = 1;      /* The last DirRec for entry */
  2048.     /* search for next DirRec */
  2049.     if (cdromFsDirBound (fd) == ERROR)         /* errno is set already */
  2050. return ERROR;        
  2051.         
  2052.     /* File Section of directory is not finished yet, BUT... */    
  2053.     
  2054.     return (last ? ERROR : OK);     /* It depends if the DirRec was last */
  2055.     }
  2056. /*******************************************************************************
  2057. *
  2058. * cdromFsDirBound - sets new pointers to Dir Record
  2059. *
  2060. * This routine assigns a new value to pointers to the current directory
  2061. * record skipping empty places in logical sector
  2062. *
  2063. * RETURNS: OK or ERROR
  2064. */
  2065. LOCAL STATUS cdromFsDirBound
  2066.     (
  2067.     T_CDROM_FILE_ID fd   /* File descriptor */
  2068.     )
  2069.     /*   
  2070.      * Hereafter the local definition will be set out. It can be used
  2071.      * only inside this function and will be excepted after the function
  2072.      * definition end.
  2073.      */
  2074. #define L_DRLEN * (fd->FCDirRecPtr + ISO_DIR_REC_REC_LEN)
  2075.     {    
  2076.     fd->FCDirRecAbsOff += L_DRLEN;                     /* To a new DirRec */
  2077.     fd->FCDirRecOffInLB += L_DRLEN;
  2078.     fd->FCDirRecNum++;
  2079.     fd->FCDirRecPtr += L_DRLEN;        /* Skip the length of prev. DirRec */
  2080.     if (fd->FCDirRecOffInLB >= fd->pVDList->LBSize)
  2081.         {
  2082. /* go to a new logical block */
  2083.         fd->FCDirRecLB++;
  2084.         fd->FCDirRecOffInLB -= fd->pVDList->LBSize;
  2085.         fd->FCDirRecPtr = cdromFsGetLB (fd->pVDList, fd->FCDirRecLB,
  2086. &(fd->sectBuf));
  2087.         if (fd->FCDirRecPtr == NULL)
  2088.             return ERROR;  
  2089.         fd->FCDirRecPtr += fd->FCDirRecOffInLB;
  2090.         }
  2091.          
  2092.     /* end of DirRec's in a Logical Sector !   */
  2093.     if (L_DRLEN == 0)
  2094.         {
  2095.         short offset;   /* offset in Logical Sector */
  2096.         
  2097.         offset = LAST_BITS(fd->FCDirRecLB, fd->pVDList->LBToLSShift) *
  2098.                  fd->pVDList->LBSize + fd->FCDirRecOffInLB;
  2099.                  
  2100.         /* to the end of current logical sector */
  2101.         
  2102.         fd->FCDirRecAbsOff += fd->pVDList->pVolDesc->sectSize - offset;
  2103. fd->FCDirRecLB += 1 + fd->pVDList->LBToLSShift -
  2104.   LAST_BITS(fd->FCDirRecLB, fd->pVDList->LBToLSShift);
  2105.         if (fd->FCDirRecAbsOff >= fd->FSize)   
  2106.             {
  2107.             fd->FCEOF = 1;
  2108.             return OK;      /* It's the first time  */
  2109.             }    
  2110.         /* the next logical sector */
  2111.         if ((fd->FCDirRecPtr = 
  2112.      cdromFsGetLB (fd->pVDList, fd->FCDirRecLB, &(fd->sectBuf))) ==
  2113.     NULL)
  2114.     return ERROR;
  2115. fd->FCDirRecOffInLB = 0;
  2116.         }
  2117.     return OK;
  2118. #undef L_DRLEN    
  2119.     } 
  2120. /*******************************************************************************
  2121. *
  2122. * cdromFsSkipGap - sets pointers to the new current data Logical Block
  2123. *
  2124. * This routine fixes data connected with new Logical Block found
  2125. *
  2126. * RETURNS: N/A
  2127. */
  2128. LOCAL void cdromFsSkipGap
  2129.     (
  2130.     T_CDROM_FILE_ID fd,     /* file descriptor      */
  2131.     u_long * absLb,    /* current block number */
  2132.     long absPos    /* new abs position     */
  2133.     )
  2134.     {
  2135.     if (absPos - fd->FCSAbsOff >= fd->FCSSize)   /* End of FSect ? */
  2136.         {
  2137. /* next file section */
  2138. fd->FCDirRecAbsOff += *(fd->FCDirRecPtr + ISO_DIR_REC_REC_LEN);
  2139. fd->FCDirRecNum++;
  2140. fd->FCSAbsOff += fd->FCSSize;
  2141.      fd->FCDirRecPtr += *(fd->FCDirRecPtr + ISO_DIR_REC_REC_LEN);
  2142.      fd->FCDirRecNum++;
  2143. C_BUF_TO_LONG(fd->FCSSize, fd->FCDirRecPtr,
  2144.                 ISO_DIR_REC_DATA_LEN);
  2145. cdromFsFixFsect (fd);
  2146. }
  2147.     
  2148.     else if (fd->FCSInterleaved & CDROM_INTERLEAVED) 
  2149. if (*absLb % (fd->FCSFUSizeLB + fd->FCSGapSizeLB) ==
  2150.      fd->FCSFUSizeLB)     /* End of FUnit */
  2151.     {
  2152.     *absLb += fd->FCSGapSizeLB;             /* Next FUnit   */
  2153.     }    
  2154.     }
  2155.    
  2156. /*******************************************************************************
  2157. * cdromFsFixFsect - sets pointers to the new current File Section
  2158. *
  2159. * This routine fixes data connected with new File Section found
  2160. *
  2161. * RETURNS: N/A
  2162. */
  2163. LOCAL void cdromFsFixFsect 
  2164.     (
  2165.     T_CDROM_FILE_ID fd   /* cdrom file descriptor id */
  2166.     )
  2167.     {
  2168.     UINT32 place1;                       /* Buffer to read long from DR  */
  2169.     UINT16 place2;  /* Buffer to read short from DR */
  2170.     /* new pointer to the New DirRec is already set in fd->FCDirRecPtr */
  2171.     memmove (&place1, fd->FCDirRecPtr + ISO_DIR_REC_EXTENT_LOCATION, LEN32);
  2172.     fd->FCSStartLB = place1 + *(fd->FCDirRecPtr + ISO_DIR_REC_EAR_LEN);
  2173.     memmove (&place1, fd->FCDirRecPtr + ISO_DIR_REC_DATA_LEN, LEN32);
  2174.     fd->FCSSize = place1;
  2175.     fd->FCSSizeLB = A_PER_B(fd->pVDList->LBSize, fd->FCSSize);
  2176.     memmove (&place2, fd->FCDirRecPtr + ISO_DIR_REC_VOL_SEQU_N, LEN16);
  2177.     fd->FCSSequenceSetNum = place2;
  2178.     fd->FCSGapSizeLB = *(fd->FCDirRecPtr + ISO_DIR_REC_IGAP_SIZE);
  2179.     fd->FCSFUSizeLB = *(fd->FCDirRecPtr + ISO_DIR_REC_FU_SIZE);
  2180.     fd->FDType = (*(fd->FCDirRecPtr + ISO_DIR_REC_FLAGS) & DRF_DIRECTORY) ?
  2181.  S_IFDIR : S_IFREG;    /* constants are from io.h */
  2182.     fd->FCSFlags = *(fd->FCDirRecPtr + ISO_DIR_REC_FLAGS); 
  2183.     return; 
  2184.     }
  2185. /*******************************************************************************
  2186. *
  2187. * cdromFsFixPos - fixes current position in a file
  2188. *
  2189. * This routine sets current data pointer positions in its file descriptor
  2190. * It is called only when new and old positions are in the same FileSection
  2191. *
  2192. * RETURN: N/A
  2193. */
  2194. LOCAL void cdromFsFixPos
  2195.     (
  2196.     T_CDROM_FILE_ID fd,                             /* file descriptor */
  2197.     u_long length,                                  /* additional offset */
  2198.     u_long absLb      /* new LogBlock number */
  2199.     )
  2200.     {
  2201.     fd->FCDAbsLB = absLb;
  2202.     fd->FCDOffInLB = (fd->FCDOffInLB + length) %
  2203.      fd->pVDList->LBSize;
  2204.     fd->FCDAbsPos += length;
  2205.     return;
  2206.     }
  2207.   
  2208. /*******************************************************************************
  2209. *
  2210. * cdromFsOpen - open file/directory for following access.
  2211. *
  2212. * This routine tries to find absolute <path> within all volume
  2213. * primary/supplementary directory hierarchys and create and fill in
  2214. * T_CDROM_FILE structure for following accsess.
  2215. * levels in path have to be split by '' or '/'.
  2216. *
  2217. * ERRNO: S_cdromFsLib_MAX_DIR_LEV_OVERFLOW
  2218. * S_cdromFsLib_NO_SUCH_FILE_OR_DIRECTORY
  2219. * S_cdromFsLib_INVALID_PATH_STRING
  2220. *
  2221. * RETURNS: T_CDROM_FILE_ID or ERROR if any error encounted.
  2222. */
  2223. LOCAL T_CDROM_FILE_ID cdromFsOpen
  2224.     (
  2225.     CDROM_VOL_DESC_ID pVolDesc, /* ptr to volume descriptor */
  2226.     u_char *         path,     /* absolute path to directory/file to open */
  2227.     int                 options   /* spare, not used currently */
  2228.     )
  2229.     {
  2230.     if ((pVolDesc == NULL) || pVolDesc->magic != VD_SET_MAG)
  2231.      {
  2232.      errnoSet (S_cdromFsLib_INVAL_VOL_DESCR);
  2233.      return (T_CDROM_FILE_ID)ERROR;
  2234.      }
  2235.     
  2236.     /* check for volume was mounted and has not been changed */
  2237.     if ((pVolDesc->pBlkDev->bd_statusChk != NULL) &&
  2238. pVolDesc->pBlkDev->bd_statusChk(pVolDesc->pBlkDev) == ERROR)
  2239.      {
  2240.      cdromFsVolUnmount (pVolDesc);
  2241.      errnoSet (S_cdromFsLib_VOL_UNMOUNTED);
  2242.      return (T_CDROM_FILE_ID)ERROR;
  2243.      }
  2244.     
  2245.     if (pVolDesc->unmounted || pVolDesc->pBlkDev->bd_readyChanged)
  2246. if (cdromFsVolMount (pVolDesc) == ERROR)
  2247.     return (T_CDROM_FILE_ID)ERROR;
  2248.     
  2249.     if (path == NULL)
  2250.      {
  2251. errnoSet (S_cdromFsLib_INVALID_PATH_STRING);
  2252.      return (T_CDROM_FILE_ID)ERROR;
  2253.      }
  2254.         
  2255.     return cdromFsFindPath (pVolDesc,  path, options);
  2256.     }
  2257. /*******************************************************************************
  2258. *
  2259. * cdromFsClose - close file/directory
  2260. *
  2261. * This routine deallocates all memory, allocated over opening
  2262. * given file/directory and excludes FD from volume FD list.
  2263. *
  2264. * ERRNO: S_cdromFsLib_INVALID_FILE_DESCRIPTOR
  2265. *
  2266. * RETURNS: OK or ERROR if bad FD supplied.
  2267. */
  2268. LOCAL STATUS cdromFsClose
  2269.     (
  2270.     T_CDROM_FILE_ID pFD  /* ptr to cdrom file id */
  2271.     )
  2272.     {
  2273.     if ((pFD == NULL) || pFD->magic != FD_MAG)
  2274.      {
  2275.      errnoSet (S_cdromFsLib_INVALID_FILE_DESCRIPTOR);
  2276.      return ERROR;
  2277.      }
  2278.     
  2279.     cdromFsFDFree (pFD);
  2280.     
  2281.     return OK;
  2282.     }
  2283. /*******************************************************************************
  2284. *
  2285. * cdromFsWrite - cdrom pseudo write function
  2286. *
  2287. * CD-ROM is read-only device.
  2288. *
  2289. * ERRNO: S_cdromFsLib_READ_ONLY_DEVICE
  2290. *
  2291. * RETURN: ERROR.
  2292. */
  2293. LOCAL STATUS cdromFsWrite ()
  2294.     {
  2295.     errnoSet(S_cdromFsLib_READ_ONLY_DEVICE);
  2296.     return ERROR;
  2297.     }
  2298. /*******************************************************************************
  2299. *
  2300. * cdromFsIoctl -  I/O control routine for "cdromFs" file system 
  2301. *
  2302. * This routine performs the subset of control functions defined in ioLib.h
  2303. * These functions are possible to be applied to cdromFs file system.
  2304. *  
  2305. * RETURNS: OK, ERROR or the file pointer position (if requested)
  2306. *
  2307. * ERRNO:       S_cdromFsLib_INVALID_FILE_DESCRIPTOR
  2308. */
  2309. LOCAL STATUS cdromFsIoctl
  2310.     (
  2311.     T_CDROM_FILE_ID fd, /* file descriptor*/
  2312.     int function, /* an action number */
  2313.     int arg /* special parameter for each function */
  2314.     )
  2315.     {
  2316.     if ((fd == NULL) || (fd->magic != FD_MAG))
  2317.      {
  2318.      errnoSet(S_cdromFsLib_INVALID_FILE_DESCRIPTOR);
  2319.      return ERROR; /* fd - exists at least ? */
  2320.      }
  2321.                           
  2322.     /* check for volume has not been changed */
  2323.     if (((fd->pVDList->pVolDesc->pBlkDev->bd_statusChk != NULL) &&
  2324.  fd->pVDList->pVolDesc->pBlkDev->bd_statusChk (
  2325.  fd->pVDList->pVolDesc->pBlkDev) == ERROR) ||
  2326. fd->pVDList->pVolDesc->pBlkDev->bd_readyChanged ||
  2327. fd->pVDList->pVolDesc->unmounted)
  2328.      {
  2329.      cdromFsVolUnmount (fd->pVDList->pVolDesc);
  2330.      errnoSet (S_cdromFsLib_VOL_UNMOUNTED);
  2331.      return ERROR;
  2332.      }
  2333.     
  2334. #ifdef NODEF
  2335.     /*
  2336.      * TBD: Vlad: You must to make this check, but, may be,
  2337.      * not for all FIO-Codes
  2338.      */
  2339.     if (fd->volUnmount != 0)                          /* No valid Volume */
  2340. {
  2341. errnoSet (S_cdromFsLib_VOL_UNMOUNTED);
  2342.   return ERROR;
  2343. }
  2344. #endif /* NODEF */
  2345.     switch (function)
  2346.         {
  2347.         case FIOGETNAME:
  2348.             strcpy ((u_char *)arg, fd->name);
  2349.             return OK;
  2350.             
  2351.         case FIOLABELGET:
  2352.             {
  2353.             u_char * sectData;                 /* for the temp. allocation */
  2354.             
  2355.             if (semTake (fd->pVDList->pVolDesc->mDevSem, WAIT_FOREVER)
  2356. == ERROR)
  2357. {
  2358. /* leave errno as set by semLib */
  2359.             
  2360. return ERROR;
  2361. }
  2362.             
  2363.             /* Volume label - in the 1st (relative) sector  */
  2364.             sectData = cdromFsGetLB (fd->pVDList,
  2365.     (fd->pVDList->pVolDesc->sectSize /
  2366.      fd->pVDList->LBSize) * ISO_PVD_BASE_LS,
  2367.        NULL );
  2368.        
  2369.     if (sectData == NULL)
  2370.      {
  2371. semGive (fd->pVDList->pVolDesc->mDevSem); /* No checking */
  2372. return ERROR;
  2373. }
  2374.     /*  It's assumed that there's sufficient place pointed by arg */
  2375.     
  2376.             strncpy ((u_char *)arg, sectData + ISO_VD_VOLUME_ID ,
  2377.      ISO_VD_VOLUME_ID_SIZE);
  2378.             *((u_char *)arg + ISO_VD_VOLUME_ID_SIZE) = '';
  2379.             
  2380.             if (semGive (fd->pVDList->pVolDesc->mDevSem) == ERROR)
  2381. {
  2382. errnoSet (S_cdromFsLib_SEMGIVE_ERROR);
  2383. return ERROR;
  2384.                 }
  2385.             return OK;
  2386.             }    
  2387.     
  2388.         case FIOWHERE:                /* Current position */
  2389.             return fd->FCDAbsPos;     /* doesn't return OK or ERROR */
  2390.             
  2391.         case FIOSEEK:                 /* Setting of current position */
  2392.             { 
  2393.             u_char * ptr;             /* ptr to CurDirRec */
  2394.             int save;                 /* temp. buf. with position */
  2395.          long len = 0;             /* Sum length of all prev.FileSect */
  2396.     UINT32 add;               /* temp. buffer */
  2397.             long i = 0;               /* Number of File Sections tested */
  2398.             
  2399.             /* 'Seek' is not defined for directories, 'pos' is not neg.  */   
  2400.             if ((arg < 0) || (fd->FType == S_IFDIR)) 
  2401.                 {
  2402.                 /* leave errno as set by semLib */
  2403.                 return ERROR;         /* the offset is non-negative */
  2404.                 }     
  2405.             if (arg >= fd->FSize)               /* Out of bounds ?? */
  2406.                 {
  2407.                 fd->FCEOF = 1;
  2408.                 return OK;
  2409.                 }
  2410.             else
  2411.                 fd->FCEOF = 0;
  2412.                     
  2413.             save = fd->FCDAbsPos;
  2414.             
  2415.             /*       
  2416.      * Firstly we should test if it isn't the same LB      
  2417.      * and if "arg" isn't out of high bound of the File Section    
  2418.      */
  2419.             
  2420.             if (semTake (fd->pVDList->pVolDesc->mDevSem, WAIT_FOREVER) ==
  2421.               ERROR)
  2422. {
  2423. /* leave errno as set by semLib */
  2424. return ERROR;
  2425. }
  2426.             if (((fd->FCDAbsPos ^ arg) <  fd->pVDList->LBSize) &&
  2427.                  (arg < (fd->FCSAbsOff + fd->FCSSize)))
  2428.                 {                  /* The same logical block */
  2429.                 fd->FCDAbsPos = arg;
  2430.                 fd->FCDOffInLB = arg & (fd->pVDList->LBSize - 1);
  2431.                 }
  2432.             else            /* if the new offset needs dir reading */ 
  2433.                 {
  2434. ptr = fd->FRecords;
  2435.    while (len <= arg)                   /* skipping entry */
  2436.     {
  2437.     memmove (&add, ptr + ISO_DIR_REC_DATA_LEN , LEN32); 
  2438.     len += (u_long)add;
  2439.     
  2440.     if ((*(ptr + ISO_DIR_REC_FLAGS) & DRF_LAST_REC) == 0)
  2441. break;                          /* The last DirRec */
  2442.     i++;
  2443.     ptr += *(ptr + ISO_DIR_REC_REC_LEN);
  2444.                     }
  2445.                 if (len < arg)          /* the new offset is out of bounds */ 
  2446.                     {
  2447.     if (semGive (fd->pVDList->pVolDesc->mDevSem) == ERROR)
  2448. errnoSet (S_cdromFsLib_SEMGIVE_ERROR);
  2449.                     return ERROR;
  2450.                     }
  2451.                     
  2452.                 /*  
  2453.  * len > arg, 'prev' points the necessary File Section    
  2454.  * i - number of the File Section, the offset belongs to 
  2455.  */      
  2456.                 cdromFsFillPos (fd, ptr, i, len, arg);              
  2457.                 }
  2458.                 
  2459.             cdromFsCountMdu (fd, save);  /*new offset in MDU for the arg,*/
  2460.             if (semGive (fd->pVDList->pVolDesc->mDevSem) == ERROR)
  2461. {
  2462.                 errnoSet (S_cdromFsLib_SEMGIVE_ERROR);
  2463.                 return ERROR;
  2464.                 }                      /* but we don't support records  */
  2465.                 
  2466.             return OK;
  2467.             }
  2468.         case FIONREAD:          /* Number of unread bytes in the file */
  2469.             {
  2470.     *(u_long *) arg = fd->FSize - fd->FCDAbsPos;
  2471.             return OK;
  2472.             }
  2473.     
  2474.         case FIOREADDIR:        /* Next directory entry */
  2475.             {
  2476.             short len;                 /* assumed length of the entry name */
  2477.             u_char * ptr;              /* temp.pointer to LogBlock */
  2478.             if (semTake (fd->pVDList->pVolDesc->mDevSem, WAIT_FOREVER) ==
  2479. ERROR)
  2480. {
  2481. /* leave errno as set by semLib */
  2482. return ERROR;
  2483. }
  2484.             
  2485.     if ((ptr = cdromFsGetLB (fd->pVDList, fd->FCDirRecLB, 
  2486.              &(fd->sectBuf))) == NULL)
  2487. {
  2488. /* errno is set already */
  2489. semGive (fd->pVDList->pVolDesc->mDevSem);
  2490. return ERROR;
  2491. }
  2492.     else
  2493.         fd->FCDirRecPtr = ptr + fd->FCDirRecOffInLB;
  2494.         
  2495.     if (fd->FCEOF == 1)
  2496.         {
  2497.         /* Without checking */
  2498. semGive (fd->pVDList->pVolDesc->mDevSem);
  2499.         return ERROR;   
  2500.         }
  2501.         
  2502.             /* skip current directory entry */
  2503.             /* 
  2504.      * if fd->FDType == (u_short)-1, i.e. the entry is the first 
  2505.      * in directory, I have to return current point (truly - first 
  2506.      * point).if not - next                                       
  2507.     */
  2508.             
  2509.     if (fd->FDType != (u_short)(-1))
  2510. {
  2511.         while (cdromFsSkipDirRec (fd, DRF_LAST_REC) == OK)
  2512.                     {
  2513.                     ; /* While not the last record is found out */
  2514.                     }
  2515.                 
  2516.                 if (fd->FCDirRecAbsOff >= fd->FSize)    /* End of File ? */
  2517.                     {
  2518.                     fd->FCEOF = 1;    
  2519.     /* Without checking */
  2520.     semGive (fd->pVDList->pVolDesc->mDevSem);
  2521.                     return ERROR;
  2522.                     }
  2523.                 }    
  2524.     
  2525.     /* 
  2526.      * We have skipped already the last DirRec of previous    
  2527.      * directory entry. And we do know that we didn't come to
  2528.      * the end of file: some DirRec's remain (a new entry)  
  2529.      */          
  2530.     /*
  2531.      * Now we have to fix the new DirRec data connected,       
  2532.      * accordingly to ISO9660, with a new directory entry       
  2533.      */
  2534.     
  2535.     cdromFsFixFsect (fd);
  2536.                       
  2537.     /* Codes of root and parent directory should be changed        */
  2538.     if (*(fd->FCDirRecPtr + ISO_DIR_REC_FI) == '')
  2539. {
  2540. len = 1;
  2541. ((DIR *)arg)->dd_dirent.d_name[0] = '.';         /* itself */
  2542. }
  2543.     else if (*(fd->FCDirRecPtr + ISO_DIR_REC_FI) == '01')
  2544. {
  2545. len = 2;
  2546. ((DIR *)arg)->dd_dirent.d_name[0] = '.';     /* parent dir */
  2547. ((DIR *)arg)->dd_dirent.d_name[1] = '.';
  2548. }
  2549.     else
  2550.         {
  2551.         /*  We must truncate the name to fit it in the struct DIR  */
  2552.         len = min (*(fd->FCDirRecPtr + ISO_DIR_REC_LEN_FI),
  2553.                         sizeof(((DIR *)arg)->dd_dirent.d_name) - 1);
  2554.         strncpy (((DIR *)arg)->dd_dirent.d_name,
  2555.                          fd->FCDirRecPtr + ISO_DIR_REC_FI, len);
  2556.         }
  2557.         
  2558.     ((DIR *)arg)->dd_dirent.d_name[len] = EOS;
  2559.             if (semGive (fd->pVDList->pVolDesc->mDevSem) == ERROR)
  2560. {
  2561. errnoSet (S_cdromFsLib_SEMGIVE_ERROR);
  2562. return ERROR;
  2563.                 }
  2564.             }
  2565.             return OK;
  2566.         
  2567.         case FIODISKCHANGE:                 /* setting of 'ready change' */
  2568.             
  2569.             return (cdromFsReadyChange (fd->pVDList->pVolDesc));
  2570.             
  2571.         case FIOUNMOUNT:                   /* device unmounting */
  2572.             cdromFsVolUnmount (fd->pVDList->pVolDesc);
  2573.             return OK;
  2574.             
  2575.         case FIOFSTATGET:    /* taking of the file status */
  2576.             cdromFsFillStat (fd, (struct stat *)arg);
  2577.             return OK;
  2578.              
  2579.         default:
  2580.             if (fd->pVDList->pVolDesc->pBlkDev->bd_ioctl == NULL)
  2581.                 return ERROR;     /* No 'ioctl' function in blk_dev driver */
  2582.                 
  2583.             return (fd->pVDList->pVolDesc->pBlkDev->bd_ioctl(
  2584.              fd->pVDList->pVolDesc->pBlkDev,
  2585.                                    function, arg));     
  2586.         } /* switch */
  2587.                 
  2588.     }
  2589. /*******************************************************************************
  2590. *
  2591. * cdromFsRead - routine for reading data from a CD
  2592. *
  2593. * This routine reads data from a CD into a buffer provided by user.
  2594. *
  2595. * ERRNO:    
  2596. * S_cdromFsLib_SEMGIVE_ERROR
  2597. * S_cdromFsLib_VOL_UNMOUNTED
  2598. *
  2599. * RETURNS: 0 - if end of file is found out,
  2600. * number of bytes were read - if any,
  2601. * ERROR - error reading or access behind an end of file*
  2602. */
  2603. LOCAL STATUS cdromFsRead
  2604.     (
  2605.     int desc, /* file descriptor */
  2606.     u_char * buffer, /* buffer for data provided by user */ 
  2607.     size_t maxBytes /* number of bytes to be read */
  2608.     )
  2609.     {
  2610.     T_CDROM_FILE_ID fd = (T_CDROM_FILE_ID) desc;        /* file descriptor */
  2611.     u_long rest = maxBytes;               /* number of unread bytes */
  2612.     u_long absLb = fd->FCDAbsLB;          /* current absolute LB number */
  2613.     u_long absPos = fd->FCDAbsPos;        /* absolute position in the file */
  2614.     u_char * ptr;                         /* pointer to file data */
  2615.     u_long field;                         /* current portion' length */
  2616.     u_int blocks;                     /* full blocks to read */
  2617.     u_char flag = 0;                      /* flag EOF */     
  2618.     if ((fd == NULL) || (fd->magic != FD_MAG))
  2619.      {
  2620.      errnoSet(S_cdromFsLib_INVALID_FILE_DESCRIPTOR);
  2621.      return ERROR;  /* fd - exists at least ? */
  2622.      }
  2623.           
  2624.     /* check for volume has not been changed */
  2625.     if (((fd->pVDList->pVolDesc->pBlkDev->bd_statusChk != NULL) &&
  2626.            fd->pVDList->pVolDesc->pBlkDev->bd_statusChk (
  2627.              fd->pVDList->pVolDesc->pBlkDev) == ERROR) ||
  2628.          fd->pVDList->pVolDesc->pBlkDev->bd_readyChanged ||
  2629.          fd->pVDList->pVolDesc->unmounted)
  2630.      {
  2631.      cdromFsVolUnmount (fd->pVDList->pVolDesc);
  2632.      errnoSet (S_cdromFsLib_VOL_UNMOUNTED);
  2633.      return ERROR;
  2634.      }
  2635.     
  2636.     if (fd->volUnmount != 0)     /* No valid Volume */
  2637. {
  2638. errnoSet (S_cdromFsLib_VOL_UNMOUNTED);
  2639.   return ERROR;
  2640. }
  2641.     if (fd->FCEOF == 1)
  2642.         return 0;                                           /* End of File */
  2643.     if (semTake (fd->pVDList->pVolDesc->mDevSem, WAIT_FOREVER) == ERROR)
  2644. {
  2645. /* leave errno as set by semLib */
  2646. return ERROR;
  2647. }
  2648.     if ((ptr = cdromFsGetLB (fd->pVDList, fd->FCDAbsLB, 
  2649.                     &(fd->sectBuf))) == NULL)  
  2650.         {
  2651.         semGive (fd->pVDList->pVolDesc->mDevSem);   /* Without checking */
  2652.         return ERROR;
  2653.         }
  2654.     ptr += fd->FCDOffInLB;         /* Starting position */
  2655.     
  2656.     if ((fd->FCDAbsPos + maxBytes) >= fd->FSize)
  2657. { /* to prevent reading after bound */  
  2658. maxBytes = fd->FSize - fd->FCDAbsPos;
  2659.   flag = 1;
  2660. }
  2661.     rest = maxBytes;
  2662.     field = (rest <= fd->pVDList->LBSize - fd->FCDOffInLB) ? 
  2663.     rest : (fd->pVDList->LBSize - fd->FCDOffInLB);
  2664.     bcopy (ptr, buffer, field);
  2665.     buffer += field;
  2666.     absPos += field;
  2667.     absLb += (fd->FCDOffInLB + field) /  fd->pVDList->LBSize ;
  2668.     /* 
  2669.      * interleave will be counted properly or in the cycle below or during 
  2670.      * next reading, because we are in the same block (maybe at the bound) 
  2671.      */
  2672.     rest -= field;
  2673.     if (rest > 0)
  2674.         {    
  2675.         /* readings of full blocks */
  2676. if ((blocks = rest / fd->pVDList->LBSize) > 0)
  2677.     {
  2678.     for (; blocks > 0; blocks--)
  2679. {
  2680. cdromFsSkipGap (fd, &absLb, absPos);
  2681. if ((ptr = cdromFsGetLB (fd->pVDList, absLb,
  2682.                      &(fd->sectBuf)))== NULL) 
  2683.     {
  2684.     cdromFsFixPos (fd, maxBytes - rest , absLb); 
  2685.     /* No checking */
  2686.                     semGive (fd->pVDList->pVolDesc->mDevSem) ;
  2687.             return (maxBytes - rest);
  2688.     }
  2689. bcopy (ptr, buffer, fd->pVDList->LBSize);
  2690. buffer += fd->pVDList->LBSize;
  2691.      absPos += fd->pVDList->LBSize;
  2692.      absLb ++;    
  2693.      rest -= fd->pVDList->LBSize;
  2694. }
  2695.     }
  2696. cdromFsSkipGap (fd, &absLb, absPos); /* The last reading */
  2697. if ((ptr = cdromFsGetLB (fd->pVDList, absLb,
  2698.  &(fd->sectBuf)))== NULL) 
  2699.     {
  2700.     cdromFsFixPos (fd, maxBytes - rest , absLb); 
  2701.             semGive (fd->pVDList->pVolDesc->mDevSem);  /* No checking */
  2702.             return (maxBytes - rest);
  2703.     }
  2704. /* The last portion to read */
  2705. bcopy (ptr, buffer, rest);
  2706. absPos += rest;
  2707. }
  2708.     if  (flag)
  2709. {
  2710.         fd->FCEOF = 1;
  2711. }  /* EOF */
  2712.     cdromFsFixPos (fd, maxBytes, absLb);
  2713.     if (semGive (fd->pVDList->pVolDesc->mDevSem) == ERROR)
  2714. {
  2715. errnoSet (S_cdromFsLib_SEMGIVE_ERROR);
  2716. return ERROR;
  2717. }
  2718.     return (maxBytes);
  2719.     }
  2720. /*******************************************************************************
  2721. *
  2722. * cdromFsReadyChange - sets special sign in the volume descriptor
  2723. *
  2724. * This function sets the value with meaning "CD was changed in the
  2725. * unit" to the block device structure assigned to the unit. The function can
  2726. * be called from the interrupt level
  2727. *
  2728. * RETURNS: N/A
  2729. */
  2730. LOCAL STATUS cdromFsReadyChange
  2731.     (
  2732.     CDROM_VOL_DESC_ID arg
  2733.     )
  2734.     {
  2735.     if (arg == NULL)
  2736.         return ERROR;
  2737.     
  2738.     arg->pBlkDev->bd_readyChanged = TRUE;     /* It is "short", not a bit */ 
  2739.     return OK;       
  2740.     }
  2741. /*******************************************************************************
  2742. *
  2743. * cdromFsVolConfigShow - show the volume configuration information
  2744. * This routine retrieves the volume configuration for the named cdromFsLib
  2745. * device and prints it to standard output.  The information displayed is 
  2746. * retrieved from the BLK_DEV structure for the specified device.
  2747. *
  2748. * RETURNS: N/A
  2749. */
  2750. VOID cdromFsVolConfigShow
  2751.     (
  2752.     void * arg /* device name or CDROM_VOL_DESC * */
  2753.     )
  2754.     {
  2755.     CDROM_VOL_DESC * pVolDesc = arg;
  2756.     char * devName  = arg;
  2757.     T_CDROMFS_VD_LST_ID pVDList;
  2758.     char * nameTail;
  2759.     u_int lsNum;
  2760.     
  2761.     if (arg == NULL)
  2762.         {
  2763.         printf("
  2764. device name or CDROM_VOL_DESC * must be supplyed as parametrn");
  2765.         return;
  2766.         }
  2767.     /* check type of supplyed argument */
  2768.     if (pVolDesc->magic != VD_SET_MAG)
  2769. {
  2770. /* if not CDROM_VOL_DESC_ID, may be device name */
  2771. pVolDesc = (CDROM_VOL_DESC_ID)iosDevFind(devName, &nameTail);
  2772. if (nameTail == devName ||
  2773.     (pVolDesc == NULL) || pVolDesc->magic != VD_SET_MAG)
  2774.     {
  2775.     printf("not cdrom fs device");
  2776.     return;
  2777.     }
  2778. }
  2779.     devName = pVolDesc->devHdr.name;
  2780.     printf("
  2781. ndevice config structure ptr 0x%lxn
  2782. device name %sn
  2783. bytes per blkDevDrv sector %ldn",
  2784. (u_long)pVolDesc,
  2785. devName,
  2786. pVolDesc->pBlkDev->bd_bytesPerBlk);
  2787.     if (pVolDesc->unmounted)
  2788. {
  2789. printf("no volume mountedn");
  2790. return;
  2791. }
  2792.     
  2793.     for (pVDList = (T_CDROMFS_VD_LST_ID) lstFirst(&(pVolDesc->VDList)),
  2794.    lsNum = 16; pVDList != NULL; lsNum ++,
  2795.  pVDList = (T_CDROMFS_VD_LST_ID) lstNext((NODE *)pVDList))
  2796. {
  2797. u_char * pData;
  2798. T_ISO_PVD_SVD volDesc;
  2799. char * non  = "none";
  2800. char * space = " ";
  2801. struct
  2802. {
  2803.     char year[ ISO_V_DATE_TIME_YEAR_SIZE +1 ],
  2804. month[ ISO_V_DATE_TIME_FIELD_STD_SIZE +1 ],
  2805. day[ ISO_V_DATE_TIME_FIELD_STD_SIZE +1 ],
  2806. hour[ ISO_V_DATE_TIME_FIELD_STD_SIZE +1 ],
  2807. minute[ ISO_V_DATE_TIME_FIELD_STD_SIZE +1 ],
  2808. sec[ ISO_V_DATE_TIME_FIELD_STD_SIZE +1 ],
  2809. sec100[ ISO_V_DATE_TIME_FIELD_STD_SIZE +1 ];
  2810.     } date;
  2811. if (semTake (pVolDesc->mDevSem, WAIT_FOREVER) == ERROR)
  2812.     return;
  2813.     
  2814. pData = cdromFsGetLS (pVolDesc, lsNum, &(pVolDesc->sectBuf));
  2815. if (pData == NULL)
  2816.     {
  2817.     semGive (pVolDesc->mDevSem);
  2818.     printf ("error reading volumen");
  2819.     return;
  2820.     }
  2821.     
  2822. /* fill in volume configuration structure */
  2823. bzero (&volDesc, sizeof (volDesc));
  2824. volDesc.volSize = pVDList->volSize;
  2825. volDesc.PTSize = pVDList->PTSize;
  2826. volDesc.volSetSize = pVDList->volSetSize;
  2827. volDesc.volSeqNum = pVDList->volSeqNum;
  2828. volDesc.LBSize = pVDList->LBSize;
  2829. volDesc.PTSize = pVDList->PTSize;
  2830. volDesc.type = pVDList->type;
  2831. volDesc.fileStructVersion = pVDList->fileStructVersion;
  2832. bcopy (((T_ISO_VD_HEAD_ID)pData)->stdID, volDesc.stdID,
  2833.        ISO_STD_ID_SIZE );
  2834. bcopy (pData + ISO_VD_SYSTEM_ID , volDesc.systemId,
  2835.        ISO_VD_SYSTEM_ID_SIZE );
  2836. bcopy (pData + ISO_VD_VOLUME_ID , volDesc.volumeId,
  2837.        ISO_VD_ID_STD_SIZE );
  2838. bcopy (pData + ISO_VD_VOL_SET_ID , volDesc.volSetId,
  2839.        ISO_VD_ID_STD_SIZE);
  2840. bcopy (pData + ISO_VD_PUBLISH_ID , volDesc.publisherId,
  2841.        ISO_VD_ID_STD_SIZE );
  2842. bcopy (pData + ISO_VD_DATA_PREP_ID , volDesc.preparerId,
  2843.        ISO_VD_ID_STD_SIZE );
  2844. bcopy (pData + ISO_VD_APPLIC_ID , volDesc.applicatId,
  2845.        ISO_VD_ID_STD_SIZE );
  2846.          
  2847. bcopy (pData + ISO_VD_COPYR_F_ID , volDesc.cprightFId,
  2848.        ISO_VD_F_ID_STD_SIZE );
  2849. bcopy (pData + ISO_VD_ABSTR_F_ID , volDesc.abstractFId,
  2850.        ISO_VD_F_ID_STD_SIZE );
  2851. bcopy (pData + ISO_VD_BIBLIOGR_F_ID , volDesc.bibliogrFId,
  2852.        ISO_VD_F_ID_STD_SIZE );
  2853. bcopy (pData + ISO_VD_VOL_CR_DATE_TIME , &(volDesc.creationDate),
  2854.        ISO_VD_VOL_DATE_TIME_STD_SIZE );
  2855. bcopy (pData + ISO_VD_VOL_MODIF_DATE_TIME, &(volDesc.modificationDate),
  2856.        ISO_VD_VOL_DATE_TIME_STD_SIZE );
  2857. bcopy (pData + ISO_VD_VOL_EXPIR_DATE_TIME , &(volDesc.expirationDate),
  2858.        ISO_VD_VOL_DATE_TIME_STD_SIZE );
  2859. bcopy (pData + ISO_VD_VOL_EFFECT_DATE_TIME , &(volDesc.effectiveDate),
  2860.        ISO_VD_VOL_DATE_TIME_STD_SIZE );
  2861. printf("
  2862. t%s directory hierarchy: nn
  2863. standard ID :%sn
  2864. volume descriptor version :%un
  2865. system ID :%sn
  2866. volume ID :%sn
  2867. volume size :%lu = %lu MBn
  2868. number of logical blocks :%lu = 0x%lxn
  2869. volume set size  :%un
  2870. volume sequence number  :%un
  2871. logical block size :%un
  2872. path table size (bytes) :%lun
  2873. path table entries :%un
  2874. volume set ID :%sn
  2875. volume publisher ID :%sn
  2876. volume data preparer ID :%sn
  2877. volume application ID :%sn
  2878. copyright file name :%sn
  2879. abstract file name :%sn
  2880. bibliographic file name :%sn",
  2881.        (volDesc.type == ISO_VD_PRIMARY)? "nPrimary" :
  2882.    "nSuplementary",
  2883. volDesc.stdID,
  2884. (u_int)volDesc.fileStructVersion,
  2885. volDesc.systemId,
  2886. volDesc.volumeId,
  2887. volDesc.volSize * volDesc.LBSize,
  2888. volDesc.volSize * volDesc.LBSize / 0x100000,
  2889. volDesc.volSize,
  2890. volDesc.volSize,
  2891. (u_int)volDesc.volSetSize,
  2892. (u_int)volDesc.volSeqNum,
  2893. (u_int)volDesc.LBSize,
  2894. volDesc.PTSize,
  2895. pVDList->numPTRecs,
  2896. volDesc.volSetId,
  2897. volDesc.publisherId,
  2898. volDesc.preparerId,
  2899. volDesc.applicatId,
  2900. (strspn(volDesc.cprightFId, space) == ISO_VD_F_ID_STD_SIZE)?
  2901. non : (char *)volDesc.cprightFId,
  2902. (strspn(volDesc.abstractFId, space) == ISO_VD_F_ID_STD_SIZE)?
  2903. non : (char *)volDesc.abstractFId,
  2904. (strspn(volDesc.bibliogrFId, space) == ISO_VD_F_ID_STD_SIZE)?
  2905. non : (char *)volDesc.bibliogrFId
  2906.      );
  2907.     
  2908. /* date - time */
  2909. volDesc.creationDate =
  2910. *(T_ISO_VD_DATE_TIME_ID)(pData + ISO_VD_VOL_CR_DATE_TIME);
  2911. volDesc.modificationDate =
  2912. *(T_ISO_VD_DATE_TIME_ID)(pData + ISO_VD_VOL_MODIF_DATE_TIME);
  2913. volDesc.expirationDate =
  2914. *(T_ISO_VD_DATE_TIME_ID)(pData + ISO_VD_VOL_EXPIR_DATE_TIME);
  2915. volDesc.effectiveDate =
  2916. *(T_ISO_VD_DATE_TIME_ID)(pData + ISO_VD_VOL_EFFECT_DATE_TIME);
  2917. bzero (&date, sizeof (date));
  2918. bcopy (volDesc.creationDate.year , date.year, 
  2919.        ISO_V_DATE_TIME_YEAR_SIZE );
  2920. bcopy (volDesc.creationDate.month , date.month, 
  2921.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2922. bcopy (volDesc.creationDate.day , date.day, 
  2923.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2924. bcopy (volDesc.creationDate.hour , date.hour, 
  2925.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2926. bcopy (volDesc.creationDate.minute , date.minute, 
  2927.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2928. bcopy (volDesc.creationDate.sec , date.sec, 
  2929.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2930. bcopy (volDesc.creationDate.sec100 , date.sec100, 
  2931.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2932.        
  2933. printf ("
  2934. creation date :%s.%s.%s  %s:%s:%s:%sn",
  2935.        date.day, date.month, date.year,
  2936.        date.hour, date.minute, date.sec, date.sec100
  2937.      );
  2938. bzero (&date, sizeof(date));
  2939. bcopy (volDesc.modificationDate.year , date.year, 
  2940.        ISO_V_DATE_TIME_YEAR_SIZE );
  2941. bcopy (volDesc.modificationDate.month , date.month, 
  2942.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2943. bcopy (volDesc.modificationDate.day , date.day, 
  2944.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2945. bcopy (volDesc.modificationDate.hour , date.hour, 
  2946.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2947. bcopy (volDesc.modificationDate.minute , date.minute, 
  2948.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2949. bcopy (volDesc.modificationDate.sec , date.sec, 
  2950.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2951. bcopy (volDesc.modificationDate.sec100 , date.sec100, 
  2952.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2953.        
  2954. printf ("
  2955. modification date :%s.%s.%s  %s:%s:%s:%sn",
  2956.        date.day, date.month, date.year,
  2957.        date.hour, date.minute, date.sec, date.sec100
  2958.      );
  2959. bzero (&date, sizeof(date));
  2960. bcopy (volDesc.expirationDate.year , date.year, 
  2961.        ISO_V_DATE_TIME_YEAR_SIZE );
  2962. bcopy (volDesc.expirationDate.month , date.month, 
  2963.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2964. bcopy (volDesc.expirationDate.day , date.day, 
  2965.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2966. bcopy (volDesc.expirationDate.hour , date.hour, 
  2967.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2968. bcopy (volDesc.expirationDate.minute , date.minute, 
  2969.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2970. bcopy (volDesc.expirationDate.sec , date.sec, 
  2971.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2972. bcopy (volDesc.expirationDate.sec100 , date.sec100, 
  2973.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2974.        
  2975. printf ("
  2976. expiration date :%s.%s.%s  %s:%s:%s:%sn",
  2977.        date.day, date.month, date.year,
  2978.        date.hour, date.minute, date.sec, date.sec100
  2979.      );
  2980. bzero (&date, sizeof(date));
  2981. bcopy (volDesc.effectiveDate.year , date.year, 
  2982.        ISO_V_DATE_TIME_YEAR_SIZE );
  2983. bcopy (volDesc.effectiveDate.month , date.month, 
  2984.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2985. bcopy (volDesc.effectiveDate.day , date.day, 
  2986.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2987. bcopy (volDesc.effectiveDate.hour , date.hour, 
  2988.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2989. bcopy (volDesc.effectiveDate.minute , date.minute, 
  2990.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2991. bcopy (volDesc.effectiveDate.sec , date.sec, 
  2992.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2993. bcopy (volDesc.effectiveDate.sec100 , date.sec100, 
  2994.        ISO_V_DATE_TIME_FIELD_STD_SIZE );
  2995. printf ("
  2996. effective date :%s.%s.%s  %s:%s:%s:%sn",
  2997.        date.day, date.month, date.year,
  2998.        date.hour, date.minute, date.sec, date.sec100
  2999.      );
  3000. semGive (pVolDesc->mDevSem);
  3001. }
  3002.     return;
  3003.     }
  3004. /*******************************************************************************
  3005. *
  3006. * cdromFsDevDelete - delete a cdromFsLib device from I/O system.
  3007. *
  3008. * This routine unmounts device and deallocates all memory.
  3009. * Argument <arg> defines device to be reset. It may be device name
  3010. * or ptr to CDROM_VOL_DESC.
  3011. * Argument <retStat> must be 0.
  3012. *
  3013. * RETURNS: NULL
  3014. *
  3015. * SEE ALSO:  cdromFsInit(), cdromFsDevCreate()
  3016. */
  3017. LOCAL CDROM_VOL_DESC_ID cdromFsDevDelete
  3018.     (
  3019.     void * arg, /* device name or ptr to CDROM_VOL_DESC */
  3020.     STATUS retStat /* 0 only */
  3021.     )
  3022.     {
  3023.     CDROM_VOL_DESC_ID pVolDesc = arg;
  3024.     char * devName = arg;
  3025.     char * nameTail;
  3026.     
  3027.     if (retStat == ERROR)
  3028. {
  3029. printf ("cdromFsLib ERROR: device init failed: ");
  3030. printErrno (errnoGet());
  3031. }
  3032.     if (arg == NULL)
  3033.         {
  3034.         printf ("Invalid argumentn");
  3035. goto ret;
  3036. }
  3037.     /* check type of supplyed argument */
  3038.     if (pVolDesc->magic != VD_SET_MAG)
  3039. {
  3040. /* if not CDROM_VOL_DESC_ID, may be device name? */
  3041. pVolDesc = (CDROM_VOL_DESC_ID)iosDevFind(devName, &nameTail);
  3042. if (nameTail == devName ||
  3043.     (pVolDesc == NULL) || pVolDesc->magic != VD_SET_MAG)
  3044.     {
  3045.     printf ("not cdrom fs device");
  3046.     return NULL;
  3047.     }
  3048. }
  3049.     /* 
  3050.      * retStat == ERROR indicates request from cdromFsDevCreate
  3051.      * routine in case one failed, and so device not connected to list yet.
  3052.      * If not,- delete device from list
  3053.      */
  3054.     if (retStat != ERROR)
  3055.         iosDevDelete ((DEV_HDR  *)pVolDesc);
  3056.     /* make all resets and memory deallocations */
  3057.     
  3058.     /* firstly, private semaphore */
  3059.     if (pVolDesc->mDevSem != NULL)
  3060. semTake (pVolDesc->mDevSem, WAIT_FOREVER);
  3061.     
  3062.     cdromFsVolUnmount (pVolDesc); /* this routine resets VD and
  3063.       * FD lists */
  3064.     cdromFsSectBufFree (&(pVolDesc->sectBuf));
  3065.     /* volume descriptor inconsistent */
  3066.     pVolDesc->magic = 0;
  3067.     pVolDesc->pBlkDev = NULL;
  3068.     if (pVolDesc->mDevSem != NULL)
  3069. {
  3070. semGive (pVolDesc->mDevSem);
  3071. semDelete (pVolDesc->mDevSem);
  3072. }
  3073.     free (pVolDesc);
  3074. ret:
  3075.     return NULL;
  3076.     }
  3077. /*******************************************************************************
  3078. * cdromFsDevCreate - create a cdromFsLib device
  3079. *
  3080. * This routine creates an instance of a cdromFsLib device in the I/O system.
  3081. * As input, this function requires a pointer to a BLK_DEV structure for 
  3082. * the CD-ROM drive on which you want to create a cdromFsLib device.  Thus,
  3083. * you should already have called scsiBlkDevCreate() prior to calling
  3084. * cdfromFsDevCreate().
  3085. *
  3086. * RETURNS: CDROM_VOL_DESC_ID, or NULL if error.
  3087. *
  3088. * SEE ALSO: cdromFsInit()
  3089. */
  3090. CDROM_VOL_DESC_ID cdromFsDevCreate
  3091.     (
  3092.     char * devName,    /* device name */
  3093.     BLK_DEV * pBlkDev     /* ptr to block device */
  3094.     )
  3095.     {
  3096.     CDROM_VOL_DESC_ID pVolDesc;
  3097.     if (cdromFsDrvNum == ERROR)
  3098. {
  3099. if (cdromFsInit() == ERROR)
  3100.     return NULL ;
  3101. }
  3102.     
  3103.     /* TBD check pBlkDev contents */
  3104.     if ((pBlkDev == NULL))
  3105.      return NULL;
  3106.     pVolDesc = malloc(sizeof(CDROM_VOL_DESC));
  3107.     if (pVolDesc == NULL)
  3108. return cdromFsDevDelete(pVolDesc, ERROR);
  3109.     
  3110.     bzero ((u_char *) pVolDesc, sizeof(CDROM_VOL_DESC));
  3111.     pVolDesc->mDevSem = NULL; /* semaphore not created */
  3112.     lstInit(&(pVolDesc->VDList)); /* preparing for VD list */
  3113.     lstInit(&(pVolDesc->FDList)); /* preparing for FD list */
  3114.     pVolDesc->unmounted = 1; /* VDList must be built */
  3115.     pVolDesc->pBlkDev  = pBlkDev;
  3116.     /* 
  3117.      * adapt to blkDevDrv block size (think of CDROM_STD_LS_SIZE is
  3118.      * less than or multiple of bd_bytesPerBlk)
  3119.      */
  3120.     if (pBlkDev->bd_bytesPerBlk < CDROM_STD_LS_SIZE)
  3121.      {
  3122. pVolDesc->sectSize = CDROM_STD_LS_SIZE;
  3123. pVolDesc->LSToPhSSizeMult =
  3124.    CDROM_STD_LS_SIZE / pBlkDev->bd_bytesPerBlk;
  3125. }
  3126.     else
  3127.      {
  3128. pVolDesc->sectSize = pBlkDev->bd_bytesPerBlk;
  3129. pVolDesc->LSToPhSSizeMult = 1;
  3130. }
  3131.     pVolDesc->magic = VD_SET_MAG;
  3132.     
  3133.     /* common sectors buffer initiation */
  3134.     pVolDesc->sectBuf.sectData = NULL;
  3135.     if (cdromFsSectBufAlloc (pVolDesc, &(pVolDesc->sectBuf), 0) == ERROR)
  3136. return cdromFsDevDelete (pVolDesc, ERROR);
  3137.     /* create device protection mutual-exclusion semaphore */
  3138.     pVolDesc->mDevSem = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
  3139.     if (pVolDesc->mDevSem == NULL)
  3140. return cdromFsDevDelete (pVolDesc, ERROR);
  3141.     /* add device to device list */
  3142.     if (iosDevAdd ((DEV_HDR *)pVolDesc, devName,
  3143. cdromFsDrvNum) == ERROR)
  3144. return cdromFsDevDelete (pVolDesc, ERROR);
  3145.     DBG_MSG(50)("cdromFsDevCreate done for BLK_DEV * = 0x%x, sect = %dn",
  3146. (int)pBlkDev, pVolDesc->sectSize);
  3147.     return pVolDesc;
  3148.     }