home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / DOS_HELP / REST51.ZIP / RESTORE.ASM next >
Encoding:
Assembly Source File  |  1989-05-24  |  122.9 KB  |  4,200 lines

  1. name   RESTORE
  2. title  RESTORE.Com 5.1 for MS DOS 2.0 - 4.01
  3. ; copyright (c) 1989 Canadian Mind Products
  4. ;    - condensed Alps Allegro
  5. ;     - condensed    Toshiba P351
  6. page  60, 132
  7.  
  8. Comment |
  9.  
  10. Written in Microsoft Assembler MASM 5.0
  11. Last Updated:  1989 May 24 by Roedy Green
  12.  
  13. Authors:  Dan Wright and Roedy Green
  14.  
  15. Canadian Mind Products
  16. #162 - 1020 Mainland Street
  17. Vancouver, BC
  18. Canada    V6B 2T4
  19. (604) 684-6529
  20.  
  21.  
  22. Purpose
  23. =======
  24.  
  25. To restore files backed up under any version of DOS to any other
  26. version of DOS, Roedy Green wrote the original the Canadian Mind
  27. Products RESTORE program.  Versions 1 through 4.4 handled the
  28. Backup format used by MS and PC DOS 2.0 through 3.2.  CMP
  29. Restore replaces the RESTORE program that comes with MS DOS or
  30. IBM PC DOS.
  31.  
  32. Dan Wright wrote version 5 of Restore to further extend the
  33. capability to include the new DOS backup format introduced with
  34. DOS 3.3.  With this version, either of the formats will be
  35. recognized automatically and restored to any version of DOS from
  36. 2.0 to 4.01
  37.  
  38. CMP Restore corrects the 20 bugs in the official Restore.  This
  39. will allow people to restore from backups where before they
  40. could not.
  41.  
  42. ShareWare
  43. =========
  44.  
  45. Though versions 1.0 through 4.4 were in the public domain as
  46. Charware, starting with Version 5, Restore is ShareWare.  To use
  47. it legally you must send $15 US or $20 Canadian to Canadian Mind
  48. Products at the address above.    When you do so, we will send you
  49. a diskette.  This way you can be sure your version of Restore
  50. has not been tampered with to include viruses.
  51.  
  52. Syntax
  53. ======
  54.  
  55. RESTORE A: [C:][path\][filespec] [/S] [/P] [/Q]
  56.  
  57. Where:
  58.  
  59. A:     = source floppy drive, i.e. A:, B:, etc.
  60. C:     = target hard drive, i.e. C:, D:, etc.
  61. path     = the directory where the files will be placed.
  62. filespec = the specification of files to be restored.
  63.        May include wildcard chars. * and ?.
  64. /S     = restore subdirectories also.
  65. /P     = prompt before restoring each file.
  66. /Q     = quiet, suppress advertising banner.
  67.  
  68.  
  69. Samples of Use
  70. ==============
  71.  
  72. RESTORE A: C:\MySub\MyFile.Ext
  73. RESTORE A: C:\MySub\*.*/P/S/Q
  74. RESTORE A: C:\MySub/P
  75. RESTORE A: C:\MySub
  76. RESTORE A: \MySub        -- presumes default drive
  77. RESTORE A: C:*.*        -- presumes default directory
  78. RESTORE A: C:\*.BAT/S        -- restores all BAT files in all
  79.                 subdirectories.
  80.  
  81.  
  82. It is not as elaborate as the commercial versions, only the /S
  83. and /P switches are supported.
  84.  
  85. Version History:
  86.  
  87. Version 1:
  88.     - not released to the public
  89.     - restored all files ignoring the filespec
  90.  
  91. Version 2: released Christmas 1986
  92.     - /P /Q /S options.
  93.      - allowed you to select files to be restored.
  94.  
  95. Version 3: released to Charware subscribers Jan 28 1987
  96.      - fixed bug when restore had to handle 10 or more diskettes.
  97.  
  98. Version 4: released to BIX March 5 1987
  99.     - fixed bug RESTORE A: C:*.*/S in root directory did not work.
  100.       was treated as RESTORE A: C:\\*.*/S instead of C:\*.*/S
  101.     - fixed bug.  Originally all disks in the backup set were
  102.       checked to makes sure they were created on the same day
  103.       to make sure they were part of the same set.    Because backups
  104.       can be created with the /A option, it is possible each diskette
  105.       in the set is part of a different set.  Thus the check was
  106.       removed.
  107.  
  108. Version 4.1: released May 8 1987
  109.     - version number now prints as part of the "Screwed up" message
  110.     - RESTORE.TXT documention separated from ASM source code
  111.     - change mailing address
  112.  
  113. Version 4.2: released July 9 1987
  114.     - beeps when wants disk
  115.  
  116. Version 4.3: released April 9 1988
  117.     - change of mailing address in banner
  118.  
  119. Version 4.4: released December 24 1988
  120.     - change of mailing address in banner
  121.  
  122. Version 5.0: released March 4 1989
  123.     - very limited distribution
  124.     - added support for DOS 3.3 through DOS 4.01
  125.     - this was a major rewrite that took many times
  126.       longer to write than the original.  For this
  127.       reason Version 5.0 is not Charware, but rather
  128.       ShareWare.
  129.  
  130. Version 5.1: released May 24 1989
  131.     - more friendly, simpler, less technical error messages.
  132.     - fancier prompts.
  133.     - tidier source code.
  134.     - bug fixed that restored a file fragment when you inserted
  135.       the wrong diskette.
  136.     - avoid reprompting entire prompt when input bad.
  137.     - Abort Retry Ignore keystrokes no longer echo.
  138.     - / options no longer picky about leading space.
  139.     - warning message if source not A: or B:
  140.     - warning message if target not C: through G:
  141.     - fancier banner, with pause
  142.  
  143. About the Authors
  144. =================
  145.  
  146. Dan Wright is a legally blind programmer seeking work in the
  147. field either on a contract or full-time basis.    He is presenting
  148. this version of RESTORE as an example of his work.  This code
  149. was written, and parts of it adapted from Canadian Mind Products
  150. RESTORE version 4.4, using a speech synthesizer and a minimal
  151. amount of visual feedback from the screen (not enough to read).
  152. Information on DOS function calls, MASM, etc. was obtained using
  153. Norton Guides and various reference books which I have had read
  154. onto cassette tape.  The integrity of restored files was
  155. verified by redirecting the output of DIR commands and the
  156. output of a CRC utility to files before and after restoring and
  157. then comparing these using the DOS COMP and FC commands.
  158.  
  159. Roedy Green is the author of the public domain Abundance
  160. Database compiler and the 32 bit BBL Forth compiler as well as a
  161. suite of many small public domain utilities.  He also writes for
  162. The Computer Paper - a Vancouver free advertising paper.
  163.  
  164. WARNING TO HACKERS
  165. ==================
  166.  
  167. If you modify this program to look for existing files on hard
  168. disk before restoring, beware the APPEND command.  It will fool
  169. you into thinking the file already exists when in fact it does
  170. not, there is just a similarly named file in one of the APPEND
  171. directories.  The guys who wrote FastBack got fooled by this
  172. one.
  173.  
  174. Notes an How BACKUP Works
  175. =========================
  176.  
  177. BACKUP uses standard DOS-formatted disks (they must be
  178. pre-formatted, but not necessarily cleared of all files).
  179. Backup first erases all files in the root directory of the
  180. diskette -- even read only files.  (I have heard unconfirmed
  181. reports that some versions of BACKUP have a bug and you have to
  182. erase the hidden, system and read-only files yourself with QDOS
  183. II first.) If they were not erased, they could confuse RESTORE
  184. no end!
  185.  
  186. In addition BACKUP will not work if there are subdirectories on
  187. the floppies.  Instead of erasing them, it terminates with a
  188. mysterious stack overflow error.
  189.  
  190. Notes on DOS 3.2 Backup Format
  191. ==============================
  192.  
  193. MS DOS and PC DOS 2.0 through 3.2 use this format.  There is a
  194. slight difference between MS and PC DOS formats -- the \ verses
  195. the / in file names.
  196.  
  197. Each backup disk begins with a file called BackupId.@@@,
  198. followed by one or more of the backed-up files.  If two
  199. identically named files are backed up onto the same physical
  200. disk, the subsequent file extensions are listed as @01, @02,
  201. etc.  A file may be split across more than one disk, and in this
  202. case the name of all subsequent chunks are the same as the first
  203. chunk's (regardless of whether a non-unique name which had to be
  204. modified on its initial disk is unique on a later disk).
  205.  
  206. Backup puts a file called \BackupId.@@@ on each diskette.  In it
  207. you can find the diskette sequence number and the date the
  208. backup was done.  There is also an indicator flag to tell if
  209. this is the last diskette of the set.
  210.  
  211. offset    len
  212. 01..01    1    -1 if this is last diskette in the set.
  213. 02..03    2    Sequence no. of diskette.  In 8 bit BCD
  214. 04..05    2    Year e.g. 1986 backup done.
  215.         True 1900 form, not 1980 relative.
  216. 06..06    1    Day backup done, binary 1..31.
  217. 07..07    1    Month backup done, binary 1..12.
  218.  
  219.  
  220. Each file is backed up with a 128 byte preamble.  In the
  221. preamble is the fully qualified name of the file.  To make life
  222. interesting, the subdirectories may be separated with either /
  223. or \. This goofiness is 90% of the reason my version of RESTORE
  224. had to be written.
  225.  
  226. If files are too big to fit on diskette, there are two other
  227. numbers of interest in the preamble:
  228.  
  229. 1. The sequence number of this chunk 1, 2 etc
  230.  
  231. 2. A flag that indicates this is the last chunk.
  232.  
  233. offset     len
  234. 01 .. 01  1    -1 if last fragment of file, 0 otherwise.
  235. 02 .. 03  2    Sequence no. of this fragment,
  236. 04 .. 05  2    Padding.
  237. 06 .. 69 64    Fully qualified filename on hard disk without drive specifier
  238.         padded on right with nuls.  May have / instead \.
  239. 70 .. 83 14    Padding.
  240. 84 .. 84  1    Length of fully qualified name including one trailing nul.
  241. 85 ..129 45    Padding.
  242.  
  243. Note that the preamble does NOT contain any of the following
  244. information that you might expect.
  245.  
  246. 1. attribute byte of the file.
  247. 2. date and time file was last modified.
  248. 3. Length in bytes of the chunk.
  249. 4. offset in file where this chunk fits.
  250. 5. Length in bytes of the entire file.
  251. 6. Count of how many chunks there are supposed to be in total.
  252. 7. Checksum
  253.  
  254. To glean this information we must examine the date, time and
  255. attribute bytes of the backup file itself.  To figure out where
  256. the chunk fits in, we simply have to start at the beginning and
  257. keep track.  Thus it is impossible to restore a file unless you
  258. start at chunk 1 and work sequentially through.  Bad news if one
  259. of the chunks is unreadable.
  260.  
  261. Following the preamble is the file itself -- absolutely raw --
  262. no compression of any kind.
  263.  
  264. When restoring a file we have four versions of the filename:
  265.  
  266. Fname    -- from the floppy directory - part of the floppy file name
  267.     missing A:\ e.g. XXXXXX.XXX
  268.  
  269. InName    -- the actual name of the floppy file
  270.     e.g. A:\XXXXXXXX.XXX
  271.  
  272. HardName -- the name in the floppy premamble
  273.     missing C:
  274.     e.g. \SUB1\SUB2\XXXXXXXX.XXX
  275.  
  276. OutName  -- the actual name of the file on the hard disk
  277.     e.g. C:\SUB1\SUB2\XXXXXXXX.XXX
  278.  
  279.  
  280. Notes on DOS 3.3 Backup Format
  281. ==============================
  282.  
  283. MS and PC DOS 3.3 through 4.01 (and probably beyond) use the
  284. following format:
  285.  
  286. On each backup diskette are two files
  287. CONTROL.001 - list of files, subdirectories, sizes
  288.  
  289. BACKUP.001  - actual data files, not compressed, crammed together
  290.     end to end in a single file.
  291.  
  292. volume id is BACKUP  001
  293.  
  294. The diskettes are numbered in three places:
  295. CONTROL.002
  296. BACKUP.002
  297. volume id is BACKUP  002
  298.  
  299. The Control file
  300. ****************
  301. The control file begins with a 139 byte header:
  302.  
  303. offset    len
  304. 00..00    1    8B=139 length of record
  305. 01..08    8    the word BACKUP signature padded on the right with spaces
  306. 09..0A    2    diskette number, simple binary starting at 1
  307.         Does not use the goofy BCD format of DOS 3.2
  308. 0B..89    127    zeroes
  309. 8A..8A    1    -1 if last diskette in set, 0 otherwise
  310.  
  311. Then come two types of entries: subdirectories and files.  There
  312. is no special marker for the end of file other than the file size
  313. recorded in the directory.
  314.  
  315. Subdirectory entry
  316. ******************
  317.  
  318. A 70-byte subdirectory entry looks like this.
  319. 00..00    1    HEX 46=70 length of record
  320. 01..3F    63    subdirectory name, no drive, no lead \, with embedded \,
  321.         no trail \, zero padded on right
  322. 40..41    2    count of files following on this diskette in this subdir
  323. 42..45    4    offset in the Control file of the next subdirectory
  324.         record.  If there is no further subdirectory on this
  325.         diskette, contains -1.    The offset is absolute, not
  326.         relative to this record.  This way if we are restoring
  327.         only some subdirectories, we can rapidly get on with
  328.         the next one.
  329.  
  330. The date, time and attribute byte of the subdirectory are NOT
  331. recorded.  Restore builds directories as needed with the current
  332. date and time with a default attribute byte.
  333.  
  334. File entry
  335. **********
  336.  
  337. Following a subdirectory entry are multiple file entries for the
  338. files being backed up in that subdirectory.
  339.  
  340. A 34 byte file entry looks like this:
  341.  
  342. 00..00    1    HEX 22=34 length of record
  343. 01..0C    12    file name with embedded dot, padded with 0s.
  344.         no embedded spaces.
  345. 0D..0D    1    02 = another fragment to come on another diskette after this one.
  346.         03 = this is the last (possibly only) fragment.
  347. 0E..11    4    total size of file in bytes
  348. 12..13    2    Sequence number of this fragment starting at 1.
  349. 14..17    4    offset into Backup.nnn of start of file.
  350. 18..1B    4    size of fragment of file in bytes on this diskette
  351. 1C..1C    1    attribute byte of file in directory format.
  352.         usually the archive bit is on.
  353. 1D..1D    1    zeroes
  354. 1E..1F    2    time in DOS directory format
  355. 20..21    2    date in DOS directory format
  356.  
  357.  
  358. Note on register conventions
  359. ============================
  360.  
  361. Whenever we call a subroutine, the subroutine is permitted to
  362. trash all registers.  Thus the caller must save any registers
  363. needed.  The way the code is written, this is very rarely
  364. necessary as all high level routines do nothing but calls and
  365. comparisons of memory resident variables.
  366.  
  367. Setting the carry flag is often used by a subroutine to inform
  368. its caller that trouble has occurred.
  369.  
  370. Callers often cheat when calling very simple routines.    They
  371. fail to save necessary registers knowing that the called routine
  372. will not mess them up.    If you make changes to low level
  373. routines beware!
  374.  
  375. | ; End of comment.
  376.  
  377. ;==============================================================
  378.  
  379.  
  380. ifdef DEBUG                ;; Declared on MASM command line.
  381.   if1
  382.     %out Debug version.
  383.   endif
  384.   .xlist
  385.   .lall
  386.   include restore.dbg            ;; PUBLIC declarations for SYMDEB.
  387. else
  388.   if1
  389.     %out Production version.
  390.   endif
  391. endif
  392.  
  393. ;==============================================================
  394. ;    E Q U A T E S
  395.  
  396. CR        equ    0DH
  397. LF        equ    0AH
  398. BEL        equ    7
  399.  
  400. STD_IN        equ    0        ; Handle for standard input device.
  401. STD_OUT     equ    1        ; Handle for standard output device.
  402. STD_ERR     equ    2        ; Handle for standard error device.
  403.  
  404. STACK_SIZE    equ    256        ; Size of program stack in bytes.  Used
  405.                     ; to check for sufficient memory.
  406. BUFF_SIZE    equ    512*9*10    ; Size of buffer for disk I/O.    Size = 10
  407.                     ; tracks for 360K floppy.
  408. HDR_REC_LEN    equ    139        ; Length of header record in
  409.                     ; CONTROL.XXX.
  410. SUBDIR_REC_LEN    equ    70        ; Length of subdirectory records
  411.                     ; in CONTROL.XXX.
  412. FILE_REC_LEN    equ    34        ; Length of file records in
  413.                     ; CONTROL.XXX.
  414.  
  415.  
  416. ;==============================================================
  417.  
  418. dbln    macro Message, Msg_Lbl
  419. ;; Define Message as one line of a message terminated by CR/LF.  If the
  420. ;; message label Msg_Lbl is supplied, make sure it has been declared and use it
  421. ;; to calculate the length of the message after the current line is defined.
  422.   ifnb <Msg_Lbl>            ;; If the message label has been supplied
  423.     ifndef Msg_Lbl            ;; but not declared, declare it.
  424.       even
  425.       Msg_Lbl label byte
  426.     else
  427.       if $+1 eq Msg_Lbl         ;; Ensure start address of message is
  428.     even                ;; the same on both passes.
  429.       endif
  430.     endif
  431.   endif
  432.  
  433.   ifnb <Message>            ;; Define text of message.
  434.     db "&Message"
  435.   endif
  436.     db CR, LF            ;; Terminate line.
  437.  
  438.   ifnb <Msg_Lbl>            ;; Calculate current length of message.
  439.     Msg_Lbl&_Len = $ - Msg_Lbl
  440.   endif
  441. endm                    ;; End of macro dbln.
  442.  
  443. ;==============================================================
  444.  
  445. dbpl    macro Prompt, Prompt_Lbl
  446. ;; Define partial line Prompt as a prompt with no terminating CR/LF.   If
  447. ;; the prompt label Prompt_Lbl is supplied, make sure it has been declared and
  448. ;; use it to calculate the length of the prompt after the current line is
  449. ;; defined.
  450.   ifnb <Prompt_Lbl>            ;; If the label is supplied but not
  451.     ifndef Prompt_Lbl            ;; declared, declare it.
  452.       even
  453.       Prompt_Lbl label byte
  454.     else
  455.       if $+1 eq Prompt_Lbl        ;; Ensure start address of prompt is
  456.     even                ;; the same for both passes.
  457.       endif
  458.     endif
  459.   endif
  460.  
  461.   ifnb <Prompt>             ;; Define text of prompt.
  462.     db "&Prompt"
  463.   endif
  464.   ifnb <Prompt_Lbl>            ;; Calculate current length of prompt
  465.                     ;; if label supplied.
  466.     Prompt_Lbl&_Len = $ - Prompt_Lbl
  467.   endif
  468. endm                    ;; End of macro dbpl
  469.  
  470. ;==============================================================
  471. dbs    Macro    Len            ;; Len spaces
  472.     DB    &Len DUP (" ")        ;; define string of spaces
  473.     endm
  474. ;==============================================================
  475.  
  476. dbpr    macro Prompt, Prompt_Lbl
  477. ;; Define Prompt as a prompt with no terminating CR/LF and one bell char.  If
  478. ;; the prompt label Prompt_Lbl is supplied, make sure it has been declared and
  479. ;; use it to calculate the length of the prompt after the current line is
  480. ;; defined.
  481.   ifnb <Prompt_Lbl>            ;; If the label is supplied but not
  482.     ifndef Prompt_Lbl            ;; declared, declare it.
  483.       even
  484.       Prompt_Lbl label byte
  485.     else
  486.       if $+1 eq Prompt_Lbl        ;; Ensure start address of prompt is
  487.     even                ;; the same for both passes.
  488.       endif
  489.     endif
  490.   endif
  491.  
  492.   ifnb <Prompt>             ;; Define text of prompt.
  493.     db "&Prompt"
  494.   endif
  495.     db BEL                ;; Add one bell char.
  496.   ifnb <Prompt_Lbl>            ;; Calculate current length of prompt
  497.                     ;; if label supplied.
  498.     Prompt_Lbl&_Len = $ - Prompt_Lbl
  499.   endif
  500. endm                    ;; End of macro dbpr.
  501.  
  502. ;==============================================================
  503.  
  504. dbzs    macro Z_String, Z_String_Lbl
  505. ;; Define the contents of Z_String as an ASCII Z string with the label
  506. ;; Z_String_Lbl.
  507.   ifnb <Z_String_Lbl>            ;; Declare label for Z string.
  508.     even
  509.     Z_String_Lbl label byte
  510.   else                    ;; Force error if no label.
  511.     .err
  512.   endif
  513.  
  514.   ifnb <Z_String>            ;; Define Z string.
  515.     db "&Z_String"
  516.   endif
  517.     db 0                ;; Add terminating nul.
  518. endm                    ;; End of macro dbzs.
  519.  
  520. ;==============================================================
  521.  
  522. Patch_Num macro Hex_Num, Num_Start, Num_Width
  523. local PN_More
  524. ;; Display the 16 bit quantity Hex_Num as a decimal integer right justified
  525. ;; in a field Num_Width characters wide with the right most digit at offset
  526. ;; Num_Start.  It generally patches the number into an error message or prompt.
  527.   ifdif <Hex_Num>,<ax>
  528.     mov    ax, Hex_Num        ;; Value to display in ASCII decimal.
  529.   endif
  530.     lea    di, Num_Start        ;; Location of right most digit.
  531.     mov    cx, Num_Width        ;; Width of field in which to place
  532.                     ;; Number.
  533.     Call    Patch_Sub
  534. endm                    ;; End of macro Patch_Num.
  535.  
  536. ;==============================================================
  537.  
  538. Say_Err_Msg macro Err_Msg
  539. ;; Print Err_Msg&_Len characters beginning at the address of Err_Msg
  540. ;; to the standard error device.
  541.     lea    dx, Err_Msg
  542.     mov    cx, Err_Msg&_Len
  543.     mov    bx, STD_ERR
  544.     mov    ah, 40H
  545.     int    21H            ;; 40H=Write.
  546. endm                    ;; End of macro Say_Err_Msg.
  547.  
  548. ;==============================================================
  549.  
  550. Say_Msg    macro Msg
  551. ;; Print Msg&_Len characters beginning at the address of Msg
  552. ;; to the standard output device.  These can be redirected via Pipes.
  553.     lea    dx, Msg
  554.     mov    cx, Msg&_Len
  555.     mov    bx, STD_OUT
  556.     mov    ah, 40H
  557.     int    21H            ;; 40H=Write.
  558. endm                    ;; End of macro Say_Msg.
  559.  
  560. ;==============================================================
  561.  
  562. D_Count    = 0                ;; Initialize count of dangerous files.
  563. Test_Count = 0                ;; Used to detect incorrect parameters.
  564.  
  565. ;==============================================================
  566.  
  567. Def_D_File macro D_Filename, DC
  568. ;; Define an ASCII Z string containing the filename passed in D_File and
  569. ;; calculate its length.
  570. ;; Keep track of the number of filenames processed in D_Count and use this
  571. ;; value to generate unique symbols for the address and length of each
  572. ;; Z string.
  573. ;; Only the first parameter, the filename of a file which could be dangerous
  574. ;; to restore to the root directory, should be supplied when calling this
  575. ;; macro.
  576.   ifb <DC>                ;; This part executes on initial call.
  577.     D_Count = D_Count + 1        ;; Increment count of dangerous files.
  578.  
  579. ;; Now the macro calls itself passing the value of D_Count as a second
  580. ;; parameter.  This enables the generation of symbol names made unique by
  581. ;; including the current value of D_Count for the address of the string and
  582. ;; its length.
  583.     Def_D_File <D_Filename>, %D_Count
  584.  
  585.   else                    ;; This part executes when the macro
  586.                     ;; calls itself.
  587.     if Test_Count eq D_Count        ;; This occurs if the macro was
  588.       .err                ;; erroneously called with a second
  589.       exitm                ;; parameter supplied.
  590.     endif
  591.  
  592.     even
  593.     D_File&DC label byte        ;; Generate label for string address.
  594.     ifnb <D_Filename>            ;; The first parameter can't be blank.
  595.       db "&D_Filename"            ;; Define string.
  596.       db 0                ;; Add terminating nul.
  597.     else
  598.       .err
  599.     endif
  600.  
  601.     D_File&DC&_Len = $ - D_File&DC    ;; Generate symbol containing string
  602.                     ;; length.
  603.  
  604. ;; Test_Count follows the value of D_Count to prohibit the execution of the
  605. ;; second part of the macro before the first part which would happen if a
  606. ;; second parameter was included in the initial call.  D_Count is incremented
  607. ;; on execution of the first part allowing subsequent error free execution of
  608. ;; the second part.  Incrementing Test_Count at the end of the second part
  609. ;; ensures that the first part must be executed before the second part may
  610. ;; be executed again.
  611.     Test_Count = Test_Count + 1
  612.   endif
  613. endm                    ;; End of macro Def_D_File.
  614.  
  615. ;==============================================================
  616.  
  617. Blank_Extension macro Ext_Start
  618. ;; Patch a filename extension with wild card characters.  Ext_Start points
  619. ;; at the beginning of the file extension.
  620.     lea    di, Ext_Start
  621.     mov    cx, 3            ;; Length of a file extension.
  622.     mov    al, '?'
  623.     cld
  624.     rep    stosb
  625. endm                    ;; End of macro Blank_Extension.
  626.  
  627. ;==============================================================
  628.  
  629. DTA    equ 80H         ;; Offset in PSP of default DTA.
  630.  
  631. ; Template for DTa after call to dir. search functions 4EH and 4FH.
  632. Dir_Search struc
  633. DS_Reserved    db 21 dup (?)        ; Reserved for DOS.
  634. DS_Attr     db ?            ; File attribute in dir. format.
  635. DS_Time     dw ?            ; File time in dir. format.
  636. DS_Date     dw ?            ; File date in dir. format.
  637. DS_Size     dd ?            ; file size.
  638. DS_Name     db 13 dup (?)        ; Filename as ASCII Z string.
  639. Dir_Search ends
  640.  
  641.  
  642. ;==============================================================
  643.  
  644. ;    BACKUPID.@@@ file format in DOS 3.2
  645. Bkp_ID_Rec struc            ; 7 bytes of interesting info in
  646.                     ; \BACKUPID.@@@.
  647. BI_Last     db ?            ; -1 if this is last diskette in the set.
  648. BI_Seq        dw ?            ; Sequence no. of diskette.  This is
  649.                     ; originally in 8 bit BCD form but
  650.                     ; will be converted to true binary.
  651. BI_YYYY     dw ?            ; Year e.g. 1986 backup done.
  652.                     ; True 1900 form, not 1980 relative.
  653. BI_DD        db ?            ; Day backup done, binary 1..31.
  654. BI_MM        db ?            ; Month backup done, binary 1..12.
  655. Bkp_ID_Rec ends
  656.  
  657.  
  658. ;==============================================================
  659.  
  660. ;    128 byte header at the beginning of every DOS 3.2 backup file.
  661. Preamble   struc
  662. P_Last        db ?            ; -1 if last fragment of file, 0
  663.                     ; otherwise.
  664. P_Frag_Seq    dw ?            ; Sequence no. of this fragment,
  665.                     ; 1 = first, 2 = second, etc.
  666.         dw ?            ; Padding.
  667. P_Hard_Name    db 64 dup (?)        ; Fully qualified filename on hard disk
  668.                     ; without drive specifier, padded on
  669.                     ; right with nuls.  May have / instead
  670.                     ; of \.
  671.         db 14 dup (?)        ; Padding.
  672. P_Hard_Len    db ?            ; Length of fully qualified name
  673.                     ; including one trailing nul.
  674.         db 45 dup (?)        ; Padding.
  675. Preamble   ends
  676.  
  677. ;==============================================================
  678.  
  679. ; Header Record in DOS 3.3 Control.XXX file
  680. Hdr_Rec     struc
  681. Hdr_Len     db ?            ; Length of header record.
  682. Hdr_Sig     db "BACKUP  "        ; Backup signature.
  683. Hdr_Seq     dw ?            ; Disk number in set, 1=first, 2=
  684.                     ; second, etc.
  685.         db 127 dup (?)        ; Padding.
  686. HDR_Last    db ?            ; -1 if last diskette in set, 0 otherwise
  687. Hdr_Rec     ends
  688.  
  689. ;==============================================================
  690.  
  691. ; Subdir Record in DOS 3.3 Control.XXX file
  692. Subdir_Rec    struc
  693. Subdir_Len    db ?            ; Length of subdirectory record.
  694. Subdir_Name    db 61 dup (?)        ; Subdirectory name.  No leading or
  695.                     ; trailing backslash, 0 padded on right.
  696.         dw ?            ; Padding.
  697. Subdir_Count    dw ?            ; Count of files following in this
  698.                     ; subdirectory on this diskette.
  699. Subdir_Next    dd ?            ; Absolute offset in CONTROL.XXX of next
  700.                     ; subdirectory record. (-1 if no more
  701.                     ; subdir entries)
  702. Subdir_Rec    ends
  703.  
  704. ;==============================================================
  705.  
  706. ; File Record in DOS 3.3 Control.XXX file
  707. File_Rec    struc
  708. File_Len    db ?            ; Length of file record.
  709. File_Name    db 12 dup (?)        ; file name with embedded dot, zero
  710.                     ; padded, no embedded spaces.
  711. File_More    db ?            ; 2=another fragment on next diskette, 3=
  712.                     ; last and possibly only fragment.
  713. File_Size    dd ?            ; Size of file in bytes.
  714. File_Frag_Seq    dw ?            ; Sequence number of this fragment,
  715.                     ; 1=first, 2=second, etc.
  716. File_Frag_Start dd ?            ; Offset in BACKUP.XXX where frag.
  717.                     ; starts.
  718. File_Frag_Size    dd ?            ; Size of fragment of file on this
  719.                     ; diskette.
  720. File_Attr    db ?            ; File attributes in dir. format.
  721.         db ?            ; Padding.
  722. File_Time    dw ?            ; File time in dir. format.
  723. File_Date    dw ?            ; File date in dir. format.
  724. File_Rec    ends
  725.  
  726. ;==============================================================
  727.  
  728. Code    segment para
  729.     assume cs : Code, ds : Code, ss : Code, es : Code
  730.     org 100H
  731.  
  732. Start:    jmp Restore_Main
  733.  
  734. ;==============================================================
  735. ;    V A R I A B L E S
  736.     even
  737. Rest_Count    dw 0            ; count of files restored.
  738. Want_Seq    dw 1            ; Expected disk sequence no.
  739. Want_Frag_Seq    dw 1            ; Expected fragment sequence no.
  740. Want_Size    dd 0            ; Expected file size for multiple
  741.                     ; fragment files and for verifying copy.
  742. Bkp_Seq     dw 1            ; Current Diskette sequence no.
  743.  
  744. Ctl_Hndl    dw -1            ; CONTROL.XXX or BACKUPID.@@@ handle.
  745. Bkp_Hndl    dw -1            ; Handle for backup data files.
  746. Out_Hndl    dw -1            ; Output file handle.
  747.  
  748. Format_Flags    db 0            ; Used to indicate format of backup
  749.                     ; diskettes being restored.
  750. DOS32        equ 1            ; Bit 0 set = DOS 3.2 format.
  751. DOS33        equ 2            ; Bit 1 set = DOS 3.3 format.
  752.  
  753. Flags        db 01H            ; If bit set:
  754. LastFrag    EQU 01H         ; bit 0 = last file fragment.
  755. LastDisk    EQU 02H         ; bit 1 = last diskette in set.
  756. NewDisk     EQU 04H         ; Bit 2 = New Diskette.
  757. WrongOk     EQU 08H         ; Bit 3 = user OKed diskette out of seq.
  758. SkipFile    EQU 10H         ; Bit 4 = Do not restore file.
  759. FileMatched    EQU 20H         ; Bit 5 = filename was matched.
  760. WildCards    EQU 40H         ; Bit 6 = wild card chars. in command
  761.                     ; line pathspec.
  762. WasPeriod    EQU 80H         ; Bit 7 = period processed in command
  763.                     ; line pathspec.
  764.  
  765. Cmd_Flags    db 0            ; Flags for command line switches.
  766. Prompt_Needed    equ 01h         ; Bit 0 set = prompted restore (/p)
  767. RestoreSubs    equ 04h         ; Bit 2 set = restore subdirectories (/s)
  768. Quietly     equ 08h         ; Bit 3 set = quiet, suppress banner (/Q)
  769.  
  770. Bkp_Sig     db "BACKUP  "        ; Valid backup control file signature.
  771. Bkp_Sig_Len equ $ - Bkp_Sig
  772.  
  773. ; Define filenames used in both backup schemes.  X's will be patched later with
  774. ; correct values.
  775. dbzs <X:\BACKUPID.@@@>    Bkp_ID_Name    ; Backup ID filename (DOS 3.2).
  776. dbzs <X:\*.*>        All_Pattern    ; Pattern to find files on floppy in
  777.                     ; DOS 3.2 backup scheme.
  778. dbzs <X:\CONTROL.XXX>    Ctl_Filename    ; Backup control file name (DOS 3.3).
  779. dbzs <X:\BACKUP.XXX>    Bkp_Filename    ; Backup data filename (DOS 3.3).
  780. ; allocate two more bytes so Bkp_Filename can be used to hold floppy filenames
  781. ; in DOS 3.2 scheme.
  782.         db 2 dup (0)
  783.  
  784. Rest_Name    label byte        ; Pathspec to be restored.
  785. Rest_Drive    db 'X:'         ; Hard disk drive letter.  Patched later.
  786.         db '\'            ; Not supplied in subdir records.
  787. Rest_Path    db 75 dup (0)
  788. Filespec_Ptr    dw 0            ; Ptr. to start of filespec in Rest_Path.
  789. Rest_Name_Len    dw 0            ; Length of drive and pathspec to be
  790.                     ; restored not including terminating nul.
  791.  
  792. Match_File    db "XXXXXXXX.XXX"    ; Name of file proposed to be restored.
  793.                     ; Extracted from Rest_Path in format
  794.                     ; comparable with command line pattern.
  795.  
  796. CL_Subdir_Pattern db 64 dup (0)     ; Subdirectory pattern from command line
  797.                     ; of files to be restored.
  798. Subdir_Pat_Len    dw 0            ; Length of subdirectory pattern
  799.                     ; including trailing backslash, but
  800.                     ; excluding leading backslash and
  801.                     ; trailing nul.
  802.  
  803. CL_File_Pattern db "????????.???"    ; Pattern from command line of files
  804.                     ; to be restored.
  805.  
  806. ; Files dangerous to restore to the root directory.
  807.     Def_D_File <IBMBIO.COM1>
  808.     Def_D_File <IBMDOS.COM>
  809.     Def_D_File <IO.SYS>
  810.     Def_D_File <MSDOS.SYS>
  811.     Def_D_File <COMMAND.COM>
  812.  
  813. ; Define prompts and informational and error messages.
  814. Wrong_Ver    db "RESTORE requires DOS 2.0 or later.$"
  815. ; Not done with dbline since handles may not work.
  816.  
  817. Part_X_Msg    db " part "
  818. Part_X        db "XXX"
  819. Part_X_Msg_Len    equ $ - Part_X_Msg
  820.  
  821. dbpl    <X>                        ,echochar
  822.     DB    08                    ; allow keystroke echo
  823. dbpl                            ,echochar
  824. ; Embedded tabs are ok, since DOS will expand them again.
  825. dbln    <    ╔════════════════════════════════════════════════════╗>, Banner
  826. dbln    <    ║ RESTORE 5.1 for PC DOS and MS DOS 2.0 through 4.01 ║>
  827. dbln    <    ╚════════════════════════════════════════════════════╝>
  828. dbln
  829. dbln    <      (c) Copyright 1989 Dan Wright and Roedy Green>
  830. dbln
  831. dbln    <        ░▒▓█ Canadian Mind Products █▓▒░>
  832. dbln
  833. dbln    <              #162 - 1020 Mainland>
  834. dbln    <         Vancouver, BC    Canada    V6B 2T4>
  835. dbln    <             (604) 684-6529>
  836. dbln
  837. dbln    <Restore 5.1 is direct replacement for MS DOS Restore that works across DOS>
  838. dbln    <versions.  You can restore files backed up under any level of PC or MS DOS 2.0>
  839. dbln    <though 4.01 to any other level.  Restore fixes the many bugs in the official>
  840. dbln    <Restore.  Restore can also be used to distribute files on floppy.>
  841. dbln
  842. dbln    <To continue legally using this Shareware program, you must send a $US 15 or>
  843. dbln    <$CDN 20 registration fee.  In return, we will send you the latest version of>
  844. dbln    <Restore.  Registration is the only way to completely protect yourself from>
  845. dbln    <viruses.  Restore 5.1 is for non-military use only.>
  846. dbln                                ,Banner
  847.  
  848.  
  849. dbln <┌──────────────────────────────────────────────────┐>    ,Help_Msg
  850. dbln <│ RESTORE A: [C:][\path\][filespec] [/S] [/P] [/Q] │>
  851. dbln <└──────────────────────────────────────────────────┘>
  852. dbln <A:       = source floppy drive, i.e. A:, B:, etc.>
  853. dbln <C:       = target hard drive, i.e. C:, D:, etc.>
  854. dbln <path     = the directory where the files will be placed.>
  855. dbln <filespec = the specification of files to be restored.>
  856. dbln <         May include wildcard chars. * and ?.>
  857. dbln </S       = restore subdirectories also.>
  858. dbln </P       = prompt before restoring each file.>
  859. dbln </Q       = quiet, suppress advertising banner.>
  860. dbln
  861. dbln <e.g. the command line should look something like this:
  862. dbln
  863. dbln < Restore A: C:\MySub\MyFile.Ext>
  864. dbln < Restore A: C:\M???.Bat/P/S/Q>
  865. dbln < Restore A: C:\*.*/S>
  866. dbln < Restore A: C:\MySub\>
  867. dbln < RESTORE A: C:\MySub\MyFile.>                ,Help_Msg
  868.  
  869. dbln                                ,Insert
  870. dbln            <┌────────────────────────────────────────┐>
  871. dbpl            <│ Insert backup diskette >
  872. Insert_Seq    db    "XXX in drive "
  873. Insert_Drive    db    "X: │"
  874. dbln
  875. dbln            <└────────────────────────────────────────┘>
  876. dbln                                ,Insert
  877.  
  878. dbpr                                ,Strike_Any
  879. dbln <Strike the space bar to continue...  Hit Ctrl-Break to Abort>  ,Strike_Any
  880.  
  881.  
  882. dbln                                ,Announce_Bkp_Msg
  883. dbs        3
  884. dbpl            <You inserted diskette number >
  885. ABM_Seq     db    "XXX"
  886. dbpl            < into drive >
  887. ABM_Drive    db    "X:"
  888. dbln
  889. dbs        3
  890. dbPl            <Backed up on >
  891. ABM_MM        db    "XX-"
  892. ABM_DD        db    "XX-"
  893. ABM_YYYY    db    "XXXX"
  894. dbln                                ,Announce_Bkp_Msg
  895.  
  896. dbpl                                ,Old_Bkp_Format
  897. dbs    3
  898. dbln <Diskettes were backed up with DOS 2.0, 2.1, 3.0, 3.1 or 3.2>
  899. dbln                                ,Old_Bkp_Format
  900.  
  901. dbpl                                ,New_Bkp_Format
  902. dbs    3
  903. dbln <Diskettes were backed up with DOS 3.3 or 4.01.>
  904. dbln                                ,New_Bkp_Format
  905.  
  906. dbln <░▒▓█ Usually the source floppy drive is A: or B: Are you sure?█▓▒░> ,Strange_Source
  907.  
  908. dbln <░▒▓█ Usually the target hard drive is C: D: ... G: Are you sure?█▓▒░> ,Strange_Target
  909.  
  910. dbln    <░▒▓█ Your request to restore was ambiguous.█▓▒░>,    Ambiguous
  911. dbln    <Use forms like:>
  912. dbln    <┌──────────────────────┬───────┐>
  913. dbln    <│ Restore A: C:\Mysub\X\ /S /P │ if X is a subirectory>
  914. dbln    <│ Restore A: C:\Mysub\X. /S /P │ if X is a file>
  915. dbln    <└──────────────────────┴───────┘>            , Ambiguous
  916.  
  917.  
  918. dbln <░▒▓█ Diskette is from another backup set. █▓▒░>        ,Wrong_Set
  919.  
  920. dbln <Not to worry, all is forgiven.  Now you can either:>    ,AR_Msg
  921. dbln <A. Abort and give up.  Any partly restored file will be corrupted.>
  922. dbln <R. Retry with the proper diskette.>
  923. dbpr <Abort or Retry (A/R): >                    ,AR_Msg
  924.  
  925. dbln                                ,Out_Of_Seq
  926. dbln <░▒▓█ Diskette out of sequence. █▓▒░>
  927. dbln
  928. dbln <This is not the diskette you were supposed to insert.>    ,Out_Of_Seq
  929.  
  930. dbln <Not to worry, all is forgiven.  Now you can either:>    ,ARI_Msg
  931. dbln <A. Abort and give up. No files will be damaged.>
  932. dbln <R. Retry with the proper diskette.>
  933. dbln <I. Ignore the sequence error and attempt to restore from this diskette.>
  934. dbpr <Abort, Retry, or Ignore (A/R/I): >            ,ARI_Msg
  935.  
  936. dbpl                                ,Prompt_User1
  937. dbs    9
  938. dbpl    <Restore?  >                        ,Prompt_User1
  939.  
  940. dbpl < (Y/N): >                         ,Prompt_User2
  941.  
  942. dbln < restored>                        ,Restored
  943.                                 ; single file msg
  944. dbln                                ,Done_Msg
  945. dbln
  946. dbpl            <Restore completed with >
  947. DM_Count    db    "XXXXX file(s) restored."
  948. dbln                                ,Done_Msg
  949.  
  950. dbpr                                ,None_Restored
  951. dbln <WARNING: No files were found to restore.>         ,None_Restored
  952.  
  953. dbln <░▒▓█ Insufficient memory. █▓▒░>                ,Insufficient
  954. dbln <Get rid of large TSR programs to free up RAM.>        ,Insufficient
  955.  
  956. dbln <░▒▓█ Invalid parameters. █▓▒░>                    ,Bad_Params
  957.  
  958. dbln <░▒▓█ Invalid path. █▓▒░>                    ,Bad_Path
  959.  
  960. dbln <░▒▓█ Invalid file specification. █▓▒░>                ,Bad_Filespec
  961.  
  962. dbln <░▒▓█ Invalid source drive specification. █▓▒░>            ,Bad_Source
  963.  
  964. dbln <░▒▓█ Invalid target drive specification. █▓▒░>            ,Bad_Target
  965.  
  966. dbln <░▒▓█ Target drive must not be same as source. █▓▒░>        ,Same
  967.  
  968. dbln <░▒▓█ Wildcard characters not allowed in path. █▓▒░>        ,Bad_Wildcards
  969.  
  970. dbln <░▒▓█ Unrecognized command line switch. █▓▒░>            ,Bad_Switch
  971.  
  972. dbln <░▒▓█ Input error -- possibly you removed the floppy too soon. █▓▒░> ,In_IO_Err
  973.  
  974. dbln <░▒▓█ Output error -- possibly the hard disk is full. █▓▒░>    ,Out_IO_Err
  975.  
  976. dbln <░▒▓█ Possibly damaged backup diskette. █▓▒░>            ,Floppy_Trouble
  977.  
  978. dbln <░▒▓█ Hard disk trouble. █▓▒░>                    ,Hard_Disk_Trouble
  979.  
  980. dbln <░▒▓█ Too many open files. █▓▒░>                ,Too_Many_Open
  981. dbln <Increase FILES=30 parameter in CONFIG.SYS.>        ,Too_Many_Open
  982.  
  983. dbln <░▒▓█ Mysterious error. Diskette possibly damaged. █▓▒░>    ,Unknown
  984.  
  985. dbln                                ,CRLF
  986.  
  987. dbpr                                ,Beep
  988.  
  989. dbln                                , Cant_Restore
  990. dbln <Unable to restore file: >         ,        Cant_Restore
  991.  
  992. dbln                                ,Not_Bkp
  993. dbpl            <░▒▓█ Non-backup diskette in drive >
  994. NB_Drive    db    "X: █▓▒░"
  995. dbln                                ,Not_Bkp
  996.  
  997.  
  998. dbln                                ,Special_Attr
  999. dbln <░▒▓█ This is a Read-only, Hidden, and/or System file. █▓▒░>
  1000. dbln <Do not restore it unless you are absolutely sure of what>
  1001. dbln <you are doing.>                        ,Special_Attr
  1002.  
  1003. dbln                                ,Aborted
  1004. dbpl            <Restore Aborted with >
  1005. Aborted_Count    db    "XXXXX"
  1006. dbln            < files restored.>            ,Aborted
  1007.  
  1008. ; Define table of valid filename and pathname chars.
  1009. Valid_Chars db 0,"!",0,"#$%&'()",0,0,0,"-",0,0, "0123456789", 6 dup (0)
  1010.     db "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]",0,"_"
  1011.     db "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{",0,"}",0,0
  1012.  
  1013. ;==============================================================
  1014.  
  1015. Patch_Sub    PROC    Near
  1016. ;    DOS 3.2 and 3.3
  1017. ;    on entry ax=num di=target addr cx=num width
  1018. ;    See Patch_Num macro for more details.
  1019.     mov    bx, 10
  1020.     std
  1021. PN_More:
  1022.     xor    dx, dx            ; Zero out high word.
  1023.     div    bx
  1024.     xchg    dx, ax            ; Get remainder in al.
  1025.     add    al, '0'         ; Convert to ASCII
  1026.     stosb                ; and store it in the string.
  1027.     mov    ax, dx
  1028.     or    ax, ax            ; All done?
  1029.     loopnz    PN_More         ; Drop out if so.
  1030.  
  1031.     mov    al, '0'         ; Pad on the left with zeros.
  1032.     rep    stosb
  1033.     cld
  1034.     Ret
  1035. Patch_Sub    ENDP
  1036.  
  1037. ;==============================================================
  1038.  
  1039. Parse    proc near
  1040. ; DOS 3.2 and 3.3
  1041. ; parse the command line tail for the source drive, target drive,
  1042. ; pathspec pattern, and switches specified.
  1043. ;
  1044. ; Returns:
  1045. ;
  1046. ;    CL_Subdir_Pattern contains the pattern against which the dirspecs.
  1047. ;    of files to be restored are compared.  An empty pattern specifies
  1048. ;    the root directory; otherwise, the pattern is an absolute dirspec.
  1049. ;    stored with a trailing but no leading backslash.
  1050. ;
  1051. ;    Subdir_Pat_Len contains the length of the subdir pattern against
  1052. ;    which the dirspecs. of files to be restored are matched.  If the
  1053. ;    pattern specifies the root directory, this value is 0; otherwise,
  1054. ;    it contains the length of the pattern including a trailing but not
  1055. ;    a leading backslash.
  1056. ;
  1057. ;    CL_File_Pattern contains a 12 byte fixed length file pattern which
  1058. ;    files to be restored must match.  The pattern contains a period at
  1059. ;    the 9th position and the filename and extension are padded on the
  1060. ;    right to full length with blanks.  Any asterisks are expanded to
  1061. ;    their question mark equivalents.
  1062. ;
  1063. ;    Cmd_Flags bit 0 set if /P switch specified, clear otherwise .
  1064. ;
  1065. ;    Cmd_Flags bit 2 set if /S switch specified, clear otherwise.
  1066. ;
  1067. ;    Cmd_Flags bit 3 set if /Q switch specified, clear otherwise.
  1068. ;
  1069.     xor    ch, ch
  1070.     mov    cl, ds:80H        ; Get length of command line tail.
  1071.     jcxz    P_Help
  1072.     mov    di, 81H         ; Point at command line tail.
  1073.     mov    al, ' '         ; Skip leading spaces.
  1074.     cld
  1075.     repe    scasb
  1076.     jz    P_Help
  1077.     jcxz    P_Err
  1078.     cmp    byte ptr [di], ':'
  1079.     jnz    P_Err
  1080.     push    cx            ; Save no. of remaining chars.
  1081.     call    Get_Source_Drive
  1082.     pop    cx
  1083.     inc    di            ; Bypass the colon.
  1084.     dec    cx
  1085.     jnz    P_Get_Target
  1086.     call    Default_Drive
  1087.     call    Default_Subdir
  1088.     ret
  1089.  
  1090. P_Help: Say_Err_Msg Banner        ; Just plain RESTORE no parms
  1091.     Call    Strike_Any_Key
  1092.     call    Abort_With_Help
  1093.  
  1094. P_Err:    Say_Err_Msg Bad_Params
  1095.     call    Abort_With_Help
  1096.  
  1097. P_Get_Target:
  1098.     cmp    byte ptr [di], '/'    ; Is target supplied?
  1099.     jz    P_Use_Dflts        ; No, use default drive and pathspec.
  1100.     mov    ah, cl            ; Should be at least one space
  1101.     dec    ah            ; between source and target.
  1102.     mov    al, ' '         ; Skip spaces between source and
  1103.     repe    scasb            ; target specifications.
  1104.     jz    P_Use_Dflts        ; Rest of command line was spaces.
  1105.     cmp    ah, cl            ; At least one space?
  1106.     jz    P_Err            ; No, abort.
  1107.  
  1108.     jcxz    P_Use_Dflt_Drv        ; Use default drive for target if
  1109.     cmp    byte ptr [di], ':'    ; if none specified.
  1110.     jnz    P_Use_Dflt_Drv
  1111.     push    cx
  1112.     call    Get_Target_Drive
  1113.     pop    cx
  1114.     inc    di            ; Point to start of pathspec.
  1115.     dec    cx
  1116.     jnz    P_Get_Pathspec
  1117.     call    Default_Subdir        ; Use default subdir for pathspec
  1118.     ret                ; if none specified.
  1119.  
  1120. P_Use_Dflt_Drv:
  1121.     push    cx
  1122.     call    Default_Drive
  1123.     pop    cx
  1124.     inc    cx            ; Back up to start of pathspec.
  1125.     dec    di
  1126.  
  1127. P_Get_Pathspec:
  1128.     cmp    byte ptr [di], '/'    ; Switches could be here.
  1129.     jz    P_Get_Switches        ; They are, skip to switch processing.
  1130.     cmp    byte ptr [di], ' '    ; If space here, switches must follow.
  1131.     jz    P_Get_Switches        ;
  1132.     call    Get_Pathspec
  1133.     jmp    short P_Get_Switches
  1134.  
  1135. P_Use_Dflts:
  1136.     push    cx
  1137.     push    di
  1138.     call    Default_Drive
  1139.     call    Default_Subdir
  1140.     pop    di
  1141.     pop    cx
  1142.  
  1143. ; If any switches were specified, di points at the first slash.
  1144. P_Get_Switches:
  1145.     mov    al, '/'
  1146. P_More:
  1147.     jcxz    P_Done
  1148.     repne    scasb
  1149.     jne    P_No_More
  1150.     jcxz    P_Err
  1151.     call    Get_Switch
  1152.     inc    di
  1153.     dec    cx
  1154.     jmp    short P_More
  1155.  
  1156. P_No_More:
  1157.     mov    al, ' '         ; Ignore trailing spaces on command line.
  1158.     cmp    [di-1], al
  1159.     jnz    P_Err
  1160.     jcxz    P_Done
  1161.     repe    scasb
  1162.     jnz    P_Err
  1163. P_Done:
  1164.     ret
  1165. ;    actual Parse EndP but contains nested procs.
  1166.  
  1167. ;==============================================================
  1168.  
  1169. Get_Source_Drive proc near
  1170. ; DOS 3.2 and 3.3
  1171. ; nested in Parse
  1172. ; Test the validity of the drive letter pointed to by [di-1].  Patch the
  1173. ; names of the backup control and data files with it if it is valid, abort
  1174. ; otherwise. Used by Parse
  1175.     and    byte ptr [di-1], 0DFH    ; Convert drive to upper case.
  1176.     mov    bl, [di-1]
  1177.     sub    bl, 'A'-1        ; 1 = drive A, 2 = drive B, etc.
  1178.     xor    cx, cx            ; Read 0 bytes.
  1179.     lea    dx, Buffer        ; Point at a safe place in case something
  1180.                     ; is returned.
  1181.     mov    ax, 4404H        ; Function = IOCTL Read from block
  1182.     int    21H            ; device.
  1183.     jnc    GSD_Check        ; Drive is valid.
  1184.     cmp    ax, 0FH         ; Was drive invalid?
  1185.     jz    GSD_Err         ; Yes, abort
  1186. GSD_Check:
  1187.     mov    al, [di-1]        ; get drive letter
  1188.     cmp    al,'A'            ; usually source is A: or B:
  1189.     jb    GSD_Warn
  1190.     cmp    al,'B'
  1191.     ja    GSD_Warn
  1192.  
  1193. GSD_OK:
  1194.     mov    al, [di-1]        ; Patch filenames with drive letter.
  1195.     mov    Ctl_Filename, al
  1196.     mov    Bkp_Filename, al
  1197.     mov    Bkp_ID_Name, al
  1198.     mov    All_Pattern, al
  1199.     mov    Insert_Drive, al    ; Patch insert message.
  1200.     mov    ABM_Drive, al
  1201.     mov    NB_Drive, al
  1202.     ret
  1203.  
  1204. GSD_Warn:
  1205.     Say_Err_Msg    Strange_Source    ; expect A: or B: as source.
  1206.     Call    Strike_Any_Key
  1207.     jmp    GSD_OK
  1208.  
  1209. GSD_Err:
  1210.     Say_Err_Msg Bad_Source
  1211.     call    Abort_With_Help
  1212.  
  1213. Get_Source_Drive    endp
  1214.  
  1215. ;==============================================================
  1216.  
  1217. Get_Target_Drive proc near
  1218. ; DOS 3.2 and 3.3
  1219. ; nested in Parse
  1220. ; Get the target drive specification pointed to by [di-1] and make sure that
  1221. ; it is valid and that it is different from the
  1222. ; source drive.  If all is OK, use it to patch the restore name drive
  1223. ; letter.  Abort otherwise.  Used by Parse.
  1224. ;
  1225.     and    byte ptr [di-1], 0DFH    ; Convert drive to upper case.
  1226.     mov    bl, [di-1]
  1227.     sub    bl, 'A'-1        ; 1 = drive A, 2 = drive B, etc.
  1228.     xor    cx, cx            ; Read 0 bytes.
  1229.     lea    dx, Buffer        ; Point at a safe place in case something
  1230.                     ; is returned.
  1231.     mov    ax, 4404H        ; Function = IOCTL Read from block
  1232.     int    21H            ; device.
  1233.     jnc    GTD_Check        ; Drive is valid.
  1234.     cmp    ax, 0FH         ; Was drive invalid?
  1235.     jz    GTD_Err1        ; Yes, abort
  1236. GTD_Check:
  1237.     mov    al, [di-1]
  1238.     cmp    al, 'C'
  1239.     jb    GTD_Warn
  1240.     cmp    al, 'G'
  1241.     ja    GTD_Warn
  1242.  
  1243. GTD_OK:
  1244.     mov    al, [di-1]        ; Make sure source and target drives
  1245.     cmp    al, Ctl_Filename    ; are different.
  1246.     jz    GTD_Err2        ; Abort if not.
  1247.     mov    Rest_Drive, al        ; Patch restore name with drive letter.
  1248.     ret
  1249.  
  1250. GTD_Warn:
  1251.     Say_Err_Msg    Strange_Target    ; expect C: or D: as source.
  1252.     Call    Strike_Any_Key
  1253.     jmp    GTD_OK
  1254.  
  1255. GTD_Err1:    Say_Err_Msg Bad_Target
  1256.     call    Abort_With_Help
  1257.  
  1258. GTD_Err2:
  1259.     Say_Err_Msg Same
  1260.     call    Abort_With_Help
  1261. Get_Target_Drive    endp
  1262.  
  1263. ;==============================================================
  1264.  
  1265. Default_Drive proc near
  1266. ; DOS 3.2 and 3.3
  1267. ; nested in Parse
  1268. ; Get the default drive to use as the target drive.  Make sure it is
  1269. ; different from the source drive.  Use it to patch the
  1270. ; pathspec of files to be restored if its OK, abort otherwise.
  1271. ; Used by Parse.
  1272.     mov    ah, 19H         ; Function = Get Current Disk.
  1273.     int    21H
  1274.     add    al, 'A'         ; Convert to ASCII.  0=A, 1=B, etc.
  1275.     cmp    al, Ctl_Filename    ; Make sure target is different from
  1276.                     ; source.
  1277.     jz    DD_Same
  1278.  
  1279.     mov    Rest_Drive, al        ; Patch restore pathspec with drive.
  1280.     ret
  1281.  
  1282. DD_Same:
  1283.     Say_Err_Msg Same
  1284.     call    Abort_With_Help
  1285. Default_Drive    endp
  1286.  
  1287. ;==============================================================
  1288.  
  1289. Default_Subdir proc near
  1290. ; DOS 3.2 and 3.3
  1291. ; nested in Parse
  1292. ; Begin restore pattern with default subdir
  1293. ; Calculate length of default subdir including trailing backslash but not
  1294. ; including leading backslash or trailing nul and return it in Subdir_Pat_Len.
  1295. ; used by Parse
  1296.     mov    dl, Rest_Drive        ; Get target drive letter and convert
  1297.     sub    dl, 'A'-1        ; to code (1=A, 2=B, etc.).
  1298.     lea    si, CL_Subdir_Pattern    ; si points to buffer for returned
  1299.                     ; subdir.
  1300.     mov    ah, 47H         ; Function = Get Current Subdir.
  1301.     int    21H
  1302.     jc    DS_Err
  1303.  
  1304. ; Calculate length of subdir name with trailing backslash which we will
  1305. ; add, but without leading backslash or trailing nul.  The returned subdir
  1306. ; name is nul terminated without leading or trailing backslash.
  1307.     lea    di, CL_Subdir_Pattern
  1308.     mov    cx, size CL_Subdir_Pattern
  1309.     mov    al, 0
  1310.     repne    scasb
  1311.     sub    cx, size CL_Subdir_Pattern-1
  1312.     neg    cx
  1313.     cmp    di, offset CL_Subdir_Pattern+1    ; Was default subdir root?
  1314.     jz    DS_Root             ; Yes, don't need trailing backslash.
  1315.     mov    byte ptr [di-1], '\'        ; Add trailing backslash.
  1316.     inc    cx
  1317. DS_Root:
  1318.     mov    Subdir_Pat_Len, cx
  1319.     ret
  1320.  
  1321. DS_Err: Say_Err_Msg Unknown
  1322.     call    Abort_With_Help
  1323. Default_Subdir    endp
  1324.  
  1325. ;==============================================================
  1326.  
  1327. Get_Pathspec proc near
  1328. ; DOS 3.2 and 3.3
  1329. ; nested in Parse
  1330. ; Parse the pathspec entered on the command line inserting the current
  1331. ; directory if it is relative.    Perform edit checks on the pathspec and abort
  1332. ; if it is invalid.  Used by Parse
  1333. ;
  1334. ; Called with:
  1335. ;
  1336. ;    di points to the character following the target drive on the
  1337. ;    command line or to the first non-blank character following the
  1338. ;    source drive if no target drive is specified.
  1339. ;
  1340. ;    cx contains the number of characters of the command line tail
  1341. ;    remaining to be processed.
  1342. ;
  1343. ; Returns:
  1344. ;
  1345. ;    di points to the first switch char (/) on the command line if
  1346. ;    there are any, otherwise it points 1 byte past the end of the line.
  1347. ;
  1348. ;    cx Contains the number of characters in the command line tail
  1349. ;    remaining to be processed.
  1350. ;
  1351. ;    CL_Subdir_Pattern contains the full absolute dirspec. against which
  1352. ;    files to be restored must be matched.  This string includes a
  1353. ;    trailing but no leading backslash.  If the resultant dirspec.
  1354. ;    is the root, its value is empty.
  1355. ;
  1356. ;    Subdir_Pat_Len contains the length of the dirspec. contained in
  1357. ;    CL_Subdir_Pattern including a trailing but no leading backslash.  If
  1358. ;    the resultant dirspec. is the root, it contains 0.
  1359. ;
  1360. ;    CL_File_Pattern contains a 12 byte fixed length file pattern against
  1361. ;    which files to be restored must match.    It contains a period in
  1362. ;    the 9th position with the filename and extension padded on the right
  1363. ;    to full length with blanks and any asterisks expanded to their
  1364. ;    question mark equivalent.
  1365. ;
  1366.     cmp    byte ptr [di], '\'    ; absolute path specified?
  1367.     jz    GP_Absolute        ; Yes, don't get  current dir.
  1368.     push    cx
  1369.     push    di
  1370.     call    Default_Subdir
  1371.     pop    di
  1372.     pop    cx
  1373.     jmp    short GP_Trailing    ; Proceed to check for trailing spaces on
  1374.                     ; command line.
  1375.  
  1376. GP_Absolute:
  1377.     inc    di            ; Bypass leading backslash.
  1378.     dec    cx
  1379.     jnz    GP_Trailing
  1380.     ret
  1381.  
  1382. GP_Trailing:
  1383.     cmp    byte ptr [di], ' '    ; Check for trailing spaces on command
  1384.                     ; line.
  1385.     jnz    GP_Copy         ; If none, proceed.
  1386.                     ; allow optional spaces
  1387.     ret
  1388.  
  1389. GP_Copy:
  1390.     mov    si, di            ; Save ptr. to start of pathspec.
  1391.     mov    al, '/'         ; Search for switches.
  1392.     repne    scasb            ; Find beginning of switches if any.
  1393.     jne    GP_No_Switches        ; If none, di points one past end of line
  1394.     dec    di            ; otherwise, two past end of pattern.
  1395.     inc    cx
  1396.                     ; allow optional space before switches
  1397. GP_No_Switches:
  1398.     cmp    byte ptr [di-1], ' '    ; Ignore trailing spaces on command line.
  1399.     jnz    GP_Onward        ; No more trailing spaces, proceed.
  1400.     dec    di            ; Skip trailing space.
  1401.     inc    cx            ;
  1402.     jmp    short GP_No_Switches    ; Look for more.
  1403.  
  1404. GP_Err0:
  1405.     Say_Err_Msg Bad_Wildcards
  1406.     call    Abort_With_Help
  1407.  
  1408.  
  1409. GP_Err1:
  1410.     Say_Err_Msg Bad_Params
  1411.     call    Abort_With_Help
  1412.  
  1413. ; Now di points 1 past end of pattern.
  1414. GP_Onward: push  cx            ; Save remaining char count
  1415.     push    di            ; and ptr. to switches.
  1416.     mov    cx, di            ; Get length of pathspec in cx.
  1417.     sub    cx, si
  1418.     lea    di, CL_Subdir_Pattern    ; Copy pathspec.
  1419.     add    di, Subdir_Pat_Len    ; Move ptr. past default dir. if any.
  1420.     lea    bx, Valid_Chars     ; Table of valid chars for pathspecs.
  1421.     inc    cx            ; compensate for DEC CX inside loop.
  1422.  
  1423. GP_More_Zero:
  1424.     test    Flags, WasPeriod    ; Did last path element end with a dot?
  1425.     jz    GP_No_Dot        ; No, proceed.
  1426.     dec    di            ; Yes, get rid of it.
  1427.     mov    byte ptr [di-1], '\'
  1428. GP_No_Dot:    mov Subdir_Pat_Len, di    ; Used to get length of subdir pattern.
  1429.     xor    dx, dx            ; Zero path element length counter.
  1430.     test    Flags, WildCards    ; Wild card char in path?
  1431.     jnz    GP_Err0         ; Yes, abort.
  1432.     dec    cx            ; Decrement count of remaining chars.
  1433.     jcxz    GP_Copied
  1434.     cmp    byte ptr [si], '\'    ; "\\" not allowed.
  1435.     jz    GP_Err2
  1436. GP_More:
  1437.     cmp    di, offset CL_Subdir_Pattern+62 ; Pattern too long?
  1438.     jae    GP_Err1
  1439.     lodsb
  1440.     call    Edit_Pathspec        ; Convert char in al to upper case and
  1441.     jc    GP_Err2         ; set Carry if char is invalid.
  1442.     stosb                ; copying.
  1443.     inc    dx            ; Increment counter for this path
  1444.                     ; element.
  1445.     cmp    al, '\'         ; Is this a path separator?
  1446.     jz    GP_More_Zero        ; Yes, zero dx before re-entering loop.
  1447.     cmp    dx, 12            ; Is this element too long?
  1448.     ja    GP_Err2         ; Yes, abort.
  1449.     loop    GP_More
  1450.  
  1451. GP_Copied:
  1452.     cmp di, Subdir_Pat_Len        ; Is this the nul file pattern?
  1453.     jz    GP_Nul            ; Yes, no need to decode file pattern.
  1454.     call    Get_File_Pattern
  1455. GP_Nul:
  1456.     sub    Subdir_Pat_Len, offset CL_Subdir_Pattern
  1457.                     ; Calculate subdir pattern length.
  1458.     pop    di            ; Retrieve ptr. to switches.
  1459.     pop    cx            ; Retrieve remaining char count.
  1460. GP_Done:
  1461.     ret
  1462.  
  1463. GP_Err2:
  1464.     mov    di, si
  1465.     mov    al, '\'         ; Was this part of filespec
  1466.     repne    scasb
  1467.     jnz    GP_Err3         ; Yes, use next error message.
  1468.     Say_Err_Msg    Bad_Path
  1469.     call    Abort_With_Help
  1470.  
  1471. GP_Err3:
  1472.     Say_Err_Msg Bad_Filespec
  1473.     call    Abort_With_Help
  1474. Get_Pathspec    endp
  1475.  
  1476. ;==============================================================
  1477.  
  1478. Edit_Pathspec proc near
  1479. ; DOS 3.2 and 3.3
  1480. ; Determine if the char in al is a valid filename or pathname
  1481. ; char and if it is a wildcard char  Used by Get_PathSpec
  1482. ;
  1483. ; Called with:
  1484. ;
  1485. ;    al contains char to be validated.
  1486. ;
  1487. ;    bx contains ptr. to table of valid filename and pathname chars.
  1488. ;
  1489. ;    dx contains number of preceding chars for this pathspec element.
  1490. ;
  1491. ; Returns:
  1492. ;
  1493. ;    Carry flag set if char was invalid, clear otherwise.
  1494. ;
  1495. ;    Flags bit 6 set if char was a wildcard char, clear otherwise.
  1496. ;
  1497. ;    Flags bit 7 set if the char was a period, clear if
  1498. ;    no period has been processed or if some character other than a
  1499. ;    backslash has been processed since the last period.    The calling
  1500. ;    routine needs to know if a search pattern contains a period not
  1501. ;    followed by an extension in a path element since in this form
  1502. ;    the pattern will not match any dirspec's originating in the
  1503. ;    backup control file.
  1504. ;
  1505.     cmp    al, '.'
  1506.     jnz    EP_Not_Period
  1507.     or    dx, dx            ; Is this the first char in a
  1508.                     ; path element.
  1509.     jz    EP_Err            ; Yes, abort.
  1510.     cmp    dx, 8            ; Has this element already got a '.'?
  1511.     ja    EP_Err            ; Yes, abort.
  1512.     mov    dx, 8            ; Can only have 3 chars. after this.
  1513.     or    Flags, WasPeriod    ; Signal calling routine period
  1514.                     ; processed.
  1515.     jmp    short EP_OK
  1516.  
  1517. EP_Not_Period:
  1518.     cmp    al, '\'         ; See Flags bit 7 description in
  1519.                     ; this procedure's description.
  1520.     jz    EP_OK
  1521.     and    Flags,0ffh-WasPeriod    ; 7fH
  1522.  
  1523.     cmp    dx, 8            ; Should this have been a period?
  1524.     jz    EP_Err            ; Yes, abort.
  1525.  
  1526.     cmp    al, '?'         ; Set Flag if wildcard.
  1527.     jz    EP_Wilds
  1528.     cmp    al, '*'
  1529.     jz    EP_Wilds
  1530.     sub    al, 20H
  1531.     jl    EP_Err            ; al is out of range.
  1532.     xlat    Valid_Chars        ; Return upper case if letter,
  1533.     or    al, al            ; 0 if not a valid char.
  1534.     jz    EP_Err
  1535.  
  1536. EP_OK:
  1537.     clc
  1538.     ret
  1539.  
  1540. EP_Wilds:
  1541.     or    Flags, Wildcards    ; Bit 6 set = wildcards found in
  1542.     clc                ; command line pathspec.
  1543.     ret
  1544.  
  1545. EP_Err:
  1546.     stc
  1547.     ret
  1548. Edit_Pathspec    endp
  1549.  
  1550. ;==============================================================
  1551.  
  1552. Get_File_Pattern proc near
  1553. ; DOS 3.2 and 3.3
  1554. ; Convert the file pattern entered on the command line to a fixed format 12
  1555. ; chars. in length with a period in the 9th position.  Pad the filename and
  1556. ; extension on the right with blanks and expand any asterisks to their
  1557. ; question mark equivalent.  Used by Get_PathSpec
  1558. ;
  1559. ; Called with:
  1560. ;
  1561. ;    di points to the byte following the last char copied from the
  1562. ;    command line to CL_Subdir_Pattern.  This char is guaranteed to
  1563. ;    be either a filespec or part of a filespec.
  1564. ;
  1565. ;    Subdir_Pat_Len contains the offset relative to ds of the filespec
  1566. ;    copied from the command line into CL_Subdir_Pattern.
  1567. ;
  1568. ;    CL_Subdir_Pattern contains the pathspec entered from the command
  1569. ;    line.  It is guaranteed to contain a filespec.
  1570. ;
  1571. ;    CL_File_Pattern is a 12 byte string initialized to the nul file
  1572. ;    pattern "????????.???".
  1573. ;
  1574. ; Returns:
  1575. ;
  1576. ;    CL_File_Pattern contains the file pattern as described used for
  1577. ;    deciding whether or not to restore a given file.
  1578. ;
  1579. ;    If DX > 8 then filename contains explicit period.
  1580. ;    If BIT 6 in Flags is set we have a wildcard.
  1581. ;    Ambiguous case is C:\X
  1582. ;    Which should be C:\X\ for subdirectory or C:\X. for file
  1583.     cmp    dx, 8
  1584.     ja    Notambiguous
  1585.     test    flags, Wildcards
  1586.     jnz    Notambiguous
  1587.     Say_Err_Msg    Ambiguous
  1588.     Call    Strike_Any_Key
  1589.     Call    Abort_With_Help
  1590. Notambiguous:
  1591.     mov    cx, di            ; Get length of file pattern in cx.
  1592.     sub    cx, Subdir_Pat_Len
  1593.     mov    si, Subdir_Pat_Len
  1594.     lea    di, CL_File_Pattern
  1595.  
  1596. GFP_More:
  1597.     lodsb                ; Get a byte.
  1598.     cmp    al, '*'
  1599.     jnz    GFP_Not_Star
  1600.     cmp    di, offset CL_File_Pattern+9
  1601.                     ; Is this the extension?
  1602.     jae    GFP_Done        ; Yes, all done.
  1603.     mov    di, si
  1604.     mov    al, '.'         ; Scan for the period if any.
  1605.     dec    cx
  1606.     repnz    scasb
  1607.     mov    si, di            ; Point at first char of extension.
  1608.     lea    di, CL_File_Pattern+9    ; Skip to file extension.
  1609.     jcxz    GFP_Fill
  1610.     jmp    short GFP_More
  1611.  
  1612. GFP_Not_Star:
  1613.     cmp    al, '.'
  1614.     jnz    GFP_Copy
  1615. GFP_Blank:
  1616.     cmp byte ptr [di], '.'
  1617.     jz    GFP_Copy
  1618.     mov    byte ptr [di], ' '
  1619.     inc    di
  1620.     jmp    short GFP_Blank
  1621.  
  1622. GFP_Copy:
  1623.     stosb                ; Copy the char.
  1624.     loop    GFP_More
  1625. GFP_Fill:
  1626.     mov    al, ' '
  1627.     mov    cx, offset CL_File_Pattern+12
  1628.     sub    cx, di
  1629.     rep    stosb
  1630.     mov    CL_File_Pattern+8, '.'
  1631. GFP_Done:
  1632.     ret
  1633.  
  1634. Get_File_Pattern endp
  1635.  
  1636. ;==============================================================
  1637.  
  1638. Get_Switch proc near
  1639. ; DOS 3.2 and 3.3
  1640. ; nested in Parse
  1641. ; di points to the letter following a switch char on the command line.
  1642. ; Examine it and set the appropriate bit in Cmd_Flags or abort if it is
  1643. ; not recognizable.  Called by Parse.
  1644.     and    byte ptr [di], 0DFH    ; Convert to upper case.
  1645.     cmp    byte ptr [di], 'P'    ; Prompted restore?
  1646.     jnz    GS_SlashS        ; No
  1647.     or    Cmd_Flags, Prompt_Needed; Bit 0 set = prompted restore.
  1648.     ret
  1649.  
  1650.  
  1651. GS_SlashS:
  1652.     cmp byte ptr [di], 'S'    ; Restore subdirectories?
  1653.     jnz    GS_SlashQ        ; No.
  1654.     or    Cmd_Flags, RestoreSubs    ; Bit 3 set = restore subdirectories.
  1655.     ret
  1656.  
  1657. GS_SlashQ:
  1658.     cmp byte ptr [di], 'Q'    ; Quiet, suppress banner.
  1659.     jnz    GS_Bad            ; No.
  1660.     or    Cmd_Flags, Quietly    ; Bit 3 set = quiet.
  1661.     ret
  1662.  
  1663. GS_Bad:
  1664.     Say_Err_Msg Bad_Switch
  1665.     call    Abort_With_Help
  1666. Get_Switch    endp
  1667.  
  1668. ;==============================================================
  1669. Abort_With_Help proc near
  1670. ; called when syntax on command line is bad.  We abort.
  1671. ; We also give some help with the syntax.
  1672. ; DOS 3.2 3.3
  1673. ; Print syntax help exit with return code of 4.
  1674.     Say_Err_Msg    Help_Msg
  1675.     mov    ax,    4C04H        ; Function = exit with return code of 4.
  1676.     int    21H
  1677. Abort_With_Help  endp
  1678.  
  1679. ;==============================================================
  1680. ;==============================================================
  1681.  
  1682. Parse    endp
  1683.  
  1684. ;==============================================================
  1685.  
  1686. Get_Next_Disk proc near
  1687. ; DOS 3.2 and 3.3
  1688. ; Prompt the user for the next diskette in the set and continue to prompt until
  1689. ; he inserts a valid backup diskette.  If the diskette inserted is not in
  1690. ; sequence prompt him to select either Abort or Retry.    In addition if there
  1691. ; is currently no partially restored file on the hard disk allow the option of
  1692. ; Ignore.
  1693. ;
  1694. ; Returns:
  1695. ;
  1696. ;    Flags bit 2 set to indicate a new diskette.
  1697. ;
  1698. ;    Flags bit 3 set if the user accepted a diskette out of sequence.
  1699. ;
  1700. ;    Format_Flags bit 0 set if diskettes were backed up with DOS 3.2
  1701. ;    format.
  1702. ;
  1703. ; Format_Flags bit 1 set if diskettes were backed up using DOS 3.3 format.
  1704. ;
  1705. ; Patch insert prompt with sequence number.
  1706.     Patch_Num    Want_Seq, Insert_Seq+2, 3
  1707.  
  1708. GND_Again:
  1709.     Say_Err_Msg    Insert        ; Force the message to the console
  1710.     call    Strike_Any_Key        ; no matter where the output is going.
  1711.     call    Process_Bkp_ID        ; Is diskette in old format?
  1712.     jc    GND_Again        ; Yes, but we were restoring from new.
  1713.     jnz    GND_OK            ; Yes, proceed. Sequence no. is in ax.
  1714.     call    Process_Ctl_Filename    ; Sequence no. returned in ax.
  1715.     jc    GND_Again        ; CY=invalid backup diskette.
  1716.  
  1717. GND_OK:
  1718.     cmp    ax, Want_Seq        ; Check returned sequence no.
  1719.     jz    GND_Done        ; Continue if its what we expected.
  1720.     push    ax
  1721.     Say_Err_Msg    Out_Of_Seq
  1722.     Say_Err_Msg    CrLf
  1723.     pop    ax
  1724.  
  1725. comment |
  1726.  
  1727. If the user has inserted a valid backup diskette with the wrong sequence
  1728. number, allow him to choose either to abort or to insert a different diskette
  1729. (Retry).  In addition if the last file restored from the previous diskette
  1730. is complete allow the user to continue despite the wrong sequence number.
  1731. | ; end of comment.
  1732.     test    Flags, LastFrag     ; Is last file restored complete?
  1733.     jnz    GND_Can_Ignore        ; Yes, ignore is an option.
  1734.     test    Flags, SkipFile     ; Was last file being skipped?
  1735.     jnz    GND_Can_Ignore        ; Yes, Ignore is an option.
  1736.     call    Abort_Retry
  1737.     jmp    short GND_Again
  1738.  
  1739. GND_Can_Ignore:
  1740.     push    ax            ; Save seq. no.
  1741.     call    Abort_Retry_Ignore
  1742.     pop    ax            ; Retrieve seq. no. in ax.
  1743.     jc    GND_Again
  1744.     or    Flags, WrongOk+SkipFile ; User has accepted a diskette
  1745.                     ; out of sequence, and
  1746.                     ; do not restore frag.
  1747.  
  1748. GND_Done:
  1749.     mov    Bkp_Seq, ax        ; Save current sequence no.
  1750.     inc    ax            ; Compute and store next sequence no.
  1751.     mov    Want_Seq, ax
  1752.     or    Flags, NewDisk        ; Set New Disk flag.
  1753.     ret
  1754. ;    actual Get_Next_Disk endp but contains nested procs
  1755.  
  1756. ;==============================================================
  1757.  
  1758. Process_Bkp_ID proc near
  1759. ; DOS 3.2
  1760. ; nested in Get_Next_Disk
  1761. ; If the current diskette is in DOS 3.2 backup format, process the backup ID
  1762. ; file and announce the diskette sequence no. and date.
  1763. ;
  1764. ; Returns zero flag set if diskette is not in DOS 3.2 format, clear
  1765. ; otherwise.
  1766. ;
  1767. ; Returns carry flag set if diskette is in DOS 3.2 format but the set
  1768. ; currently being restored is in DOS 3.3 format, clear otherwise.
  1769. ;
  1770. ; Returns with bit 0 of Format_Flags set if the backup diskette is in
  1771. ; DOS 3.2 format and this is acceptable, i.e. either this is the first
  1772. ; diskette to be restored or the previous diskettes were in DOS 3.2 format.
  1773. ;
  1774.     call    Open_Bkp_ID
  1775.     call    Get_Bkp_ID
  1776.     jnc    PBI_Old         ; BACKUPID.@@@ was read successfully.
  1777.     clc                ; Return with ZF and NC meaning
  1778.     ret                ; unrecognized format.
  1779.  
  1780. PBI_Old:
  1781.     call    Close_Ctl_File        ; Close BACKUPID.@@@.
  1782. ; Announce diskette.
  1783.     Patch_Num    Buffer.BI_Seq, ABM_Seq+2, 3
  1784.     Patch_Num    Buffer.BI_YYYY, ABM_YYYY+3, 4
  1785.     xor        ax, AX
  1786.     mov        al, Buffer.BI_MM
  1787.     Patch_Num    ax, ABM_MM+1, 2
  1788.     xor        ax, AX
  1789.     mov        al, Buffer.BI_DD
  1790.     Patch_Num    ax, ABM_DD+1, 2
  1791.     Say_Msg     Announce_Bkp_Msg
  1792.  
  1793.     test    Format_Flags, DOS33    ; Were we already restoring a new
  1794.                     ; format set?
  1795.     jnz    PBI_Err         ; Yes.
  1796.     or    Format_Flags, DOS32    ; No, set flag for old format.
  1797.  
  1798.     and    Flags, 0ffh - LastDisk    ; 0FDH
  1799.                     ; Reset flag for last diskette. Could
  1800.                     ; have been set prematurely if a user
  1801.                     ; rejected a diskette out of sequence.
  1802.     cmp    Buffer.BI_Last, -1    ; Is this last diskette in set?
  1803.     jne    PBI_Done        ; No, don't set flag.
  1804.     or    Flags, LastDisk     ; Yes, set flag for last diskette.
  1805.  
  1806. PBI_Done:
  1807.     mov    ax, Buffer.BI_Seq    ; Return sequence no. in ax.
  1808.     or    ax, ax            ; Return NZ for valid diskette.
  1809.     clc                ; Return NC for correct format.
  1810.     ret
  1811.  
  1812. PBI_Err:
  1813.     Say_Err_Msg    Wrong_Set
  1814.     Say_Err_Msg    CrLf
  1815.     call        Abort_Retry
  1816.     stc                ; CY = diskette in wrong format.
  1817.     ret
  1818. ;    actual Process_Bkp_ID EndP but contains nested procs
  1819.  
  1820. ;==============================================================
  1821.  
  1822. Open_Bkp_ID proc near
  1823. ; DOS 3.3
  1824. ; nested in Get_Next_Disk
  1825. ; nested in Process_Bkp_ID
  1826. ; Open BACKUPID.@@@ on current floppy and return handle in Ctl_Hndl.  If file
  1827. ; cannot be found, return with handle of -1.  Abort if any other error occurs.
  1828.     lea    dx, Bkp_ID_Name
  1829.     mov    ax, 3D00H        ; open read-only 3D:00
  1830.     int    21H
  1831.     jc    OBI_Err
  1832.     mov    Ctl_Hndl, ax
  1833.     ret
  1834.  
  1835. OBI_Err:
  1836.     cmp        ax, 2            ; File not found?
  1837.     je        OBI_Err1
  1838.     cmp        ax, 3            ; Invalid path or file missing?
  1839.     je        OBI_Err1
  1840.     push        ax            ; Save error code.
  1841.     Say_Err_Msg    Floppy_Trouble        ; Cant_Open_BC
  1842.     pop        ax            ; Retrieve error code.
  1843.     cmp        ax, 4            ; Too many files open?
  1844.     je        OBI_Err2
  1845.     Say_Err_Msg    Unknown         ; Unknown error, abort.
  1846.     call        Abort
  1847.  
  1848. OBI_Err1:
  1849.     ret                    ; Return handle of -1.
  1850.  
  1851. OBI_Err2:
  1852.     Say_Err_Msg    Too_Many_Open
  1853.     call        Abort            ; not enough handles, abort.
  1854.  
  1855. Open_Bkp_ID    endp
  1856.  
  1857. ;==============================================================
  1858.  
  1859. Get_Bkp_ID proc near
  1860. ; DOS 3.3
  1861. ; nested in Get_Next_Disk
  1862. ; nested in Process_Bkp_ID
  1863. ; If BACKUPID.@@@ was successfully opened, read its first 7 bytes into the
  1864. ; buffer and convert the sequence no. to true binary form.
  1865. ;
  1866. ; Called with:
  1867. ;
  1868. ;    Ctl_Hndl contains the handle of BACKUPID.@@@ if it was successfully
  1869. ;    opened, -1 otherwise.
  1870. ;
  1871. ; Returns if successful:
  1872. ;
  1873. ;    Buffer contains the first 7 bytes of BACKUP.@@@ with the sequence no.
  1874. ;    converted to true binary form.
  1875. ;
  1876. ;    Carry Flag = clear.
  1877. ;
  1878. ; Returns carry flag set if BACKUPID.@@@ was not previously successfully opened.
  1879. ;
  1880.     mov    bx, Ctl_Hndl
  1881.     cmp    bx, -1
  1882.     jz    GBI_Not_Bkp
  1883.     mov    cx, 7            ; Read 7 bytes.
  1884.     lea    dx, Buffer        ; ds:dx points at buffer.
  1885.     mov    ah, 3FH         ; Function = Read.
  1886.     int    21H
  1887.     jc    GBI_Err         ; Abort if trouble.
  1888.     cmp    ax, 7
  1889.     jne    GBI_Err
  1890.  
  1891. ; Convert 8 bit BCD BI_Seq into true binary format.
  1892.     mov    al, 10
  1893.     mul    byte ptr Buffer.BI_Seq+1
  1894.     add    al, byte ptr Buffer.BI_Seq
  1895.     adc    ah, 0
  1896.     mov    Buffer.BI_Seq, ax
  1897.     clc                ; NC means all is in order.
  1898.     ret
  1899.  
  1900. GBI_Not_Bkp:                ; Return CY if diskette is not
  1901.     stc                ; DOS 3.2 backup.
  1902.     ret
  1903.  
  1904. GBI_Err:
  1905.     Say_Err_Msg    Unknown
  1906.     call    Abort
  1907. Get_Bkp_ID    endp
  1908.  
  1909. ;==============================================================
  1910.  
  1911. Process_Bkp_ID    endp
  1912.  
  1913. ;==============================================================
  1914.  
  1915. Process_Ctl_Filename proc near
  1916. ; DOS 3.3
  1917. ; nested in Get_Next_Disk
  1918. ; Blank out the extension of the previous backup control filename with "?"
  1919. ; wildcard characters and use it to find the backup control file on the new
  1920. ; diskette.  If a file is found, convert its sequence number contained in its
  1921. ; extension to a hex value returned to the calling procedure.    If no filename
  1922. ; is matched, or if the extension of a matched filename does not contain three
  1923. ; numeric digits, print an error message and signal the calling routine to prompt
  1924. ; for another diskette. If some other error occurs, abort the program with an
  1925. ; error message.  Called by Get_Next_Disk
  1926. ;
  1927. ; Called with:
  1928. ;
  1929. ;    Ctl_Filename contains the complete nul terminated drive and pathspec
  1930. ;    which when the extension is patched with the sequence no. of the
  1931. ;    current disk will refer to the backup control file on that disk.
  1932. ;
  1933. ;    Bkp_Filename contains the same as Ctl_filename but with respect
  1934. ;    to the backup data filename.
  1935. ;
  1936. ; Returns if successful:
  1937. ;
  1938. ;    ax contains the hex representation of the sequence no. for the
  1939. ;    current diskette.
  1940. ;
  1941. ;    Ctl_filename and Bkp_Filename are as when called but patched with
  1942. ;    the correct extensions.
  1943. ;
  1944.     Blank_Extension     Ctl_Filename+11
  1945.     lea    dx, Ctl_Filename
  1946.     xor    cx, cx            ; Use normal attributes.
  1947.     or    cx, 10H         ; Turn on subdir bit as well.    I've
  1948.                     ; heard that MS DOS 3.2 may not return
  1949.                     ; all normal files unless subdirs. are
  1950.                     ; included.
  1951.     mov    ah, 4EH         ; Function = Search for First
  1952.     int    21H
  1953.     jnc    PCF_Found
  1954.     cmp    ax, 12H         ; Matching file not found?
  1955.     jz    PCF_Err1        ; Yes, not a backup diskette.
  1956.     jmp    short PCF_Err2        ; No, unknown error.
  1957.  
  1958. PCF_Found:
  1959.     cmp    ds:DTA.DS_Name + 7, '.'
  1960.     jnz    PCF_Err1
  1961.     mov    si, DTA.DS_Name+8    ; Point di to beginning of extension.
  1962.     mov    cx, 3            ; cx = field length.
  1963.     call    ASCII_Dec_To_Hex
  1964.     jc    PCF_Err1        ; CY = non-numeric char in field.
  1965.     test    ds:DTA.DS_Attr, 10H    ; Was file a subdir?
  1966.     jnz    PCF_Err1        ; Yes, non-backup diskette.
  1967.  
  1968. ; si points at terminating nul following DTA.DS_Name.  di points at terminating
  1969. ; nul following Ctl_Filename.
  1970.     call    Patch_Filename_Exts
  1971.     push    ax            ; Save sequence no.
  1972.     call    Patch_Announce_Bkp_Msg
  1973.     Say_Msg Announce_Bkp_Msg
  1974.     pop    ax            ; Retrieve seq. no. in ax.
  1975.     test    Format_Flags, DOS32    ; Were we already restoring files
  1976.                     ; from a backup set in the old format?
  1977.     jnz    PCF_Err3        ; Yes.
  1978.     or    Format_Flags, DOS33    ; No, set flag for DOS 3.3 format.
  1979.     clc
  1980.     ret
  1981.  
  1982. PCF_Err1:
  1983.     Say_Err_Msg    Not_Bkp
  1984.     Say_Err_Msg    CrLf
  1985.     call        Abort_Retry
  1986.     stc
  1987.     ret
  1988.  
  1989. PCF_Err2:
  1990.     Say_Err_Msg    Unknown
  1991.     call        Abort
  1992.  
  1993. PCF_Err3:
  1994.     Say_Err_Msg    Wrong_Set
  1995.     Say_Err_Msg    CrLf
  1996.     call        Abort_Retry
  1997.     stc
  1998.     ret
  1999. ; actual Process_Ctl_Filename EndP but contains nested procs.
  2000.  
  2001. ;==============================================================
  2002.  
  2003. Patch_Filename_Exts proc near
  2004. ; DOS 3.3
  2005. ; nested in Get_Next_Disk
  2006. ; nested in Process_Ctl_Filename
  2007. ; Fill in the extensions for CONTROL.XXX and BACKUP.XXX.
  2008. ;
  2009. ; Called with:
  2010. ;
  2011. ;    Offset DTA.DS_Name contains filename returned from function 4EH
  2012. ;    Search For First.
  2013. ;
  2014. ;    si points at the nul terminating the above name.
  2015. ;
  2016. ;    di points at the nul terminating Ctl_Filename.
  2017. ;
  2018. ; Returns:
  2019. ;
  2020. ;    Ctl_Filename and Bkp_Filename extensions filled in with the
  2021. ;    apparent sequence no. of the diskette according to the directory
  2022. ;    search for CONTROL.XXX in the procedure Process_Ctl_Filename.
  2023. ;
  2024.     mov    cx, 4            ; 3 chars. plus trailing nul.
  2025.     std
  2026.     rep    movsb
  2027.     lea    di, Bkp_Filename + 9    ; Point to "." before Bkp_filename ext.
  2028.     mov    cx, 4            ; "." + 3 chars. file ext.
  2029.     cld
  2030.     rep    movsb
  2031.     ret
  2032. Patch_Filename_Exts    endp
  2033.  
  2034. ;==============================================================
  2035.  
  2036. Process_Ctl_Filename    endp
  2037.  
  2038. ;==============================================================
  2039.  
  2040. Patch_Announce_Bkp_Msg    proc near
  2041. ; DOS 3.3
  2042. ; Patch the message which announces the current diskette with its sequence no.
  2043. ; and date.
  2044.     Patch_Num    ax, ABM_Seq+2, 3
  2045.  
  2046.     mov        ax, ds:DTA.DS_Date    ; Date of CONTROL.XXX file.
  2047.     push        ax            ; Save a copy.
  2048.     mov        cl, 5            ; Isolate month and patch it into msg.
  2049.     shr        ax, cl
  2050.     and        ax, 000FH
  2051.     Patch_Num    ax, ABM_MM+1, 2
  2052.     pop    ax
  2053.  
  2054.     push        ax
  2055.     and        ax, 001FH        ; Isolate day and patch it into msg.
  2056.     Patch_Num    ax, ABM_DD+1, 2
  2057.     pop        ax
  2058.  
  2059.     mov        cl, 7            ; Isolate year and patch it into msg.
  2060.     rol        ax, cl
  2061.     and        ax, 07FH
  2062.     add        ax, 1980
  2063.     Patch_Num    ax, ABM_YYYY+3, 4
  2064.     ret
  2065. Patch_Announce_Bkp_Msg    endp
  2066.  
  2067. ;==============================================================
  2068.  
  2069. Get_Next_Disk endp
  2070.  
  2071. ;==============================================================
  2072.  
  2073. ASCII_Dec_To_Hex proc near
  2074. ; DOS 3.3
  2075. ; used by Process_Control_FileName
  2076. ; Convert ASCII string of decimal digits to a 16 bit hex value.
  2077. ;
  2078. ; Called with:
  2079. ;
  2080. ;    si points to leftmost digit in string.
  2081. ;
  2082. ;    cx contains field width.
  2083. ;
  2084. ; Returns if successful:
  2085. ;
  2086. ;    ax contains 16 bit quantity.
  2087. ;
  2088. ;    si points to char following last digit.
  2089. ;
  2090. ;    carry flag = clear.
  2091. ;
  2092. ; Returns carry flag set if non-numeric char in string.
  2093. ;
  2094.     xor    ax, ax
  2095.     mov    bl, 0AH
  2096. ADTH_More:
  2097.     mul bl
  2098.     mov    dl, [si]        ; Fetch a digit.
  2099.     inc    si
  2100.     cmp    dl, '9'
  2101.     ja    ADTH_Err
  2102.     sub    dl, '0'         ; Convert from ASCII and make sure
  2103.     jb    ADTH_Err            ; char is numeric.
  2104.  
  2105.     add    al, dl
  2106.     adc    ah, 0
  2107.     loop    ADTH_More
  2108.     clc
  2109.     ret
  2110.  
  2111. ADTH_Err:
  2112.     stc
  2113.     ret
  2114. ASCII_Dec_To_Hex endp
  2115.  
  2116. ;==============================================================
  2117.  
  2118. Strike_Any_Key proc near
  2119. ; DOS 3.2 and 3.3
  2120. ; Prompt the user to strike spacebar and return to caller when any key detected.
  2121. ; This is better than asking him to strike any key since there are at least
  2122. ; 6 keys which wont be detected.
  2123.     Say_Err_Msg    Strike_Any    ; Force message to print
  2124.                     ; on console regardless of I/O
  2125.                     ; redirection.
  2126.     mov    ax, 0C08H        ; Clear typeahead buffer and get one
  2127.     int    21H            ; filtered char without echo.
  2128.     or    al, al            ; If extended code, get rid of it.
  2129.     jnz    SAK_Done
  2130.     mov    ah, 7            ; Function = Get Unfiltered Char.
  2131.     int    21H            ;w/o echo.
  2132.  
  2133. SAK_Done:
  2134.     ret
  2135. Strike_Any_Key endp
  2136.  
  2137. ;==============================================================
  2138.  
  2139. Open_Ctl_File proc near
  2140. ; DOS 3.3
  2141. ; OPEN CONTROL.XXX
  2142. ; Open the current backup control file and store the returned handle in
  2143. ; Ctl_Hndl.  print error message and abort if operation failed.
  2144. ;
  2145. ; Returns:
  2146. ;
  2147. ;    Ctl_Hndl contains the handle of the successfully opened backup
  2148. ; control file with the file ptr. positioned at the beginning of the file.
  2149. ;
  2150. OCF_Retry:
  2151.     lea    dx, Ctl_Filename
  2152.     mov    ax, 3D00H        ; Open file with read access.
  2153.     int    21H
  2154.     jc    OCF_Err
  2155.     mov    Ctl_Hndl, ax        ; Save handle.
  2156.     ret
  2157.  
  2158. ; File could not be opened, process condition.
  2159. OCF_Err:
  2160.     push    ax            ; Would be trashed by Say_Err_Msg
  2161.     Say_Err_Msg    Floppy_Trouble    ; Cant_Open_BC
  2162.     pop    ax            ; Restore error code to ax.
  2163.     cmp    ax, 4            ; Too many files open?
  2164.     je    OCF_Err1
  2165.     Say_Err_Msg    Unknown
  2166.     call        Abort
  2167.  
  2168. OCF_Err1:
  2169.     Say_Err_Msg    Too_Many_Open
  2170.     call        Abort        ; not enough handles, abort.
  2171.  
  2172. Open_Ctl_File    endp
  2173.  
  2174. ;==============================================================
  2175.  
  2176. Open_Bkp_File proc near
  2177. ; DOS 3.2
  2178. ; If restoring files backup up with DOS 3.2 format, copy the filespec of the
  2179. ; backup data file from the DTA into Bkp_Filename.
  2180. ; Open the current backup data file and store the returned handle in
  2181. ; Bkp_Hndl.  print error message and abort if operation failed.
  2182. ;
  2183. ; Returns:
  2184. ;
  2185. ;    Bkp_Hndl contains the handle of the successfully opened backup
  2186. ; data file with the file ptr. positioned at the beginning of the file.
  2187. ;
  2188. OBF_Retry:
  2189.     test    Format_Flags, DOS33    ; Is this DOS 3.3 format?
  2190.     jnz    OBF_New         ; Yes, Bkp_Filename already contains
  2191.                     ; filespec
  2192.  
  2193. ; This is DOS 3.2 format.  Copy the backup data filename from the DTA.
  2194.     mov    cx, 13            ; Max. length of filename with nul.
  2195.     mov    si, DTA.DS_Name
  2196.     lea    di, Bkp_Filename+3    ; Bypass d:\.
  2197.     rep    movsb            ; Copy filename.
  2198.  
  2199. OBF_New:
  2200.     lea    dx, Bkp_Filename
  2201.     mov    ax, 3D00H        ; Open with read access.
  2202.     int    21H
  2203.     jc    OBF_Err
  2204.     mov    Bkp_Hndl, ax
  2205.     ret
  2206.  
  2207. ; File could not be opened, process condition.
  2208. OBF_Err:
  2209.     push    ax            ; Would be trashed by Say_Err_Msg
  2210.     Say_Err_Msg    Floppy_Trouble    ; Bkp_File_Msg
  2211.     pop    ax            ; Restore error code to ax.
  2212.     cmp    ax, 2            ; File not found?
  2213.     je    OBF_Err1
  2214.     cmp    ax, 3            ; Invalid path or file missing?
  2215.     je    OBF_Err1
  2216.     cmp    ax, 4            ; Too many files open?
  2217.     je    OBF_Err2
  2218.     Say_Err_Msg    Unknown     ; Unknown error, abort.
  2219.     call        Abort
  2220.  
  2221. OBF_Err1:
  2222.     Say_Err_Msg    Floppy_Trouble    ; File_Not_Found
  2223.     call        Abort
  2224.  
  2225. OBF_Err2:
  2226.     Say_Err_Msg    Too_Many_Open
  2227.     call        Abort        ; not enough handles, abort.
  2228.  
  2229. Open_Bkp_File    endp
  2230.  
  2231. ;==============================================================
  2232.  
  2233. Process_Hdr proc near
  2234. ; DOS 3.3
  2235. ; in CONTROL.XXX file
  2236. ; Read the header record from the current backup control file and confirm
  2237. ; the validity of the file.
  2238. ; Set a flag if this is the last diskette in the set.
  2239. ;
  2240. ; Called with:
  2241. ;
  2242. ;    Ctl_Hndl contains the handle of the currently open control file
  2243. ;    with the file ptr. positioned at the beginning of the file.
  2244. ;
  2245. ; Returns:
  2246. ;
  2247. ;    Buffer contains the successfully read header record beginning
  2248. ;    at offset zero.
  2249. ;
  2250.     call    Read_Hdr
  2251.     call    Chk_Sig
  2252.     call    Chk_Seq
  2253.  
  2254.     cmp    Buffer.HDR_Last, 0ffh    ; Is this last diskette in set?
  2255.     jnz    PH_Done
  2256.     or    Flags, LastDisk     ; Set flag if it is.
  2257. PH_Done:
  2258.     ret
  2259.  
  2260. ;==============================================================
  2261.  
  2262. Read_Hdr  proc near
  2263. ; DOS 3.3
  2264. ; nested in Process_Hdr
  2265. ; Read the header record into the buffer from the currently open backup control
  2266. ; file.  Print error message and abort if operation failed.
  2267. ;
  2268. ; Called with:
  2269. ;
  2270. ;    Ctl_Hndl contains the handle of the currently open backup control
  2271. ;    file with the file ptr. positioned at the beginning of the file.
  2272. ;
  2273. ; Returns:
  2274. ;
  2275. ;    Buffer contains the successfully read header record beginning
  2276. ;    at offset buffer.
  2277. ;
  2278.     lea    dx, Buffer
  2279.     mov    bx, Ctl_Hndl
  2280.     mov    cx, HDR_REC_LEN
  2281.     mov    ah, 3FH         ; Function = Read.
  2282.     int    21H
  2283.     jc    RH_Err
  2284.     cmp    cx, ax            ; Read o.k.?
  2285.     jne    RH_Err            ; Abort if not.
  2286.     ret
  2287.  
  2288. RH_Err:
  2289.     Say_Err_Msg    Floppy_Trouble    ; Bad_Ctl_File
  2290.     call        Abort
  2291.  
  2292. Read_Hdr    endp
  2293.  
  2294. ;==============================================================
  2295.  
  2296. Chk_Seq    proc near
  2297. ; DOS 3.3
  2298. ; nested in Process_Hdr
  2299. ; Make sure the sequence number in the control file header agrees with that
  2300. ; of the volume label and file extensions.  Abort if it does not.
  2301. ;
  2302.     mov    ax, Bkp_Seq
  2303.     cmp    ax, Buffer.Hdr_Seq
  2304.     jnz    CSeq_Err
  2305.     ret
  2306.  
  2307. CSeq_Err:
  2308.     Say_Err_Msg    Floppy_Trouble        ; Bad_Hdr_Seq
  2309.     call        Abort
  2310. Chk_Seq    endp
  2311.  
  2312. ;==============================================================
  2313.  
  2314. Chk_Sig    proc near
  2315. ; DOS 3.3
  2316. ; nested in Process_Hdr
  2317. ; Verify backup control file signature.
  2318. ;
  2319.     lea    si, Bkp_Sig
  2320.     lea    di, Buffer.Hdr_Sig
  2321.     mov    cx, Bkp_Sig_Len
  2322.     repe    cmpsb
  2323.     jnz    CS_Err
  2324.     ret
  2325.  
  2326. CS_Err:
  2327.     Say_Err_Msg    Floppy_Trouble        ; Bad_Sig
  2328.     call        Abort
  2329. Chk_Sig     endp
  2330.  
  2331. ;==============================================================
  2332.  
  2333. Process_Hdr    endp
  2334.  
  2335. ;==============================================================
  2336.  
  2337. Get_Subdir proc near
  2338. ; DOS 3.3
  2339. ; Process all of the subdir records for the current diskette.
  2340. ;
  2341. GS_More:
  2342.     call    Get_Subdir_Rec        ; Get  a subdir record.
  2343.     call    Get_Dirspec        ; Copy out the pathname.
  2344.     jc    GS_Wrong_Set
  2345.  
  2346. ; Save ptr. to next subdir record.
  2347.     push    word ptr Buffer.Subdir_Next + 2
  2348.     push    word ptr Buffer.Subdir_Next
  2349.  
  2350.     call    Select_Subdir        ; Zero flag set means this dirspec.
  2351.     clc                ; doesn't match the command line
  2352.     jnz    GS_Bypass        ; pattern, clear otherwise.
  2353.     mov    cx, Buffer.Subdir_Count ; Pass file record count in cx.
  2354.     call    Get_Files
  2355. GS_Bypass:
  2356.     pop dx                ; Pass offset of next subdir record
  2357.                     ; low word in dx.
  2358.     pop cx                ; Pass offset of next subdir record
  2359.                     ; high word in cx.
  2360.     jc    GS_Wrong_Set        ; cy set by Get_Files.    Needed to
  2361.                     ; pop stack before test.
  2362.     call    Seek_Next_Subdir    ; NC = no more subdirs on this diskette.
  2363.     jc    GS_More         ; CY = go back for more.
  2364.     ret
  2365.  
  2366. GS_Wrong_Set:
  2367.     Say_Err_Msg    Wrong_Set
  2368.     Say_Err_Msg    CrLf
  2369.     call    Abort_Retry
  2370.     call    Close_Bkp_File        ; If Retry, go back for another diskette.
  2371.     call    Close_Ctl_File        ; after closing files on this diskette.
  2372.     dec    Want_Seq
  2373.     stc                ; CY signals to prompt for another disk.
  2374.     ret
  2375.  
  2376. ;==============================================================
  2377.  
  2378. Get_Subdir_Rec proc near
  2379. ; DOS 3.3
  2380. ; Read the next subdir record into the buffer and verify it by checking
  2381. ; its length field.  Abort with error message if record proves invalid.
  2382. ;
  2383. ; Called with:
  2384. ;
  2385. ;    Ctl_Hndl contains the handle of the currently open backup control
  2386. ;    file with the file ptr. positioned at the beginning of the next
  2387. ;    subdir record.
  2388. ;
  2389. ; Returns:
  2390. ;
  2391. ;    Buffer contains the successfully read subdir record beginning
  2392. ;    at offset buffer.
  2393. ;
  2394.     lea    dx, Buffer
  2395.     mov    cx, SUBDIR_REC_LEN
  2396.     mov    bx, Ctl_Hndl
  2397.     mov    ah, 3FH         ; Function = Read.
  2398.     int    21H
  2399.     jc    GSR_Err
  2400.     cmp    ax, cx            ; Read o.k.?
  2401.     jne    GSR_Err         ; Abort if not.
  2402.     cmp    Buffer.Subdir_Len, cl    ; If this record is valid, these
  2403.     jne    GSR_Err         ; should be equal.
  2404.     ret
  2405.  
  2406. GSR_Err:
  2407.     Say_Err_Msg    Floppy_Trouble    ; Bad_Ctl_File
  2408.     call        Abort
  2409.  
  2410. Get_Subdir_Rec endp
  2411.  
  2412. ;==============================================================
  2413.  
  2414. Get_Dirspec proc near
  2415. ; DOS 3.3
  2416. ; If the current diskette is not in sequence and this is the first subdir
  2417. ; record or if the last file was not to be continued, copy the dirspec from
  2418. ; the current subdir record to the pathspec to be restored.  Otherwise, make
  2419. ; sure the dirspec in this subdir record is the same as that from the last.
  2420. ; A discrepancy probably indicates the new diskette is from a different set
  2421. ; so alert the user and prompt for the proper diskette.
  2422. ;
  2423. ; Called with:
  2424. ;
  2425. ;    Buffer contains the last subdir record read from the backup control
  2426. ;    file.
  2427. ;
  2428. ;    Flags bit 0 is set if the last file was not to be continued, clear
  2429. ;    otherwise.
  2430. ;
  2431. ;    Flags bit 3 is set if the newly inserted diskette is out of
  2432. ;    sequence, clear otherwise.
  2433. ;
  2434. ; Returns if Successful:
  2435. ;
  2436. ;    Filespec_Ptr points to the offset in Rest_Path where the filespec
  2437. ;    will begin.
  2438. ;
  2439. ;    Rest_Path contains the dirspec. of the current subdir record
  2440. ;    left justified with a trailing backslash if required.  The
  2441. ;    drive and leading backslash have already been filled in immediately
  2442. ;    before Rest_Path.
  2443. ;
  2444. ;    Carry flag = clear.
  2445. ;
  2446. ; Returns carry flag set if the dirspec. for a continuation of a file did
  2447. ; not match the previous dirspec.
  2448. ;
  2449.     lea    si, Buffer.Subdir_Name
  2450.     lea    di, Rest_Path
  2451.     cld
  2452.  
  2453.     test    Flags, WrongOk        ; Diskette out of sequence?
  2454.     jnz    GD_Copy         ; Yes, copy dirspec.
  2455.     test    Flags, LastFrag     ; Last file continued?
  2456.     jnz    GD_Copy         ; No, copy new dirspec.
  2457.  
  2458.     mov    cx, Filespec_Ptr    ; = dirspec. length with trailing
  2459.                     ; backslash
  2460.     jcxz    GD_Nul            ; or 0 if dirspec. is root.
  2461.     dec    cx            ; Don't count trailing backslash.
  2462.     repe    cmpsb
  2463.     jnz    GD_Err            ; New dirspec. is different.
  2464.  
  2465. GD_Nul:
  2466.     mov    al, 0            ; Now make sure trailing nul
  2467.     cmp    [si], al        ; comes next.
  2468.     jnz    GD_Err
  2469.     jmp    short GD_Done
  2470.  
  2471. GD_Copy:
  2472.     mov    cx, size Subdir_Name
  2473. GD_More:
  2474.     lodsb
  2475.     or    al, al            ; Watch for the trailing nul.
  2476.     jz    GD_Copied        ; Add backslash and set up ptr.
  2477.     stosb
  2478.     loop    GD_More
  2479.  
  2480. ; If we get this far there's something wrong.
  2481.     Say_Err_Msg    Floppy_Trouble    ; Bad_Ctl_File
  2482.     call        Abort
  2483.  
  2484. GD_Copied:
  2485.     cmp    di, offset Rest_Path    ; If dirspec. is root, don't add
  2486.     je    GD_Root         ; a trailing backslash.
  2487.     mov    al, '\'         ; Add trailing backslash.
  2488.     stosb
  2489.     dec    cx
  2490. GD_Root:
  2491.     mov    Filespec_Ptr, size Subdir_Name    ; Set ptr. to start of
  2492.                     ; filespec
  2493.     sub    Filespec_Ptr, cx
  2494.  
  2495. GD_Done:
  2496.     clc                ; All is in order.
  2497.     ret
  2498.  
  2499. GD_Err:
  2500.     stc
  2501.     ret
  2502.  
  2503. Get_Dirspec    endp
  2504.  
  2505. ;==============================================================
  2506.  
  2507. Seek_Next_Subdir proc near
  2508. ; DOS 3.3
  2509. ; Set the backup control file ptr. to the next subdir record, or set the
  2510. ; carry flag if there is none.    Abort if the flags indicate a file with
  2511. ; fragments pending if there are more subdir records on the disk.
  2512. ;
  2513. ; Called with:
  2514. ;
  2515. ;    cx contains high word of absolute offset in backup control file of
  2516. ;    next subdir record or -1 if there is none.
  2517. ;
  2518. ;    dx contains low word of absolute offset in backup control file of
  2519. ;    next subdir record or -1 if there is none.
  2520. ;
  2521. ;    Ctl_Hndl contains the handle of the open backup control file.
  2522. ;
  2523. ;    Flags contains bit 0 set if there are no pending file fragments for
  2524. ;    the file just restored, clear if there is.
  2525. ;
  2526. ; Returns:
  2527. ;
  2528. ;    If there is another subdir record to process, the carry flag is set
  2529. ;    and the file ptr. of the backup control file is positioned at
  2530. ;    the beginning of the next subdir record.
  2531. ;
  2532. ;    If there are no more subdir records for this diskette the carry flag
  2533. ;    is clear.
  2534. ;
  2535.     cmp    cx, 0ffffh        ; Find out if this is the last record.
  2536.     jnz    SNS_Not_Last        ; If it is, cx and dx = -1.
  2537.     cmp    dx, 0ffffh
  2538.     jnz    SNS_Not_Last
  2539.     clc
  2540.     ret
  2541.  
  2542. SNS_Not_Last:                ; Check for invalid flag.
  2543.     test    Flags, LastFrag
  2544.     jz    SNS_Err1
  2545.  
  2546. ; Point to next subdir record.
  2547.     mov    bx, Ctl_Hndl
  2548.     mov    ax, 4200H        ; Function 42 = Move File Ptr.
  2549.     int    21H            ; al=0 for absolute offset.
  2550.     jc    SNS_Err2
  2551.     stc
  2552.     ret
  2553.  
  2554. SNS_Err1:
  2555.     Say_Err_Msg    Floppy_Trouble    ; Bad_Ctl_File
  2556.     call        Abort
  2557.  
  2558. SNS_Err2:
  2559.     Say_Err_Msg    Unknown
  2560.     call        Abort
  2561. Seek_Next_Subdir    endp
  2562.  
  2563. ;==============================================================
  2564.  
  2565. Get_Subdir endp
  2566.  
  2567. ;==============================================================
  2568.  
  2569. Get_Files  proc near
  2570. ; DOS 3.3
  2571. ; Process the file records which follow a subdirectory record in the backup
  2572. ; control file.  Return with carry flag clear if all is in order or set if
  2573. ; the current diskette appears to be from the wrong set.
  2574. ;
  2575. ; Called with:
  2576. ;
  2577. ;    cx contains the number of file records in the backup control file
  2578. ;    remaining to be processed.
  2579. ;
  2580. ;    Ctl_Hndl contains the handle of the open backup control file with the
  2581. ;    file ptr. positioned at the beginning of the next file record.
  2582. ;
  2583. ;    Flags bit 0 set if the previous file fragment was not to be
  2584. ;    continued, clear otherwise.
  2585. ;
  2586. ;    Flags bit 2 set if this is a new diskette, clear otherwise.
  2587. ;
  2588. GF_More:
  2589.     or    cx, cx            ; Any more file records?
  2590.     jz    GtF_Done            ; No, return to caller.
  2591.  
  2592. Comment |
  2593.  
  2594. I am assuming that a file record which indicates that there is another file
  2595. fragment coming must always be the last file record in a backup control file.
  2596. The following tests the validity of the backup control file based on this
  2597. assumption.
  2598. | ; End of comment.
  2599.     test    Flags, LastFrag     ; Was previous file to be continued?
  2600.     jnz    GtF_OK            ; No, proceed with next file.
  2601.     test    Flags, NewDisk        ; Yes, is this a new diskette?
  2602.     jz    GtF_Err         ; No, control file is invalid.
  2603.  
  2604. GtF_OK:
  2605.     push    cx            ; Save count value.
  2606.     call    Get_File_Rec
  2607.     call    Get_Filespec
  2608.     jc    GtF_Wrong_Set
  2609.     call    Set_Checks        ; Attempt to catch diskettes from
  2610.     jc    GtF_Wrong_Set        ; another set.
  2611.     mov    dx, Buffer.File_Frag_Seq
  2612.                     ; Pass file fragment no. in dx.
  2613.     call    Select_File        ; Decide if file should be restored.
  2614.     jc    GF_Bypass        ; CY = don't restore file.
  2615.  
  2616.     mov    dx, Buffer.File_Frag_Seq
  2617.                     ; Pass file frag. seq. no. in dx.
  2618.     mov    bl, Buffer.File_Attr    ; Pass file attribute in bl.
  2619.     call    Announce_File
  2620.     jc    GF_Bypass        ; CY = User answered no to restore
  2621.                     ; prompt.
  2622.  
  2623.     call    Seek_Fragment        ; Set backup data file ptr. to beginning
  2624.                     ; of this fragment.
  2625. ; Copy over one fragment.
  2626.     mov    bl, Buffer.File_Attr    ; Pass file attribute in bl.
  2627.     mov    cx, Buffer.File_Time    ; Pass file time in cx.
  2628.     mov    dx, Buffer.File_Date    ; File date in dx.
  2629.                     ; Pass file fragment size in bp:si.
  2630.     mov    si, word ptr Buffer.File_Frag_Size
  2631.     mov    bp, word ptr Buffer.File_Frag_Size + 2
  2632.     call    Do_One_Chunk
  2633.  
  2634. GF_Bypass:
  2635.     pop    cx            ; Restore remaining file record count
  2636.                     ; to cx.
  2637.     dec    cx
  2638.     jmp    GF_More
  2639.  
  2640. GtF_Done:
  2641.     clc                ; NC means all is well.
  2642.     ret
  2643.  
  2644. GtF_Wrong_Set:
  2645.     pop    cx            ; Clear the stack.
  2646.     ret                ; Return to caller with carry flag set.
  2647.  
  2648. GtF_Err:
  2649.     Say_Err_Msg    Floppy_Trouble    ; Bad_Ctl_File
  2650.     call        Abort
  2651.  
  2652. ;==============================================================
  2653.  
  2654. Get_File_Rec proc near
  2655. ; DOS 3.3
  2656. ; Read a file record into the buffer from the backup control file and verify
  2657. ; it by checking its length field.  Abort if record is not valid.
  2658. ; Set bit 0 of Flags if record is for last fragment of a file.
  2659. ; Make sure the file fragment sequence number is correct and set the next
  2660. ; expected fragment sequence no. based on whether or not this file is continued.
  2661. ;
  2662. ; Called with:
  2663. ;
  2664. ;    Ctl_Hndl contains the handle of the open backup control file with
  2665. ;    the file ptr. positioned at the beginning of the file record to
  2666. ;    be read.
  2667. ;
  2668. ;    Want_Frag_Seq contains the expected file fragment sequence number.
  2669. ;
  2670. ; Returns:
  2671. ;
  2672. ;    Buffer contains the successfully read file record beginning at
  2673. ;    offset Buffer.
  2674. ;
  2675. ;    Flags has bit 0 set if this record is for the last fragment of
  2676. ;    a file.
  2677. ;
  2678. ;    Want_Frag_Seq contains the next expected fragment sequence number.
  2679. ;
  2680.     lea    dx, Buffer
  2681.     mov    bx, Ctl_Hndl
  2682.     mov    cx, FILE_REC_LEN
  2683.     mov    ah, 3FH         ; Function = Read.
  2684.     int    21H
  2685.     jc    GFR_Err
  2686.     cmp    cx, ax            ; Read successful?
  2687.     jne    GFR_Err         ; Abort if not.
  2688.     cmp    Buffer.File_Len, cl    ; If this record is valid, these
  2689.     jne    GFR_Err         ; should be equal.
  2690.     ret
  2691.  
  2692. GFR_Err:
  2693.     Say_Err_Msg    Floppy_Trouble    ; Bad_Ctl_File
  2694.     call        Abort
  2695.  
  2696. Get_File_Rec    endp
  2697.  
  2698. ;==============================================================
  2699.  
  2700. Get_Filespec proc near
  2701. ; DOS 3.3
  2702. Comment |
  2703. If this is the first file record on a diskette accepted out of sequence, or
  2704. if the previous file was not to be continued:
  2705. > Get filespec in current file record into target pathspec to be restored.
  2706. > Calculate the length of the complete drive and pathspec not including the
  2707.   terminating nul.
  2708. Otherwise, if this file record is for the continuation of a previous file:
  2709. > Make sure the previous filespec in the pathspec to be restored matches the
  2710.   filespec in the current file record.    If they do not match, this probably
  2711.   indicates that the new diskette is from another set.
  2712.  
  2713. Called with:
  2714.  
  2715.     Buffer contains the current file record beginning at offset 0.
  2716.  
  2717.     Filespec_Ptr contains offset into rest_Path where the filespec of
  2718.     the file to be restored must begin.
  2719.  
  2720.     Rest_Path contains the dirspec. of the file to be restored.
  2721.  
  2722.     Flags bit 3 set if this is the first file record on a diskette
  2723.     accepted out of sequence.
  2724.  
  2725.     Flags bit 0 set if the previous file was to be continued.
  2726.  
  2727.  Returns:
  2728.  
  2729.     Rest_Name  contains the complete nul terminated pathspec including
  2730.     the drive of the file being restored.
  2731.  
  2732.     Rest_Name_Len contains the length of the drive and pathspec not
  2733.     including the terminating nul.
  2734.  
  2735.     Carry Flag set if filespec comparison failed, clear otherwise.
  2736.  
  2737. | ; End of comment.
  2738.     lea    si, Buffer.File_Name    ; Set up indexes to copy or compare.
  2739.     lea    di, Rest_Path
  2740.     add    di, Filespec_Ptr    ; Point di to start of filespec.
  2741.     test    Flags, WrongOk        ; Is this the first file rec. on a
  2742.                     ; diskette out of sequence?
  2743.     jnz    GF_Copy         ; Yes, copy the new filespec
  2744.     test    Flags, LastFrag     ; Is this a continuation?
  2745.     jnz    GF_Copy         ; No, copy the new filespec
  2746.  
  2747.     mov    cx, Rest_Name_Len    ; Get length of filespec not including
  2748.     sub    cx, Filespec_Ptr    ; nul in cx.
  2749.     sub    cx, 3            ; Knock off 3 for the C:\
  2750.     repe    cmpsb
  2751.     jnz    GF_Err2         ; filespec didn't match.
  2752.  
  2753. Comment |
  2754.  
  2755. In the case of a full length filespec in the file record there will be
  2756. no trailing nul.  A matching full length filespec is shown by si pointing to
  2757. the byte following the filename field in the file record.  For the other cases
  2758. the trailing nul may be tested for.
  2759. | ; End of comment.
  2760.     cmp    si, offset Buffer + 13    ; Does si point past filename field?
  2761.     jz    GF_Done         ; Yes, name was a perfect match.
  2762.     cmp    byte ptr [si], 0    ; Otherwise check that the next byte
  2763.     jz    GF_Done         ; is 0.
  2764.     jmp    short GF_Err2        ; Filename did not match.
  2765.  
  2766. GF_Copy:
  2767.     mov    cx, size File_Name
  2768.     cld
  2769.     rep    movsb
  2770.     mov    byte ptr [di], 0    ; and make sure it's null terminated.
  2771.  
  2772.     mov    cx, 64            ; Maximum length of pathspec.
  2773.     lea    di, Rest_Path        ; Calculate total length of drive
  2774.     mov    al, 0            ; and pathspec not including trailing
  2775.     repne    scasb            ; nul.
  2776.     sub    di, offset Rest_Name + 1
  2777.     cmp    di, 65            ; Abort if length illegal.
  2778.     ja    GF_Err1
  2779.     mov    Rest_Name_Len, di
  2780. GF_Done:
  2781.     clc                ; All is in order.
  2782.     ret
  2783.  
  2784. GF_Err1:
  2785.     Say_Err_Msg    Floppy_Trouble    ; Bad_Ctl_File
  2786.     call        Abort
  2787.  
  2788. GF_Err2:
  2789.     stc                ; CY = diskette is from another set.
  2790.     ret
  2791. Get_Filespec endp
  2792.  
  2793. ;==============================================================
  2794.  
  2795. Set_Checks proc near
  2796. ; DOS 3.3
  2797. ; Attempt to catch diskettes from the wrong backup set by checking for
  2798. ; incorrect file fragment sequence numbers and file size fields in file records.
  2799. ; Also keep partial files from being restored when diskettes are inserted out
  2800. ; of sequence.
  2801. ;
  2802. ; Called with:
  2803. ;
  2804. ;    Buffer contains the current file record.
  2805. ;
  2806. ;    Want_Frag_Seq contains the expected file fragment sequence no.
  2807. ;
  2808. ;    Want_Size contains the expected file size for subsequent fragments
  2809. ;    of multiple fragment files.
  2810. ;
  2811. ;    Flags bit 0 set according to previous file record or to 1 if
  2812. ;    there was none.
  2813. ;
  2814. ;    Flags bit 3 set if this is the first file on a diskette accepted out
  2815. ;    of sequence.
  2816. ;
  2817. ; Returns if no problem detected:
  2818. ;
  2819. ;    Carry Flag = clear.
  2820. ;
  2821. ;    Want_Frag_Seq contains the next expected file fragment sequence no.
  2822. ;
  2823. ;    Want_Size contains the total file size of the current file.
  2824. ;
  2825. ;    Flags bit 0 set according to the current file record.
  2826. ;
  2827. ;    Flags bit 4 set if the current fragment is a file continuation on
  2828. ;    a diskette out of sequence.
  2829. ;
  2830. ;    Flags bits 2 and 3 cleared.
  2831. ;
  2832. ; Returns if problem detected:
  2833. ;
  2834. ;    Carry Flag = set.
  2835. ;
  2836.     test    Flags, WrongOk        ; Is this the first file rec. from a
  2837.                     ; diskette accepted out of sequence?
  2838.     jz    SC_In_Seq        ; No, test for validity.
  2839.     mov    ax, Buffer.File_Frag_Seq
  2840.                     ; Yes, re-initialize gragment sequence
  2841.                     ; number from file rec.
  2842.     mov    Want_Frag_Seq, ax
  2843.     cmp    ax, 1            ; Signal that this fragment should not
  2844.     jz    SC_Frag_Seq_OK        ; be restored if the fragment seq. no.
  2845.     or    Flags, SkipFile     ; is not 1.
  2846.     jmp    short SC_Frag_Seq_OK    ; Bypass validity check.
  2847.  
  2848. SC_In_Seq:
  2849.     mov    ax, Want_Frag_Seq    ; Make sure fragment sequence number
  2850.                     ; is as expected.
  2851.     cmp    ax, Buffer.File_Frag_Seq
  2852.     jnz    SC_Wrong_Set
  2853.  
  2854. SC_Frag_Seq_OK:             ; Now for the file size check.
  2855.     lea    si, Buffer.File_Size
  2856.     lea    di, Want_Size
  2857.     cld
  2858.     mov    cx, 2            ; cx = no. of words to compare or copy.
  2859.     test    Flags, WrongOk        ; Is this first file on diskette
  2860.                     ; accepted out of sequence?
  2861.     jnz    SC_Copy         ; Yes, copy over new file size.
  2862.     test    Flags, LastFrag     ; Was last file to be continued?
  2863.     jnz    SC_Copy         ; No, copy over new file size.
  2864.  
  2865.     repe    cmpsw            ; File sizes for current and previous
  2866.     jnz    SC_Wrong_Set        ; file records should be equal.
  2867.     jmp    short SC_Size_OK
  2868.  
  2869. SC_Copy:
  2870.     rep    movsw
  2871.  
  2872. SC_Size_OK:
  2873.     and    Flags, 0ffh-(LastFrag+WrongOk+NewDisk)
  2874.                     ; 0F2H
  2875.                     ; Clear last fragment, diskette out
  2876.                     ; of sequence and new diskette
  2877.                     ; indicators.
  2878.     and    Buffer.File_More, 1    ; Set bit 0 in Flags if this is
  2879.     jz    SC_Done         ; the record for a file's last fragment.
  2880.     or    Flags, LastFrag
  2881.     mov    Want_Frag_Seq, 0    ; Reset fragment sequence no.
  2882.  
  2883. SC_Done:
  2884.     inc    Want_Frag_Seq        ; Store next expected frag. seq. no.
  2885.     clc
  2886.     ret
  2887.  
  2888. SC_Wrong_Set:
  2889.     stc
  2890.     ret
  2891. Set_Checks    endp
  2892.  
  2893. ;==============================================================
  2894.  
  2895. Seek_Fragment proc near
  2896. ; DOS 3.3
  2897. ; Position BACKUP.XXX file ptr. to start of this fragment.  The current
  2898. ; file record is still in Buffer beginning at offset zero.
  2899. ;
  2900.     mov    dx, word ptr Buffer.File_Frag_Start
  2901.     mov    cx, word ptr Buffer.File_Frag_Start + 2
  2902.     mov    bx, Bkp_Hndl
  2903.     mov    ax, 4200H        ; Function Move File Ptr.
  2904.     int    21H            ; al=0 for absolute offset.
  2905.     jc    SF_Err
  2906.     ret
  2907.  
  2908. SF_Err:
  2909.     Say_Err_Msg    Unknown
  2910.     call        Abort
  2911. Seek_Fragment        endp
  2912.  
  2913. ;==============================================================
  2914.  
  2915. Get_Files  endp
  2916.  
  2917. ;==============================================================
  2918.  
  2919. Select_Subdir proc near
  2920. ; DOS 3.2
  2921. ; Decide whether or not the dirspec. of the file proposed to be restored
  2922. ; matches the pattern from the command line.
  2923. ;
  2924. ; Called with:
  2925. ;
  2926. ;    Filespec_Ptr contains the length of the dirspec. portion of the
  2927. ;    file(s) proposed to be restored including a trailing but no leading
  2928. ;    backslash.  If the dirspec. is the root directory its value is 0.
  2929. ;
  2930. ;    Rest_Path contains the dirspec. of the file(s) proposed to be
  2931. ;    restored including a trailing but no leading backslash.  An empty
  2932. ;    string indicates the root directory.
  2933. ;
  2934. ;    Subdir_Pat_Len contains the length of the directory portion
  2935. ;    of the pattern entered on the command line including a trailing but
  2936. ;    no leading backslash.  A value of zero indicates the root directory.
  2937. ;
  2938. ;    CL_Subdir_Pattern contains the directory portion of the pattern
  2939. ;    entered from the command line including a trailing but no leading
  2940. ;    backslash.  An empty string indicates the root directory.
  2941. ;
  2942. ;    Cmd_Flags bit 2 set if subdirectories are to be restored, clear
  2943. ;    if only files are to be restored.
  2944. ;
  2945. ; Returns:
  2946. ;
  2947. ;    Zero Flag set if directory is to be restored, clear if not.
  2948. ;
  2949.     mov    cx, Subdir_Pat_Len
  2950.     cmp    cx, Filespec_Ptr    ; If the pattern is longer, there
  2951.     ja    SS_Done         ; Cannot be a match.
  2952.  
  2953.     test    Cmd_Flags, RestoreSubs    ; /S switch specified?
  2954.     jnz    SS_Compare        ; Yes, proceed with compare.
  2955.     cmp    cx, Filespec_Ptr    ; No, lengths must equal to match.
  2956.     jne    SS_Done
  2957.  
  2958. SS_Compare:
  2959.     or    cx, cx
  2960.     jz    SS_Done         ; File matched.
  2961.     lea    si, CL_Subdir_Pattern
  2962.     lea    di, Rest_Path
  2963.     repe    cmpsb
  2964. SS_Done:
  2965.     ret                ; zR = matched, NZ = not matched.
  2966.  
  2967. Select_Subdir    endp
  2968.  
  2969. ;==============================================================
  2970.  
  2971. Select_File proc near
  2972. ; DOS 3.2 and 3.3
  2973. ; Decide whether or not the current file should be restored as directed by
  2974. ; the file pattern entered on the command line.
  2975. ;
  2976. ; Called with:
  2977. ;
  2978. ;    Rest_Path contains pathspec of file proposed to be restored less
  2979. ;    the leading backslash.
  2980. ;
  2981. ;    Filespec_ptr contains the offset of the filespec relative to
  2982. ;    Rest_Path.
  2983. ;
  2984. ;    Rest_Name_Len contains the length of the complete pathspec proposed
  2985. ;    to be restored including the "C:\" but not the trailing nul.
  2986. ;
  2987. ;    Flags bit 4 set if the previous file fragment was not to be
  2988. ;    restored, clear otherwise.
  2989. ;
  2990. ;    Flags bit 5 set if the filespec of the previous file fragment
  2991. ;    matched the command line pattern and the current pathspec refers
  2992. ;    to the same file, clear otherwise.
  2993. ;
  2994. ;    dx contains the sequence no. of the current file fragment.
  2995. ;
  2996. ; Returns if file fragment is to be restored:
  2997. ;
  2998. ;    Carry Flag clear.
  2999. ;
  3000. ;    Flags bit 4 clear.
  3001. ;
  3002. ;    Flags bit 5 set.
  3003. ;
  3004. ; Returns if file fragment not to be restored:
  3005. ;
  3006. ;    Carry Flag set.
  3007. ;
  3008. ;    Flags bit 4 set.
  3009. ;
  3010.     cmp    dx, 1            ; Release Don't Restore flag and File
  3011.     jnz    SF_Frag_Pending     ; Matched flag for each first fragment.
  3012.     and    Flags,0ffh-(SkipFile+FileMatched) ; 0CFH
  3013.  
  3014. ; Don't restore a fragment for a file whose previous fragments were not
  3015. ; restored.
  3016. SF_Frag_Pending:
  3017.     test    Flags, SkipFile     ; Bit 4 set = Don't Restore File.
  3018.     jnz    SF_Dont_Restore
  3019.  
  3020.     test    Flags, FileMatched    ; Filename matched on previous fragment?
  3021.     jnz    SF_Restore        ; Yes, no need to check again.
  3022.     call    Match_Filespec        ; Restore only files which match
  3023.     jc    SF_Dont_Restore     ; the command line filespec
  3024.     call    Dangerous_Files     ; Don't restore the system files.
  3025.     jc    SF_Dont_Restore
  3026.     or    Flags, FileMatched    ; Signal for subsequent fragments to
  3027.                     ; restore this pathspec.
  3028.  
  3029. SF_Restore:clc
  3030.     ret
  3031.  
  3032. SF_Dont_Restore:
  3033.     or    Flags, SkipFile     ; Bit 4 set = Don't Restore.
  3034.     stc
  3035.     ret
  3036.  
  3037. ;==============================================================
  3038.  
  3039. Match_Filespec proc near
  3040. ; DOS 3.2 and 3.3
  3041. ; Decide if the filespec of the pathspec proposed to be restored matches that
  3042. ; of the command line pattern.
  3043. ;
  3044. ; Called with:
  3045. ;
  3046. ;    CL_File_Pattern contains the command line file pattern to be matched.
  3047. ;    It is in the format "MYFILE__.X__" with any '*' wildcard chars.
  3048. ;    expanded to the maximum possible number of '?' wildcard chars.
  3049. ;
  3050. ; Returns carry flag clear if a match was made, set if not.
  3051. ;
  3052.     cld
  3053.     call    Extract_Filespec
  3054.  
  3055.     lea    si, CL_File_Pattern
  3056.     lea    di, Match_File
  3057.     mov    cx, 12            ; Filename length with embedded '.'.
  3058.  
  3059. MF_More:
  3060.     jcxz    MF_Matched
  3061.     repe    cmpsb
  3062.     je    MF_Matched
  3063.     cmp    byte ptr [si-1], '?'
  3064.     je    MF_More
  3065.     stc
  3066.     ret
  3067.  
  3068. MF_Matched:clc
  3069.     ret
  3070.  
  3071. ;==============================================================
  3072.  
  3073. Extract_Filespec proc near
  3074. ; DOS 3.2 and 3.3
  3075. ; Extract the filespec from the pathspec. proposed to be restored so that
  3076. ; it is in the form "MYFile__.X__" so that it may be more easily compared
  3077. ; with the pattern specified on the command line.
  3078.     lea    di, Match_File        ; Blank out string with spaces in case
  3079.     mov    ax, 2020H        ; some bytes don't get overwritten.
  3080.     mov    cx, 6
  3081.     rep    stosw
  3082.  
  3083.     lea    si, Rest_Path
  3084.     add    si, Filespec_Ptr    ; Point to start of filespec
  3085.     lea    di, Match_File
  3086.     mov    cx, Rest_Name_Len    ; Get length of filespec in cx.
  3087.     sub    cx, Filespec_Ptr
  3088.     sub    cx, 3    ; Allow for "C:\"
  3089. EF_More:
  3090.     lodsb
  3091.     cmp    al, '.'         ; Watch for the period.
  3092.     jz    EF_Ext            ; Copy it and the file extension.
  3093.     stosb
  3094.     loop    EF_More
  3095.     mov    Match_File + 8, '.'    ; '.' needed to match string properly.
  3096.     ret
  3097.  
  3098. EF_Ext:
  3099.     lea    di, Match_File+8
  3100.     stosb
  3101.     dec    cx
  3102.     rep    movsb
  3103.     ret
  3104. Extract_Filespec    endp
  3105.  
  3106. ;==============================================================
  3107.  
  3108. Match_Filespec    endp
  3109.  
  3110. ;==============================================================
  3111.  
  3112. Dangerous_File macro DC
  3113.   local DF_Exit
  3114. ;; Test the filename proposed to be restored against one of the dangerous
  3115. ;; filenames.
  3116.     cmp    cx, D_File&DC&_Len    ;; Filenames can't match if lengths
  3117.     jnz    DF_Exit         ;; aren't equal.
  3118.  
  3119.     lea    si, D_File&DC        ;; Compare filenames.
  3120.     push    cx
  3121.     call    Dangerous        ;; CY = file is dangerous.
  3122.     pop    cx
  3123.     jc    DF_Dangerous
  3124. DF_Exit label    near
  3125. endm                    ;; End of macro Dangerous_File.
  3126.  
  3127. ;==============================================================
  3128.  
  3129. Dangerous_Files proc near
  3130. ; DOS 3.2 and 3.3
  3131. ; Don't allow any files with possible operating system filenames to be
  3132. ; restored to the root directory.  Announce the names of any files skipped
  3133. ; over.  Return with the carry flag set if the file is to be skipped, clear
  3134. ; otherwise.  This rather intimidating code just compares the
  3135. ; file we are about to restore with the names of 5 files known dangerous
  3136. ; to restore, namely IBMBIO.COM IBMDOS.COM IO.SYS MSDOS.SYS and COMMAND.COM
  3137.  
  3138.     cld
  3139.     cmp    Filespec_Ptr, 0     ; Is file headed for the root directory?
  3140.     jnz    DF_OK            ; No, File OK to restore.
  3141.  
  3142.     mov    cx, Rest_Name_Len    ; Get filename length in cx.
  3143.     sub    cx, 2            ; Omit "C:\" but add 1 for trailing nul.
  3144. ; Check the filename of the file proposed to be restored to the root directory
  3145. ; to make sure it doesn't have the name of one of the system files.  If it
  3146. ; does, return to the calling procedure with carry flag set.
  3147.  
  3148. DC = 0                    ;; Keep track of which iteration were on.
  3149. rept D_Count                ;; D_Count = no. of dangerous files.
  3150.     DC = DC + 1            ;; Update iteration counter.
  3151.     Dangerous_File %DC
  3152. endm                    ;; End of repeat block.
  3153.  
  3154. DF_OK:
  3155.     clc                ; File is OK to restore.
  3156.     ret
  3157.  
  3158. DF_Dangerous:
  3159.     stc
  3160.     ret
  3161.  
  3162. ;==============================================================
  3163.  
  3164. Dangerous proc near
  3165. ; DOS 3.2 and 3.3
  3166. ; Compare the filename to which si points with the filename of the file proposed
  3167. ; to be restored.  Return to caller with carry flag set if they match, clear
  3168. ; otherwise.  The length of the filename to be checked including a trailing nul
  3169. ; is passed to this routine in cx.
  3170.     lea    di, Rest_Path
  3171.     repe    cmpsb
  3172.     jz    D_Dangerous
  3173.     clc
  3174.     ret
  3175.  
  3176. D_Dangerous:stc
  3177.     ret
  3178. Dangerous    endp
  3179.  
  3180. ;==============================================================
  3181.  
  3182. Dangerous_Files     endp
  3183.  
  3184. ;==============================================================
  3185.  
  3186. Select_File    endp
  3187.  
  3188. ;==============================================================
  3189.  
  3190. Announce_File proc near
  3191. ; DOS 3.2 and 3.3
  3192. ; If the /P switch is active and the current fragment is the first fragment
  3193. ; in a file, prompt the user whether or not to restore the file.  If the current
  3194. ; file fragment is the first fragment in a file containing Read-only, Hidden,
  3195. ; and/or System attributes prompt the user whether or not to
  3196. ; restore the file.  If the /P switch is not active and the file has normal
  3197. ; attributes or if the user indicates to restore the file, announce on the
  3198. ; standard output device the drive and full pathspec of the file being
  3199. ; restored.  If the file exists in more than one fragment, also announce the
  3200. ; fragment or part number of this fragment.
  3201. ;
  3202. ; Called with:
  3203. ;
  3204. ;    Flags bit 0 set if this fragment is the last for the file, clear
  3205. ;                otherwise.
  3206. ;
  3207. ;    Cmd_Flags bit 0 set if /P switch is active, clear otherwise.
  3208. ;
  3209. ;    dx contains the file fragment sequence no. of the current file.
  3210. ;
  3211. ;    bl contains the attribute of the file fragment about to be restored.
  3212. ;
  3213. ; Returns:
  3214. ;
  3215. ;    Carry Flag and Flags bit 4 set if user indicated not to restore
  3216. ;    a file, clear otherwise.
  3217. ;
  3218.     push    dx            ; Save frag. seq. no.
  3219.     cmp    dx, 1            ; Prompt only on first fragment.
  3220.     jnz    AF_Restore
  3221.     test    Cmd_Flags, Prompt_Needed    ; Is /P switch in effect?
  3222.     jz    AF_Attr         ; No, skip the prompt.
  3223.     push    bx            ; Save file attribute.
  3224.     call    Prompt_User        ; Get user's decision on restoring file.
  3225.     pop    bx            ; Retrieve file attribute.
  3226.     jc    AF_No            ; NC = yes, CY = no.
  3227.  
  3228. AF_Attr:
  3229.     test    bl, 7            ; Is file Read-only and/or System and/or
  3230.                     ; hidden?
  3231.     jz        AF_Restore    ; No, skip prompt.
  3232.     Say_Err_Msg    Special_Attr
  3233.     call        Prompt_User
  3234.     jnc        AF_Restore
  3235.  
  3236. AF_No:
  3237.     pop    dx            ; Clear stack.
  3238.     or    Flags, SkipFile     ; Bit 4 = Don't restore file.
  3239.     stc
  3240.     ret
  3241.  
  3242. AF_Restore:
  3243.     Say_Msg Rest_Name
  3244.     pop    dx            ; Retrieve file frag. seq. no.
  3245.     test    Flags, LastFrag     ; Is this a multi-fragment file?
  3246.     jz    AF_Part_X        ; Yes, announce part no. after name.
  3247.     cmp    dx, 1            ; Maybe, is frag. no. > 1.
  3248.     ja    AF_Part_X        ; Yes, announce part no.
  3249.     clc
  3250.     ret
  3251.  
  3252. AF_Part_X:
  3253.     Patch_Num    dx, Part_X+2, 3
  3254.     Say_Msg     Part_X_Msg
  3255.     clc
  3256.     ret
  3257.  
  3258. ;==============================================================
  3259.  
  3260. GetUCChar Proc    near
  3261. ;    Gets one upper-case char from keyboard
  3262. ;    Lower case get converted to upper case
  3263. ;    punctuation passed unmolested.
  3264. ;    Echos printable chars as letter backspace.
  3265.  
  3266.     mov    ax, 0C08H        ; Clear typeahead buffer and get
  3267.     int    21H            ; filtered no echo
  3268.     CMP    AL,'a'
  3269.     JB    FineAsIs
  3270.     CMP    AL,'z'
  3271.     JA    FineAsIs
  3272.  
  3273.     SUB    AL,20h            ; convert a: to A:
  3274. FineAsIs:
  3275.                     ; check for displayable char
  3276.     CMP    AL,32d            ; space
  3277.     JB    NoEcho
  3278.     CMP    AL,126d         ; tilde ~
  3279.     JA    NoEcho
  3280.     MOV    EchoChar,AL        ; echo upper case chars
  3281.     PUSH    AX            ; save char from destruction
  3282.     Say_Err_Msg EchoChar
  3283.     POP    AX
  3284. NoEcho:
  3285.     ret
  3286. GetUCChar ENDP
  3287.  
  3288. ;==============================================================
  3289.  
  3290. Prompt_User proc near
  3291. ; DOS 3.2 and 3.3
  3292. ; Display on the standard error device the pathspec of the file to be restored
  3293. ; and ask the user to indicate by answering y or n if it should be restored.
  3294. ; Return with carry flag set if he answers N, clear if he answers Y.
  3295. ;
  3296.     Say_Err_Msg    Prompt_User1
  3297.     Say_Err_Msg    Rest_Name
  3298.     Say_Err_Msg    Prompt_User2
  3299. PU_Again:
  3300.     Call    GetUcChar            ; get Y/N
  3301.     cmp    al, 'Y'
  3302.     jne    PU1
  3303.     Say_Err_Msg    CRLF
  3304.     clc
  3305.     jmp    short PU_Done
  3306.  
  3307. PU1:
  3308.     cmp    al, 'N'
  3309.     jne    PU_Err
  3310.     Say_Err_Msg    CRLF
  3311.     stc
  3312.  
  3313. PU_Done:
  3314.     ret
  3315.  
  3316. PU_Err:
  3317.     Say_Err_Msg    Beep
  3318.     jmp    short PU_Again
  3319. Prompt_User    endp
  3320.  
  3321. ;==============================================================
  3322.  
  3323. Announce_File    endp
  3324.  
  3325. ;==============================================================
  3326.  
  3327. Do_One_Chunk proc near
  3328. ; DOS 3.2 and 3.3
  3329. ; Copy the current file fragment to its pathname on the hard disk.  If this is
  3330. ; the first fragment of the file, create the pathspec making any needed but
  3331. ; non-existent subdirectories and creating or truncating to zero length the
  3332. ; specified filename.  If this is the last fragment for the file, close the
  3333. ; file on the hard disk after copying the fragment.
  3334. ;
  3335. ; Called with:
  3336. ;
  3337. ;    Bkp_Hndl contains the handle of the open backup data file with the
  3338. ;    file ptr. positioned at the beginning of the file fragment to be
  3339. ;    restored, ie at the first byte of data to be copied.
  3340. ;
  3341. ;    Out_Hndl contains the handle of the file being restored on the hard
  3342. ;    disk if the file has had previous fragments restored, -1 otherwise.
  3343. ;
  3344. ;    bl contains the attributes of the file being restored.
  3345. ;
  3346. ;    cx contains the file time in DOS dir. format.
  3347. ;
  3348. ;    dx contains the file date in DOS directory format.
  3349. ;
  3350. ;    bp:si contains the size of the current file fragment.
  3351. ;
  3352. ;    Flags bit 0 set if this is the last fragment for the file,
  3353. ;    clear if not.
  3354. ;
  3355. ; Returns:
  3356. ;
  3357. ;    Out_Hndl contains the handle of the open file being restored on the
  3358. ;    hard disk if there are still more fragments to go; otherwise, the
  3359. ;    output file has been closed and Out_Hndl contains -1.
  3360. ;
  3361.     push    cx            ; Save file time.
  3362.     push    dx            ; Save file date.
  3363.  
  3364.     cmp    Out_Hndl, -1        ; File will already be open if this is
  3365.                     ; not a first fragment.
  3366.     jnz    DOC_Opened
  3367.  
  3368.     call    Open_Out_File        ; Create output file on hard disk.  bx,
  3369.                     ; bp, and si may need to be saved if
  3370.                     ; Open_OUt_File is modified.
  3371.     jnc    DOC_Opened        ;  NC = file created successfully.
  3372.  
  3373. ; CY = create failed, error code returned in ax.
  3374.     cmp    ax, 5            ; Access denied?
  3375.     jne    DOC_Not_RO        ; No.  bx, bp, and si  may need to be
  3376.                     ; saved if Rid_RO is modified.
  3377.     call    Rid_RO            ; Yes, if file with same pathspec as
  3378.                     ; Rest_Name exists on hard disk, change
  3379.                     ; its attributes to normal.
  3380.     call    Open_Out_File
  3381.     jnc    DOC_Opened
  3382.     call    DOC_Unknown        ; Unknown error, abort.
  3383.  
  3384. DOC_Not_RO:
  3385.     cmp    ax, 3            ; Path not found?
  3386.     jne    DOC_Not_Path        ; No, path seems OK.
  3387.     call    Make_Dirs        ; Yes, try to create it.  May need to
  3388.                     ; save bx, bp, and si  if Make_Dirs
  3389.                     ; is modified.
  3390.     call    Open_Out_File
  3391.     jnc    DOC_Opened
  3392. DOC_Not_Path:
  3393.     call    DOC_Unknown        ; Unknown error, abort.
  3394.  
  3395. DOC_Opened:
  3396.     call    Copy_Fragment
  3397.  
  3398.     pop    dx            ; Retrieve file date.
  3399.     pop    cx            ; Retrieve file time.
  3400.  
  3401.     test    Flags, LastFrag     ; Only close output file if no more
  3402.     jz    DOC_Done        ; fragments.
  3403.     call    Close_Out_File
  3404. DOC_Done:
  3405.     ret
  3406.  
  3407. ;==============================================================
  3408.  
  3409. Rid_RO    proc near
  3410. ; DOS 3.2 and 3.3
  3411. ; nested in Do_One_Chunk
  3412. ; If a file with the same pathspec as the one proposed to be restored already
  3413. ; exists on the hard disk, change its attributes to normal.
  3414.     lea    dx, Rest_Name
  3415.     xor    cx, cx            ; Use normal attributes.
  3416.     mov    ax, 4301H        ; Function = change file attributes.
  3417.     int    21H
  3418.     ret
  3419. Rid_RO    endp
  3420.  
  3421. ;==============================================================
  3422.  
  3423. Make_Dirs  proc near
  3424. ; DOS 3.2 and 3.3
  3425. ; nested in Do_One_Chunk
  3426. ; Create the path elements necessary for the pathspec in Rest_Name to exist.
  3427. ; IF a path element cannot be created, assume that a junk file with the same
  3428. ; name as the element exists, attempt to delete it, and try again to create the
  3429. ; path element.
  3430.     mov    cx, Rest_Name_Len
  3431.     sub    cx, 4            ; Skip d:\ and first char since first
  3432.                     ; '\' delimiting a path element can't
  3433.                     ; occur there.
  3434.     lea    di, Rest_Name+4     ; Skip over d:\ and first char
  3435.     lea    dx, Rest_Name        ; dx points at path.
  3436.     mov    al, '\'
  3437. MD_More:
  3438.     jcxz    MD_Done
  3439.     repne    scasb            ; Scan for a backslash.
  3440.     jne    MD_Done         ; No more path elements to create.
  3441.     mov    byte ptr [di-1], 0    ; Temporarily change '\' to nul.
  3442.     mov    ah, 39H         ; Function = create subdirectory.
  3443.     int    21H            ; May fail because of junk file with
  3444.     jnc    MD_Success        ; same name as path.  If so, attempt to
  3445.                     ; delete pathspec and try again.
  3446.     mov    ah, 41H         ; Function = Delete File.
  3447.     int    21H
  3448.     mov    ah, 39H         ; Try again.
  3449.     int    21H
  3450. MD_Success:
  3451.     mov    al, '\'         ; Replace backslash.
  3452.     mov    [di-1], al
  3453.     jmp    short MD_More
  3454. MD_Done:
  3455.     ret
  3456. Make_Dirs    endp
  3457.  
  3458. ;==============================================================
  3459.  
  3460. Open_Out_File proc near
  3461. ; DOS 3.2 and 3.3
  3462. ; nested in Do_One_Chunk
  3463. ; Attempt to open the file to be restored on the hard drive truncating any
  3464. ; existing file to zero length or creating the file if it doesn't exist.
  3465. ; Abort if operation fails because too many files are open.
  3466. ;
  3467. ; Called with:
  3468. ;
  3469. ;    Rest_Name contains complete pathspec of file to be restored on
  3470. ;    the hard disk.
  3471. ;
  3472. ;    bl contains attributes of file to be restored.
  3473. ;
  3474. ; Returns if successful:
  3475. ;
  3476. ;    Out_Hndl contains the handle of the successfully opened file on
  3477. ;    the hard disk.
  3478. ;
  3479. ;    Carry Flag = cleared.
  3480. ;
  3481. ; Returns If Not Successful:
  3482. ;
  3483. ;    Carry Flag = set.
  3484. ;
  3485. ;    ax contains error code.
  3486. ;    3 = Path not found.
  3487. ;    5 = Access denied.
  3488. ;
  3489.     lea    dx, Rest_Name        ; Point dx to the pathspec of the
  3490.                     ; file to be restored.
  3491.     xor    ch, ch            ; PUt file attributes in cx.
  3492.     mov    cl, bl
  3493.     or    cl, 20H         ; Force archive bit on.
  3494.     mov    ah, 3CH         ; Function 3CH=Create or Truncate file.
  3495.     int    21H
  3496.     jc    OOF_Err
  3497.     mov    Out_Hndl, ax
  3498.     ret
  3499.  
  3500. OOF_Err:
  3501.     cmp    ax, 4            ; Too many open files?
  3502.     jne    OOF_Err1
  3503.     Say_Err_Msg    Hard_Disk_Trouble ;    Cant_Open_OF
  3504.     Say_Err_Msg    Rest_Name
  3505.     Say_Err_Msg    Too_Many_Open
  3506.     call        Abort
  3507.  
  3508. OOF_Err1:
  3509.     stc
  3510.     ret
  3511. Open_Out_File    endp
  3512.  
  3513. ;==============================================================
  3514.  
  3515. Copy_Fragment proc near
  3516. ; DOS 3.2 and 3.3
  3517. ; nested in Do_One_Chunk
  3518. ; Copy the current file fragment from the backup data file to the hard disk.
  3519. ; If the backup format is DOS 3.3 and this is the last fragment for a file,
  3520. ; make sure the file size is correct.
  3521. ;
  3522. ; Called with:
  3523. ;
  3524. ;    Bkp_Hndl contains handle of open backup data file with file ptr.
  3525. ;    positioned at the beginning of the data to be restored.
  3526. ;
  3527. ;    Out_Hndl contains handle of open file on hard disk with file
  3528. ;    ptr. positioned at end-of-file.
  3529. ;
  3530. ;    Flags bit 0 set if this is the last fragment for the file, clear
  3531. ;    otherwise.
  3532. ;
  3533. ;    Format_Flags bit 0 set if the backup is in DOS 3.2 format, clear
  3534. ;    otherwise.
  3535. ;
  3536. ;    Format_Flags bit 1 set if backup is in DOS 3.3 format, clear
  3537. ;    otherwise.
  3538. ;
  3539. ;    Want_Size contains the total size of the file in bytes according
  3540. ;    to its file record(s) in CONTROL.XXX if the backup is in DOS 3.3
  3541. ;    format.
  3542. ;
  3543. ;    bp:si contains the size of the file fragment.
  3544. ;
  3545.     lea    dx, Buffer        ; For subsequent reads and writes.
  3546.  
  3547. CF_More:
  3548.     mov    cx, BUFF_SIZE        ; Assume at least one buffer full
  3549.     clc                ; to go.
  3550.     cmp    si, cx            ; Check cx against low word of bytes
  3551.                     ; remaining to be copied.
  3552.     jnc    CF_Cpy            ; If NC assumption is correct.
  3553.                     ; Proceed with copy.
  3554.  
  3555.     or    bp, bp            ; If Hi byte isn't 0, assumption is
  3556.     jnz    CF_Cpy            ; correct.
  3557.  
  3558.     mov    cx, si            ; Otherwise, copy remaining bytes.
  3559. CF_Cpy:
  3560.     mov    bx, Bkp_Hndl
  3561.     mov    ah, 3FH         ; Function = Read.
  3562.     int    21H
  3563.     jc    CF_Err_Unknown        ; Abort if trouble.
  3564.     cmp    cx, ax            ; Read o.k.?
  3565.     jne    CF_Err_In        ; Abort if not.
  3566.  
  3567.     mov    bx, Out_Hndl        ; Write this chunk.
  3568.     mov    ah, 40H         ; Function 40H = Write.
  3569.     int    21H
  3570.     jc    CF_Err_Unknown        ; Abort if trouble.
  3571.     cmp    cx, ax            ; Write o.k.?
  3572.     jne    CF_Err_Out        ; Abort if not.
  3573.  
  3574.     sub    si, cx            ; Subtract bytes read from total
  3575.     sbb    bp, 0            ; and go back if there's more.
  3576.     jnz    CF_More
  3577.     or    si, si
  3578.     jnz    CF_More
  3579.  
  3580.     test    Format_Flags, DOS32    ; Is backup DOS 3.2 format?
  3581.     jnz    CF_Done         ; Yes, can't check file size.
  3582.     test    Flags, LastFrag     ; Is this the last chunk.
  3583.     jz    CF_Done         ; No, return to caller.
  3584. Comment |
  3585. The file size may be determined by using the Move File Ptr. function (ah=42H)
  3586. to seek an offset of 0 bytes relative to EOF. (al=2).  Note that the file
  3587. handle is already in bx.
  3588. | ; End of comment.
  3589.     mov    ax, 4202H        ; Determine if file size is correct.
  3590.     xor    dx, dx            ; Low byte of offset.
  3591.     xor    cx, cx            ; High byte of offset.
  3592.     int    21H            ; dx:ax = returned offset.
  3593.     jc    CF_Err_Unknown
  3594.  
  3595.     cmp    ax, word ptr Want_Size    ; Correct size returned for low word?
  3596.     jnz    CF_Wrong_Size        ; No.
  3597.     cmp    dx, word ptr Want_Size+2; Correct size returned for high word?
  3598.     jnz    CF_Wrong_Size        ; No.
  3599.  
  3600. CF_Done:
  3601.     ret
  3602.  
  3603. CF_Wrong_Size:
  3604.     call        Say_Cant_Restore
  3605.     Say_Err_Msg    Floppy_Trouble    ; Bad_Size
  3606.     call        Abort
  3607.  
  3608. CF_Err_In:
  3609.     call        Say_Cant_Restore
  3610.     Say_Err_Msg    In_IO_Err
  3611.     call        Abort
  3612.  
  3613. CF_Err_Out:
  3614.     call        Say_Cant_Restore
  3615.     Say_Err_Msg    Out_IO_Err
  3616.     call        Abort
  3617.  
  3618. CF_Err_Unknown:
  3619.     call        Say_Cant_Restore
  3620.     Say_Err_Msg    Unknown
  3621.     call        Abort
  3622.  
  3623. ;==============================================================
  3624.  
  3625. Say_Cant_Restore proc near
  3626. ; DOS 3.2 and 3.3
  3627. ; nested in Do_One_Chunk
  3628. ; Print common part of error messages including the pathspec of the
  3629. ; unsuccessfully restored file.
  3630.     Say_Err_Msg    Cant_Restore
  3631.     Say_Err_Msg    Rest_Name
  3632.     Say_Err_Msg    CRLF
  3633.     ret
  3634. Say_Cant_Restore endp
  3635.  
  3636. ;==============================================================
  3637.  
  3638. Copy_Fragment endp
  3639.  
  3640. ;==============================================================
  3641.  
  3642. Close_Out_File proc near
  3643. ; DOS 3.2 and 3.3
  3644. ; nested in Do_One_Chunk
  3645. ; Close the file which has been restored on the hard disk.  Abort if not
  3646. ; successful.  Also set the time and date stamp to that stored in the backup.
  3647. ;
  3648. ; Called with:
  3649. ;
  3650. ;    Out_Hndl contains handle of open output file.
  3651. ;
  3652. ;    dx contains file date from backup in DOS dir. format.
  3653. ;
  3654. ;    cx contains file time from backup in DOS dir. format.
  3655. ;
  3656. ; Returns:
  3657. ;
  3658. ;    Out_Hndl contains -1.
  3659. ;
  3660.     mov    bx, Out_Hndl
  3661.     mov    ax, 5701H        ; Function 57H with al=1 = Set File
  3662.     int    21H            ; time and date.
  3663.  
  3664.     mov    ah, 3EH         ; Function 3EH=Close File.
  3665.     int    21H
  3666.     jc    COF_Err
  3667.     mov    Out_Hndl, -1        ; Indicates that file is closed.
  3668.     Say_Msg Restored
  3669.     inc    Rest_Count        ; UPdate count of files restored.
  3670.     ret
  3671.  
  3672. COF_Err:
  3673.     Say_Err_Msg    Hard_Disk_Trouble    ; Cant_Close_OF
  3674.     Say_Err_Msg    Rest_Name
  3675.     call        Abort
  3676. Close_Out_File    endp
  3677.  
  3678. ;==============================================================
  3679.  
  3680. DOC_Unknown proc near
  3681. ; DOS 3.2 and 3.3
  3682. ; nested in Do_One_Chunk
  3683. ; Restore failed for unknown reason, print error message and abort.
  3684.     Say_Err_Msg    Hard_Disk_Trouble    ; Cant_Open_OF
  3685.     Say_Err_Msg    Rest_Name
  3686.     Say_Err_Msg    CRLF
  3687.     Say_Err_Msg    Unknown
  3688.     call        Abort
  3689. DOC_Unknown endp
  3690.  
  3691. ;==============================================================
  3692.  
  3693. Do_One_Chunk endp
  3694.  
  3695. ;==============================================================
  3696.  
  3697. Close_Bkp_File proc near
  3698. ; DOS 3.3
  3699. ; CLOSE BACKUP.XXX
  3700. ; Close the backup data file and reset its handle to a value of -1.  Bkp_Hndl
  3701. ; contains the handle of the open backup data file.
  3702.     mov    bx, Bkp_Hndl
  3703.     mov    ah, 3EH         ; Function 3EH=Close File.
  3704.     int    21H
  3705.     jc    CBF_Err
  3706.     mov    Bkp_Hndl, -1        ; Indicates that file is closed.
  3707.     ret
  3708.  
  3709. CBF_Err:
  3710.     Say_Err_Msg    Floppy_Trouble    ; Cant_Close_BF
  3711.     call        Abort
  3712. Close_Bkp_File    endp
  3713.  
  3714. ;==============================================================
  3715.  
  3716. Close_Ctl_File proc near
  3717. ; DOS 3.3
  3718. ; CLOSE CONTROL.XXX
  3719. ; Close the backup control or ID file and set its handle to -1.  Abort if error.
  3720. ; Ctl_Hndl contains the handle of the open backup control or ID file.
  3721.     mov    bx, Ctl_Hndl
  3722.     mov    ah, 3EH         ; Function 3EH=Close File.
  3723.     int    21H
  3724.     jc    CCF_Err
  3725.     mov    Ctl_Hndl, -1        ; Indicates that file is closed.
  3726.     ret
  3727.  
  3728. CCF_Err:
  3729.     Say_Err_Msg    Floppy_Trouble    ; Cant_Close_CF
  3730.     call        Abort
  3731. Close_Ctl_File    endp
  3732.  
  3733. ;==============================================================
  3734.  
  3735. Abort_Retry proc near
  3736. ; DOS 3.2 and 3.3
  3737. ; Prompt user to enter A for abort or R for retry.  Terminate if abort or
  3738. ; return to caller if retry.
  3739.     Say_Err_Msg    AR_Msg        ; Prompt on standard error device.
  3740. AR_Again:
  3741.     Call    GetUcChar            ; get A/R
  3742.     cmp    al, 'A'
  3743.     jne    AR1
  3744.     call    Abort
  3745.  
  3746. AR1:
  3747.     cmp    al, 'R'
  3748.     jne    AR_Err
  3749.     Say_Err_Msg    CRLF
  3750.     ret
  3751.  
  3752. AR_Err:
  3753.     Say_Err_Msg    Beep
  3754.     jmp    short AR_Again
  3755. Abort_Retry    endp
  3756.  
  3757. ;==============================================================
  3758.  
  3759. Abort_Retry_Ignore proc near
  3760. ; DOS 3.2 and 3.3
  3761. ; Prompt user to enter A for abort, R for retry, or I for Ignore.  Terminate
  3762. ; if abort or return to caller with carry flag set if retry, clear if ignore.
  3763.     Say_Err_Msg ARI_Msg        ; Prompt on standard error device.
  3764. ARI_Again:
  3765.     Call    GetUcChar        ; get A/R/I
  3766.     cmp    al, 'A'
  3767.     jne    ARI1
  3768.     call    Abort
  3769.  
  3770. ARI1:
  3771.     cmp    al, 'I'
  3772.     jne    ARI2
  3773.     Say_Err_Msg    CRLF
  3774.     clc
  3775.     jmp    short ARI_Done
  3776.  
  3777. ARI2:
  3778.     cmp    al, 'R'
  3779.     jne    ARI_Err
  3780.     Say_Err_Msg    CRLF
  3781.     stc
  3782.  
  3783. ARI_Done:
  3784.     ret
  3785.  
  3786. ARI_Err:
  3787.     Say_Err_Msg    Beep
  3788.     jmp    short ARI_Again
  3789. Abort_Retry_Ignore    endp
  3790.  
  3791. ;==============================================================
  3792.  
  3793. Abort proc near
  3794. ; DOS 3.2 3.3
  3795. ; Print message with count of successfully restored files and exit with return
  3796. ; code of 4.
  3797.     Patch_Num    Rest_Count, Aborted_Count+4, 5
  3798.     Say_Msg     Aborted
  3799.     mov    ax, 4C04H        ; Function = exit with return code of 4.
  3800.     int    21H
  3801. Abort    endp
  3802.  
  3803. ;==============================================================
  3804.  
  3805. Bye    proc near
  3806. ; DOS 3.2 and 3.3
  3807. ; Print sign-off message with count of files restored.
  3808. ; Terminate with return code of 0.  If no files were restored, print warning
  3809. ; message and terminate with return code of 1.
  3810.     Patch_Num    Rest_Count, DM_Count+4, 5
  3811.     Say_Msg     Done_Msg
  3812.     cmp    Rest_Count, 0        ; No files restored?
  3813.     je    B_None            ; Yes, print warning and exit.
  3814.  
  3815.     mov    ax, 4C00H        ; No, files were restored.
  3816.     int    21H            ; Function = exit with return code of 0.
  3817.  
  3818. B_None:
  3819.     Say_Err_Msg    None_Restored
  3820.     mov    ax, 4C01H        ; Function = exit with return code of 1.
  3821.     int    21H
  3822. Bye    endp
  3823.  
  3824. ;==============================================================
  3825.  
  3826. Restore_File proc near
  3827. ; DOS 3.2
  3828. ; Decide if the file currently described in the DTA is a valid file fragment and
  3829. ; it should be restored.  Restore it if it should.  Return with carry flag set
  3830. ; if the diskette is determined to have a scrambled directory or to be from
  3831. ; another set, clear otherwise.
  3832. ;
  3833.     call    Bypass_Bkp_ID        ; Don't restore BACKUPID.@@@
  3834.     jc    RF_Skip         ; CY = current file is BACKUPID.@@@.
  3835.     call    Open_Bkp_File
  3836.     call    Get_Preamble
  3837.     call    Copy_Pathspec
  3838.     jc    RF_Wrong_Set
  3839.     call    Select_Subdir        ; Does subdir match command line?
  3840.     jnz    RF_Bypass        ; NO, skip this pathspec.
  3841.     call    Scramble_Check
  3842.     jc    RF_Wrong_Set
  3843.  
  3844.     mov    dx, Buffer.P_Frag_Seq    ; Pass file fragment no. in dx.
  3845.     call    Select_File        ; Decide if file should be restored.
  3846.     jc    RF_Bypass        ; CY = don't restore file.
  3847.     mov    dx, Buffer.P_Frag_Seq    ; Pass file frag. seq. no. in dx.
  3848.     mov    bl, ds:DTA.DS_Attr    ; Pass file attribute in bl.
  3849.     call    Announce_File
  3850.     jc    RF_Bypass        ; CY = User answered no to restore
  3851.                     ; prompt.
  3852.  
  3853. ; Copy over one fragment.
  3854.     mov    bl, ds:DTA.DS_Attr    ; Pass file attribute in bl.
  3855.     mov    cx, ds:DTA.DS_Time    ; Pass file time in cx.
  3856.     mov    dx, ds:DTA.DS_Date    ; File date in dx.
  3857.                     ; Pass file fragment size in bp:si.
  3858.     mov    si, word ptr ds:DTA.DS_Size
  3859.     mov    bp, word ptr ds:DTA.DS_Size+2
  3860.     sub    si, 128         ; Allow for preamble.
  3861.     sbb    bp, 0
  3862.     call    Do_One_Chunk
  3863.  
  3864. RF_Bypass:
  3865.     call    Close_Bkp_File
  3866. RF_Skip:
  3867.     clc                ; NC = all is in order.
  3868.     ret
  3869.  
  3870. RF_Wrong_Set:
  3871. ; Diskette is either from another set or its dir. is scrambled.
  3872.     call    Close_Bkp_File
  3873.     Say_Err_Msg    Floppy_Trouble    ; Scrambled
  3874.     call    Abort_Retry
  3875.     and    Flags, 0ffh - LastDisk    ; 0FDH
  3876.                     ; Clear last diskette flag so OM_Main
  3877.                     ; will prompt for another diskette.
  3878.     dec    Want_Seq
  3879.     stc
  3880.     ret
  3881. ;    actual Restore_File endp contains nested procs
  3882.  
  3883. ;==============================================================
  3884.  
  3885. Bypass_Bkp_ID proc near
  3886. ; DOS 3.2
  3887. ; nested in Restore_File
  3888. ; Return CY if file currently in DTA is BACKUPID.@@@ or a subdirectory, NC
  3889. ; otherwise.  We don't want to touch a DOS 3.3 diskette in
  3890. ; middle of DOS 3.3 restore.
  3891.     test    ds:DTA.DS_Attr, 10H    ; Is current file a subdir?
  3892.     jnz    BBI_Bypass        ; Yes, skip it.
  3893.  
  3894.     mov    cx, 12            ; Length of BACKUPID.@@@.
  3895.     lea    si, Bkp_ID_Name+3    ; Bypass d:\.
  3896.     lea    di, ds:DTA.DS_Name    ; Point at filename in DTA.
  3897.     repe    cmpsb            ; Is this BACKUPID.@@@?
  3898.     jz    BBI_Bypass        ; Yes, skip this file.
  3899.     clc                ; No, return NC.
  3900.     ret
  3901.  
  3902. BBI_Bypass:
  3903.     stc                ; Return CY so file will be skipped.
  3904.     ret
  3905. Bypass_Bkp_ID endp
  3906.  
  3907. ;==============================================================
  3908.  
  3909. Get_Preamble proc near
  3910. ; DOS 3.2
  3911. ; Read 128 byte preamble from the open backup file proposed to be restored.
  3912.     mov    bx, Bkp_Hndl        ; Handle of backup file currently
  3913.                     ; being considered.
  3914.     mov    cx, 128         ; Length of preamble.
  3915.     lea    dx, Buffer        ; ds:dx points at buffer.
  3916.     mov    ah, 3FH         ; Function = read.
  3917.     int    21H
  3918.     jc    GP_Err
  3919.     cmp    cx, ax            ; Correct no. of bytes read?
  3920.     jnz    GP_Err
  3921.     ret
  3922.  
  3923. GP_Err:
  3924.     Say_Err_Msg    Unknown
  3925.     call        Abort
  3926. Get_Preamble    endp
  3927.  
  3928. ;==============================================================
  3929.  
  3930. Copy_Pathspec proc near
  3931. ; DOS 3.2
  3932. ; nested in Restore_File
  3933. ; Copy the pathspec proposed to be restored out of the buffer into Rest_Name.
  3934. ; Calculate the total length of the pathspec including the drive but not the
  3935. ; terminating nul and the offset of the filename relative to Rest_Path.  If the
  3936. ; new fragment is a continuation of the last file, do not copy its pathspec but
  3937. ; make sure it matches the old one exactly and return CY if not.
  3938. ;
  3939. ; Called with:
  3940. ;
  3941. ;    Buffer contains the preamble of the file proposed to be restored.
  3942. ;
  3943. ;    Flags bit 1 set if this fragment should be the beginning of a new
  3944. ;    file, clear otherwise.
  3945. ;
  3946. ;    Flags bit 3 set if this is the first fragment on a diskette accepted
  3947. ;    out of sequence, clear otherwise.
  3948. ;
  3949. ;    Rest_Name contains the complete nul terminated pathspec including
  3950. ;    drive specification of the last fragment processed if any.
  3951. ;
  3952. ;    Rest_Name_Len contains the length of the pathspec of the previously
  3953. ;    processed fragment if any including the drive but not the trailing
  3954. ;    nul.
  3955. ;
  3956. ;    Filespec_Ptr contains the offset of the filename of the previously
  3957. ;    processed fragment relative to Rest_Path if any.
  3958. ;
  3959. ; Returns if successful:
  3960. ;
  3961. ;    Rest_Name contains the complete pathspec of the new fragment
  3962. ;    proposed to be restored with any slashes used as path separators
  3963. ;    converted to backslashes, i.e. MS DOS 3.2 uses slashes instead of
  3964. ;    backslashes for path separators in the BACKUP preambles.
  3965. ;
  3966. ;    Rest_Name_Len contains the length of the new pathspec including the
  3967. ;    drive but not the trailing nul.
  3968. ;
  3969. ;    Filespec_Ptr contains the offset of the filename in the new pathspec
  3970. ;    relative to Rest_path.
  3971. ;
  3972. ;    Carry Flag = clear.
  3973. ;
  3974. ; Returns if diskette dir. scrambled or diskette from another set:
  3975. ;
  3976. ;    Rest_Name, Rest_Name_Len and Filespec_Ptr as on entry.
  3977. ;
  3978. ;    Carry Flag = set.
  3979. ;
  3980.     lea    si, Buffer.P_Hard_Name+1; Skip leading backslash.
  3981.     lea    di, Rest_Path
  3982.     xor    ch, ch
  3983.     mov    cl, Buffer.P_Hard_Len    ; Get length of string to process in cx.
  3984.     dec    cx            ; Don't bother with leading backslash.
  3985.     jle    CP_Err1         ; Nul pathspecs. should never occur.
  3986.     cld
  3987.  
  3988.     test    Flags, WrongOk        ; Diskette out of sequence?
  3989.     jnz    CP_Copy         ; Yes, copy pathspec
  3990.     test    Flags, LastFrag     ; Last file continued?
  3991.     jnz    CP_Copy         ; No, copy new pathspec
  3992.  
  3993. CP_More:
  3994.     cmp    byte ptr [si], '/'    ; Convert slashes to backslashes before
  3995.     jnz    CP_Compare        ; comparison.
  3996.     mov    byte ptr [si], '\'    ; Convert '/' to '\'.
  3997. CP_Compare:
  3998.     cmpsb
  3999.     jnz    CP_Err2         ; New pathspec is different.
  4000.     loop    CP_More
  4001.     clc                ; Return NC = all is in order.
  4002.     ret
  4003.  
  4004. CP_Copy:
  4005.     lodsb                ; Copy pathspec
  4006.     cmp    al, '/'         ; Convert slashes to backslashes.
  4007.     jnz    CP_Not_Slash
  4008.     mov    al, '\'
  4009. CP_Not_Slash:
  4010.     stosb
  4011.     loop    CP_Copy
  4012.  
  4013.     mov    cl, Buffer.P_Hard_Len    ; Calculate length of pathspec
  4014.     inc    cx            ; Add 2 for d: and subtract 1 for nul.
  4015.     mov    Rest_Name_Len, cx
  4016.  
  4017.     mov    al, '\'         ; Calculate offset of filespec
  4018.     dec    di            ; Point at trailing nul of Rest_Name.
  4019.     std                ; Scan backward for first '\'.
  4020.     repne    scasb
  4021.     jcxz    CP_Err1         ; Should never get that far.
  4022.     dec    cx
  4023.     mov    Filespec_Ptr, cx
  4024.     cld
  4025.  
  4026.     clc                ; NC = all is in order.
  4027.     ret
  4028.  
  4029. CP_Err1:
  4030.     Say_Err_Msg    Unknown
  4031.     call        Abort
  4032.  
  4033. CP_Err2:
  4034.     stc                ; Return CY meaning dir. is scrambled or
  4035.     ret                ; diskette is from another set.
  4036. Copy_Pathspec    endp
  4037.  
  4038. ;==============================================================
  4039.  
  4040. Scramble_Check proc near
  4041. ; DOS 3.2
  4042. ; Nested in Restore_file
  4043. ; Check for file fragments which are out of sequence either because the current
  4044. ; diskette is from another set or because the diskette directory has been
  4045. ; scrambled.  Return CY if there's a problem, NC otherwise.  If all is well,
  4046. ; this routine also resets the diskette out of sequence and new diskette flags,
  4047. ; calculates the next fragment sequence no., and sets the last fragment flag
  4048. ; according to the current file fragment.
  4049.     mov    dx, Want_Frag_Seq    ; Save Want_Frag_Seq.
  4050.     cmp    dx, Buffer.P_Frag_Seq    ; Is this what was expected?
  4051.     je    SC_OK            ; Yes, return to caller.
  4052.  
  4053.     test    Flags, WrongOk        ; Was this diskette accepted out of
  4054.                     ; sequence?
  4055.     jnz    SC_OK            ; Yes, no problem.
  4056.     stc                ; CY = dir. is scrambled or
  4057.     ret                ; diskette is from another set.
  4058.  
  4059. SC_OK:
  4060.     and    Flags, 0ffh-(WrongOk+NewDisk+LastFrag)
  4061.                     ; 0f2h
  4062.                     ; Clear diskette out of sequence, new
  4063.                     ; diskette, and last fragment flags.
  4064.     mov    ax, Buffer.P_Frag_Seq    ; Calculate next sequence no.
  4065.     inc    ax
  4066.     cmp    Buffer.P_Last, 0    ; Is this last fragment of current file?
  4067.     je    SC_More         ; No.
  4068.     mov    ax, 1            ; Yes, reset fragment sequence no.
  4069.     or    Flags, LastFrag     ; and set last fragment flag.
  4070. SC_More:
  4071.     mov    Want_Frag_Seq, ax
  4072.  
  4073.     clc                ; NC = all is in order.
  4074.     ret
  4075.  
  4076. Scramble_Check    endp
  4077.  
  4078. ;==============================================================
  4079.  
  4080. Restore_File endp
  4081.  
  4082. ;==============================================================
  4083.  
  4084. Initial_Checks proc near
  4085.  
  4086. ; Make sure DOS version is 2.0 or later and that there is sufficient memory to
  4087. ; run RESTORE.
  4088.     mov    ah, 30H         ; Function = Get DOS Version.
  4089.     int    21H
  4090.     or    ax, ax            ; Abort if DOS Version below 2.0.
  4091.     jnz    RM_Ver_OK
  4092.     lea    dx, Wrong_Ver
  4093.     mov    ah, 9            ; Function = Write String to Console.
  4094.     int    21H            ; Use DOS 1.0 method.
  4095.     ret
  4096.  
  4097. RM_Ver_OK:
  4098.     cmp    sp, 100H + offset Buffer + BUFF_SIZE + STACK_SIZE
  4099.     ja    RM_Enough_Mem        ; Abort if insufficient memory.
  4100.     Say_Err_Msg    Insufficient
  4101.     call        Abort
  4102.  
  4103. RM_Enough_Mem:
  4104.     ret
  4105.     Initial_Checks    EndP
  4106.  
  4107. ;==============================================================
  4108.  
  4109. Old_Main   proc near
  4110. ; DOS 3.2
  4111. ; Perform the restore operation using the DOS 3.2 format.
  4112.     Say_Msg Old_Bkp_Format
  4113.  
  4114. OM_Next_Disk:
  4115.     lea    dx, All_Pattern     ; Get first file to restore.
  4116. Comment |
  4117. Rumor has it that MS DOS 3.2 might not return all normal files unless subdirs.
  4118. are requested as well.    Therefore, subdirs are included in the search here and
  4119. filtered out later by Bypass_Bkp_ID.
  4120. | End of comment.
  4121.     mov    cx, 16H         ; Include system and hidden files.  Bits
  4122.                     ; for RO. and Arc. have no effect, these
  4123.                     ; bits do not exclude a file from being
  4124.                     ; "normal".
  4125.     mov    ah, 4EH         ; Function = Search For First.
  4126. OM_Next:
  4127.     int    21H            ; Get next file.
  4128.     jc    OM_No_More        ; CY = no more files on this diskette.
  4129.     call    Restore_File
  4130.     jc    OM_No_More        ; This diskette was rejected.
  4131.     mov    ah, 4FH         ; Function = Search For Next.
  4132.     jmp    short OM_Next        ; Get next file to restore.
  4133.  
  4134. OM_No_More:
  4135.     test    Flags, LastDisk     ; Is this the last diskette?
  4136.     jnz    OM_Done         ; Yes, exit.
  4137.     CALL    Get_Next_Disk        ; No, get next diskette of set.
  4138.     jmp    OM_Next_Disk
  4139.  
  4140. OM_Done:
  4141.     call    Bye            ; Return to DOS.
  4142. Old_Main    endp
  4143.  
  4144. ;==============================================================
  4145. ;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
  4146. ;        M A I N L I N E    R O U T I N E
  4147. ;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
  4148. ;==============================================================
  4149.  
  4150. Restore_Main proc near
  4151. ; DOS 3.3 and 3.2 (most of 3.2 handled by Old_Main)
  4152.     Call    Initial_Checks        ; Check DOS version and for sufficient
  4153.                     ; memory.
  4154.     call    Parse            ; parse command line.
  4155.     test    Cmd_Flags, Quietly    ; /Q switch specified?
  4156.     jnz    RM_Quiet        ; Yes, skip banner.
  4157.     Say_Msg Banner
  4158.     Call    Strike_Any_Key
  4159. RM_Quiet:
  4160.     call    Get_Next_Disk
  4161.     test    Format_Flags, DOS32    ; Is this set in old backup format?
  4162.     jnz    Old_Main        ; Yes, do DOS 3.2 restore.
  4163.                     ; No, proceed with DOS 3.3 restore.
  4164.     Say_Msg New_Bkp_Format
  4165.  
  4166. RM_More:
  4167.     call    Open_Ctl_File
  4168.     call    Open_Bkp_File
  4169.     call    Process_Hdr
  4170.     call    Get_Subdir        ; CY means that the continuation
  4171.     jc    RM_Again        ; of a file on this diskette had a
  4172.                     ; different dirspec. than the previous
  4173.                     ; fragment, probably indicating the
  4174.                     ; diskette is from another set.
  4175.     call    Close_Bkp_File
  4176.     call    Close_Ctl_File
  4177.  
  4178.     test    Flags, LastDisk     ; Is this the last diskette?
  4179.     jnz    RM_Done         ; If so, exit to DOS.
  4180. RM_Again:
  4181.     call    Get_Next_Disk
  4182.     jmp    RM_More         ; Go back for more.
  4183.  
  4184. RM_Done:
  4185.     call    Bye            ; Terminate with return code of 0.
  4186.  
  4187. Restore_Main    endp
  4188.  
  4189. ;==============================================================
  4190.  
  4191.     even
  4192.  
  4193. Buffer    label    byte            ; Buffer for disk I/O.    Will actually be
  4194.                     ; Buffer BUFF_SIZE dup (?).
  4195.                     ; we place buffer here
  4196.                     ; it won't take space in
  4197.                     ; load module.
  4198. Code    ends
  4199.     end Start
  4200.