home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / SHSUCD11.ZIP / CMDS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-28  |  24.6 KB  |  875 lines

  1. /**********************************************************************
  2.  
  3.   CMDS.C  Version 0.09
  4.   (c)John H. McCoy, March 1994
  5.   Sam Houston St. Univ., TX 77341-2206
  6.  
  7.   CMDS.C is a subset of redirector functions used by SHSUCDX.  SHSUCDX
  8.   is an unloadable CD_ROM redirector substitute for the Mirosoft CD-ROM
  9.   extensions (MSCDEX).
  10.  
  11.   Microsoft has not documented the redirector functions.  I have borrowed
  12.   from and am particularly indebted to the authors of:
  13.  
  14.      A CD-ROM redirector for HighSierra and ISO 9660 disks.
  15.         Jim Harper, DDJ, March 1993
  16.  
  17.      Inside the ISO-9660 Filesystem Format
  18.         William and Lynne Jolitz, DDJ, December 1992
  19.  
  20.      Undocumented DOS, Chapter 4.
  21.         Andrew Schulman, et. al, Addison Wesley, 1990
  22.  
  23.    SHSUCDX and CMDS.C are copyright reserved, free use programs.
  24.    (c)John H. McCoy, 1994, Sam Houston St. Univ., TX 77341-2206
  25.  
  26. ***********************************************************************
  27.    C subroutines written for MSC 5.1
  28. ***********************************************************************/
  29.  
  30. #pragma check_stack(off)
  31. #pragma pack(1)
  32.  
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <stddef.h>
  36. #include <dos.h>
  37. #include <bios.h>
  38. #include <memory.h>
  39. #include <errno.h>
  40.  
  41. typedef unsigned char  BYTE;
  42. typedef unsigned int   WORD;
  43. typedef unsigned long  DWORD;
  44. typedef void *         NPTR;
  45. typedef void far *     FPTR;
  46.  
  47. #include "cdrom.h"
  48. #include "redir.h"
  49.  
  50. #define MSCDEX_Q        0xADAD
  51. #define MSCDEX_R        0xDADA
  52.  
  53. /* Offsets in the CDS File Name */
  54. #define DriveOff        2
  55. #define RootSlashOff    7
  56.  
  57. /* Set & Clear Error Flag MACROS */
  58. #define SetC(X)         (X) |=  0x01
  59. #define ClrC(X)         (X) &= ~0x01
  60.  
  61. typedef struct DrvEnt
  62. {
  63.    BYTE            No;
  64.    BYTE            Letter;
  65.    BYTE            Unit;
  66.    BYTE            FlagsOff;
  67.    WORD            Type;
  68.    WORD            LastAccess;
  69.    FPTR            DevAddrp;
  70.    char            DriverName[8];
  71.    FPTR            DevStrategyp;
  72.    FPTR            DevInterruptp;
  73.    DWORD           VolSize;
  74.    WORD            BlkSize;
  75.    struct DirEnt   RootEnt;
  76.    DWORD           BufBlkNo;         /* block number of last block read    */
  77.    char            *Bufp;            /* into buffer  0xffffffffL if none   */
  78.    char            CopyRightID[13];
  79.    char            AbstractID[13];
  80.    char            VLabel[12];
  81. };
  82.  
  83. /* Globals.  Most of these are set up in SHSUCDX.ASM */
  84. extern char _far *FN1p, _far *SAttrp;
  85. extern char _far *DosDp, _far * _far *DTApp, _far * _far *SFTpp;
  86. extern struct SDB _far *SDBp;
  87. extern DWORD CDSp;
  88. extern WORD _far *PSPp;
  89. extern BYTE DeviceUnit, DriveNo, DriveIndex, NoDrives;
  90. extern char *IODatap;
  91. extern WORD _AX,_BX,_CX,_DX,_SI,_DI,_ES,_FLAGS, DataSeg;
  92.  
  93. extern struct DrvEnt    Drive[];
  94.  
  95. char   *IOBuf;
  96. WORD far *Ticks = (WORD far *)0x0040006CL;  /* clock in BIOS data area */
  97.  
  98. /* Protos */
  99.  
  100. void ToIBM(char *,int,char *),
  101.      ToFront(struct DirEnt *),
  102.      InitCD(void),
  103.      ToHex(WORD);
  104.      MsgOut(char *);
  105.  
  106. WORD DoGetAttr(void),
  107.      CDMediaChanged(void),
  108.      SetDDD(char),
  109.      ForUs(char),
  110.      CdReadBlk(DWORD),
  111.      CdReadLong(char _far *,DWORD,WORD),
  112.      DoFindFirst(void),
  113.      DoChDir(void),
  114.      DoClose(struct SFT _far *),
  115.      DoRead(struct SFT _far *),
  116.      DoGetSpace(void),
  117.      DoOpen(void),
  118.      DoFindNext(void),
  119.      DoSeek(struct SFT _far *),
  120.      PathLook(char _far *Dp, char _far *Pathp),
  121.      ToDosDate(struct Date_Time *),
  122.      ToDosTime(struct Date_Time *);
  123.  
  124. int  Match(char *,char *),
  125.      Lookup(struct DirEnt **),
  126.      DirLook(struct DirEnt *,struct DirEnt **,char *);
  127.  
  128. WORD SetDDD(char DriveLetter){
  129.  
  130. /* Search for matching drive letter and set DriveIndex, DriveNo
  131.    and DeviceUnit */
  132.  
  133.    DriveIndex = 0;
  134.    while (DriveIndex < NoDrives){
  135.        if ((Drive[DriveIndex].Letter) == DriveLetter){
  136.            DriveNo = Drive[DriveIndex].No;
  137.            DeviceUnit = Drive[DriveIndex].Unit;
  138.            return(0);
  139.        }
  140.        else
  141.            DriveIndex++;
  142.    }
  143.    return(1);
  144.  
  145. }
  146.  
  147. WORD ForUs(char DriveLetter){
  148. /* See if this call is for us and set DriveIndex, DeviceUnit and DriveNo */
  149.  
  150.    if (SetDDD(DriveLetter)) return(1);
  151.  
  152. /* Force re-init if its been a while and the media has changed.  */
  153.  
  154.    if ((*Ticks - Drive[DriveIndex].LastAccess) > 128 ){
  155.       if (CDMediaChanged() != 01){
  156.          Drive[DriveIndex].Type = UNKNOWN;
  157.       }
  158.    }
  159.  
  160.  
  161. /* May need to initialize this drive  */
  162.  
  163.    if (Drive[DriveIndex].Type == UNKNOWN){
  164.       Drive[DriveIndex].BufBlkNo = 0xFFFFFFFFL;
  165.       if (!CdReadBlk( 0x10L)){
  166.          InitCD();
  167.       }else{
  168.          SetC(_FLAGS);
  169.          return(0x02);
  170.       }
  171.    }
  172.  
  173.    Drive[DriveIndex].LastAccess = *Ticks;
  174.  
  175.    return (0);
  176.  
  177. }
  178.  
  179. void InitCD(void)
  180. {
  181.    int                    i,j;
  182.    struct isoVolDesc      *isoVolDescp;
  183.    struct isoDirRec       *isoDp;
  184.    struct hsVolDesc       *hsVolDescp;
  185.    struct hsDirRec        *hsDp;
  186.    struct DirEnt          *Dp;
  187.  
  188.    /* Flush the directory cache */
  189.  
  190.    for (Dp  = Drive[DriveIndex].RootEnt.Forw;
  191.         Dp != Drive[DriveIndex].RootEnt.Back;
  192.         Dp = Dp->Forw)
  193.       for (j=0; j< sizeof (Dp->FName);j++)
  194.          Dp->FName[j] = ' ';
  195.  
  196.    hsVolDescp = (struct hsVolDesc *) IOBuf;
  197.    isoVolDescp = (struct isoVolDesc *) IOBuf;
  198.  
  199.    if (strncmp(isoVolDescp->ID,"CD001",5) == 0) {
  200.  
  201.       for (i=0; i<11 && isoVolDescp->VolID[i] != '\0'; i++)
  202.            Drive[DriveIndex].VLabel[i] = isoVolDescp->VolID[i];
  203.       Drive[DriveIndex].VLabel[i] = '\0';
  204.  
  205.       for (i=0; i<12 && isoVolDescp->CopyRightID[i] != ' '; i++)
  206.          Drive[DriveIndex].CopyRightID[i] = isoVolDescp->CopyRightID[i];
  207.       Drive[DriveIndex].CopyRightID[i] = '\0';
  208.  
  209.       for (i = 0; i<12 && isoVolDescp->AbstractID[i] != ' '; i++)
  210.          Drive[DriveIndex].AbstractID[i] = isoVolDescp->AbstractID[i];
  211.       Drive[DriveIndex].AbstractID[i] = '\0';
  212.  
  213.       Drive[DriveIndex].Type = ISO9660;
  214.       Drive[DriveIndex].FlagsOff = 25;
  215.       isoDp = (struct isoDirRec *)isoVolDescp->DirRec;
  216.       Drive[DriveIndex].RootEnt.Fattr = _A_SUBDIR;
  217.       Drive[DriveIndex].RootEnt.FTime = ToDosTime(&isoDp->Date);
  218.       Drive[DriveIndex].RootEnt.FDate = ToDosDate(&isoDp->Date);
  219.       Drive[DriveIndex].RootEnt.BlkNo = isoDp->ExtLocLSB;
  220.       Drive[DriveIndex].RootEnt.FSize = isoDp->DataLenLSB;
  221.       Drive[DriveIndex].RootEnt.ParentBlk = isoDp->ExtLocLSB;
  222.       Drive[DriveIndex].BlkSize = isoVolDescp->BlkSizeLSB;
  223.       Drive[DriveIndex].VolSize = isoVolDescp->VolSizeLSB;
  224.    }
  225.  
  226.    if (strncmp(hsVolDescp->ID,"CDROM",5) == 0) {
  227.  
  228.        for (i=0; i<11 && hsVolDescp->VolID[i] != '\0'; i++)
  229.            Drive[DriveIndex].VLabel[i] = hsVolDescp->VolID[i];
  230.        Drive[DriveIndex].VLabel[i] = '\0';
  231.  
  232.  
  233.       for (i=0; i<12 && hsVolDescp->CopyRightID[i] != ' '; i++)
  234.          Drive[DriveIndex].CopyRightID[i] = hsVolDescp->CopyRightID[i];
  235.       Drive[DriveIndex].CopyRightID[i] = '\0';
  236.  
  237.       for (i = 0; i<12 && hsVolDescp->AbstractID[i] != ' '; i++)
  238.          Drive[DriveIndex].AbstractID[i] = hsVolDescp->AbstractID[i];
  239.       Drive[DriveIndex].AbstractID[i] = '\0';
  240.  
  241.       Drive[DriveIndex].Type = HIGHSIERRA;
  242.       Drive[DriveIndex].FlagsOff = 24;
  243.       hsDp = (struct hsDirRec *)hsVolDescp->DirRec;
  244.       Drive[DriveIndex].RootEnt.Fattr = _A_SUBDIR;
  245.       Drive[DriveIndex].RootEnt.FTime = ToDosTime(&hsDp->Date);
  246.       Drive[DriveIndex].RootEnt.FDate = ToDosDate(&hsDp->Date);
  247.       Drive[DriveIndex].RootEnt.BlkNo = hsDp->ExtLocLSB;
  248.       Drive[DriveIndex].RootEnt.FSize = hsDp->DataLenLSB;
  249.       Drive[DriveIndex].RootEnt.ParentBlk = hsDp->ExtLocLSB;
  250.       Drive[DriveIndex].BlkSize = hsVolDescp->BlkSizeLSB;
  251.       Drive[DriveIndex].VolSize = hsVolDescp->VolSizeLSB;
  252.    }
  253.  
  254.    for (i = 10; i>=0 && (Drive[DriveIndex].VLabel[i] == ' ' ||
  255.                                    Drive[DriveIndex].VLabel[i] == '\0');i--);
  256.  
  257.    Drive[DriveIndex].VLabel[i+1] = '\0';
  258.  
  259.    return;
  260. }
  261.  
  262. WORD DoOpen(void)
  263. {
  264.    struct SFT _far  *SFTp;
  265.    struct DirEnt    *Dp;
  266.    int              i;
  267.    WORD             Err;
  268.  
  269.    /* Look up filename */
  270.    if ((Err = Lookup(&Dp)) != 0) {
  271.       SetC(_FLAGS);
  272.       return(Err);
  273.    }
  274.  
  275.    /* Gotta be a file, not a dir */
  276.    if (Dp->Fattr & _A_SUBDIR) {
  277.       SetC(_FLAGS);
  278.       return(FILENOTFOUND);
  279.    }
  280.  
  281.    /* Get system file table pointer */
  282.    SFTp = (struct SFT _far *) *SFTpp;
  283.  
  284.    /* And fill it in */
  285.    for (i = 0; i < 11; i++) SFTp->Name[i] = Dp->FName[i];
  286.    SFTp->Mode = SFTp->Mode | 0x02;
  287.    SFTp->DirAttrib = Dp->Fattr;
  288.    SFTp->Flags = 0x8000 | 0x40 | DriveNo;
  289.    SFTp->HHMMSS = Dp->FTime;
  290.    SFTp->YYMMDD = Dp->FDate;
  291.    SFTp->FilSiz = Dp->FSize;
  292.    SFTp->FilPos = 0L;
  293.    SFTp->FBN = Dp->BlkNo;
  294.    SFTp->CDSp = CDSp;
  295.    SFTp->Owner = MSCDEX_R;
  296.    ClrC(_FLAGS);
  297.    return(0);
  298. }
  299.  
  300. WORD DoChDir(void)
  301. {
  302.    WORD            Err;
  303.    struct DirEnt   *Dp;
  304.  
  305.    /* Validate the proposed current directory */
  306.    if ((Err = Lookup(&Dp)) != 0) {
  307.       SetC(_FLAGS);
  308.       return(Err);
  309.    }
  310.  
  311.    /* Gotta be a dir, not a file */
  312.    if ((Dp->Fattr & _A_SUBDIR) == 0 ) {
  313.       SetC(_FLAGS);
  314.       return(PATHNOTFOUND);
  315.    }
  316.  
  317.    ClrC(_FLAGS);
  318.    return(0);
  319. }
  320.  
  321. WORD DoFindFirst(void){
  322.    struct DirEnt      *Dp;
  323.    int                i, Ch;
  324.    unsigned           Err;
  325.    char               *Chp, _far *Fnp, FNBuf[12], TemPlate[11];
  326.    struct FDB _far    *FDBp;
  327.  
  328.    FDBp = (struct FDB _far *) (*DTApp + sizeof(struct SDB));
  329.    SDBp->DriveLet = (DriveNo | 0xC0);
  330.  
  331.    /*
  332.     * Set up SDB and call findnext.
  333.     */
  334.  
  335.    /* Find end of path string */
  336.    for (i = RootSlashOff; FN1p[i]; i++)    ;
  337.  
  338.    /* find last path separator */
  339.    while (FN1p[i] != PATHSEPARATOR && i > RootSlashOff)  i-- ;
  340.  
  341.    /* Isolate directory path */
  342.    Ch = FN1p[i];
  343.    FN1p[i] = '\0';
  344.  
  345.  
  346.    /* Handle vol id */
  347.    if (*SAttrp & _A_VOLID){
  348.       if ((*SAttrp == _A_VOLID) || (FN1p[RootSlashOff] == '\0')){
  349.          for (i = 0; i<11 ; i++){
  350.             FDBp->FName[i] = Drive[DriveIndex].VLabel[i];
  351.          }
  352.          for (i = 0; i < 11; i++) SDBp->TemPlate[i] = '?';
  353.          SDBp->SAttr = *SAttrp & 0x1e;
  354.          SDBp->Entry = 1;
  355.          FDBp->Fattr = _A_VOLID;
  356.          FDBp->FDate = 0;
  357.          FDBp->FTime = 0;
  358.          FDBp->FSize = 0;
  359.          ClrC(_FLAGS);
  360.          return(0);
  361.       }
  362.    }
  363.    /* Look for the directory */
  364.    if ((Err = Lookup(&Dp)) != 0){
  365.       SetC(_FLAGS);
  366.       return(Err);
  367.    }
  368.  
  369.    /* Restore full pathname */
  370.    FN1p[i] = Ch;
  371.  
  372.    /* Gotta be a dir, not a file */
  373.    if ((Dp->Fattr & _A_SUBDIR) == 0){
  374.       SetC(_FLAGS);
  375.       return(PATHNOTFOUND);
  376.    }
  377.  
  378.    /* FN1p is far ptr.  Copy name to local field and convert it to DOS style */
  379.    if (Ch == PATHSEPARATOR)  i++ ;
  380.    Fnp = &FN1p[i];
  381.    for (i = 0; *Fnp; i++)  FNBuf[i] = *Fnp++;
  382.    ToIBM(TemPlate,i,FNBuf);
  383.  
  384.    /* Fill in the SDB */
  385.    for (i = 0; i < 11; i++)  SDBp->TemPlate[i] = TemPlate[i];
  386.    SDBp->SAttr = *SAttrp & 0x1e;
  387.    SDBp->ParentBlk = Dp->BlkNo;
  388.    SDBp->ParentSize = Dp->FSize;
  389.    if (Dp->BlkNo == Drive[DriveIndex].RootEnt.BlkNo){
  390.       SDBp->Entry = 3;            /* Skip the . & .. entries in root dir */
  391.    }else{
  392.       SDBp->Entry = 1;
  393.    }
  394.  
  395.    /* Now see if it can be found */
  396.    Err = DoFindNext();
  397.    return(Err);
  398. }
  399.  
  400. unsigned DoFindNext(void)
  401. {
  402.    int                  Entry, Flags, ExtRecLen, i;
  403.    char                 *Chp, IBMName[11], TemPlate[11];
  404.    unsigned long        BlkNo, EndBlk;
  405.    struct FDB _far      *FDBp;
  406.    WORD                 NoMatchingEntry;
  407.  
  408.  
  409.    FDBp = (struct FDB _far *) (*DTApp + sizeof(struct SDB));
  410.  
  411.    /* Get copy of search template */
  412.    for (i = 0; i < 11; i++) TemPlate[i] = SDBp->TemPlate[i];
  413.  
  414.    /* Where's the end of the dir extent?
  415.       ISO directories are supposed to be padded with zeroes to 2048
  416.       bytes.  Don't know about HS and not all ISO CD's do so we will
  417.       take precautions.
  418.    */
  419.  
  420.    EndBlk = SDBp->ParentBlk + (SDBp->ParentSize / Drive[DriveIndex].BlkSize);
  421.    if ((SDBp->ParentSize % Drive[DriveIndex].BlkSize)==0) EndBlk--;
  422.  
  423.    /* Search parent dir for matching entry */
  424.    NoMatchingEntry = 1;
  425.    for (BlkNo = SDBp->ParentBlk; BlkNo <= EndBlk; BlkNo++) {
  426.        CdReadBlk(BlkNo);
  427.        Entry = 1;
  428.        for (Chp = IOBuf; *Chp; Chp += *(BYTE *)Chp, Entry++) {
  429.            /* Ignore entries < our start entry # */
  430.            if ((Entry < SDBp->Entry) ||
  431.                (*(Chp+Drive[DriveIndex].FlagsOff)& ASSOCFILE)) continue;
  432.            ToIBM(IBMName,*(Chp+FIDLenoff),Chp+Nameoff);
  433.            Flags = (*(Chp+Drive[DriveIndex].FlagsOff) & DIR) ?
  434.                                                          _A_SUBDIR : 0;
  435.  
  436.            Flags |= (*(Chp+Drive[DriveIndex].FlagsOff) & HIDDEN ) ?
  437.                                                          _A_HIDDEN : 0;
  438.  
  439.            if (Flags == 0 ){
  440.                /* return all matching normal files  */
  441.                if (Match(IBMName,TemPlate)){
  442.                    NoMatchingEntry = 0; break;
  443.                }
  444.            }else if ((SDBp->SAttr & Flags) == Flags){
  445.                /* return matching dirs and/or hidden files */
  446.                if (Match(IBMName,TemPlate)){
  447.                    NoMatchingEntry = 0; break;
  448.                }
  449.            }
  450.  
  451.        }
  452.        if (!NoMatchingEntry) break;
  453.        /* Subtract what's been searched in case we come this way again */
  454.        SDBp->ParentSize -= Drive[DriveIndex].BlkSize;
  455.        SDBp->ParentBlk = BlkNo + 1;
  456.        SDBp->Entry = 1;
  457.    }
  458.  
  459.    if (NoMatchingEntry){
  460.       SetC(_FLAGS);
  461.       return(NOMOREFILES);
  462.    }
  463.  
  464.    /* Save start point for next time */
  465.    SDBp->Entry = Entry + 1;
  466.  
  467.    /* Fill in the FDB */
  468.    for (i = 0; i < 11; i++) FDBp->FName[i] = IBMName[i];
  469.    FDBp->Fattr = Flags | _A_RDONLY;
  470.    FDBp->FDate = ToDosDate((struct Date_Time *)(Chp + Dateoff));
  471.    FDBp->FTime = ToDosTime((struct Date_Time *)(Chp + Dateoff));
  472.    FDBp->FSize = *((unsigned long *)(Chp + Sizeoff));
  473.  
  474.    ClrC(_FLAGS);
  475.    return(0);
  476. }
  477.  
  478. WORD DoGetSpace(void)
  479. {
  480.    _CX = Drive[DriveIndex].BlkSize;    /* # bytes/sector */
  481.    _DX = 0U;                          /* # clusters available */
  482.    _AX = 1;             /* # sectors/cluster */
  483.    if (Drive[DriveIndex].VolSize <= 0xffffU){
  484.       _BX = Drive[DriveIndex].VolSize;       /*  # clusters on drive */
  485.    }else{
  486.       _BX = 0xffffU;       /* best we can do for clusters on drive */
  487.    }                       /* and be compatable with MSCDEX        */
  488.    ClrC(_FLAGS);
  489.    return(0);
  490. }
  491.  
  492. WORD DoRead(struct SFT _far *SFTp)
  493. {
  494.    char _far           *DTAp;
  495.    char                *BufPosp;
  496.    WORD                Offset, NumRead, ReadLen, N;
  497.    DWORD               BlkNo;
  498.  
  499.    /* Get DTA ptr */
  500.    DTAp = (char _far *) *DTApp;
  501.  
  502.    /* Cant't read past EOF */
  503.    if (SFTp->FilPos >= SFTp->FilSiz) {
  504.      _CX = 0x00;
  505.      ClrC(_FLAGS);
  506.      return(0);
  507.    }
  508.  
  509.    /* Chop read back if too long */
  510.    if ((SFTp->FilPos + _CX) > SFTp->FilSiz)
  511.       _CX = SFTp->FilSiz - SFTp->FilPos;
  512.    /* Keep track of how much we've read */
  513.    NumRead = 0;
  514.  
  515.    while (NumRead < _CX) {
  516.       /* Calc blk w/start of data */
  517.       BlkNo = SFTp->FBN + (SFTp->FilPos / Drive[DriveIndex].BlkSize);
  518.       ReadLen = _CX - NumRead;
  519.  
  520.       /* Special case - read direct (on blk boundry, over 1 blk) */
  521.       if ((SFTp->FilPos % Drive[DriveIndex].BlkSize) == 0 &&
  522.                        (ReadLen / Drive[DriveIndex].BlkSize) > 0) {
  523.          ReadLen = (ReadLen / Drive[DriveIndex].BlkSize) * Drive[DriveIndex].BlkSize;
  524.          CdReadLong(DTAp,BlkNo,ReadLen/Drive[DriveIndex].BlkSize);
  525.          SFTp->FilPos += ReadLen;
  526.          NumRead += ReadLen;
  527.          DTAp += ReadLen;
  528.       } else {
  529.          /* Partial block */
  530.          Offset = SFTp->FilPos % Drive[DriveIndex].BlkSize;
  531.          N = min(Drive[DriveIndex].BlkSize - Offset,_CX - NumRead);
  532.          CdReadBlk(BlkNo);
  533.          BufPosp = IOBuf + Offset;
  534.          movedata((int)DataSeg,
  535.                   (int)(BufPosp),
  536.                   FP_SEG(DTAp),
  537.                   FP_OFF(DTAp),
  538.                   (WORD)N);
  539.          SFTp->FilPos += N;
  540.          NumRead += N;
  541.          DTAp += N;
  542.       }
  543.    }
  544.  
  545.    ClrC(_FLAGS);
  546.    return(0);
  547. }
  548.  
  549. WORD DoClose(struct SFT _far *SFTp)
  550. {
  551.  
  552.    if (SFTp->RefCnt > 1)
  553.       SFTp->RefCnt--;     /* Schulman says don't but MSCDEX does */
  554.    else if (SFTp->RefCnt = 1){
  555.            SFTp->RefCnt--;
  556.            SFTp->FBN = 0L;
  557.         }
  558.    SFTp->Owner = 0;
  559.    ClrC(_FLAGS);
  560.    return(0);
  561. }
  562.  
  563. WORD DoGetAttr(void){
  564.  
  565.    struct DirEnt        *Dp;
  566.    int                  Err;
  567.  
  568.    /* Look up filename (full path) */
  569.    if ((Err = Lookup(&Dp)) != 0) {
  570.       SetC(_FLAGS);
  571.       _AX = Err;
  572.       return;
  573.    }
  574.  
  575.    /* Get attributes */
  576.    _AX = Dp->Fattr;
  577.    ClrC(_FLAGS);
  578.    return;
  579. }
  580.  
  581. WORD DoSeek(struct SFT _far *SFTp) {
  582.  
  583.    DWORD        Offset;
  584.  
  585.    /* Should make a seek call to cd but just fake it for now.
  586.       Shulman changes file pos but MSCDEX doesn't             */
  587.  
  588.    Offset = SFTp->FilSiz - (unsigned long)((_CX<<16U) + _DX);
  589.  
  590.    /* return seek to position in DX:AX */
  591.    _AX = (WORD) Offset;
  592.    _DX = (WORD) (Offset >> 16U);
  593.    ClrC(_FLAGS);
  594.    return(0);
  595. }
  596.  
  597. WORD CdReadBlk(DWORD BlkNo)
  598. {
  599.    WORD      DriveStatus;
  600.  
  601.    IOBuf = Drive[DriveIndex].Bufp;
  602.    if (BlkNo == Drive[DriveIndex].BufBlkNo) return(0U);
  603.    DriveStatus = CdReadLong((char _far *) IOBuf, BlkNo, 1L);
  604.    if (DriveStatus == 0x100){
  605.       Drive[DriveIndex].BufBlkNo = BlkNo;
  606.       return(0U);
  607.    }else{
  608.       Drive[DriveIndex].BufBlkNo = 0xffffffffL;
  609.       return(1U);
  610.    }
  611. }
  612.  
  613. void ToIBM(char *IBMName,int FIDLen,char *Chp) /* 9660 name to DOS name */
  614. {
  615.    int                  i, j;
  616.  
  617.    for (i = 0; i < 11; i++) IBMName[i] = ' ';
  618.  
  619.    /* return '.' for self */
  620.    if (FIDLen == 1 && *Chp == 0x00) {
  621.       IBMName[0] = '.';
  622.       return;
  623.    }
  624.  
  625.    /* return '..' for parent */
  626.    if (FIDLen == 1 && *Chp == 0x01) {
  627.       IBMName[0] = '.';
  628.       IBMName[1] = '.';
  629.       return;
  630.    }
  631.  
  632.    for (i = j = 0; j < 11 && i < FIDLen && Chp[i] != '.' &&
  633.                Chp[i] != ';' && Chp[i] != '\0'; i++) IBMName[j++] = Chp[i];
  634.  
  635.    if (i < FIDLen && Chp[i++] == '.')
  636.        for (j = 8; i < FIDLen && j < 11 &&
  637.                Chp[i] != ';' && Chp[i] != '\0'; i++) IBMName[j++] = Chp[i];
  638. }
  639.  
  640. int Match(char *Name,char *TemPlate) /* Check name against wildcard */
  641. {
  642.    int i;
  643.  
  644.    for (i = 0; i < 11; i++) {
  645.       if (TemPlate[i] == '?') continue;
  646.       if (TemPlate[i] != Name[i]) return(0);
  647.    }
  648.  
  649.    return(1);
  650. }
  651.  
  652. WORD ToDosDate(struct Date_Time *Date)
  653. { if (Date->Yr < 80)
  654.     return(  0 | (Date->Mth << 5U) | Date->Day );
  655.   else
  656.     return( ((Date->Yr - 80) << 9U) | (Date->Mth << 5U) | Date->Day );
  657. }
  658.  
  659. WORD ToDosTime(struct Date_Time *Date)
  660. {
  661.    return ( (Date->Hr << 11U) | (Date->Min << 5U) | (Date->Sec >> 1U));
  662. }
  663.  
  664. int Lookup(struct DirEnt **Dpp) /* Find name in dir if it exists */
  665. {
  666.    char                Name[13];
  667.    struct DirEnt        *pDp, *cDp;
  668.    int                  Err;
  669.    char _far            *Pathp, *Chp;
  670.  
  671.    /* Check for root */
  672.    if (FN1p[RootSlashOff] == '\0') {
  673.       *Dpp = &Drive[DriveIndex].RootEnt;
  674.       return(0);
  675.    }
  676.  
  677.    /* Skip drive letters form \\D.\U.    */
  678.  
  679.    Pathp = FN1p + RootSlashOff +1;
  680.  
  681.    /* Start at root */
  682.    pDp = cDp = &Drive[DriveIndex].RootEnt;
  683.  
  684.    while (*Pathp) {
  685.       Chp = Name;
  686.       while(*Pathp && *Pathp != PATHSEPARATOR) *Chp++ = *Pathp++;
  687.       *Chp++ = '\0';
  688.  
  689.       /* Look up Name */
  690.       if ((Err = DirLook(pDp,&cDp,Name)) != 0) return(Err);
  691.  
  692.       /* Move down a level */
  693.       pDp = cDp;
  694.  
  695.       if (*Pathp == PATHSEPARATOR) Pathp++;
  696.    }
  697.    *Dpp = cDp;
  698.    return(0);
  699. }
  700.  
  701. WORD PathLook(char _far *Dp, char _far *Pathp) /* Find path */
  702. {
  703.    char                Name[13],WantName[11], FName[11];
  704.    struct DirEnt        *pDp, *cDp;
  705.    int                  i,j,Err;
  706.    int                  ExtRecLen, NoMatchingEntry;
  707.    char                 *Chp;
  708.    DWORD                BlkNo, EndBlk;
  709.  
  710.    if (*Pathp != PATHSEPARATOR){
  711.       SetC(_FLAGS);
  712.       return(FILENOTFOUND);
  713.    }
  714.  
  715.    /* Check for filename and isolate it */
  716.    for (j=0;*(Pathp +j) != '\0';j++);
  717.    for (i=j;*(Pathp+i) != PATHSEPARATOR;i--);
  718.    if ( (j-i) < 2){
  719.       SetC(_FLAGS);
  720.       return(FILENOTFOUND);
  721.    }
  722.  
  723.  
  724.    Pathp[i] = '\0';  /* isolate path from file name */
  725.  
  726.    /* Find subdirectory */
  727.    cDp = &Drive[DriveIndex].RootEnt;
  728.    if (i > 1){
  729.      Pathp++;
  730.      while (*Pathp) {
  731.        Chp = Name;
  732.        while(*Pathp && *Pathp != PATHSEPARATOR) *Chp++ = *Pathp++;
  733.        *Chp++ = '\0';
  734.        pDp = cDp;
  735.        /* Look up Name */
  736.        if ( DirLook(pDp,&cDp,Name)){
  737.          SetC(_FLAGS);
  738.          return(PATHNOTFOUND);
  739.        }
  740.  
  741.        if (*Pathp == PATHSEPARATOR) Pathp++;
  742.      }
  743.    }
  744.    /* Gotta be a dir, not a file */
  745.    if ((cDp->Fattr & _A_SUBDIR) == 0){
  746.       SetC(_FLAGS);
  747.       return(PATHNOTFOUND);
  748.    }
  749.    /* found directory now find the directory entry for the file */
  750.  
  751.    pDp = cDp;
  752.  
  753.    Pathp++;
  754.    Chp = Name;
  755.    while(*Pathp && *Pathp != PATHSEPARATOR) *Chp++ = *Pathp++;
  756.    *Chp++ = '\0';
  757.    ToIBM(WantName,12,Name);
  758.  
  759.    /* Where's the end of the dir extent?
  760.       ISO directories are supposed to be padded with zeroes to 2048
  761.       bytes.  Don't know about HS and not all ISO CD's do so we will
  762.       take precautions.
  763.    */
  764.    EndBlk = pDp->BlkNo + (pDp->FSize / Drive[DriveIndex].BlkSize);
  765.    if ((pDp->FSize % Drive[DriveIndex].BlkSize)==0) EndBlk--;
  766.  
  767.    /* Read dir extent and scan it for match */
  768.    NoMatchingEntry = 1;
  769.    for (BlkNo = pDp->BlkNo; (NoMatchingEntry) && (BlkNo <= EndBlk); BlkNo++) {
  770.       CdReadBlk(BlkNo);
  771.  
  772.       for (Chp = IOBuf; *Chp; Chp += *(BYTE *)Chp) {
  773.  
  774.          /* Don't match assoc files   */
  775.          if (*(Chp+Drive[DriveIndex].FlagsOff)& ASSOCFILE)  continue;
  776.  
  777.          /* Convert to IBM style name */
  778.          ToIBM(FName,*(Chp+FIDLenoff),Chp+Nameoff);
  779.  
  780.          if (Match(FName,WantName)){NoMatchingEntry = 0; break;}
  781.       }
  782.    }
  783.  
  784.    if (NoMatchingEntry)  return(FILENOTFOUND);
  785.    j= *Chp;
  786.    Chp++;
  787.    for (i=1;i<j;i++){*Dp++ = *Chp++;}
  788.    return( Drive[DriveIndex].Type);
  789.  
  790. }
  791.  
  792. int DirLook(struct DirEnt *pDp,struct DirEnt **cDpp,char *Name)
  793. /*
  794.  * See if Name is present in pDp, if so return a DirEnt struct using cDpp
  795.  * pDp - Parent DirEnt structure pointer.
  796.  * cDpp - Child DirEnt structure pointer pointer.
  797.  */
  798.  
  799. {
  800.    struct DirEnt        *Dp;
  801.    char                 *Chp, WantName[11], FName[11];
  802.    int                  ExtRecLen, NoMatchingEntry;
  803.    DWORD                BlkNo, EndBlk;
  804.  
  805.  
  806.    /* Is a dir? */
  807.    if ((pDp->Fattr & _A_SUBDIR) == 0) return(PATHNOTFOUND);
  808.  
  809.    /* Convert Name to IBM style */
  810.    ToIBM(WantName,12,Name);
  811.  
  812.    /* Check cache */
  813.    for (Dp = Drive[DriveIndex].RootEnt.Forw;
  814.         Dp != &Drive[DriveIndex].RootEnt; Dp = Dp->Forw) {
  815.       if (Dp->ParentBlk == pDp->BlkNo && !strncmp(WantName,Dp->FName,11)) {
  816.           ToFront(Dp);
  817.           *cDpp = Dp;
  818.           return(0);
  819.        }
  820.    }
  821.  
  822.    /* Where's the end of the dir extent?
  823.       ISO directories are supposed to be padded with zeroes to 2048
  824.       bytes.  Don't know about HS and not all ISO CD's do so we will
  825.       take precautions.
  826.    */
  827.    EndBlk = pDp->BlkNo + (pDp->FSize / Drive[DriveIndex].BlkSize);
  828.    if ((pDp->FSize % Drive[DriveIndex].BlkSize)==0) EndBlk--;
  829.  
  830.    /* Read dir extent and scan it for match */
  831.    NoMatchingEntry = 1;
  832.    for (BlkNo = pDp->BlkNo; (NoMatchingEntry) && (BlkNo <= EndBlk); BlkNo++) {
  833.       CdReadBlk(BlkNo);
  834.  
  835.       for (Chp = IOBuf; *Chp; Chp += *(BYTE *)Chp) {
  836.          /* ignore associative entries  */
  837.          if (*(Chp+Drive[DriveIndex].FlagsOff)& ASSOCFILE)  continue;
  838.          /* Convert to IBM style name */
  839.          ToIBM(FName,*(Chp+FIDLenoff),Chp+Nameoff);
  840.  
  841.          if (Match(FName,WantName)){NoMatchingEntry = 0; break;}
  842.       }
  843.    }
  844.  
  845.    if (NoMatchingEntry)  return(FILENOTFOUND);
  846.  
  847.    /* Take from tail of cache queue */
  848.    Dp = Drive[DriveIndex].RootEnt.Back;
  849.    strncpy(Dp->FName,FName,11);
  850.    ExtRecLen = *(Chp+1) & 0xff;
  851.    Dp->Fattr = (*(Chp+Drive[DriveIndex].FlagsOff) & DIR) ?
  852.                                      _A_SUBDIR : _A_RDONLY;
  853.    Dp->FTime = ToDosTime((struct Date_Time *)(Chp + Dateoff));
  854.    Dp->FDate = ToDosDate((struct Date_Time *)(Chp + Dateoff));
  855.    Dp->BlkNo = *((DWORD *)(Chp + Blkoff)) + ExtRecLen;
  856.    Dp->FSize = *((DWORD *)(Chp + Sizeoff));
  857.    Dp->ParentBlk = pDp->BlkNo;
  858.  
  859.    /* Move Dp to front of cache queue */
  860.    ToFront(Dp);
  861.  
  862.    *cDpp = Dp;
  863.    return(0);
  864. }
  865.  
  866. void ToFront(struct DirEnt *Dp) /* Move cache entry to front */
  867. {
  868.    Dp->Forw->Back = Dp->Back;                   /* Unlink */
  869.    Dp->Back->Forw = Dp->Forw;
  870.  
  871.    Dp->Forw = Drive[DriveIndex].RootEnt.Forw;   /* Link in after RootEnt */
  872.    Drive[DriveIndex].RootEnt.Forw = Dp;
  873.    Dp->Back = Dp->Forw->Back;
  874.    Dp->Forw->Back = Dp;
  875. }