home *** CD-ROM | disk | FTP | other *** search
/ CD-X 1 / cdx_01.iso / shareuti / secdev13 / source / secdev.asm < prev    next >
Encoding:
Assembly Source File  |  1994-05-02  |  70.6 KB  |  1,766 lines

  1. ; This file is a part of SecureDevice 1.3
  2. ; Copyright (C) 1994 by Max Loewenthal and Arthur Helwig
  3.  
  4. ; This program is free software; you can redistribute it and/or modify
  5. ; it under the terms of the GNU General Public License as published by
  6. ; the Free Software Foundation; either version 2 of the License, or
  7. ; (at your option) any later version.
  8.  
  9. ; This program is distributed in the hope that it will be useful,
  10. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ; GNU General Public License for more details.
  13.  
  14. ; You should have received a copy of the GNU General Public License
  15. ; along with this program; if not, write to the Free Software
  16. ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. IDEAL
  19. MODEL       TINY,C
  20.  
  21. JUMPS
  22. LOCALS      @@
  23.  
  24.             STRUC       DirEntry
  25.                         FileName    DB          11 DUP(?)
  26.                         Attr        DB          ?
  27.                         Reserved    DB          10 DUP(?)
  28.                         DateTime    DD          ?
  29.                         Cluster     DW          ?
  30.                         Size        DD          ?
  31.             ENDS        DirEntry
  32.  
  33.             ; values for Attr:
  34.             atReadOnly  =            1h
  35.             atHidden    =            2h
  36.             atSystem    =            4h
  37.             atVolLabel  =            8h
  38.             atDirectory =           10h
  39.             atArchive   =           20h
  40.  
  41.             StackSize   =          2048
  42.  
  43.             KeySize     =           104
  44.  
  45. INCLUDE     'GLOBALS.ASM'
  46. INCLUDE     'DVSTRUCS.ASM'
  47.  
  48. MinorName   EQU         "SECDEV.SYS"
  49. MinorVer    EQU         "1.03"
  50.       
  51. MaxNofVols  =           10
  52. MaxMaxTimeOut=          59
  53.  
  54.             STRUC       ChainElm
  55.                         Cluster                 DW ?
  56.                         Count                   DW ?
  57.             ENDS        ChainElm
  58.  
  59.             STRUC       VolumeRec
  60.                         FileName                DB '           '
  61.                         Drive                   DB ?
  62.                         Unit                    DB ?
  63.                         MediaDesc               DB ?
  64.  
  65.                         DadsDPB                 DD ?
  66.                         DadsAttr                DW ?
  67.                         DadsStrategy            DD ?
  68.                         DadsInterrupt           DD ?
  69.  
  70.                         NofTicks                DW -1
  71.  
  72.                         MyBPB                   BPBRec <>
  73.                         FirstCluster            DW ?
  74.                         Chain                   ChainElm MaxNofParts DUP (<0,0>)
  75.                         Key                     DB KeySize DUP (0)
  76.                         IV                      DW 4 DUP (?)
  77.                         Check                   DW 4 DUP (?)
  78.                         KeyOk                   DB 0        ; 1=key ok.
  79.  
  80.                         Error                   DB 1        ; 0=no error on last op.
  81.             ENDS        VolumeRec
  82.  
  83. ; format of Chain:
  84. ;        Cluster  ,  Count:WORD
  85. ;          ...          ...
  86. ;           0
  87.  
  88.             MACRO       DumpString  Msg
  89.                         ;; kills DX en AX
  90.                                     MOV         DX,Msg
  91.                                     MOV         AH,9
  92.                                     INT         21h
  93.             ENDM        DumpString
  94.  
  95.             MACRO       InBound     Value,Lower,Upper
  96.                         LOCAL       @@Exit
  97.                         ;; ZF := Lower<=Value<=Upper
  98.                                     CMP         Value,Lower
  99.                                     JB          @@Exit
  100.                                     CMP         Value,Upper
  101.                                     JA          @@Exit
  102.                                     CMP         AX,AX
  103.                         @@Exit:
  104.             ENDM        InBound
  105.  
  106. CODESEG
  107.             ORG         0
  108.  
  109.             ASSUME      SS:NOTHING,DS:NOTHING,ES:NOTHING,CS:@CODE
  110.  
  111.             Header      DeviceHeader <-1,2,OFFSET Strategy,OFFSET Interrupt,1>
  112.  
  113. MASM
  114. INCLUDE     IDEA.INC
  115. IDEAL
  116.  
  117.             RequestPtr  DD          ?
  118.             OldInt2F    DD          ?
  119.             OldInt08    DD          ?
  120.             MaxNofTicks DW          0
  121.  
  122. LABEL       BPBArray    WORD
  123.  
  124.             i           =           0
  125.             REPT        MaxNofVols
  126.                         DW          i+OFFSET Volume.MyBPB
  127.                         i           =i+SIZE VolumeRec
  128.             ENDM
  129.  
  130.             NofVolumes  DB          0
  131.             DosVersion  DW          0
  132.             OldStack    DD          ?
  133.  
  134.             MaxCmd      EQU         23
  135.  
  136.             JmpTab      DW          Init            ; init
  137.                         DW          MediaCheck      ; media check
  138.                         DW          Buildbpb        ; build bpb
  139.                         DW          Noerror         ; IOCTL input
  140.                         DW          Input           ; input (read from device)
  141.                         DW          Noerror         ; non-destructive input [char]
  142.                         DW          Noerror         ; input status [char]
  143.                         DW          Noerror         ; input flush [char]
  144.                         DW          Output          ; output (write to device)
  145.                         DW          Output          ; output with verify
  146.                         DW          Noerror         ; output status [char]
  147.                         DW          Noerror         ; output flush [char]
  148.                         DW          Noerror         ; IOCTL output
  149.                         DW          Noerror         ; Device Open
  150.                         DW          Noerror         ; Device Close
  151.                         DW          Noerror         ; Removable Media
  152.                         DW          Noerror         ; --- reserved ---
  153.                         DW          Noerror         ; --- reserved ---
  154.                         DW          Noerror         ; --- reserved ---
  155.                         DW          Noerror         ; Generic IOCTL request
  156.                         DW          Noerror         ; --- reserved ---
  157.                         DW          Noerror         ; --- reserved ---
  158.                         DW          Noerror         ; --- reserved ---
  159.  
  160.             BaseDrive   DB          ?           ; 0-based drive of 1st volume
  161.             DriverIndex DW          ?           ; 0-based index of this driver (or how many
  162.                                                 ;      drivers were loaded before this one)
  163.  
  164. PROC        NewInt2F    FAR
  165.             ; AH=E2
  166.             ; Subfuncs:
  167.  
  168.             ;   AL=0                Login to drive
  169.             ;     expects: DL       drive (0=A)
  170.             ;              DS:SI    ptr to key (104 bytes)
  171.             ;     returns: AL       0: don't know if key is good
  172.             ;                       1: key is good
  173.             ;                       FF: key is not good
  174.  
  175.             ;   AL=1                Get information
  176.             ;     expects: DX       driver index (0-based)
  177.             ;     returns: AL       number of volumes
  178.             ;              DL       drive number of 1st volume (0=A)
  179.  
  180.             ;   AL=3                Destroy password
  181.             ;     expects: DL       drive (0=A, 0FFh=all)
  182.             ;     returns:          nothing
  183.  
  184.             ;   AL=9                counts drivers/installation check
  185.             ;     expects: DX=0,AX=0
  186.             ;     returns: DX       number of drivers in memory
  187.             ;              AX       1DEAh on success
  188.  
  189.  
  190.             ASSUME      DS:NOTHING,SS:NOTHING,ES:NOTHING,CS:@CODE
  191.                         CMP         AH,0E2h
  192.                         JE          @@1
  193.  
  194.             @@DoOld:    JMP         [OldInt2F]
  195.  
  196.             @@1:        CMP         AL,0
  197.                         JNE         @@2
  198.  
  199.             @@Login:    CMP         DL,[BaseDrive]
  200.                         JB          @@DoOld
  201.                         PUSH        DX
  202.                         SUB         DL,[BaseDrive]
  203.                         CMP         DL,[NofVolumes]
  204.                         POP         DX
  205.                         JNB         @@DoOld
  206.                         SUB         DL,[BaseDrive]
  207.  
  208.                         PUSH        ES DI DX CX BX
  209.  
  210.                         PUSH        SI
  211.                         MOV         DH,0
  212.                         MOV         AX,SIZE VolumeRec
  213.                         MUL         DX
  214.                         MOV         BX,AX
  215.                         ADD         BX,OFFSET Volume
  216.                         LEA         DI,[(VolumeRec PTR CS:BX).Key]
  217.                         MOV         [(VolumeRec PTR CS:BX).KeyOk],0
  218.                         PUSH        CS
  219.                         POP         ES
  220.                         POP         SI
  221.  
  222.                         MOV         CX,KeySize
  223.                         REP         MOVSB
  224.                         MOV         AL,-1
  225.                         PUSH        DS SI
  226.                         PUSH        CS
  227.                         POP         DS
  228.                         MOV         SI,BX
  229.                         CALL        CheckKey
  230.                         POP         SI DS
  231.                         JNZ         @@Exit
  232.                         MOV         AL,1
  233.             @@Exit:     POP         BX CX DX DI ES
  234.                         IRET
  235.  
  236.             @@2:        CMP         AL,1
  237.                         JNE         @@4
  238.                         CMP         DX,[DriverIndex]
  239.                         JNE         @@DoOld
  240.                         MOV         AL,[NofVolumes]
  241.                         MOV         DL,[BaseDrive]
  242.                         IRET
  243.  
  244.             @@4:        CMP         AL,3
  245.                         JNE         @@5
  246.                         CMP         DL,0FFh
  247.                         JE          @@KillAll
  248.                         CMP         DL,[BaseDrive]
  249.                         JB          @@DoOld
  250.                         PUSH        DX
  251.                         SUB         DL,[BaseDrive]
  252.                         CMP         DL,[NofVolumes]
  253.                         POP         DX
  254.                         JAE         @@DoOld
  255.                         SUB         DL,[BaseDrive]
  256.  
  257.                         PUSH        AX CX DI ES
  258.  
  259.                         PUSH        CS
  260.                         POP         ES
  261.  
  262.                         MOV         DH,0
  263.                         MOV         AX,SIZE VolumeRec
  264.                         MUL         DX
  265.                         MOV         DI,AX
  266.                         ADD         DI,OFFSET Volume
  267.  
  268.                         MOV         [(VolumeRec PTR ES:DI).KeyOk],0
  269.                         LEA         DI,[(VolumeRec PTR ES:DI).Key]
  270.                         MOV         AL,0
  271.                         MOV         CX,KeySize
  272.                         CLD
  273.                         REP         STOSB
  274.                         POP         ES DI CX AX
  275.  
  276.                         JMP         @@DoOld
  277.  
  278.             @@KillAll:  PUSH        AX CX DI ES
  279.  
  280.                         PUSH        CS
  281.                         POP         ES
  282.                         MOV         DI,OFFSET Volume
  283.                         MOV         CL,[NofVolumes]
  284.                         MOV         CH,0
  285.                         CLD
  286.                         JCXZ        @@Done
  287.  
  288.             @@Next:     MOV         [(VolumeRec PTR ES:DI).KeyOk],0
  289.                         PUSH        DI CX
  290.                         LEA         DI,[(VolumeRec PTR ES:DI).Key]
  291.                         MOV         AL,0
  292.                         MOV         CX,KeySize
  293.                         REP         STOSB
  294.                         POP         CX DI
  295.                         ADD         DI,SIZE VolumeRec
  296.                         LOOP        @@Next
  297.  
  298.             @@Done:     POP         ES DI CX AX
  299.                         JMP         @@DoOld
  300.  
  301.             @@5:        CMP         AL,9
  302.                         JNE         @@DoOld
  303.  
  304.                         MOV         DX,[DriverIndex]
  305.                         INC         DX
  306.                         MOV         AX,1DEAh
  307.                         IRET
  308. ENDP        NewInt2F
  309.  
  310. PROC        NewINT08
  311.             ASSUME      DS:NOTHING,SS:NOTHING,ES:NOTHING,CS:@CODE
  312.  
  313.                         PUSH        CX AX ES DI
  314.  
  315.                         CMP         [MaxNofTicks],0
  316.                         JE          @@Leave
  317.  
  318.                         MOV         CH,0
  319.                         MOV         CL,[NofVolumes]
  320.                         PUSH        CS
  321.                         POP         ES
  322.                         MOV         DI,OFFSET Volume
  323.  
  324.                         JCXZ        @@Leave                 ; you never know
  325.             @@Next:     CMP         [(VolumeRec PTR ES:DI).NofTicks],-1
  326.                         JE          @@0
  327.                         INC         [(VolumeRec PTR ES:DI).NofTicks]
  328.                         MOV         AX,[(VolumeRec PTR ES:DI).NofTicks]
  329.                         CMP         AX,[MaxNofTicks]
  330.                         JNGE        @@0
  331.  
  332.                         PUSH        CX DI
  333.                         MOV         AL,0
  334.                         CLD
  335.                         LEA         DI,[(VolumeRec PTR ES:DI).Key]
  336.                         MOV         CX,KeySize
  337.                         REP         STOSB
  338.                         POP         DI CX
  339.                         MOV         [(VolumeRec PTR ES:DI).NofTicks],-1
  340.                         MOV         [(VolumeRec PTR ES:DI).KeyOk],0
  341.  
  342.             @@0:        ADD         DI,SIZE VolumeRec
  343.                         LOOP        @@Next
  344.  
  345.             @@Leave:
  346.                         POP         DI ES AX CX
  347.                         JMP         [OldInt08]
  348. ENDP        NewINT08
  349.  
  350. PROC        Strategy    FAR
  351.             ASSUME      DS:NOTHING,SS:NOTHING,ES:NOTHING,CS:@CODE
  352.                         MOV         [WORD PTR RequestPtr],BX
  353.                         MOV         [WORD PTR RequestPtr+2],ES
  354.                         RET
  355. ENDP        Strategy
  356.  
  357. PROC        Interrupt   FAR
  358.             ASSUME      DS:NOTHING,SS:NOTHING,ES:NOTHING,CS:@CODE
  359.                         PUSH        AX BX CX DX DS ES SI DI
  360.                         PUSHF
  361.  
  362.                         MOV         [WORD PTR CS:OldStack],SP
  363.                         MOV         [WORD PTR CS:OldStack+2],SS
  364.                         PUSH        CS
  365.                         POP         DS
  366.             ASSUME      DS:@CODE
  367.  
  368.                         LES         DI,[RequestPtr]
  369.                         MOV         BL,[(RequestHeader PTR ES:DI).Command]
  370.                         XOR         BH,BH
  371.             IFDEF       DEBUG
  372.                         CALL        DebugCode
  373.             ENDIF
  374.                         CMP         BL,MaxCmd
  375.                         JBE         @@1
  376.                         MOV         AX,dverUnknownCommand+8000h
  377.                         JMP         @@2
  378.  
  379.             @@1:        CLI
  380.                         MOV         AX,CS
  381.                         MOV         SS,AX
  382.             ASSUME      SS:@CODE
  383.                         MOV         SP,OFFSET StackTop
  384.                         STI
  385.  
  386.                         CMP         BX,dvcmInit
  387.                         JE          @@3
  388.  
  389.                         MOV         DL,[(RequestHeader PTR ES:DI).Unit]
  390.                         CMP         DL,[NofVolumes]
  391.                         MOV         AL,dverUnknownUnit
  392.                         JNB         @@2
  393.                         MOV         DH,0
  394.                         MOV         AX,SIZE VolumeRec
  395.                         MUL         DX
  396.                         MOV         SI,AX
  397.                         ADD         SI,OFFSET Volume
  398.                         CMP         [(VolumeRec PTR DS:SI).KeyOk],1
  399.                         JE          @@3
  400.                         CMP         BL,dvcmMediaChk
  401.                         JE          @@3
  402.                         MOV         AX,dverDeviceNotReady
  403.                         JMP         @@Error
  404.  
  405.             @@3:        SHL         BX,1
  406.                         CALL        [WORD PTR JmpTab+BX]
  407.                         MOV         AH,0
  408.                         JNC         @@2
  409.  
  410.             @@Error:    MOV         [(VolumeRec PTR SI).Error],1
  411.                         OR          AX,swError
  412.  
  413.             @@2:        OR          AX,swDone
  414.                         MOV         [(RequestHeader PTR ES:DI).Status],AX
  415.             @@Exit:     CLI
  416.                         MOV         SP,[WORD PTR OldStack]
  417.                         MOV         SS,[WORD PTR OldStack+2]
  418.                         STI
  419.                         POPF
  420.                         POP         DI SI ES DS DX CX BX AX
  421.                         RET
  422. ENDP        Interrupt
  423.  
  424. PROC        CryptData
  425.             ; entry:
  426.             ;   BL = device command (if dvcmOutput: encrypt data
  427.             ;                        if dvcmInput:  decrypt data)
  428.             ;   DX:AX = sector number
  429.             ;   CX    = count
  430.             ;   DS:SI -> VolumeRec
  431.             ;   ES:DI -> Buffer
  432.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  433.  
  434.             LOCAL       IV:WORD:4,Encrypt:BYTE
  435.  
  436.                         PUSH        AX BX CX DX ES DI
  437.             IFDEF       DEBUG
  438.                         PUSH        BX
  439.                         MOV         BX,'G'-'0'
  440.                         CALL        DebugCode
  441.                         POP         BX
  442.             ENDIF
  443.  
  444.                         MOV         [Encrypt],0
  445.                         CMP         BL,dvcmInput
  446.                         JE          @@CryptLoop
  447.                         INC         [Encrypt]
  448.  
  449.             @@CryptLoop:OR          AX,AX
  450.                         JNE         @@NotBoot
  451.                         OR          DX,DX
  452.                         JE          @@Skip
  453.             @@NotBoot:  PUSH        AX CX DX
  454.                         MOV         BX,[(VolumeRec PTR DS:SI).IV]
  455.                         MOV         [IV],BX
  456.                         MOV         BX,[(VolumeRec PTR DS:SI+2).IV]
  457.                         MOV         [IV+2],BX
  458.                         MOV         BX,[(VolumeRec PTR DS:SI+4).IV]
  459.                         MOV         [IV+4],BX
  460.                         MOV         BX,[(VolumeRec PTR DS:SI+6).IV]
  461.                         MOV         [IV+6],BX
  462.                         XOR         [IV],AX
  463.                         XOR         [IV+2],DX
  464.                         XOR         [IV+4],AX
  465.                         XOR         [IV+6],DX
  466.  
  467.                         PUSH        ES          ; IDEA-routine destroys these!
  468.  
  469.                         MOV         AX,1        ;Actually zero blocks, will just pre-encrypt IV
  470.                         PUSH        AX          ;Store number of blocks
  471.                         SUB         SP,8        ;Pretend to push plaintext/ciphertext addresses
  472.                         LEA         BX,[(VolumeRec PTR DS:SI).Key]
  473.                         PUSH        DS BX          ; Push address of key
  474.                         LEA         BX,[IV]
  475.                         PUSH        SS BX
  476.  
  477.                         CALL        _IdeaCFB    ; Encrypt IV
  478.                         ADD         SP,18       ;Remove extra word
  479.                         POP         ES
  480.  
  481.                         PUSH        ES
  482.                         MOV         AX,1+(SectorSize/8)   ;Nof Blocks
  483.                         PUSH        AX          ;Store number of blocks
  484.                         PUSH        ES DI
  485.                         PUSH        ES DI
  486.                         LEA         BX,[(VolumeRec PTR DS:SI).Key]
  487.                         PUSH        DS
  488.                         PUSH        BX          ; Push address of key
  489.                         LEA         BX,[IV]
  490.                         PUSH        SS
  491.                         PUSH        BX
  492.  
  493.                         TEST        [Encrypt],1
  494.                         JNE         @@2
  495.                         CALL        _IdeaCFBx
  496.                         JMP         @@3
  497.             @@2:        CALL        _IdeaCFB
  498.             @@3:        ADD         SP,18
  499.                         POP         ES
  500.  
  501.                         POP         DX CX AX
  502.             @@Skip:     ADD         AX,1
  503.                         ADC         DX,0
  504.  
  505.                         ADD         DI,SectorSize
  506.                         LOOP        @@CryptLoop
  507.  
  508.                         POP         DI ES DX CX BX AX
  509.                         RET
  510. ENDP        CryptData
  511.  
  512. PROC        RebuildDPB
  513.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  514.             ; Rebuilds Dad's DPB out of his BPB
  515.             ;
  516.             ; DS:SI -> VolumeRec
  517.  
  518.             LOCAL       ReqBuffer:BBPBRequest,Buffer:BYTE:400h
  519.  
  520.                         PUSH        BX CX DX ES
  521.  
  522.             IFDEF       DEBUG
  523.  
  524.                         MOV         BL,'A'-'0'
  525.                         CALL        DebugCode
  526.  
  527.             ENDIF
  528.  
  529.                         MOV         DX,0
  530.                         MOV         AX,1
  531.                         MOV         CX,1
  532.                         LEA         DI,[Buffer]
  533.                         PUSH        SS
  534.                         POP         ES
  535.             ASSUME      ES:@CODE
  536.                         MOV         BL,dvcmInput
  537.                         CALL        DadsIO
  538.                         JC          @@Exit
  539.  
  540.                         MOV         [ReqBuffer.Header.Command],dvcmBuildBPB
  541.                         MOV         [ReqBuffer.Header.Length],SIZE BBPBRequest
  542.                         MOV         BL,[(VolumeRec PTR SI).Unit]
  543.                         MOV         [ReqBuffer.Header.Unit],BL
  544.                         MOV         BL,[Buffer]
  545.                         MOV         [ReqBuffer.MediaDesc],BL
  546.                         LEA         BX,[Buffer]
  547.                         MOV         [WORD PTR ReqBuffer.BufferPtr],BX
  548.                         MOV         [(WORD PTR ReqBuffer.BufferPtr)+2],SS
  549.                         LEA         BX,[ReqBuffer]
  550.                         CALL        [(VolumeRec PTR SI).DadsStrategy]
  551.                         CALL        [(VolumeRec PTR SI).DadsInterrupt]
  552.                         MOV         AX,[ReqBuffer.Header.Status]
  553.                         TEST        AX,swError
  554.                         STC
  555.                         JNE         @@Exit
  556.  
  557.                         PUSH        DS SI BP
  558.                         LES         BX,[(VolumeRec PTR SI).DadsDPB]
  559.             ASSUME      ES:NOTHING
  560.                         LDS         SI,[ReqBuffer.BPBPtr]
  561.             ASSUME      DS:NOTHING
  562.                         MOV         BP,BX
  563.                         MOV         AH,53h
  564.                         INT         21h
  565.                         POP         BP SI DS
  566.             ASSUME      DS:@CODE
  567.                         CLC
  568.  
  569.             @@Exit:     POP         ES DX CX BX
  570.                         RET
  571.  
  572. ENDP        RebuildDPB
  573.  
  574. PROC        MediaCheck
  575.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  576.             ; DS:SI -> VolumeRec
  577.             ; ES:DI -> Request
  578.  
  579.             LOCAL       ReqBuffer:MChkRequest
  580.  
  581.                         PUSH        BX
  582.  
  583.                         MOV         [ReqBuffer.Header.Command],dvcmMediaChk
  584.                         MOV         [ReqBuffer.Header.Length],SIZE MChkRequest
  585.                         MOV         BL,[(VolumeRec PTR SI).Unit]
  586.                         MOV         [ReqBuffer.Header.Unit],BL
  587.                         MOV         BL,[(VolumeRec PTR SI).MediaDesc]
  588.                         MOV         [ReqBuffer.MediaDesc],BL
  589.  
  590.                         LEA         BX,[ReqBuffer]
  591.                         PUSH        ES
  592.                         PUSH        SS
  593.                         POP         ES
  594.             ASSUME      ES:@CODE
  595.                         CALL        [(VolumeRec PTR SI).DadsStrategy]
  596.                         CALL        [(VolumeRec PTR SI).DadsInterrupt]
  597.                         POP         ES
  598.                         MOV         AX,[ReqBuffer.Header.Status]
  599.                         TEST        AX,swError
  600.                         STC
  601.                         JNE         @@Error
  602.  
  603.                         MOV         BL,[ReqBuffer.Result]
  604.                         MOV         [(MChkRequest PTR ES:DI).Result],BL
  605.                         CMP         BL,1
  606.                         JE          @@NotChanged
  607.                         CALL        RebuildDPB
  608.                         JC          @@Error
  609.                         CALL        ConstructBPB
  610.                         JC          @@Error
  611.                         CLC         
  612.  
  613.             @@Exit:     MOV         AX,[ReqBuffer.Header.Status]   ; Return Daddy's error
  614.             @@Error:    POP         BX
  615.                         RET
  616.  
  617.             @@NotChanged:
  618.                         CMP         [(VolumeRec PTR SI).Error],0
  619.                         JNE         @@1
  620.                         CMP         [(VolumeRec PTR SI).KeyOK],1
  621.                         JE          @@Exit
  622.  
  623.             @@1:        MOV         [(MChkRequest PTR ES:DI).Result],0FFh
  624.                         CALL        ConstructBPB
  625.                         JC          @@Error
  626.                         JMP         @@Exit
  627. ENDP        MediaCheck
  628.  
  629. PROC        MyIO
  630.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  631.             ; entry:
  632.             ;   BL = device command
  633.             ;   DX:AX = sector number
  634.             ;   CX    = count
  635.             ;   DS:SI -> VolumeRec
  636.             ;   ES:DI -> Buffer
  637.             ; return:
  638.             ;   IF Carry set then AX = status
  639.  
  640.             LOCAL       pClusterSize:BYTE,MaxSector:BYTE,FirstData:WORD
  641.             LOCAL       InCluster:WORD,Bookmark:WORD,Command:BYTE
  642.             LOCAL       OldAX:WORD
  643.  
  644.             IFDEF       DEBUG
  645.                         PUSH        BX
  646.                         MOV         BX,'B'-'0'
  647.                         CALL        DebugCode
  648.                         POP         BX
  649.             ENDIF
  650.                         PUSH        BX
  651.                         PUSH        CX ES DI
  652.                         MOV         [OldAX],AX
  653.                         LES         DI,[(VolumeRec PTR SI).DadsDPB]
  654.                         MOV         CL,[BYTE PTR ES:DI+4]           ; Max sector in cluster
  655.                         MOV         [MaxSector],CL
  656.                         MOV         CX,[WORD PTR ES:DI+0Bh]
  657.                         MOV         [FirstData],CX
  658.                         MOV         CL,[BYTE PTR ES:DI+5]
  659.                         MOV         [pClusterSize],CL
  660.                         MOV         [Command],BL
  661.  
  662.                         MOV         BX,AX
  663.                         AND         BL,[MaxSector]          ; BX := offset in cluster
  664.                         MOV         BH,0
  665.                         MOV         [InCluster],BX
  666.  
  667.                         MOV         CH,0
  668.                         JCXZ        @@01
  669.             @@0:        SHR         DX,1                    ; AX := cluster no
  670.                         RCR         AX,1
  671.                         LOOP        @@0
  672.  
  673.             @@01:       POP         DI ES CX
  674.                         
  675.                         PUSH        CX DX DI
  676.                         PUSH        SI
  677.                         CMP         DX,0                    ; cluster should be < FFFF
  678.                         JNE         @@NotFound
  679.                         MOV         DX,AX
  680.                         LEA         SI,[(VolumeRec PTR SI).Chain]
  681.                         MOV         [Bookmark],SI
  682.  
  683.             @@NextStroke:
  684.                         JCXZ        @@Done
  685.             @@1:        LODSW
  686.                         CMP         AX,0
  687.                         JE          @@NotFound
  688.                         MOV         BX,AX
  689.                         LODSW
  690.                         CMP         DX,AX
  691.                         JB          @@Found
  692.                         SUB         DX,AX
  693.                         JMP         @@1
  694.  
  695.             @@Found:    ; Right now BX contains the first cluster in a
  696.                         ;    contiguous area containing the 1st sector we need.
  697.                         ;    This area is AX clusters long. 1st Sector lies in
  698.                         ;    cluster # (BX+DX), sector [InCluster]
  699.  
  700.                         PUSH        CX                ; DX:AX -> first sector to read
  701.                         MOV         CL,[pClusterSize] ; BX = max n. of sectors readable in this stroke
  702.                         MOV         CH,0
  703.                         XCHG        BX,AX
  704.                         SUB         BX,DX
  705.                         ADD         AX,DX
  706.                         SUB         AX,2
  707.                         PUSH        CX
  708.                         JCXZ        @@3
  709.             @@2:        SHL         BX,1
  710.                         JC          @@Max
  711.                         LOOP        @@2
  712.                         JMP         @@3
  713.             @@Max:      MOV         BX,0FFFFh
  714.             @@3:        POP         CX
  715.                         MOV         DX,0
  716.                         JCXZ        @@5
  717.             @@4:        SHL         AX,1
  718.                         RCL         DX,1
  719.                         LOOP        @@4
  720.             @@5:        SUB         BX,[InCluster]
  721.                         ADD         AX,[InCluster]
  722.                         ADC         DX,0
  723.                         ADD         AX,[FirstData]
  724.                         ADC         DX,0
  725.                         POP         CX
  726.  
  727.                         MOV         [Bookmark],SI
  728.                         POP         SI
  729.  
  730.                         PUSH        CX
  731.                         CMP         BX,CX
  732.                         JA          @@6
  733.                         MOV         CX,BX
  734.             @@6:        MOV         BL,[Command]
  735.                         CALL        DadsIO
  736.                         MOV         BX,CX
  737.                         POP         CX
  738.                         PUSH        SI
  739.                         MOV         SI,[Bookmark]
  740.                         JC          @@Error
  741.  
  742.                         PUSH        CX BX              ; adjust pointer in write buffer
  743.                         MOV         CL,pSectorSize
  744.                         SHL         BX,CL
  745.                         ADD         DI,BX
  746.                         POP         BX CX
  747.  
  748.                         SUB         CX,BX
  749.                         MOV         DX,0
  750.                         MOV         [InCluster],0
  751.                         JMP         @@NextStroke
  752.  
  753.             @@Done:     CLC
  754.  
  755.             @@Exit:     POP         SI
  756.                         POP         DI DX CX
  757.                         POP         BX
  758.                         JC          @@7
  759.                         MOV         [(VolumeRec PTR SI).NofTicks],0
  760.                         MOV         AX,[OldAX]
  761.             @@7:        RET
  762.  
  763.             @@Error:    STC
  764.                         JMP         @@Exit
  765.  
  766.             @@NotFound: STC
  767.                         MOV         AL,dverGeneralFailure   ; sector not found?
  768.                         JMP         @@Exit
  769. ENDP        MyIO
  770.  
  771. PROC        CheckKey
  772.             ASSUME      DS:NOTHING,SS:NOTHING,ES:NOTHING,CS:@CODE
  773.             ; DS:SI -> VolumeRec
  774.             ; return:
  775.             ;   Zero flag set if key is OK
  776.             LOCAL       KeyOk:BYTE,MyIV:WORD:4,MyCheck:WORD:4
  777.  
  778.                         PUSH        AX BX CX DX ES DI
  779.                         MOV         BX,[(VolumeRec PTR DS:SI).IV]
  780.                         NOT         BX
  781.                         MOV         [MyIV],BX
  782.                         MOV         BX,[(VolumeRec PTR DS:SI+2).IV]
  783.                         NOT         BX
  784.                         MOV         [MyIV+2],BX
  785.                         MOV         BX,[(VolumeRec PTR DS:SI+4).IV]
  786.                         NOT         BX
  787.                         MOV         [MyIV+4],BX
  788.                         MOV         BX,[(VolumeRec PTR DS:SI+6).IV]
  789.                         NOT         BX
  790.                         MOV         [MyIV+6],BX
  791.  
  792.                         MOV         BX,1
  793.                         PUSH        BX
  794.                         SUB         SP,8
  795.                         LEA         BX,[(VolumeRec PTR DS:SI).Key]
  796.                         PUSH        DS
  797.                         PUSH        BX          ; Push address of key
  798.                         LEA         BX,[MyIV]
  799.                         PUSH        SS
  800.                         PUSH        BX
  801.  
  802.                         CALL        _IdeaCFB
  803.                         ADD         SP,18
  804.  
  805.                         MOV         BX,2        ;Nof Blocks
  806.                         PUSH        BX          ;Store number of blocks
  807.                         LEA         DI,[MyCheck]
  808.                         PUSH        SS DI
  809.                         LEA         DI,[(VolumeRec PTR DS:SI).Check]
  810.                         PUSH        DS DI
  811.                         LEA         BX,[(VolumeRec PTR DS:SI).Key]
  812.                         PUSH        DS
  813.                         PUSH        BX          ; Push address of key
  814.                         LEA         BX,[MyIV]
  815.                         PUSH        SS
  816.                         PUSH        BX
  817.  
  818.                         CALL        _IdeaCFBx
  819.                         ADD         SP,18
  820.  
  821.                         CMP         [MyCheck],1234h
  822.                         JNE         @@0
  823.                         MOV         [(VolumeRec PTR DS:SI).NofTicks],0
  824.  
  825.             @@0:        POP         DI ES DX CX BX AX
  826.                         RET
  827. ENDP        CheckKey
  828.  
  829. PROC        AskKey
  830.             ; DS:SI -> VolumeRec
  831.  
  832.                         PUSH        AX DX ES DI
  833.  
  834.                         LES         DI,[RequestPtr]
  835.                         MOV         DL,[(RequestHeader PTR ES:DI).Unit]
  836.                         ADD         DL,[BaseDrive]
  837.                         MOV         AX,0E202h
  838.                         INT         2Fh                     ; AL=02: ask for password
  839.  
  840.                         POP         DI ES DX AX
  841.                         RET
  842. ENDP        AskKey
  843.  
  844. PROC        ConstructBPB
  845.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  846.             ; DS:SI -> VolumeRec
  847.             ; Carry set if error in AL
  848.  
  849.             LOCAL       BootRecord:BYTE:SectorSize
  850.  
  851.             IFDEF       DEBUG
  852.                         PUSH        BX
  853.                         MOV         BX,'C'-'0'
  854.                         CALL        DebugCode
  855.                         POP         BX
  856.             ENDIF
  857.                         PUSH        BX CX DX ES DI
  858.  
  859.                         MOV         [(VolumeRec PTR DS:SI).KeyOk],0
  860.  
  861.                         CALL        MakeChain
  862.                         JC          @@Error
  863.  
  864.                         MOV         DX,0
  865.                         MOV         AX,0
  866.                         MOV         CX,1
  867.                         PUSH        SS
  868.                         POP         ES
  869.             ASSUME      ES:@CODE
  870.                         LEA         DI,[BootRecord]
  871.                         MOV         BL,dvcmInput
  872.                         CALL        MyIO
  873.                         JC          @@Error
  874.                         PUSH        DI SI
  875.                         LEA         DI,[(VolumeRec PTR SI).MyBPB]
  876.                         LEA         SI,[BootRecord+0bh]
  877.                         MOV         CX,SIZE BPBRec
  878.                         CLD
  879.                         REP         MOVSB
  880.                         POP         SI
  881.                         PUSH        SI
  882.                         LEA         DI,[(VolumeRec PTR SI).IV]
  883.                         LEA         SI,[BootRecord+3Eh]
  884.                         MOV         CX,8                    ; Size of IV
  885.                         REP         MOVSB
  886.                         POP         SI
  887.                         PUSH        SI
  888.                         LEA         DI,[(VolumeRec PTR SI).Check]
  889.                         LEA         SI,[BootRecord+46h]
  890.                         MOV         CX,8                    ; Size of check
  891.                         REP         MOVSB
  892.                         POP         SI
  893.                         POP         DI
  894.  
  895.                         MOV         AL,dverDeviceNotReady
  896.                         CALL        CheckKey
  897.                         JE          @@Ok
  898.                         CALL        AskKey
  899.                         CALL        CheckKey
  900.                         JNE         @@Error
  901.  
  902.             @@Ok:       MOV         [(VolumeRec PTR DS:SI).KeyOk],1
  903.                         CLC
  904.                         MOV         [(VolumeRec PTR SI).Error],0
  905.             @@Exit:     POP         DI ES DX BX CX
  906.                         RET
  907.  
  908.             @@Error:    STC
  909.                         JMP         @@Exit
  910. ENDP        ConstructBPB
  911.  
  912. PROC        BuildBPB
  913.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  914.             ; DS:SI -> VolumeRec
  915.             ; ES:DI -> BBPBRequest
  916.  
  917.                         PUSH        BX
  918.  
  919.                         MOV         [(WORD PTR (BBPBRequest PTR ES:DI).BPBPtr)+2],CS
  920.                         LEA         BX,[(VolumeRec PTR SI).MyBPB]
  921.                         MOV         [WORD PTR (BBPBRequest PTR ES:DI).BPBPtr],BX
  922.  
  923.                         POP         BX
  924.                         CLC
  925.                         RET
  926. ENDP        BuildBPB
  927.  
  928. PROC        Input
  929.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  930.             ; DS:SI -> VolumeRec
  931.             ; ES:DI -> IORequest
  932.  
  933.                         PUSH        BX CX DX ES DI
  934.                         MOV         CX,[(IORequest PTR ES:DI).Count]
  935.                         MOV         AX,[(IORequest PTR ES:DI).Sector]
  936.                         MOV         DX,0
  937.                         CMP         AX,-1
  938.                         JNE         @@DoIt
  939.                         MOV         AX,[(WORD PTR (IORequest PTR ES:DI).Sector32b)]
  940.                         MOV         DX,[(WORD PTR (IORequest PTR ES:DI).Sector32b)+2]
  941.             @@DoIt:     MOV         BL,dvcmInput
  942.                         LES         DI,[(IORequest PTR ES:DI).Buffer]
  943.                         CALL        MyIO
  944.                         JC          @@Error
  945.                         CALL        CryptData
  946.             @@Error:    POP         DI ES DX CX BX
  947.                         RET
  948. ENDP        Input
  949.  
  950. PROC        Output
  951.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  952.             ; DS:SI -> VolumeRec
  953.             ; ES:DI -> IORequest
  954.             LOCAL       OldAX:WORD
  955.  
  956.                         PUSH        BX CX DX ES DI
  957.                         MOV         CX,[(IORequest PTR ES:DI).Count]
  958.                         MOV         AX,[(IORequest PTR ES:DI).Sector]
  959.                         MOV         DX,0
  960.                         CMP         AX,-1
  961.                         JNE         @@DoIt
  962.                         MOV         AX,[(WORD PTR (IORequest PTR ES:DI).Sector32b)]
  963.                         MOV         DX,[(WORD PTR (IORequest PTR ES:DI).Sector32b)+2]
  964.             @@DoIt:     MOV         BL,dvcmOutput
  965.                         LES         DI,[(IORequest PTR ES:DI).Buffer]
  966.                         MOV         [OldAX],AX
  967.                         CALL        CryptData
  968.                         CALL        MyIO
  969.                         PUSH        AX
  970.                         MOV         AX,[OldAX]
  971.                         MOV         BL,dvcmInput
  972.                         CALL        CryptData
  973.                         POP         AX
  974.                         POP         DI ES DX CX BX
  975.                         RET
  976. ENDP        Output
  977.  
  978. PROC        NoError
  979.                         CLC
  980.                         RET
  981. ENDP        NoError
  982.  
  983. PROC        DadsIO
  984.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  985.             LOCAL       ReqBuffer:IORequest
  986.             ; entry:
  987.             ;   BL    = device command
  988.             ;   DX:AX = sector number
  989.             ;   CX    = count
  990.             ;   DS:SI -> VolumeRec
  991.             ;   ES:DI -> Buffer
  992.             ; return:
  993.             ;   AX = status
  994.             IFDEF       DEBUG
  995.                         PUSH        BX
  996.                         MOV         BX,'D'-'0'
  997.                         CALL        DebugCode
  998.                         POP         BX
  999.             ENDIF
  1000.                         PUSH        ES BX
  1001.                         MOV         [ReqBuffer.Header.Command],BL
  1002.  
  1003.                         MOV         [ReqBuffer.Header.Length],SIZE IORequest
  1004.                         MOV         BL,[(VolumeRec PTR SI).Unit]
  1005.                         MOV         [ReqBuffer.Header.Unit],BL
  1006.                         MOV         [WORD PTR (IORequest PTR ReqBuffer).Buffer],DI
  1007.                         MOV         [(WORD PTR (IORequest PTR ReqBuffer).Buffer)+2],ES
  1008.                         MOV         [ReqBuffer.Count],CX
  1009.  
  1010.                         TEST        [(VolumeRec PTR SI).DadsAttr],2    ; support >32M?
  1011.                         JE          @@2
  1012.                         MOV         [WORD PTR ReqBuffer.Sector32b],AX
  1013.                         MOV         [(WORD PTR ReqBuffer.Sector32b)+2],DX
  1014.                         MOV         [ReqBuffer.Sector],-1
  1015.                         JMP         @@3
  1016.             @@2:        CMP         DX,0
  1017.                         JE          @@21
  1018.                         MOV         AL,dverGeneralFailure
  1019.                         JMP         @@Error
  1020.  
  1021.             @@21:       MOV         [ReqBuffer.Sector],AX
  1022.                         SUB         [ReqBuffer.Header.Length],4
  1023.  
  1024.             @@3:        LEA         BX,[ReqBuffer]
  1025.                         PUSH        SS
  1026.                         POP         ES
  1027.                         CALL        [(VolumeRec PTR SI).DadsStrategy]
  1028.                         CALL        [(VolumeRec PTR SI).DadsInterrupt]
  1029.                         MOV         CX,[ReqBuffer.Count]                
  1030.                         MOV         AX,[(RequestHeader PTR ReqBuffer).Status]
  1031.                         CLC
  1032.                         TEST        AX,swError
  1033.                         JE          @@Exit
  1034.             @@Error:    STC
  1035.             @@Exit:     POP         BX ES
  1036.                         RET
  1037. ENDP        DadsIO
  1038.  
  1039. PROC        FindFile
  1040.             ASSUME      DS:@CODE,SS:@CODE,ES:@CODE,CS:@CODE
  1041.             ; SI         -> VolumeRec,
  1042.             ; CF set if error in AX ?
  1043.             ;        else first cluster in AX
  1044.  
  1045.             LOCAL       Sector:BYTE:SectorSize, SectorCounter:WORD
  1046.  
  1047.                         PUSH        BX CX DX ES DI
  1048.  
  1049.                         LES         BX,[(VolumeRec PTR SI).DadsDPB]
  1050.             ASSUME      ES:NOTHING
  1051.                         MOV         DI,[ES:BX+09h]          ; nof dir entries
  1052.                         SHR         DI,1
  1053.                         SHR         DI,1
  1054.                         SHR         DI,1
  1055.                         MOV         [SectorCounter],DI
  1056.  
  1057.                         TEST        DX,0D0h    ; voor als ik rekening moet
  1058.                         JE          @@0         ;  houden met extra entries
  1059.                         AND         DX,0D0h
  1060.                         INC         DX
  1061.             @@0:
  1062.  
  1063.                         CMP         [BYTE PTR DosVersion],4
  1064.                         JB          @@1
  1065.                         INC         BX
  1066.             @@1:        MOV         AX,[ES:BX+10h]          ; first ROOT sector
  1067.                         MOV         DX,0
  1068.                         PUSH        SS
  1069.                         POP         ES
  1070.  
  1071.             @@NextSctr: MOV         CX,SectorSize/SIZE DirEntry
  1072.                         PUSH        AX
  1073.                         LEA         DI,[Sector]
  1074.                         MOV         CX,1
  1075.                         MOV         BL,dvcmInput
  1076.                         CALL        DadsIO
  1077.                         POP         AX
  1078.                         JC          @@Error
  1079.                         CMP         CX,1                    ; ??
  1080.                         JNE         @@Error
  1081.  
  1082.                         MOV         CX,SectorSize/SIZE DirEntry
  1083.                         LEA         DI,[Sector]
  1084.  
  1085.             @@NextEntry:CMP         [BYTE PTR DI],0
  1086.                         JE          @@NotFound                 ; end of dir.
  1087.  
  1088.                         PUSH        DI SI CX
  1089.                         LEA         SI,[(VolumeRec PTR SI).FileName]
  1090.                         MOV         CX,11
  1091.                         REP         CMPSB
  1092.                         POP         CX SI DI
  1093.                         JE          @@Found
  1094.                         ADD         DI,SIZE DirEntry
  1095.                         DEC         CX
  1096.                         JNZ         @@NextEntry
  1097.  
  1098.                         INC         AX
  1099.                         DEC         [SectorCounter]
  1100.                         JNZ         @@NextSctr
  1101.  
  1102.             @@Found:    TEST        [(DirEntry PTR DI).Attr],atVolLabel+atDirectory
  1103.                         JNE         @@InvalidFile
  1104.                         MOV         AX,[(DirEntry PTR DI).Cluster]
  1105.                         CLC
  1106.  
  1107.             @@Exit:     POP         DI ES DX CX BX
  1108.                         RET
  1109.  
  1110.             @@Error:    STC
  1111.                         JMP         @@Exit
  1112.             @@InvalidFile:
  1113.             @@NotFound: MOV         AL,dverGeneralFailure
  1114.                         JMP         @@Error
  1115. ENDP        FindFile
  1116.  
  1117. PROC        MakeChain
  1118.             ASSUME      DS:@CODE,SS:@CODE,ES:NOTHING,CS:@CODE
  1119.             ; DS:SI -> VolumeRec
  1120.             ; CF set if error in AX
  1121.  
  1122.             LOCAL       FATBase:WORD,FATSector:BYTE:SectorSize,FATSectorNo:WORD
  1123.             LOCAL       Shift:BYTE,Ofs:WORD,Sector:WORD
  1124.             LOCAL       NofClusters:WORD,FAT12:BYTE                     ; 0=16 bit fat
  1125.  
  1126.             IFDEF       DEBUG
  1127.                         PUSH        BX
  1128.                         MOV         BX,'E'-'0'
  1129.                         CALL        DebugCode
  1130.                         POP         BX
  1131.             ENDIF
  1132.                         LES         DI,[(VolumeRec PTR SI).DadsDPB]
  1133.                         ASSUME      ES:NOTHING
  1134.                         CMP         [WORD PTR ES:DI+2],SectorSize
  1135.                         JNE         @@Error
  1136.                         MOV         AX,[WORD PTR ES:DI+0Dh]        ; n of clusters
  1137.                         MOV         [NofClusters],AX
  1138.                         MOV         [FAT12],1
  1139.                         CMP         AX,0FF6h
  1140.                         JBE         @@F
  1141.                         MOV         [FAT12],0
  1142.             @@F:        MOV         AX,[WORD PTR ES:DI+6]          ; n of reserved
  1143.                         MOV         [FATBase],AX
  1144.  
  1145.                         PUSH        DS
  1146.                         POP         ES
  1147.             ASSUME      ES:@CODE
  1148.                         LEA         DI,[(VolumeRec PTR SI).Chain]
  1149.                         MOV         BX,-4
  1150.                         MOV         [FATSectorNo],-1
  1151.  
  1152.                         CALL        FindFile
  1153.                         JC          @@Error
  1154.  
  1155.             @@NextCluster:
  1156.                         CMP         [FAT12],0
  1157.                         JNE         @@1
  1158.  
  1159.                         CMP         AX,0FFF8h
  1160.                         JAE         @@Ready
  1161.                         InBound     AX,0FFF0h,0FFF7h
  1162.                         JZ          @@Error
  1163.                         JMP         @@2
  1164.  
  1165.             @@1:        CMP         AX,0FF8h
  1166.                         JAE         @@Ready
  1167.                         InBound     AX,0FF0h,0FF7h
  1168.                         JZ          @@Error
  1169.  
  1170.             @@2:        CMP         BX,-4                           ; add cluster to chain
  1171.                         JE          @@NewPart
  1172.                         MOV         CX,AX
  1173.                         SUB         CX,[(ChainElm PTR BX+DI).Cluster]
  1174.                         CMP         CX,[(ChainElm PTR BX+DI).Count]
  1175.                         JNE         @@NewPart
  1176.                         INC         [(ChainElm PTR DS:BX+DI).Count]
  1177.                         JMP         @@0
  1178.  
  1179.             @@NewPart:  CMP         BX,4*MaxNofParts
  1180.                         JGE         @@Error
  1181.                         ADD         BX,4
  1182.                         MOV         [(ChainElm PTR BX+DI).Count],1
  1183.                         MOV         [(ChainElm PTR BX+DI).Cluster],AX
  1184.  
  1185.             @@0:        InBound     AX,2,[NofClusters]
  1186.                         JNZ         @@Error
  1187.  
  1188.                         CMP         [FAT12],0
  1189.                         JE          @@Compute16
  1190.  
  1191.                         MOV         CX,AX               ; compute Shift,Ofs,Sector for 12-bit FAT
  1192.                         MOV         DX,0
  1193.                         SHL         AX,1
  1194.                         RCL         DX,1
  1195.                         ADD         AX,CX
  1196.                         ADC         DX,0
  1197.                         MOV         [Shift],AL
  1198.                         AND         [Shift],1
  1199.                         SHR         DX,1
  1200.                         RCR         AX,1
  1201.                         MOV         [Ofs],AX
  1202.                         AND         [Ofs],SectorSize-1
  1203.             REPT        pSectorSize
  1204.                         SHR         AX,1
  1205.             ENDM
  1206.             REPT        16-pSectorSize
  1207.                         SHL         DX,1
  1208.             ENDM
  1209.                         OR          AX,DX
  1210.                         MOV         [Sector],AX
  1211.                         JMP         @@4
  1212.  
  1213.             @@Compute16:SHL         AX,1
  1214.                         RCL         DX,1
  1215.                         MOV         [Ofs],AX             ; same for 16-bit FAT
  1216.                         AND         [Ofs],SectorSize-1
  1217.             REPT        pSectorSize
  1218.                         SHR         DX,1
  1219.                         RCR         AX,1
  1220.             ENDM
  1221.                         MOV         [Sector],AX
  1222.                         MOV         [Shift],-1
  1223.  
  1224.             @@4:        MOV         AX,[Sector]
  1225.                         CALL        @@GetFATSector
  1226.                         JC          @@Error
  1227.                         PUSH        SI
  1228.                         MOV         SI,[Ofs]
  1229.                         MOV         CL,[FATSector+SI]
  1230.                         POP         SI
  1231.                         INC         [Ofs]
  1232.                         CMP         [Ofs],SectorSize
  1233.                         JB          @@3
  1234.                         MOV         [Ofs],0
  1235.                         INC         [Sector]
  1236.                         MOV         AX,[Sector]
  1237.                         CALL        @@GetFATSector
  1238.                         JC          @@Error
  1239.             @@3:        PUSH        SI
  1240.                         MOV         SI,[Ofs]
  1241.                         MOV         CH,[FATSector+SI]
  1242.                         POP         SI
  1243.  
  1244.                         CMP         [Shift],-1
  1245.                         JE          @@GotIt
  1246.                         CMP         [Shift],0
  1247.                         JE          @@5
  1248.             REPT        4
  1249.                         SHR         CX,1
  1250.             ENDM
  1251.             @@5:        AND         CX,0FFFh
  1252.  
  1253.             @@Gotit:    MOV         AX,CX
  1254.                         JMP         @@NextCluster
  1255.  
  1256.             @@Ready:    ADD         BX,4
  1257.                         MOV         [(ChainElm PTR DS:BX+DI).Count],0
  1258.                         MOV         [(ChainElm PTR DS:BX+DI).Cluster],0
  1259.  
  1260.                         CLC
  1261.             @@Exit:     RET
  1262.  
  1263.             @@Error:    MOV         [(VolumeRec PTR SI).Chain.Count],0
  1264.                         MOV         [(VolumeRec PTR SI).Chain.Cluster],0
  1265.                         STC
  1266.                         MOV         AL,dverGeneralFailure
  1267.                         JMP         @@Exit
  1268.  
  1269.             @@GetFATSector:
  1270.             ; pre:
  1271.             ;   AX = fat sector no.
  1272.             ; post:
  1273.             ;   Carry set if error else wanted sector in [Sector]
  1274.                         CMP         [FATSectorNo],AX
  1275.                         JE          @@@Exit
  1276.                         MOV         [FATSectorNo],AX
  1277.                         PUSH        BX CX DX ES DI
  1278.                         MOV         DX,0
  1279.                         ADD         AX,[FATBase]
  1280.                         ADC         DX,0
  1281.                         MOV         CX,1
  1282.                         PUSH        SS
  1283.                         POP         ES
  1284.             ASSUME      ES:@CODE
  1285.                         LEA         DI,[FATSector]
  1286.                         MOV         BL,dvcmInput
  1287.                         CALL        DadsIO
  1288.                         POP         DI ES DX CX BX
  1289.             ASSUME      ES:NOTHING
  1290.                         JNC         @@@Exit
  1291.                         MOV         [FATSectorNo],-1
  1292.                         STC
  1293.             @@@Exit:    RETN
  1294. ENDP        MakeChain
  1295.  
  1296. IFDEF       DEBUG
  1297.  
  1298. PROC        DebugCode
  1299.             ASSUME      DS:@CODE,SS:NOTHING,ES:NOTHING,CS:@CODE
  1300.                         PUSH        AX BX DX
  1301.  
  1302.                         DumpString  <OFFSET DebugMsg>
  1303.                         MOV         DX,BX
  1304.                         ADD         DX,30h
  1305.                         MOV         AH,06
  1306.                         INT         21h
  1307.                         DumpString  <OFFSET CrLf>
  1308.                         POP         DX BX AX
  1309.                         RET
  1310.  
  1311.             DebugMsg    DB          'Request #$'
  1312.             CrLf        DB          0Dh,0Ah,'$'
  1313.  
  1314. ENDP        DebugCode
  1315.  
  1316. PROC        DumpParms
  1317.             ASSUME      DS:NOTHING,ES:NOTHING,SS:@CODE,CS:@CODE
  1318.  
  1319.                         PUSH        AX CX DX DS SI
  1320.                         PUSH        ES
  1321.                         POP         DS
  1322.                         MOV         SI,DI
  1323.                         MOV         CX,80
  1324.                         MOV         AH,2h
  1325.  
  1326.             @Loop:      LODSB
  1327.                         MOV         DH,AL
  1328.                         MOV         DL,DH
  1329.                         SHR         DL,1
  1330.                         SHR         DL,1
  1331.                         SHR         DL,1
  1332.                         SHR         DL,1
  1333.                         ADD         DL,30h
  1334.                         CMP         DL,3Ah
  1335.                         JB          @Digit1
  1336.                         ADD         DL,7
  1337.             @Digit1:    INT         21h
  1338.                         MOV         DL,DH
  1339.                         AND         DL,0Fh
  1340.                         ADD         DL,30h
  1341.                         CMP         DL,3Ah
  1342.                         JB          @Digit2
  1343.                         ADD         DL,7
  1344.             @Digit2:    INT         21h
  1345.                         LOOP        @Loop
  1346.  
  1347.                         POP         SI DS DX CX AX
  1348.                         RET
  1349.  
  1350. ENDP        DumpParms
  1351.  
  1352. ENDIF
  1353.  
  1354. PROC        Init
  1355.             ASSUME      DS:@CODE,ES:NOTHING,SS:@CODE,CS:@CODE
  1356.  
  1357.                         LEA         DX,[NameVersion]
  1358.                         MOV         AH,9
  1359.                         INT         21h
  1360.  
  1361.                         MOV         AH,30h
  1362.                         INT         21h
  1363.                         MOV         [DosVersion],AX
  1364.                         MOV         AL,[(InitRequest PTR ES:DI).DriveNo]
  1365.                         MOV         [BaseDrive],AL
  1366.  
  1367.                         MOV         DX,0
  1368.                         MOV         AX,0E209h
  1369.                         INT         2Fh
  1370.                         CMP         AX,1DEAh
  1371.                         JE          @@2
  1372.                         MOV         DX,0
  1373.             @@2:        MOV         [DriverIndex],DX
  1374.  
  1375.                         CALL        ExtractParms
  1376.  
  1377.                         MOV         AL,[NofVolumes]
  1378.  
  1379.                         MOV         [(InitRequest PTR ES:DI).NofUnits],AL
  1380.                         MOV         [(WORD PTR (InitRequest PTR ES:DI).EndAddress)+2],CS
  1381.                         MOV         [(WORD PTR (InitRequest PTR ES:DI).ReturnBPB)],OFFSET BPBArray
  1382.                         MOV         [(WORD PTR (InitRequest PTR ES:DI).ReturnBPB)+2],CS
  1383.                         PUSH        SI ES CX AX DI
  1384.                         PUSH        CS
  1385.                         POP         ES
  1386.                         MOV         SI,OFFSET EndOfCode
  1387.                         MOV         DI,OFFSET Volume
  1388.                         MOV         AH,0
  1389.                         MOV         CX,SIZE VolumeRec
  1390.                         MUL         CX
  1391.                         MOV         CX,AX
  1392.                         CLD
  1393.                         JCXZ        @@1
  1394.                         REP         MOVSB
  1395.             @@1:        POP         SI AX CX ES
  1396.                         MOV         [(WORD PTR (InitRequest PTR ES:SI).EndAddress)],DI
  1397.                         MOV         DI,SI
  1398.                         POP         SI
  1399.  
  1400.                         CMP         AL,0
  1401.                         JE          @@NotInst
  1402.                         PUSH        DS
  1403.                         XOR         AX,AX
  1404.                         MOV         DS,AX
  1405.                         MOV         AX,[WORD PTR DS:2Fh*4]
  1406.                         MOV         [WORD PTR CS:OldInt2F],AX
  1407.                         MOV         AX,[WORD PTR DS:2Fh*4+2]
  1408.                         MOV         [WORD PTR CS:OldInt2F+2],AX
  1409.                         MOV         AX,[WORD PTR DS:8h*4]
  1410.                         MOV         [WORD PTR CS:OldInt08],AX
  1411.                         MOV         AX,[WORD PTR DS:8h*4+2]
  1412.                         MOV         [WORD PTR CS:OldInt08+2],AX
  1413.                         CLI
  1414.                         MOV         [WORD PTR DS:8h*4],OFFSET NewInt08
  1415.                         MOV         [WORD PTR DS:8h*4+2],CS
  1416.                         MOV         [WORD PTR DS:2Fh*4],OFFSET NewInt2F
  1417.                         MOV         [WORD PTR DS:2Fh*4+2],CS
  1418.                         STI
  1419.                         POP         DS
  1420.                         JMP         @@Exit
  1421.             @@NotInst:  DumpString  <OFFSET NotInstMsg>
  1422.                         MOV         [(WORD PTR (InitRequest PTR ES:DI).EndAddress)],0
  1423.             @@Exit:     CLC
  1424.                         RET
  1425. ENDP        Init
  1426.  
  1427. ALIGN       2h
  1428.  
  1429.             DB          StackSize DUP ('!')
  1430. LABEL       Stacktop
  1431.  
  1432. LABEL       Volume      VolumeRec
  1433.  
  1434. PROC        AddVolume
  1435.             ASSUME      DS:@CODE,ES:NOTHING,SS:@CODE,CS:@CODE
  1436.             ; ES:DI -> file-spec
  1437.  
  1438.                         PUSH        DS SI ES DI
  1439.  
  1440.                         PUSH        ES
  1441.                         POP         DS
  1442.             ASSUME      DS:NOTHING
  1443.                         MOV         SI,DI
  1444.  
  1445.                         MOV         AX,SIZE VolumeRec  ; ES:DI -> VolumeRec
  1446.                         MOV         BL,[NofVolumes]
  1447.                         MOV         BH,0
  1448.                         CMP         BL,MaxNofVols
  1449.                         MOV         DX,OFFSET @@TooMany
  1450.                         JAE         @@Error
  1451.                         MUL         BX
  1452.                         MOV         DI,AX
  1453.                         ADD         DI,OFFSET EndOfCode
  1454.                         PUSH        CS
  1455.                         POP         ES
  1456.                         PUSH        DS DI SI CX
  1457.                         LEA         SI,[@@DefaultVR]
  1458.                         MOV         CX,SIZE VolumeRec
  1459.                         PUSH        CS
  1460.                         POP         DS
  1461.                         CLD
  1462.                         REP         MOVSB
  1463.                         POP         CX SI DI DS
  1464.  
  1465.                         MOV         DX,BX                   ; get drive #
  1466.             ASSUME      ES:@CODE
  1467.                         LODSB
  1468.                         CMP         AL,'a'
  1469.                         JB          @@0
  1470.                         CMP         AL,'z'
  1471.                         JA          @@0
  1472.                         SUB         AL,'a'-'A'
  1473.             @@0:        SUB         AL,'A'
  1474.                         CMP         AL,[BaseDrive]
  1475.                         MOV         DX,OFFSET @@InvDrive
  1476.                         JAE         @@Error
  1477.                         MOV         [(VolumeRec PTR ES:DI).Drive],AL
  1478.                         LODSB
  1479.                         CMP         AL,':'
  1480.                         JNE         @@Error
  1481.                         LODSB
  1482.                         CMP         AL,'\'
  1483.                         MOV         DX,OFFSET @@InvName
  1484.                         JNE         @@Error
  1485.  
  1486.                         MOV         BX,0
  1487.                         MOV         CH,0
  1488.  
  1489.             @@Next:     LODSB
  1490.                         MOV         DX,OFFSET @@InvName
  1491.                         CMP         AL,0Dh
  1492.                         JE          @@Ready
  1493.                         CMP         AL,9
  1494.                         JE          @@Ready
  1495.                         CMP         AL,' '
  1496.                         JE          @@Ready
  1497.                         CMP         AL,'\'
  1498.                         JE          @@Error
  1499.                         CMP         AL,'.'
  1500.                         JNE         @@1
  1501.                         CMP         CH,0
  1502.                         JNE         @@Error
  1503.                         CMP         BX,0
  1504.                         JE          @@Error
  1505.                         MOV         CH,1
  1506.                         MOV         BX,8
  1507.                         JMP         @@Next
  1508.             @@1:        CMP         BX,11
  1509.                         JAE         @@Next
  1510.                         CMP         BX,8
  1511.                         JB          @@2
  1512.                         CMP         CH,0
  1513.                         JE          @@Next
  1514.             @@2:        CMP         AL,'a'
  1515.                         JB          @@21
  1516.                         CMP         AL,'z'
  1517.                         JA          @@21
  1518.                         SUB         AL,'a'-'A'
  1519.             @@21:       MOV         [(VolumeRec PTR ES:DI+BX).FileName],AL
  1520.                         INC         BX
  1521.                         JMP         @@Next
  1522.  
  1523.             @@Ready:    CMP         BX,0
  1524.                         JE          @@Error
  1525.  
  1526.                         PUSH        ES DI
  1527.                         MOV         AH,52h
  1528.                         INT         21h         ; get list of lists
  1529.                         LDS         SI,[DWORD PTR ES:BX]  ; get pointer to 1st DPB
  1530.                         POP         DI ES
  1531.                         MOV         AL,[(VolumeRec PTR ES:DI).Drive]
  1532.                         MOV         BX,0
  1533.                         CMP         [BYTE PTR CS:DosVersion],4
  1534.                         JB          @@3
  1535.                         MOV         BX,1
  1536.             @@3:        CMP         [BYTE PTR SI],AL
  1537.                         JE          @@Found
  1538.                         CMP         [WORD PTR SI+BX+18h],-1
  1539.                         JNE         @@Next2
  1540.                         CMP         [WORD PTR SI+BX+1Ah],-1
  1541.                         JE          @@Error
  1542.  
  1543.             @@Next2:    LDS         SI,[DWORD PTR SI+BX+18h]
  1544.                         JMP         @@3
  1545.  
  1546.             @@Found:    MOV         DL,[SI+1]                        ; unit no
  1547.                         MOV         [(VolumeRec PTR ES:DI).Unit],DL
  1548.                         MOV         DL,[SI+BX+16h]                   ; media ID
  1549.                         MOV         [(VolumeRec PTR ES:DI).MediaDesc],DL
  1550.                         MOV         [WORD PTR (VolumeRec PTR ES:DI).DadsDPB],SI
  1551.                         MOV         [(WORD PTR (VolumeRec PTR ES:DI).DadsDPB)+2],DS
  1552.                         LDS         SI,[DWORD PTR SI+BX+12h]
  1553.                         MOV         [(WORD PTR (VolumeRec PTR ES:DI).DadsStrategy)+2],DS
  1554.                         MOV         [(WORD PTR (VolumeRec PTR ES:DI).DadsInterrupt)+2],DS
  1555.                         MOV         DX,[(DeviceHeader PTR SI).Strategy]
  1556.                         MOV         [WORD PTR (VolumeRec PTR ES:DI).DadsStrategy],DX
  1557.                         MOV         DX,[(DeviceHeader PTR SI).Interrupt]
  1558.                         MOV         [WORD PTR (VolumeRec PTR ES:DI).DadsInterrupt],DX
  1559.                         MOV         DX,[(DeviceHeader PTR SI).Attr]
  1560.                         MOV         [(VolumeRec PTR ES:DI).DadsAttr],DX
  1561.  
  1562.                         POP         DI ES
  1563.                         CALL        DumpWord
  1564.  
  1565.                         MOV         AL,[NofVolumes]
  1566.                         ADD         AL,[BaseDrive]
  1567.                         ADD         AL,'A'
  1568.                         MOV         [@@Drive],AL
  1569.                         POP         SI DS
  1570.             ASSUME      DS:@CODE
  1571.                         DumpString  <OFFSET @@Added>
  1572.                         INC         [NofVolumes]
  1573.                         RET
  1574.  
  1575.             ASSUME      DS:NOTHING,ES:NOTHING
  1576.             @@Error:    POP         DI ES
  1577.  
  1578.                         CALL        DumpWord
  1579.  
  1580.                         POP         SI DS
  1581.                         PUSH        DX
  1582.             ASSUME      DS:@CODE
  1583.                         DumpString  <OFFSET @@NotAdded>
  1584.                         POP         DX
  1585.                         DumpString  DX
  1586.                         RET
  1587.  
  1588.             @@DefaultVR VolumeRec   <>
  1589.  
  1590.             @@Added     DB          ' added acting as drive '
  1591.             @@Drive     DB          'A.',0Dh,0Ah,'$'
  1592.  
  1593.             @@NotAdded  DB          ' not added: ','$'
  1594.             @@TooMany   DB          'Too many volumes.',0Dh,0Ah,'$'
  1595.             @@InvDrive  DB          'Invalid drive letter.',0Dh,0Ah,'$'
  1596.             @@InvName   DB          'Invalid file FileName.',0Dh,0Ah,'$'
  1597.             @@NoDPB     DB          'Can''t find DPB.',0Dh,0Ah,'$'
  1598. ENDP        AddVolume
  1599.  
  1600.  
  1601. PROC        DumpWord
  1602.             ; ES:DI-> word
  1603.                         PUSH        DS SI AX DX
  1604.  
  1605.                         PUSH        ES
  1606.                         POP         DS
  1607.                         MOV         AH,2
  1608.                         MOV         SI,DI
  1609.  
  1610.             @@Next:     LODSB
  1611.                         CMP         AL,' '
  1612.                         JE          @@Exit
  1613.                         CMP         AL,9
  1614.                         JE          @@Exit
  1615.                         CMP         AL,0Dh
  1616.                         JE          @@Exit
  1617.                         MOV         DL,AL
  1618.                         INT         21h
  1619.                         JMP         @@Next
  1620.  
  1621.             @@Exit:     POP         DX AX SI DS
  1622. ENDP        DumpWord
  1623.  
  1624. PROC        NextWord
  1625.             ; entry:
  1626.             ;   ES:DI-> string
  1627.             ; return:
  1628.             ;   ES:DI-> beginning of next word in string
  1629.  
  1630.                         CMP         [BYTE PTR ES:DI],' '
  1631.                         JE          @@Next
  1632.                         CMP         [BYTE PTR ES:DI],09h
  1633.                         JE          @@Next
  1634.                         RET
  1635.  
  1636.             @@Next:     INC         DI
  1637.                         JMP         NextWord
  1638. ENDP        NextWord
  1639.  
  1640. PROC        NextSpace
  1641.             ; entry:
  1642.             ;   ES:DI-> string
  1643.             ; return:
  1644.             ;   ES:DI-> beginning of next space/tab in string
  1645.                         CMP         [BYTE PTR ES:DI],' '
  1646.                         JE          @@Exit
  1647.                         CMP         [BYTE PTR ES:DI],09h
  1648.                         JE          @@Exit
  1649.                         CMP         [BYTE PTR ES:DI],0Ah
  1650.                         JE          @@Exit
  1651.                         INC         DI
  1652.                         JMP         NextSpace
  1653.  
  1654.             @@Exit:     RET
  1655. ENDP        NextSpace
  1656.  
  1657. PROC        GetOption
  1658.             ; ES:DI-> option
  1659.  
  1660.                         PUSH        DI AX DX
  1661.                         INC         DI
  1662.  
  1663.                         MOV         AL,[ES:DI]
  1664.                         CMP         AL,'a'
  1665.                         JB          @@0
  1666.                         CMP         AL,'z'
  1667.                         JA          @@0
  1668.                         SUB         AL,'a'-'A'
  1669.             @@0:        CMP         AL,'T'
  1670.                         JE          @@TimeOut
  1671.  
  1672.                         MOV         AL,[ES:DI]
  1673.                         MOV         [@@Opt],AL
  1674.                         DumpString  <OFFSET @@UnkOpt>
  1675.  
  1676.             @@Exit:     POP         DX AX DI
  1677.                         RET
  1678.                         
  1679.             @@TimeOut:  INC         DI
  1680.                         MOV         SI,DI
  1681.                         MOV         AX,0
  1682.                         MOV         BX,10d
  1683.                         MOV         DH,0
  1684.  
  1685.             @@Next:     XCHG        DL,AL
  1686.                         LODS        [BYTE PTR ES:SI]
  1687.                         XCHG        DL,AL
  1688.                         CMP         DL,' '
  1689.                         JE          @@End
  1690.                         CMP         DL,0Dh                  ;? art
  1691.                         JE          @@End
  1692.                         CMP         DL,9
  1693.                         JE          @@End
  1694.                         CMP         DL,'0'
  1695.                         JB          @@Ill
  1696.                         CMP         DL,'9'
  1697.                         JA          @@Ill
  1698.                         SUB         DL,'0'
  1699.                         MUL         BL
  1700.                         ADD         AX,DX
  1701.                         CMP         AX,MaxMaxTimeOut
  1702.                         JA          @@Ill
  1703.                         JMP         @@Next
  1704.                                          
  1705.             @@End:      MOV         DX,AX
  1706.                         MOV         AX,0
  1707.                         MOV         BX,60
  1708.                         DIV         BX
  1709.                         MOV         [MaxNofTicks],AX
  1710.                         DumpString  <OFFSET @@AutoCl>
  1711.                         CALL        DumpWord
  1712.                         DumpString  <OFFSET @@Minutes>
  1713.                         JMP         @@Exit
  1714.  
  1715.             @@Ill:      DumpString  <OFFSET @@InvNum>
  1716.                         JMP         @@Exit
  1717.  
  1718.             @@UnkOpt    DB          'Unknown option: '
  1719.             @@Opt       DB          ?,0dh,0ah,'$'
  1720.             @@AutoCl    DB          'Auto-close timeout set at $'
  1721.             @@Minutes   DB          ' minutes.',0dh,0ah,'$'
  1722.             @@InvNum    DB          'invalid value for auto-close timeout.',0dh,0ah,'$'
  1723.  
  1724. ENDP        GetOption
  1725.  
  1726. PROC        ExtractParms NEAR
  1727.             ASSUME      DS:@CODE,ES:NOTHING,SS:@CODE,CS:@CODE
  1728.             ; entry:
  1729.             ;   ES:DI -> InitRequest
  1730.  
  1731.                         PUSH        ES DI
  1732.  
  1733.                         LES         DI,[(InitRequest PTR ES:DI).ParamStr]
  1734.                         MOV         [NofVolumes],0
  1735.  
  1736.             IFDEF       DEBUG
  1737.                         CALL        DumpParms
  1738.             ENDIF
  1739.  
  1740.                         CALL        NextWord
  1741.             @@Next:     CALL        NextSpace
  1742.                         CALL        NextWord
  1743.                         CMP         [BYTE PTR ES:DI],0Ah
  1744.                         JE          @@Exit
  1745.                         CMP         [BYTE PTR ES:DI],'/'
  1746.                         JE          @@opt
  1747.                         CMP         [BYTE PTR ES:DI],'-'
  1748.                         JNE         @@vol
  1749.             @@opt:      CALL        GetOption
  1750.                         JMP         @@Next
  1751.  
  1752.             @@vol:      CALL        AddVolume
  1753.                         JMP         @@Next
  1754.  
  1755.             @@Exit:     POP         DI ES
  1756.                         RET
  1757. ENDP        ExtractParms
  1758.  
  1759.             NotInstMsg  DB          'No volumes mounted, driver not installed.',0Dh,0Ah,'$'
  1760.             NameVersion DB          MajorName,' ',MajorVer,'''s ',MinorName,' ',MinorVer,0Dh,0Ah
  1761.                         DB          'Written by ',AuthorName,0Dh,0Ah,'$'
  1762.  
  1763. LABEL       EndOfCode
  1764. END
  1765.  
  1766.